[PATCH v9 0/3] MR10869: atl: Implement registering ATL window messages.
The [documentation](https://source.winehq.org/WineAPI/AtlAxWinInit.html) for `AtlAxWinInit` states that it initialises ATL's control hosting code by registering window classes "_and some messages_". MSDN's documentation phrases this as "_plus a couple of custom window messages_", but Wine's implementation didn't register any custom window messages. Logging calls to `RegisterWindowMessage` showed that Visual Studio 2005, when going into Options -\> Projects and Solutions -\> VC++ Directories, calls this function to get the message IDs for custom messages name `WM_ATLGETCONTROL` and `WM_ATLGETHOST`. I've then registered those same messages in `AtlAxWinInit` and logged when they were called in `AtlAxWin_wndproc`. Since they were called with 0 for both `wParam` and `lParam`, the only sensible implementation would be routing the calls through `AtlAxGetControl` and `AtlAxGetHost` and returning the `IUnknown` pointer from the window procedure. This minor change now makes the VC++ Directories control in Visual Studio 2005 work as expected (and probably other stuff too). In that, it fixes one of the problems listed on the [Visual Studio 2005 AppDb page](https://appdb.winehq.org/objectManager.php?sClass=version&iId=4494), specifically as described in the comment "Building" posted by Dave on 2021-08-01. -- v9: Clean up nicely after test. https://gitlab.winehq.org/wine/wine/-/merge_requests/10869
From: Steven Don <gitlab@shdon.com> The MSDN documentation for AtlAxWinInit states that it initialises ATL's control hosting code by registering window classes *plus a couple of custom window messages* Logging calls to `RegisterWindowMessage` showed that Visual Studio 2005, when going into Options -> Projects and Solutions -> VC++ Directories, calls this function to get the message IDs for custom messages name WM_ATLGETCONTROL and WM_ATLGETHOST. I've then registered those same messages in AtlAxWinInit and logged when they were called in `AtlAxWin_wndproc`. Since they were called with 0 for both `wParam` and `lParam`, the only sensible implementation would be routing the calls through `AtlAxGetControl` and `AtlAxGetHost` and returning the `IUnknown` pointer from the window procedure. This change now makes the VC++ Directories control in Visual Studio 2005 work as expected (and probably other stuff too). --- dlls/atl/atl_ax.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dlls/atl/atl_ax.c b/dlls/atl/atl_ax.c index 4ff0a796d3b..3bf2ce662e4 100644 --- a/dlls/atl/atl_ax.c +++ b/dlls/atl/atl_ax.c @@ -55,6 +55,9 @@ typedef struct IOCS { BOOL fActive, fInPlace, fWindowless; } IOCS; +static UINT wmAtlGetHost = 0; +static UINT wmAtlGetControl = 0; + /********************************************************************** * AtlAxWin class window procedure */ @@ -71,6 +74,18 @@ static LRESULT CALLBACK AtlAxWin_wndproc( HWND hWnd, UINT wMsg, WPARAM wParam, L free( ptr ); return 0; } + if ( wMsg == wmAtlGetControl ) + { + IUnknown *control = NULL; + AtlAxGetControl( hWnd, &control ); + return (LRESULT)control; + } + if ( wMsg == wmAtlGetHost ) + { + IUnknown *host = NULL; + AtlAxGetHost( hWnd, &host ); + return (LRESULT)host; + } return DefWindowProcW( hWnd, wMsg, wParam, lParam ); } @@ -132,6 +147,11 @@ BOOL WINAPI AtlAxWinInit(void) return FALSE; } + if (!wmAtlGetControl) + wmAtlGetControl = RegisterWindowMessageW( L"WM_ATLGETCONTROL" ); + if (!wmAtlGetHost) + wmAtlGetHost = RegisterWindowMessageW( L"WM_ATLGETHOST" ); + return TRUE; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10869
From: Steven Don <gitlab@shdon.com> --- dlls/atl/tests/atl_ax.c | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/dlls/atl/tests/atl_ax.c b/dlls/atl/tests/atl_ax.c index 26e4ea5a54d..61bf5f62ee9 100644 --- a/dlls/atl/tests/atl_ax.c +++ b/dlls/atl/tests/atl_ax.c @@ -128,6 +128,47 @@ static void test_ax_win(void) ok(wcex.style == CS_GLOBALCLASS, "wcex.style %08x\n", wcex.style); } +static void test_atl_messages(void) +{ + UINT wmAtlGetHost = 0; + UINT wmAtlGetControl = 0; + HWND hwnd; + HRESULT ret; + IUnknown *host1 = NULL; + IUnknown *ctrl1 = NULL; + IUnknown *host2 = NULL; + IUnknown *ctrl2 = NULL; + + /* Already called by test_ax_win, but left in to allow this test to be standalone */ + AtlAxWinInit(); + + wmAtlGetHost = RegisterWindowMessageW( L"WM_ATLGETHOST" ); + wmAtlGetControl = RegisterWindowMessageW( L"WM_ATLGETCONTROL" ); + + hwnd = CreateWindowExW(0, L"AtlAxWin", L"Shell.Explorer", 0, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, NULL, NULL, NULL, NULL); + ok(hwnd != NULL, "Failed to create AtlAxWin window\n"); + + ret = AtlAxGetHost(hwnd, &host1); + ok(ret == S_OK, "AtlAxGetHost failed\n"); + ok(host1 != NULL, "AtlAxGetHost did not fill the out pointer\n"); + + ret = AtlAxGetControl(hwnd, &ctrl1); + ok(ret == S_OK, "AtlAxGetControl failed\n"); + ok(ctrl1 != NULL, "AtlAxGetControl did not fill the out pointer\n"); + + host2 = (IUnknown *)SendMessageW(hwnd, wmAtlGetHost, 0, 0); + ok(host2 != NULL, "WM_ATLGETHOST did not return a value\n"); + ctrl2 = (IUnknown *)SendMessageW(hwnd, wmAtlGetControl, 0, 0); + ok(ctrl2 != NULL, "WM_ATLGETCONTROL did not return a value\n"); + + ok(host1 == host2, "Mismatch between AtlAxGetHost and WM_ATLGETHOST\n"); + ok(ctrl1 == ctrl2, "Mismatch between AtlAxGetControl and WM_ATLGETCONTROL\n"); + + DestroyWindow(hwnd); +} + START_TEST(atl_ax) { init_function_pointers(); @@ -143,6 +184,7 @@ START_TEST(atl_ax) win_skip("AtlAxAttachControl is not available\n"); test_ax_win(); + test_atl_messages(); CoUninitialize(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10869
From: Steven Don <gitlab@shdon.com> --- dlls/atl/tests/atl_ax.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dlls/atl/tests/atl_ax.c b/dlls/atl/tests/atl_ax.c index 61bf5f62ee9..f2ca9eef081 100644 --- a/dlls/atl/tests/atl_ax.c +++ b/dlls/atl/tests/atl_ax.c @@ -166,6 +166,11 @@ static void test_atl_messages(void) ok(host1 == host2, "Mismatch between AtlAxGetHost and WM_ATLGETHOST\n"); ok(ctrl1 == ctrl2, "Mismatch between AtlAxGetControl and WM_ATLGETCONTROL\n"); + IUnknown_Release(host1); + IUnknown_Release(ctrl1); + IUnknown_Release(host2); + IUnknown_Release(ctrl2); + DestroyWindow(hwnd); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10869
On Wed Jun 10 16:47:41 2026 +0000, Alexandre Julliard wrote:
Yes, that looks good, thanks. Please rebase your branch to get rid of the merge commit. Added some cleanup code to the test so that the four retrieved IUknown pointers are released, and removed the merge commit.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10869#note_142660
participants (2)
-
Steven Don -
Steven Don (@shdon)