/* Unit test suite for uxtheme API functions * * Copyright 2006 Paul Vriens * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * */ #include #include "windows.h" #include "vfwmsgs.h" #include "uxtheme.h" #include "msg.h" #include "wine/test.h" static HTHEME (WINAPI * pOpenThemeDataEx)(HWND, LPCWSTR, DWORD); static HPAINTBUFFER (WINAPI *pBeginBufferedPaint)(HDC, const RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *); static HRESULT (WINAPI *pBufferedPaintClear)(HPAINTBUFFER, const RECT *); static HRESULT (WINAPI *pEndBufferedPaint)(HPAINTBUFFER, BOOL); static HRESULT (WINAPI *pGetBufferedPaintBits)(HPAINTBUFFER, RGBQUAD **, int *); static HDC (WINAPI *pGetBufferedPaintDC)(HPAINTBUFFER); static HDC (WINAPI *pGetBufferedPaintTargetDC)(HPAINTBUFFER); static HRESULT (WINAPI *pGetBufferedPaintTargetRect)(HPAINTBUFFER, RECT *); /* For message tests */ enum seq_index { PARENT_SEQ_INDEX, CHILD_SEQ_INDEX, NUM_MSG_SEQUENCES }; static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; static void init_funcs(void) { HMODULE hUxtheme = GetModuleHandleA("uxtheme.dll"); #define UXTHEME_GET_PROC(func) p ## func = (void*)GetProcAddress(hUxtheme, #func) UXTHEME_GET_PROC(BeginBufferedPaint); UXTHEME_GET_PROC(BufferedPaintClear); UXTHEME_GET_PROC(EndBufferedPaint); UXTHEME_GET_PROC(GetBufferedPaintBits); UXTHEME_GET_PROC(GetBufferedPaintDC); UXTHEME_GET_PROC(GetBufferedPaintTargetDC); UXTHEME_GET_PROC(GetBufferedPaintTargetRect); UXTHEME_GET_PROC(BufferedPaintClear); UXTHEME_GET_PROC(OpenThemeDataEx); #undef UXTHEME_GET_PROC } /* Try to make sure pending X events have been processed before continuing */ static void flush_events(void) { MSG msg; int diff = 200; int min_timeout = 100; DWORD time = GetTickCount() + diff; while (diff > 0) { if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break; while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); diff = time - GetTickCount(); } } static LRESULT WINAPI TestSetWindowThemeParentProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static LONG defwndproc_counter; struct message msg = {0}; LRESULT ret; /* Only care about WM_THEMECHANGED */ if (message != WM_THEMECHANGED) return DefWindowProcA(hwnd, message, wParam, lParam); msg.message = message; msg.flags = sent | wparam | lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; add_message(sequences, PARENT_SEQ_INDEX, &msg); InterlockedIncrement(&defwndproc_counter); ret = DefWindowProcA(hwnd, message, wParam, lParam); InterlockedDecrement(&defwndproc_counter); return ret; } static LRESULT WINAPI TestSetWindowThemeChildProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static LONG defwndproc_counter; struct message msg = {0}; LRESULT ret; /* Only care about WM_THEMECHANGED */ if (message != WM_THEMECHANGED) return DefWindowProcA(hwnd, message, wParam, lParam); msg.message = message; msg.flags = sent | wparam | lparam; if (defwndproc_counter) msg.flags |= defwinproc; msg.wParam = wParam; msg.lParam = lParam; add_message(sequences, CHILD_SEQ_INDEX, &msg); InterlockedIncrement(&defwndproc_counter); ret = DefWindowProcA(hwnd, message, wParam, lParam); InterlockedDecrement(&defwndproc_counter); return ret; } static void test_IsThemed(void) { BOOL bThemeActive; BOOL bAppThemed; BOOL bTPDefined; bThemeActive = IsThemeActive(); trace("Theming is %s\n", (bThemeActive) ? "active" : "inactive"); bAppThemed = IsAppThemed(); trace("Test executable is %s\n", (bAppThemed) ? "themed" : "not themed"); SetLastError(0xdeadbeef); bTPDefined = IsThemePartDefined(NULL, 0 , 0); ok( bTPDefined == FALSE, "Expected FALSE\n"); ok( GetLastError() == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", GetLastError()); } static void test_GetWindowTheme(void) { HTHEME hTheme; HWND hWnd; SetLastError(0xdeadbeef); hTheme = GetWindowTheme(NULL); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", GetLastError() ); /* Only do the bare minimum to get a valid hwnd */ hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL); ok(hWnd != NULL, "Failed to create a test window.\n"); SetLastError(0xdeadbeef); hTheme = GetWindowTheme(hWnd); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); DestroyWindow(hWnd); } static const struct message SetWindowThemeSeq[] = { {WM_THEMECHANGED, sent}, {0} }; static const struct message EmptySeq[] = { {0} }; static void test_SetWindowTheme(void) { WNDCLASSA cls = {0}; HWND hWnd, child; HTHEME hTheme; HRESULT hRes; MSG msg; hRes = SetWindowTheme(NULL, NULL, NULL); ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes); /* Test that WM_THEMECHANGED is sent and not posted to windows */ cls.hInstance = GetModuleHandleA(0); cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); cls.hbrBackground = GetStockObject(WHITE_BRUSH); cls.lpfnWndProc = TestSetWindowThemeParentProcA; cls.lpszClassName = "TestSetWindowThemeParentClass"; RegisterClassA(&cls); cls.lpfnWndProc = TestSetWindowThemeChildProcA; cls.lpszClassName = "TestSetWindowThemeChildClass"; RegisterClassA(&cls); hWnd = CreateWindowA("TestSetWindowThemeParentClass", "parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 200, 200, 0, 0, 0, NULL); ok(!!hWnd, "Failed to create a parent window.\n"); child = CreateWindowA("TestSetWindowThemeChildClass", "child", WS_CHILD | WS_VISIBLE, 0, 0, 50, 50, hWnd, 0, 0, NULL); ok(!!child, "Failed to create a child window.\n"); flush_events(); flush_sequences(sequences, NUM_MSG_SEQUENCES); hRes = SetWindowTheme(hWnd, NULL, NULL); ok(hRes == S_OK, "Expected %#x, got %#x.\n", S_OK, hRes); while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { struct message recv_msg = {0}; if (msg.message == WM_THEMECHANGED) { recv_msg.message = msg.message; recv_msg.flags = posted | wparam | lparam; recv_msg.wParam = msg.wParam; recv_msg.lParam = msg.lParam; add_message(sequences, msg.hwnd == hWnd ? PARENT_SEQ_INDEX : CHILD_SEQ_INDEX, &recv_msg); } DispatchMessageA(&msg); } ok_sequence(sequences, PARENT_SEQ_INDEX, SetWindowThemeSeq, "SetWindowTheme parent", FALSE); ok_sequence(sequences, CHILD_SEQ_INDEX, EmptySeq, "SetWindowTheme child", FALSE); DestroyWindow(hWnd); UnregisterClassA("TestSetWindowThemeParentClass", GetModuleHandleA(0)); UnregisterClassA("TestSetWindowThemeChildClass", GetModuleHandleA(0)); /* Only do the bare minimum to get a valid hwnd */ hWnd = CreateWindowExA(0, "button", "test", WS_POPUP, 0, 0, 100, 100, 0, 0, 0, NULL); ok(hWnd != NULL, "Failed to create a test window.\n"); hRes = SetWindowTheme(hWnd, NULL, NULL); ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); if (IsThemeActive()) { hTheme = OpenThemeData(hWnd, L"Button"); ok(!!hTheme, "OpenThemeData failed.\n"); CloseThemeData(hTheme); hRes = SetWindowTheme(hWnd, L"deadbeef", NULL); ok(hRes == S_OK, "Expected S_OK, got 0x%08x.\n", hRes); hTheme = OpenThemeData(hWnd, L"Button"); ok(!!hTheme, "OpenThemeData failed.\n"); CloseThemeData(hTheme); } else { skip("No active theme, skipping rest of SetWindowTheme tests.\n"); } DestroyWindow(hWnd); } static void test_OpenThemeData(void) { HTHEME hTheme, hTheme2; HWND hWnd; BOOL bThemeActive; HRESULT hRes; BOOL bTPDefined; const WCHAR szInvalidClassList[] = L"DEADBEEF"; const WCHAR szButtonClassList[] = L"Button"; const WCHAR szButtonClassList2[] = L"bUtToN"; const WCHAR szClassList[] = L"Button;ListBox"; bThemeActive = IsThemeActive(); /* All NULL */ SetLastError(0xdeadbeef); hTheme = OpenThemeData(NULL, NULL); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_POINTER, "Expected GLE() to be E_POINTER, got 0x%08x\n", GetLastError()); /* A NULL hWnd and an invalid classlist */ SetLastError(0xdeadbeef); hTheme = OpenThemeData(NULL, szInvalidClassList); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected 0x%08x, got 0x%08x\n", E_PROP_ID_UNSUPPORTED, GetLastError() ); SetLastError(0xdeadbeef); hTheme = OpenThemeData(NULL, szClassList); if (bThemeActive) { ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); } else { ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected 0x%08x, got 0x%08x\n", E_PROP_ID_UNSUPPORTED, GetLastError() ); } /* Only do the bare minimum to get a valid hdc */ hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL); if (!hWnd) return; SetLastError(0xdeadbeef); hTheme = OpenThemeData(hWnd, NULL); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_POINTER, "Expected GLE() to be E_POINTER, got 0x%08x\n", GetLastError()); SetLastError(0xdeadbeef); hTheme = OpenThemeData(hWnd, szInvalidClassList); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected 0x%08x, got 0x%08x\n", E_PROP_ID_UNSUPPORTED, GetLastError() ); if (!bThemeActive) { SetLastError(0xdeadbeef); hTheme = OpenThemeData(hWnd, szButtonClassList); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected 0x%08x, got 0x%08x\n", E_PROP_ID_UNSUPPORTED, GetLastError() ); skip("No active theme, skipping rest of OpenThemeData tests\n"); return; } /* Only do the next checks if we have an active theme */ SetLastError(0xdeadbeef); hTheme = OpenThemeData(hWnd, szButtonClassList); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); /* Test with bUtToN instead of Button */ SetLastError(0xdeadbeef); hTheme = OpenThemeData(hWnd, szButtonClassList2); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); SetLastError(0xdeadbeef); hTheme = OpenThemeData(hWnd, szClassList); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); /* GetWindowTheme should return the last handle opened by OpenThemeData */ SetLastError(0xdeadbeef); hTheme2 = GetWindowTheme(hWnd); ok( hTheme == hTheme2, "Expected the same HTHEME handle (%p<->%p)\n", hTheme, hTheme2); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); hRes = CloseThemeData(hTheme); ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); /* Close a second time */ hRes = CloseThemeData(hTheme); ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); /* See if closing makes a difference for GetWindowTheme */ SetLastError(0xdeadbeef); hTheme2 = NULL; hTheme2 = GetWindowTheme(hWnd); ok( hTheme == hTheme2, "Expected the same HTHEME handle (%p<->%p)\n", hTheme, hTheme2); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); SetLastError(0xdeadbeef); bTPDefined = IsThemePartDefined(hTheme, 0 , 0); todo_wine { ok( bTPDefined == FALSE, "Expected FALSE\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); } DestroyWindow(hWnd); } static void test_OpenThemeDataEx(void) { HTHEME hTheme; HWND hWnd; BOOL bThemeActive; const WCHAR szInvalidClassList[] = L"DEADBEEF"; const WCHAR szButtonClassList[] = L"Button"; const WCHAR szButtonClassList2[] = L"bUtToN"; const WCHAR szClassList[] = L"Button;ListBox"; if (!pOpenThemeDataEx) { win_skip("OpenThemeDataEx not available\n"); return; } bThemeActive = IsThemeActive(); /* All NULL */ SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(NULL, NULL, 0); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_POINTER, "Expected GLE() to be E_POINTER, got 0x%08x\n", GetLastError()); /* A NULL hWnd and an invalid classlist without flags */ SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(NULL, szInvalidClassList, 0); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected 0x%08x, got 0x%08x\n", E_PROP_ID_UNSUPPORTED, GetLastError() ); SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(NULL, szClassList, 0); if (bThemeActive) { ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); } else { ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected 0x%08x, got 0x%08x\n", E_PROP_ID_UNSUPPORTED, GetLastError() ); } /* Only do the bare minimum to get a valid hdc */ hWnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL); if (!hWnd) return; SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, NULL, 0); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_POINTER, "Expected GLE() to be E_POINTER, got 0x%08x\n", GetLastError()); SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, szInvalidClassList, 0); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected 0x%08x, got 0x%08x\n", E_PROP_ID_UNSUPPORTED, GetLastError() ); if (!bThemeActive) { SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, 0); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected 0x%08x, got 0x%08x\n", E_PROP_ID_UNSUPPORTED, GetLastError() ); skip("No active theme, skipping rest of OpenThemeDataEx tests\n"); return; } /* Only do the next checks if we have an active theme */ SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, 0); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, OTD_FORCE_RECT_SIZING); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, OTD_NONCLIENT); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, szButtonClassList, 0x3); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); /* Test with bUtToN instead of Button */ SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, szButtonClassList2, 0); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); SetLastError(0xdeadbeef); hTheme = pOpenThemeDataEx(hWnd, szClassList, 0); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError() ); DestroyWindow(hWnd); } static void test_GetCurrentThemeName(void) { BOOL bThemeActive; HRESULT hRes; WCHAR currentTheme[MAX_PATH]; WCHAR currentColor[MAX_PATH]; WCHAR currentSize[MAX_PATH]; bThemeActive = IsThemeActive(); /* All NULLs */ hRes = GetCurrentThemeName(NULL, 0, NULL, 0, NULL, 0); if (bThemeActive) ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); /* Number of characters given is 0 */ hRes = GetCurrentThemeName(currentTheme, 0, NULL, 0, NULL, 0); if (bThemeActive) ok( hRes == S_OK || broken(hRes == E_FAIL /* WinXP SP1 */), "Expected S_OK, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); hRes = GetCurrentThemeName(currentTheme, 2, NULL, 0, NULL, 0); if (bThemeActive) todo_wine ok(hRes == E_NOT_SUFFICIENT_BUFFER || broken(hRes == E_FAIL /* WinXP SP1 */), "Expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); /* The same is true if the number of characters is too small for Color and/or Size */ hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), currentColor, 2, currentSize, ARRAY_SIZE(currentSize)); if (bThemeActive) todo_wine ok(hRes == E_NOT_SUFFICIENT_BUFFER || broken(hRes == E_FAIL /* WinXP SP1 */), "Expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); /* Given number of characters is correct */ hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), NULL, 0, NULL, 0); if (bThemeActive) ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); /* Given number of characters for the theme name is too large */ hRes = GetCurrentThemeName(currentTheme, sizeof(currentTheme), NULL, 0, NULL, 0); if (bThemeActive) ok( hRes == E_POINTER || hRes == S_OK, "Expected E_POINTER or S_OK, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED || hRes == E_POINTER, /* win2k3 */ "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); /* The too large case is only for the theme name, not for color name or size name */ hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), currentColor, sizeof(currentTheme), currentSize, ARRAY_SIZE(currentSize)); if (bThemeActive) ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), currentColor, ARRAY_SIZE(currentTheme), currentSize, sizeof(currentSize)); if (bThemeActive) ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); /* Correct call */ hRes = GetCurrentThemeName(currentTheme, ARRAY_SIZE(currentTheme), currentColor, ARRAY_SIZE(currentColor), currentSize, ARRAY_SIZE(currentSize)); if (bThemeActive) ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); } static void test_CloseThemeData(void) { HRESULT hRes; hRes = CloseThemeData(NULL); ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes); hRes = CloseThemeData(INVALID_HANDLE_VALUE); ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes); } static void test_buffer_dc_props(HDC hdc, const RECT *rect) { static const XFORM ident = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }; XFORM xform; POINT org; RECT box; BOOL ret; ret = GetWorldTransform(hdc, &xform); ok(ret, "Failed to get world transform\n"); ok(!memcmp(&xform, &ident, sizeof(xform)), "Unexpected world transform\n"); ret = GetViewportOrgEx(hdc, &org); ok(ret, "Failed to get vport origin\n"); ok(org.x == 0 && org.y == 0, "Unexpected vport origin\n"); ret = GetWindowOrgEx(hdc, &org); ok(ret, "Failed to get vport origin\n"); ok(org.x == rect->left && org.y == rect->top, "Unexpected window origin\n"); ret = GetClipBox(hdc, &box); ok(ret, "Failed to get clip box\n"); ok(box.left == rect->left && box.top == rect->top, "Unexpected clip box\n"); ok(GetGraphicsMode(hdc) == GM_COMPATIBLE, "wrong graphics mode\n"); } static void test_buffered_paint(void) { HDC target, src, hdc, screen_dc; BP_PAINTPARAMS params = { 0 }; BP_BUFFERFORMAT format; HPAINTBUFFER buffer; RECT rect, rect2; RGBQUAD *bits; HBITMAP hbm; HRESULT hr; int row; if (!pBeginBufferedPaint) { win_skip("Buffered painting API is not supported.\n"); return; } buffer = pBeginBufferedPaint(NULL, NULL, BPBF_COMPATIBLEBITMAP, NULL, NULL); ok(buffer == NULL, "Unexpected buffer %p\n", buffer); target = CreateCompatibleDC(0); buffer = pBeginBufferedPaint(target, NULL, BPBF_COMPATIBLEBITMAP, NULL, NULL); ok(buffer == NULL, "Unexpected buffer %p\n", buffer); params.cbSize = sizeof(params); buffer = pBeginBufferedPaint(target, NULL, BPBF_COMPATIBLEBITMAP, ¶ms, NULL); ok(buffer == NULL, "Unexpected buffer %p\n", buffer); src = (void *)0xdeadbeef; buffer = pBeginBufferedPaint(target, NULL, BPBF_COMPATIBLEBITMAP, ¶ms, &src); ok(buffer == NULL, "Unexpected buffer %p\n", buffer); ok(src == NULL, "Unexpected buffered dc %p\n", src); /* target rect is mandatory */ SetRectEmpty(&rect); src = (void *)0xdeadbeef; buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP, ¶ms, &src); ok(buffer == NULL, "Unexpected buffer %p\n", buffer); ok(src == NULL, "Unexpected buffered dc %p\n", src); /* inverted rectangle */ SetRect(&rect, 10, 0, 5, 5); src = (void *)0xdeadbeef; buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP, ¶ms, &src); ok(buffer == NULL, "Unexpected buffer %p\n", buffer); ok(src == NULL, "Unexpected buffered dc %p\n", src); SetRect(&rect, 0, 10, 5, 0); src = (void *)0xdeadbeef; buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP, ¶ms, &src); ok(buffer == NULL, "Unexpected buffer %p\n", buffer); ok(src == NULL, "Unexpected buffered dc %p\n", src); /* valid rectangle, no target dc */ SetRect(&rect, 0, 0, 5, 5); src = (void *)0xdeadbeef; buffer = pBeginBufferedPaint(NULL, &rect, BPBF_COMPATIBLEBITMAP, ¶ms, &src); ok(buffer == NULL, "Unexpected buffer %p\n", buffer); ok(src == NULL, "Unexpected buffered dc %p\n", src); SetRect(&rect, 0, 0, 5, 5); src = NULL; buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP, ¶ms, &src); ok(buffer != NULL, "Unexpected buffer %p\n", buffer); ok(src != NULL, "Expected buffered dc\n"); hr = pEndBufferedPaint(buffer, FALSE); ok(hr == S_OK, "Unexpected return code %#x\n", hr); SetRect(&rect, 0, 0, 5, 5); buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP, ¶ms, &src); ok(buffer != NULL, "Unexpected buffer %p\n", buffer); /* clearing */ hr = pBufferedPaintClear(NULL, NULL); todo_wine ok(hr == E_FAIL, "Unexpected return code %#x\n", hr); hr = pBufferedPaintClear(buffer, NULL); todo_wine ok(hr == S_OK, "Unexpected return code %#x\n", hr); /* access buffer attributes */ hdc = pGetBufferedPaintDC(buffer); ok(hdc == src, "Unexpected hdc, %p, buffered dc %p\n", hdc, src); hdc = pGetBufferedPaintTargetDC(buffer); ok(hdc == target, "Unexpected target hdc %p, original %p\n", hdc, target); hr = pGetBufferedPaintTargetRect(NULL, NULL); ok(hr == E_POINTER, "Unexpected return code %#x\n", hr); hr = pGetBufferedPaintTargetRect(buffer, NULL); ok(hr == E_POINTER, "Unexpected return code %#x\n", hr); hr = pGetBufferedPaintTargetRect(NULL, &rect2); ok(hr == E_FAIL, "Unexpected return code %#x\n", hr); SetRectEmpty(&rect2); hr = pGetBufferedPaintTargetRect(buffer, &rect2); ok(hr == S_OK, "Unexpected return code %#x\n", hr); ok(EqualRect(&rect, &rect2), "Wrong target rect\n"); hr = pEndBufferedPaint(buffer, FALSE); ok(hr == S_OK, "Unexpected return code %#x\n", hr); /* invalid buffer handle */ hr = pEndBufferedPaint(NULL, FALSE); ok(hr == E_INVALIDARG, "Unexpected return code %#x\n", hr); hdc = pGetBufferedPaintDC(NULL); ok(hdc == NULL, "Unexpected hdc %p\n", hdc); hdc = pGetBufferedPaintTargetDC(NULL); ok(hdc == NULL, "Unexpected target hdc %p\n", hdc); hr = pGetBufferedPaintTargetRect(NULL, &rect2); ok(hr == E_FAIL, "Unexpected return code %#x\n", hr); hr = pGetBufferedPaintTargetRect(NULL, NULL); ok(hr == E_POINTER, "Unexpected return code %#x\n", hr); bits = (void *)0xdeadbeef; row = 10; hr = pGetBufferedPaintBits(NULL, &bits, &row); ok(hr == E_FAIL, "Unexpected return code %#x\n", hr); ok(row == 10, "Unexpected row count %d\n", row); ok(bits == (void *)0xdeadbeef, "Unexpected data pointer %p\n", bits); hr = pGetBufferedPaintBits(NULL, NULL, NULL); ok(hr == E_POINTER, "Unexpected return code %#x\n", hr); hr = pGetBufferedPaintBits(NULL, &bits, NULL); ok(hr == E_POINTER, "Unexpected return code %#x\n", hr); hr = pGetBufferedPaintBits(NULL, NULL, &row); ok(hr == E_POINTER, "Unexpected return code %#x\n", hr); screen_dc = GetDC(0); hdc = CreateCompatibleDC(screen_dc); ok(hdc != NULL, "Failed to create a DC\n"); hbm = CreateCompatibleBitmap(screen_dc, 64, 64); ok(hbm != NULL, "Failed to create a bitmap\n"); SelectObject(hdc, hbm); ReleaseDC(0, screen_dc); SetRect(&rect, 1, 2, 34, 56); buffer = pBeginBufferedPaint(hdc, &rect, BPBF_COMPATIBLEBITMAP, NULL, &src); test_buffer_dc_props(src, &rect); hr = pEndBufferedPaint(buffer, FALSE); ok(hr == S_OK, "Unexpected return code %#x\n", hr); DeleteObject(hbm); DeleteDC(hdc); buffer = pBeginBufferedPaint(target, &rect, BPBF_COMPATIBLEBITMAP, NULL, &src); test_buffer_dc_props(src, &rect); hr = pEndBufferedPaint(buffer, FALSE); ok(hr == S_OK, "Unexpected return code %#x\n", hr); /* access buffer bits */ for (format = BPBF_COMPATIBLEBITMAP; format <= BPBF_TOPDOWNMONODIB; format++) { buffer = pBeginBufferedPaint(target, &rect, format, ¶ms, &src); /* only works for DIB buffers */ bits = NULL; row = 0; hr = pGetBufferedPaintBits(buffer, &bits, &row); if (format == BPBF_COMPATIBLEBITMAP) ok(hr == E_FAIL, "Unexpected return code %#x\n", hr); else { ok(hr == S_OK, "Unexpected return code %#x\n", hr); ok(bits != NULL, "Bitmap bits %p\n", bits); ok(row >= (rect.right - rect.left), "format %d: bitmap width %d\n", format, row); } hr = pEndBufferedPaint(buffer, FALSE); ok(hr == S_OK, "Unexpected return code %#x\n", hr); } DeleteDC(target); } START_TEST(system) { init_funcs(); init_msg_sequences(sequences, NUM_MSG_SEQUENCES); /* No real functional theme API tests will be done (yet). The current tests * only show input/return behaviour */ test_IsThemed(); test_GetWindowTheme(); test_SetWindowTheme(); test_OpenThemeData(); test_OpenThemeDataEx(); test_GetCurrentThemeName(); test_CloseThemeData(); test_buffered_paint(); }