Embedding IWebBrowser2 in another win32 window : most of the ribbon buttons never get enabled

Julien Houssay 5 Reputation points
2023-03-17T18:50:51.6166667+00:00

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).

enter image description here

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;
}
Windows
Windows
A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.
5,099 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,636 questions
{count} vote

1 answer

Sort by: Most helpful
  1. Castorix31 83,206 Reputation points
    2023-03-17T20:59:56.76+00:00

    Don't use IWebBrowser2

    Use IExplorerBrowser