[PATCH v8 0/2] 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. -- v8: Added tests for proper handling of WM_ATLGETCONTROL and WM_ATLGETHOST. atl: Implement registering ATL window messages. 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
The MR should now be cleaned up to have only the relevant two commits. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10869#note_142646
participants (2)
-
Steven Don -
Steven Don (@shdon)