/* 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 "wine/test.h" static HRESULT (WINAPI * pCloseThemeData)(HTHEME); static HRESULT (WINAPI * pGetCurrentThemeName)(LPWSTR, int, LPWSTR, int, LPWSTR, int); static HTHEME (WINAPI * pGetWindowTheme)(HWND); static BOOL (WINAPI * pIsAppThemed)(VOID); static BOOL (WINAPI * pIsThemeActive)(VOID); static BOOL (WINAPI * pIsThemePartDefined)(HTHEME, int, int); static HTHEME (WINAPI * pOpenThemeData)(HWND, LPCWSTR); static HRESULT (WINAPI * pSetWindowTheme)(HWND, LPCWSTR, LPCWSTR); static HMODULE hUxtheme = 0; #define UXTHEME_GET_PROC(func) \ p ## func = (void*)GetProcAddress(hUxtheme, #func); \ if(!p ## func) { \ trace("GetProcAddress(%s) failed\n", #func); \ FreeLibrary(hUxtheme); \ return FALSE; \ } static BOOL InitFunctionPtrs(void) { hUxtheme = LoadLibraryA("uxtheme.dll"); if(!hUxtheme) { trace("Could not load uxtheme.dll\n"); return FALSE; } if (hUxtheme) { UXTHEME_GET_PROC(CloseThemeData) UXTHEME_GET_PROC(GetCurrentThemeName) UXTHEME_GET_PROC(GetWindowTheme) UXTHEME_GET_PROC(IsAppThemed) UXTHEME_GET_PROC(IsThemeActive) UXTHEME_GET_PROC(IsThemePartDefined) UXTHEME_GET_PROC(OpenThemeData) UXTHEME_GET_PROC(SetWindowTheme) } /* The following functions should be available, if not return FALSE. The Vista functions will * be checked (at some point in time) within the single tests if needed. All used functions for * now are present on WinXP, W2K3 and Wine. */ if (!pCloseThemeData || !pGetCurrentThemeName || !pGetWindowTheme || !pIsAppThemed || !pIsThemeActive || !pIsThemePartDefined || !pOpenThemeData || !pSetWindowTheme) return FALSE; return TRUE; } static void test_IsThemed(void) { BOOL bThemeActive; BOOL bAppThemed; BOOL bTPDefined; SetLastError(0xdeadbeef); bThemeActive = pIsThemeActive(); trace("Theming is %s\n", (bThemeActive) ? "active" : "inactive"); todo_wine ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); /* This test is not themed */ SetLastError(0xdeadbeef); bAppThemed = pIsAppThemed(); if (bThemeActive) todo_wine ok( bAppThemed == FALSE, "Expected FALSE as this test executable is not (yet) themed.\n"); else /* Although Wine currently returns FALSE, the logic behind it is wrong. It is not a todo_wine though in the testing sense */ ok( bAppThemed == FALSE, "Expected FALSE as this test executable is not (yet) themed.\n"); todo_wine ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); SetLastError(0xdeadbeef); bTPDefined = pIsThemePartDefined(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; BOOL bDestroyed; SetLastError(0xdeadbeef); hTheme = pGetWindowTheme(NULL); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); todo_wine 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); if (!hWnd) return; SetLastError(0xdeadbeef); hTheme = pGetWindowTheme(hWnd); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); bDestroyed = DestroyWindow(hWnd); if (!bDestroyed) trace("Window %p couldn't be destroyed : 0x%08x\n", hWnd, GetLastError()); } static void test_SetWindowTheme(void) { HRESULT hRes; HWND hWnd; BOOL bDestroyed; SetLastError(0xdeadbeef); hRes = pSetWindowTheme(NULL, NULL, NULL); todo_wine { ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, 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); if (!hWnd) return; SetLastError(0xdeadbeef); hRes = pSetWindowTheme(hWnd, NULL, NULL); ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); bDestroyed = DestroyWindow(hWnd); if (!bDestroyed) trace("Window %p couldn't be destroyed : 0x%08x\n", hWnd, GetLastError()); } static void test_OpenThemeData(void) { HTHEME hTheme, hTheme2; HWND hWnd; BOOL bThemeActive; HRESULT hRes; BOOL bDestroyed; BOOL bTPDefined; WCHAR szInvalidClassList[] = {'D','E','A','D','B','E','E','F', 0 }; WCHAR szButtonClassList[] = {'B','u','t','t','o','n', 0 }; WCHAR szButtonClassList2[] = {'b','U','t','T','o','N', 0 }; WCHAR szClassList[] = {'B','u','t','t','o','n',';','L','i','s','t','B','o','x', 0 }; bThemeActive = pIsThemeActive(); /* All NULL */ SetLastError(0xdeadbeef); hTheme = pOpenThemeData(NULL, NULL); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); todo_wine 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 = pOpenThemeData(NULL, szInvalidClassList); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); todo_wine ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n", GetLastError()); SetLastError(0xdeadbeef); hTheme = pOpenThemeData(NULL, szClassList); if (bThemeActive) { ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); todo_wine ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); } else { ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); todo_wine ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n", 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 = pOpenThemeData(hWnd, NULL); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); todo_wine ok( GetLastError() == E_POINTER, "Expected GLE() to be E_POINTER, got 0x%08x\n", GetLastError()); SetLastError(0xdeadbeef); hTheme = pOpenThemeData(hWnd, szInvalidClassList); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); todo_wine ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n", GetLastError()); if (!bThemeActive) { SetLastError(0xdeadbeef); hTheme = pOpenThemeData(hWnd, szButtonClassList); ok( hTheme == NULL, "Expected a NULL return, got %p\n", hTheme); todo_wine ok( GetLastError() == E_PROP_ID_UNSUPPORTED, "Expected GLE() to be E_PROP_ID_UNSUPPORTED, got 0x%08x\n", GetLastError()); trace("No active theme, skipping rest of OpenThemeData tests\n"); return; } /* Only do the next checks if we have an active theme */ SetLastError(0xdeadbeef); hTheme = pOpenThemeData(hWnd, szButtonClassList); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); todo_wine ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); /* Test with bUtToN instead of Button */ SetLastError(0xdeadbeef); hTheme = pOpenThemeData(hWnd, szButtonClassList2); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); todo_wine ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); SetLastError(0xdeadbeef); hTheme = pOpenThemeData(hWnd, szClassList); ok( hTheme != NULL, "got NULL, expected a HTHEME handle\n"); todo_wine ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); /* GetWindowTheme should return the last handle opened by OpenThemeData */ SetLastError(0xdeadbeef); hTheme2 = pGetWindowTheme(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); hRes = pCloseThemeData(hTheme); ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* Close a second time */ SetLastError(0xdeadbeef); hRes = pCloseThemeData(hTheme); ok( hRes == S_OK, "Expected S_OK, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* See if closing makes a difference for GetWindowTheme */ SetLastError(0xdeadbeef); hTheme2 = NULL; hTheme2 = pGetWindowTheme(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 = pIsThemePartDefined(hTheme, 0 , 0); todo_wine { ok( bTPDefined == FALSE, "Expected FALSE\n"); ok( GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got 0x%08x\n", GetLastError()); } bDestroyed = DestroyWindow(hWnd); if (!bDestroyed) trace("Window %p couldn't be destroyed : 0x%08x\n", hWnd, GetLastError()); } static void test_GetCurrentThemeName(void) { BOOL bThemeActive; HRESULT hRes; WCHAR currentTheme[MAX_PATH]; WCHAR currentColor[MAX_PATH]; WCHAR currentSize[MAX_PATH]; bThemeActive = pIsThemeActive(); /* All NULLs */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(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); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* Number of characters given is 0 */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(currentTheme, 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); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* When the number of characters given is too small (not 0, see above), GetCurrentThemeName returns 0x8007007a. * The only definition I found was in strsafe.h: * * #define STRSAFE_E_INSUFFICIENT_BUFFER ((HRESULT)0x8007007AL) // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(currentTheme, 2, NULL, 0, NULL, 0); if (bThemeActive) todo_wine ok(hRes == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* The same is true if the number of characters is too small for Color and/or Size */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(currentTheme, sizeof(currentTheme) / sizeof(WCHAR), currentColor, 2, currentSize, sizeof(currentSize) / sizeof(WCHAR)); if (bThemeActive) todo_wine ok(hRes == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "Expected HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), got 0x%08x\n", hRes); else ok( hRes == E_PROP_ID_UNSUPPORTED, "Expected E_PROP_ID_UNSUPPORTED, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* Given number of characters is correct */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(currentTheme, sizeof(currentTheme) / sizeof(WCHAR), 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); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* Given number of characters for the theme name is too large */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(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); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* The too large case is only for the theme name, not for color name or size name */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(currentTheme, sizeof(currentTheme) / sizeof(WCHAR), currentColor, sizeof(currentTheme), currentSize, sizeof(currentSize) / sizeof(WCHAR)); 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); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(currentTheme, sizeof(currentTheme) / sizeof(WCHAR), currentColor, sizeof(currentTheme) / sizeof(WCHAR), 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); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); /* Correct call */ SetLastError(0xdeadbeef); hRes = pGetCurrentThemeName(currentTheme, sizeof(currentTheme) / sizeof(WCHAR), currentColor, sizeof(currentColor) / sizeof(WCHAR), currentSize, sizeof(currentSize) / sizeof(WCHAR)); 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); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); } static void test_CloseThemeData(void) { HRESULT hRes; SetLastError(0xdeadbeef); hRes = pCloseThemeData(NULL); ok( hRes == E_HANDLE, "Expected E_HANDLE, got 0x%08x\n", hRes); ok( GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got 0x%08x\n", GetLastError()); } START_TEST(system) { if(!InitFunctionPtrs()) return; /* No real functional tests will be done (yet). The current tests * only show input/return behaviour */ /* IsThemeActive, IsAppThemed and IsThemePartDefined*/ trace("Starting test_IsThemed()\n"); test_IsThemed(); /* GetWindowTheme */ trace("Starting test_GetWindowTheme()\n"); test_GetWindowTheme(); /* SetWindowTheme */ trace("Starting test_SetWindowTheme()\n"); test_SetWindowTheme(); /* OpenThemeData, a bit more functional now */ trace("Starting test_OpenThemeData()\n"); test_OpenThemeData(); /* GetCurrentThemeName */ trace("Starting test_GetCurrentThemeName()\n"); test_GetCurrentThemeName(); /* CloseThemeData */ trace("Starting test_CloseThemeData()\n"); test_CloseThemeData(); FreeLibrary(hUxtheme); }