Don't use IWebBrowser2
Use IExplorerBrowser
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
I try to embed a full file explorer window (with the address bar) in my application. I managed to make it work (and get notified for the events I need) using an IWebBrowser2 which creates a full explorer window which I can reparent to a window I created.
Unfortunately, most of the buttons in the ribbon never get enabled when I select a file or a directory in the explorer window (right side of the figure) while it perfectly works when using a "native" IWebBrowser2 (i.e. an IWebBrowser2 I did not reparent, left side).
It actually seems that the ribbon never get updated when the user navigates or selects an element in the IShellView (the right part of the explorer).
I've attached bellow a sample code that creates these two windows and exhibits this problem.
#include <string>
#include <iostream>
#include <windows.h>
#include <exdisp.h>
#include <uxtheme.h>
#include <comdef.h>
int m_width = 800;
int m_height = 500;
IWebBrowser2* p_ref_wb = nullptr;
HWND m_parentWnd = nullptr;
IWebBrowser2* p_wb = nullptr;
HWND m_wb_hwnd = 0;
std::wstring GetLastErrorAsString()
{
// Get the error message ID, if any.
DWORD errorMessageID = GetLastError();
if (errorMessageID == 0)
return {};
LPWSTR messageBuffer = nullptr;
// Ask Win32 to give us the string version of that message ID.
// The parameters we pass in, tell Win32 to create the buffer that holds the message for us
// (because we don't yet know how long the message string will be).
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&messageBuffer, 0, nullptr);
// Copy the error message into a std::wstring
std::wstring message = messageBuffer;
// Free the Win32's string's buffer.
LocalFree(messageBuffer);
return message;
}
std::wstring GetErrorAsString(HRESULT hr)
{
if (! SUCCEEDED(hr))
{
_com_error err(hr);
if (const TCHAR* errorMsg = err.ErrorMessage())
return errorMsg;
else
return L"Unknown error.";
}
else
return {};
}
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_ERASEBKGND:
// To avoid flicking when the window is moved or resized, we have to ignore this message
return 0;
case WM_SIZE:
{
UINT width = LOWORD(lParam);
UINT height = HIWORD(lParam);
// Estimate the (removed) title bar height
HTHEME htheme = GetWindowTheme(m_wb_hwnd);
int h = GetThemeSysSize(htheme, SM_CXBORDER) + GetThemeSysSize(htheme, SM_CYSIZE) + GetThemeSysSize(htheme, SM_CXPADDEDBORDER) * 2;
// Set the position
BOOL okPos = SetWindowPos( m_wb_hwnd,
nullptr,
0,
- h,
width,
height + h,
SWP_NOZORDER);
if (! okPos)
std::wcerr << L"SetWindowPos failed : " << GetLastErrorAsString() << std::endl;
return 0;
}
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
static HWND CreateTheWindow(LPCWSTR WindowTitle, int width, int height)
{
static LPCWSTR sClassName = L"MyClass";
// Create & register the class
WNDCLASSEX WndClass;
WndClass.cbSize = sizeof(WNDCLASSEX);
WndClass.style = 0u;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.lpszClassName = sClassName;
WndClass.hInstance = nullptr;
WndClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
WndClass.lpszMenuName = nullptr;
WndClass.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
RegisterClassEx(&WndClass);
// Create the window
HWND hwnd = CreateWindowEx( WS_EX_STATICEDGE,
sClassName,
WindowTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
nullptr,
nullptr,
nullptr,
nullptr);
return hwnd;
}
#define CHECK(condition, errorMessage, errorCode) if (! (condition)) { std::wcerr << (errorMessage) << std::endl; return (errorCode); }
int main()
{
// Init
///////
// COM initialization
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
CHECK(SUCCEEDED(hr), L"Unable to initialize COM : " + GetErrorAsString(hr), 1);
// Reference
////////////
// Create the reference IWebBrowser2
hr = CoCreateInstance(CLSID_ShellBrowserWindow, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&p_ref_wb));
CHECK(SUCCEEDED(hr), L"Unable to create reference web browser window : " + GetErrorAsString(hr), 2);
// Make it visible
hr = p_ref_wb->put_Visible(VARIANT_TRUE);
CHECK(SUCCEEDED(hr), L"Could not get show reference web browser : " + GetErrorAsString(hr), 3);
// Embedded
///////////
// Create the parent window
m_parentWnd = CreateTheWindow(L"Embedded IExplorerBrowser", m_width, m_height);
CHECK(m_parentWnd, L"Could not create win32 window", 4);
// Create the Embedded IWebBrowser2
hr = CoCreateInstance(CLSID_ShellBrowserWindow, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&p_wb));
CHECK(SUCCEEDED(hr), L"Unable to create embedded web browser window : " + GetErrorAsString(hr), 5);
// Get the web browser window handle
hr = p_wb->get_HWND((SHANDLE_PTR*) &m_wb_hwnd);
CHECK(SUCCEEDED(hr), L"Could not get embedded web browser window handle : " + GetErrorAsString(hr), 6);
// Change web browser window flags in order to make it a child window
// This will let an empty space for the title bar, cf. WndProc
LONG rslt = SetWindowLong(m_wb_hwnd, GWL_STYLE, WS_CHILDWINDOW);
CHECK(rslt != 0, L"Could not change web browser window style : " + GetLastErrorAsString(), 7);
// Reparent the web browser window
HWND oldId = SetParent(m_wb_hwnd, m_parentWnd);
CHECK(oldId, L"Could not change embbeded web browser window parent : " + GetLastErrorAsString(), 8);
// Make it visible
ShowWindow(m_parentWnd, SW_SHOW);
UpdateWindow(m_parentWnd);
hr = p_wb->put_Visible(VARIANT_TRUE);
CHECK(SUCCEEDED(hr), L"Could not get show embedded web browser : " + GetErrorAsString(hr), 9);
// Loop
///////
MSG msg;
BOOL bRet;
while ( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Finalization
///////////////
p_wb->Quit();
p_wb->Release();
DestroyWindow(m_parentWnd);
p_ref_wb->Quit();
p_ref_wb->Release();
CoUninitialize();
// Return the exit code to the system
return (int) msg.wParam;
}
Don't use IWebBrowser2
Use IExplorerBrowser