Follow Up of Merge request !693 by Jacek Caban. That pull request changed properly the static control of user32, but didn't address the comctl32 static control.
Fix an issue of TES4:Oblivion Construction Set, reported by me in the Wine Bug: https://bugs.winehq.org/show_bug.cgi?id=53581#c5 after the merge request fixed the reported CS crash.
Signed-off-by: Lorenzo Ferrillo [lorenzofersteam@live.it](mailto:lorenzofersteam@live.it)
-- v3: comctl32: Support passing bitmap and icon resource ID as a string when creating static control.
From: Lorenzo Ferrillo lorenzofersteam@live.it
Follow Up of Merge request #693 by Jacek Caban. The pull request changed properly the static control of user32, but didn't address the comctl32 static control.
Fix an issue of TES4:Oblivion Construction Set, reported by me in Wine Bug: https://bugs.winehq.org/show_bug.cgi?id=53581#c5 after the merge request fixed the reported CS crash. --- dlls/comctl32/static.c | 10 ++++++++-- dlls/comctl32/tests/static.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/dlls/comctl32/static.c b/dlls/comctl32/static.c index c09655da903..db97bf454b5 100644 --- a/dlls/comctl32/static.c +++ b/dlls/comctl32/static.c @@ -437,6 +437,7 @@ static BOOL hasTextStyle( DWORD style )
static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { + const WCHAR* window_name = NULL; LRESULT lResult = 0; LONG full_style = GetWindowLongW( hwnd, GWL_STYLE ); LONG style = full_style & SS_TYPEMASK; @@ -549,13 +550,18 @@ static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, SetWindowPos(hwnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); }
+ if (cs->lpszName && cs->lpszName[0] == 0xffff) /*String is resource index */ + window_name = MAKEINTRESOURCEW(cs->lpszName[1]); + else + window_name = cs->lpszName; + switch (style) { case SS_ICON: { HICON hIcon;
- hIcon = STATIC_LoadIconW(cs->hInstance, cs->lpszName, full_style); + hIcon = STATIC_LoadIconW(cs->hInstance, window_name, full_style); STATIC_SetIcon(hwnd, hIcon, full_style); } break; @@ -563,7 +569,7 @@ static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, if ((ULONG_PTR)cs->hInstance >> 16) { HBITMAP hBitmap; - hBitmap = LoadBitmapW(cs->hInstance, cs->lpszName); + hBitmap = LoadBitmapW(cs->hInstance, window_name); STATIC_SetBitmap(hwnd, hBitmap, full_style); } break; diff --git a/dlls/comctl32/tests/static.c b/dlls/comctl32/tests/static.c index 756fed86fe0..551aca2720f 100644 --- a/dlls/comctl32/tests/static.c +++ b/dlls/comctl32/tests/static.c @@ -216,6 +216,8 @@ static void test_image(HBITMAP image, BOOL is_dib, BOOL is_premult, BOOL is_alph
static void test_set_image(void) { + char resource[4]; + WCHAR resource_unicode[3]; HWND hwnd = create_static(SS_BITMAP); HBITMAP bmp1, bmp2, image;
@@ -270,6 +272,33 @@ static void test_set_image(void)
test_image(image, TRUE, FALSE, FALSE);
+ resource[0] = '\xff'; + resource[1] = PtrToUlong(MAKEINTRESOURCEW(IDB_BITMAP_1x1_32BPP)); + resource[2] = PtrToUlong(MAKEINTRESOURCEW(IDB_BITMAP_1x1_32BPP)) >> 8; + resource[3] = 0; + + resource_unicode[0] = 0xffff; + resource_unicode[1] = PtrToUlong(MAKEINTRESOURCEW(IDB_BITMAP_1x1_32BPP)); + resource_unicode[2] = 0; + + hwnd = CreateWindowW(L"Static", resource_unicode, WS_VISIBLE|WS_CHILD|SS_BITMAP, 5, 5, 100, 100, + hMainWnd, (HMENU)CTRL_ID, GetModuleHandleW(NULL), 0); + + bmp1 = (HBITMAP)SendMessageW(hwnd, STM_GETIMAGE, IMAGE_BITMAP, 0); + ok(bmp1 != NULL, "got NULL\n"); + ok(bmp1 != image, "bmp == image\n"); + test_image(bmp1, TRUE, TRUE, TRUE); + DestroyWindow(hwnd); + + hwnd = CreateWindowA("Static", resource, WS_VISIBLE|WS_CHILD|SS_BITMAP, 5, 5, 100, 100, + hMainWnd, (HMENU)CTRL_ID, GetModuleHandleW(NULL), 0); + + bmp1 = (HBITMAP)SendMessageA(hwnd, STM_GETIMAGE, IMAGE_BITMAP, 0); + ok(bmp1 != NULL, "got NULL\n"); + ok(bmp1 != image, "bmp == image\n"); + test_image(bmp1, TRUE, TRUE, TRUE); + DestroyWindow(hwnd); + DeleteObject(image); }
Hi again @nsivov . How can I check the name of a window from the HWND? WINAPI have a FindWindow family functions that take the class and window name as inputs, but it doesn't seem to exist an HWND to name. The only function that come closer is GetWindowText that return the bar text, but we have no bar (its actually delegate to the control using WM_GETTEXT message). Calling this function on the static window return blank buffer.
I could subclass the Static class to hook WN_NCCREATE (this is how the static user32 test are done, but that hook the window that is created with a dummy class and that the class dialog is created with a separate function and it's not clear where the HWND is passed), but there is a guarantee that the what is passed in the params before and after the call is the actual name of the window?
That's right, GetWindowText() is the one. It's used for window text that any window can have, it's not limited to a window caption. For example Edit control will return current text contents.
@nsivov I made specific tests for the static component both in comctl32 and in user32, and in both cases the window name is empty ("") on windows. I also write the same test in user32 win.c test and let the wine testbot execute it. Even here on windows machines it seems that it's expecting an empty name here too (so it's class independant)
What do you think? It's better to keep only the user32::win tests and fix the issue here, or use the static test and instead trying to fix the issue only for the static control?
The windows name for static controls are setted in win32u defwnd.c procedure. In fact the set_Text function have a control about IS_INTRESOURCE to block assigning the name there.
However whne using MainWindowClass as class, when it hit this procedure the name is null. However it still return ?3 in the test.
It's fine to focus on getting first part fixed first, to make comctl32/static behave like user32/static to fix that new crash. Later we can address text issue separately.
@nsivov the commit already made already fix the issue I was experiencing.
Nikolay Sivov (@nsivov) commented about dlls/comctl32/static.c:
static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
- const WCHAR* window_name = NULL;
You don't need to initialize it here. Also please reformat as "const WCHAR *window_name;"
Nikolay Sivov (@nsivov) commented about dlls/comctl32/static.c:
SetWindowPos(hwnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); }
if (cs->lpszName && cs->lpszName[0] == 0xffff) /*String is resource index */
The comment could be removed, it's obvious how next character is used.