[UXTHEME][UXTHEME_APITEST][SDK] GetThemeParseErrorInfo (#7662)

Implementing missing features...
JIRA issue: CORE-12805
- Add dll/win32/uxtheme/errinfo.c.
- Implement GetThemeParseErrorInfo
  function in errinfo.c.
- Modify uxtheme.spec.
- Add GetThemeParseErrorInfo
  prototype to <uxundoc.h>.
- Adapt <uxundoc.h> to C++.
- Add global variable
  gdwErrorInfoTlsIndex.
- Add UXTHEME_UnInitSystem
  function.
This commit is contained in:
Katayama Hirofumi MZ 2025-01-28 21:05:40 +09:00 committed by GitHub
parent 0e327e9a70
commit 1b5f6c2dc0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 327 additions and 2 deletions

View file

@ -6,6 +6,7 @@ spec2def(uxtheme.dll uxtheme.spec ADD_IMPORTLIB)
list(APPEND SOURCE list(APPEND SOURCE
buffer.c buffer.c
draw.c draw.c
errinfo.c
main.c main.c
metric.c metric.c
msstyles.c msstyles.c

150
dll/win32/uxtheme/errinfo.c Normal file
View file

@ -0,0 +1,150 @@
/*
* PROJECT: ReactOS uxtheme.dll
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
* PURPOSE: UXTHEME error reporting helpers
* COPYRIGHT: Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include "uxthemep.h"
#include <stdlib.h>
#include <strsafe.h>
PTMERRINFO
UXTHEME_GetParseErrorInfo(_In_ BOOL bCreate)
{
PTMERRINFO pErrInfo;
if (gdwErrorInfoTlsIndex == TLS_OUT_OF_INDEXES)
return NULL;
pErrInfo = TlsGetValue(gdwErrorInfoTlsIndex);
if (pErrInfo)
return pErrInfo;
if (bCreate)
{
pErrInfo = LocalAlloc(LPTR, sizeof(*pErrInfo));
TlsSetValue(gdwErrorInfoTlsIndex, pErrInfo);
}
return pErrInfo;
}
VOID
UXTHEME_DeleteParseErrorInfo(VOID)
{
PTMERRINFO pErrInfo = UXTHEME_GetParseErrorInfo(FALSE);
if (!pErrInfo)
return;
TlsSetValue(gdwErrorInfoTlsIndex, NULL);
LocalFree(pErrInfo);
}
static BOOL
UXTHEME_FormatLocalMsg(
_In_ HINSTANCE hInstance,
_In_ UINT uID,
_Out_ LPWSTR pszDest,
_In_ SIZE_T cchDest,
_In_ LPCWSTR pszDrive,
_In_ PTMERRINFO pErrInfo)
{
WCHAR szFormat[MAX_PATH];
LPCWSTR args[2] = { pErrInfo->szParam1, pErrInfo->szParam2 };
if (!LoadStringW(hInstance, uID, szFormat, _countof(szFormat)) || !szFormat[0])
return FALSE;
return FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
szFormat, 0, 0, pszDest, cchDest, (va_list *)args) != 0;
}
static HRESULT
UXTHEME_FormatParseMessage(
_In_ PTMERRINFO pErrInfo,
_Out_ LPWSTR pszDest,
_In_ SIZE_T cchDest)
{
DWORD nID;
HMODULE hMod, hUxTheme;
WCHAR szFullPath[_MAX_PATH];
WCHAR szDrive[_MAX_DRIVE + 1], szDir[_MAX_DIR], szFileName[_MAX_FNAME], szExt[_MAX_EXT];
BOOL ret;
HRESULT hr;
nID = LOWORD(pErrInfo->nID);
if (!GetModuleFileNameW(NULL, szFullPath, _countof(szFullPath)))
return S_OK;
_wsplitpath(szFullPath, szDrive, szDir, szFileName, szExt);
if (lstrcmpiW(szFileName, L"packthem") == 0)
{
hMod = GetModuleHandleW(NULL);
if (UXTHEME_FormatLocalMsg(hMod, nID, pszDest, cchDest, szDrive, pErrInfo))
return S_OK;
}
hUxTheme = LoadLibraryW(L"uxtheme.dll");
if (!hUxTheme)
return E_FAIL;
ret = UXTHEME_FormatLocalMsg(hUxTheme, nID, pszDest, cchDest, szDrive, pErrInfo);
hr = (ret ? S_OK : UXTHEME_MakeLastError());
FreeLibrary(hUxTheme);
return hr;
}
// Parser should use this function on failure
HRESULT
UXTHEME_MakeParseError(
_In_ UINT nID,
_In_ LPCWSTR pszParam1,
_In_ LPCWSTR pszParam2,
_In_ LPCWSTR pszFile,
_In_ LPCWSTR pszLine,
_In_ INT nLineNo)
{
PTMERRINFO pErrInfo = UXTHEME_GetParseErrorInfo(TRUE);
if (pErrInfo)
{
pErrInfo->nID = nID;
pErrInfo->nLineNo = nLineNo;
StringCchCopyW(pErrInfo->szParam1, _countof(pErrInfo->szParam1), pszParam1);
StringCchCopyW(pErrInfo->szParam2, _countof(pErrInfo->szParam2), pszParam2);
StringCchCopyW(pErrInfo->szFile, _countof(pErrInfo->szFile), pszFile);
StringCchCopyW(pErrInfo->szLine, _countof(pErrInfo->szLine), pszLine);
}
return HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY);
}
/*************************************************************************
* GetThemeParseErrorInfo (UXTHEME.48)
*/
HRESULT WINAPI
GetThemeParseErrorInfo(_Inout_ PPARSE_ERROR_INFO pInfo)
{
PTMERRINFO pErrInfo;
HRESULT hr;
if (!pInfo)
return E_POINTER;
if (pInfo->cbSize != sizeof(*pInfo))
return E_INVALIDARG;
pErrInfo = UXTHEME_GetParseErrorInfo(TRUE);
if (!pErrInfo)
return E_OUTOFMEMORY;
hr = UXTHEME_FormatParseMessage(pErrInfo, pInfo->szDescription, _countof(pInfo->szDescription));
if (FAILED(hr))
return hr;
pInfo->nID = pErrInfo->nID;
pInfo->nLineNo = pErrInfo->nLineNo;
StringCchCopyW(pInfo->szFile, _countof(pInfo->szFile), pErrInfo->szFile);
StringCchCopyW(pInfo->szLine, _countof(pInfo->szLine), pErrInfo->szLine);
return hr;
}

View file

@ -22,7 +22,6 @@
/***********************************************************************/ /***********************************************************************/
/* For the moment, do nothing here. */
BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
{ {
TRACE("%p 0x%x %p: stub\n", hInstDLL, fdwReason, lpv); TRACE("%p 0x%x %p: stub\n", hInstDLL, fdwReason, lpv);
@ -32,6 +31,12 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
UXTHEME_InitSystem(hInstDLL); UXTHEME_InitSystem(hInstDLL);
break; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
UXTHEME_UnInitSystem(hInstDLL);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
UXTHEME_DeleteParseErrorInfo();
break; break;
} }
return TRUE; return TRUE;

View file

@ -24,6 +24,8 @@
#include <winreg.h> #include <winreg.h>
#include <uxundoc.h> #include <uxundoc.h>
DWORD gdwErrorInfoTlsIndex = TLS_OUT_OF_INDEXES;
/*********************************************************************** /***********************************************************************
* Defines and global variables * Defines and global variables
*/ */
@ -588,6 +590,19 @@ void UXTHEME_InitSystem(HINSTANCE hInst)
RtlInitializeHandleTable(0xFFF, sizeof(UXTHEME_HANDLE), &g_UxThemeHandleTable); RtlInitializeHandleTable(0xFFF, sizeof(UXTHEME_HANDLE), &g_UxThemeHandleTable);
g_cHandles = 0; g_cHandles = 0;
gdwErrorInfoTlsIndex = TlsAlloc();
}
/***********************************************************************
* UXTHEME_UnInitSystem
*/
void UXTHEME_UnInitSystem(HINSTANCE hInst)
{
UXTHEME_DeleteParseErrorInfo();
TlsFree(gdwErrorInfoTlsIndex);
gdwErrorInfoTlsIndex = TLS_OUT_OF_INDEXES;
} }
/*********************************************************************** /***********************************************************************

View file

@ -45,7 +45,7 @@
45 stdcall -noname ClassicSystemParametersInfoW(long long ptr long) 45 stdcall -noname ClassicSystemParametersInfoW(long long ptr long)
46 stdcall -noname ClassicAdjustWindowRectEx(ptr long long long) 46 stdcall -noname ClassicAdjustWindowRectEx(ptr long long long)
47 stdcall DrawThemeBackgroundEx(ptr ptr long long ptr ptr) 47 stdcall DrawThemeBackgroundEx(ptr ptr long long ptr ptr)
48 stub -noname GetThemeParseErrorInfo 48 stdcall -noname GetThemeParseErrorInfo(ptr)
49 stdcall GetThemeAppProperties() 49 stdcall GetThemeAppProperties()
50 stdcall GetThemeBackgroundContentRect(ptr ptr long long ptr ptr) 50 stdcall GetThemeBackgroundContentRect(ptr ptr long long ptr ptr)
51 stdcall GetThemeBackgroundExtent(ptr ptr long long ptr ptr) 51 stdcall GetThemeBackgroundExtent(ptr ptr long long ptr ptr)

View file

@ -90,6 +90,16 @@ typedef struct _THEME_FILE {
PTHEME_IMAGE images; PTHEME_IMAGE images;
} THEME_FILE, *PTHEME_FILE; } THEME_FILE, *PTHEME_FILE;
typedef struct tagTMERRINFO
{
UINT nID;
WCHAR szParam1[MAX_PATH];
WCHAR szParam2[MAX_PATH];
WCHAR szFile[MAX_PATH];
WCHAR szLine[MAX_PATH];
INT nLineNo;
} TMERRINFO, *PTMERRINFO;
typedef struct _UXINI_FILE *PUXINI_FILE; typedef struct _UXINI_FILE *PUXINI_FILE;
typedef struct _UXTHEME_HANDLE typedef struct _UXTHEME_HANDLE
@ -276,6 +286,7 @@ extern ATOM atWndContext;
extern BOOL g_bThemeHooksActive; extern BOOL g_bThemeHooksActive;
void UXTHEME_InitSystem(HINSTANCE hInst); void UXTHEME_InitSystem(HINSTANCE hInst);
void UXTHEME_UnInitSystem(HINSTANCE hInst);
void UXTHEME_LoadTheme(BOOL bLoad); void UXTHEME_LoadTheme(BOOL bLoad);
BOOL CALLBACK UXTHEME_broadcast_theme_changed (HWND hWnd, LPARAM enable); BOOL CALLBACK UXTHEME_broadcast_theme_changed (HWND hWnd, LPARAM enable);
@ -286,4 +297,33 @@ BOOL CALLBACK UXTHEME_broadcast_theme_changed (HWND hWnd, LPARAM enable);
/* Full alpha blending */ /* Full alpha blending */
#define ALPHABLEND_FULL 2 #define ALPHABLEND_FULL 2
extern DWORD gdwErrorInfoTlsIndex;
VOID UXTHEME_DeleteParseErrorInfo(VOID);
static inline
HRESULT
UXTHEME_MakeError(_In_ LONG error)
{
if (error < 0)
return (HRESULT)error;
return HRESULT_FROM_WIN32(error);
}
static inline
HRESULT
UXTHEME_MakeLastError(VOID)
{
return UXTHEME_MakeError(GetLastError());
}
HRESULT
UXTHEME_MakeParseError(
_In_ UINT nID,
_In_ LPCWSTR pszParam1,
_In_ LPCWSTR pszParam2,
_In_ LPCWSTR pszFile,
_In_ LPCWSTR pszLine,
_In_ INT nLineNo);
#endif /* _UXTHEME_PCH_ */ #endif /* _UXTHEME_PCH_ */

View file

@ -2,6 +2,7 @@
list(APPEND SOURCE list(APPEND SOURCE
CloseThemeData.c CloseThemeData.c
DrawThemeParentBackground.c DrawThemeParentBackground.c
GetThemeParseErrorInfo.c
SetWindowTheme.c SetWindowTheme.c
SetThemeAppProperties.c SetThemeAppProperties.c
../include/msgtrace.c ../include/msgtrace.c

View file

@ -0,0 +1,92 @@
/*
* PROJECT: ReactOS API tests
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
* PURPOSE: Tests for GetThemeParseErrorInfo
* COPYRIGHT: Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include <apitest.h>
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <uxtheme.h>
#include <uxundoc.h>
typedef HRESULT (WINAPI *FN_GetThemeParseErrorInfo)(PPARSE_ERROR_INFO);
typedef HRESULT (WINAPI *FN_ParseThemeIniFile)(LPCWSTR, LPWSTR, PARSETHEMEINIFILEPROC, LPVOID);
static BOOL CALLBACK
ParseThemeIniFileProc(
DWORD dwType,
LPWSTR pszParam1,
LPWSTR pszParam2,
LPWSTR pszParam3,
DWORD dwParam,
LPVOID lpData)
{
return TRUE;
}
START_TEST(GetThemeParseErrorInfo)
{
HRESULT hr;
PARSE_ERROR_INFO Info;
WCHAR szPath[MAX_PATH];
FN_GetThemeParseErrorInfo GetThemeParseErrorInfo =
(FN_GetThemeParseErrorInfo)GetProcAddress(GetModuleHandleW(L"uxtheme.dll"), MAKEINTRESOURCEA(48));
if (!GetThemeParseErrorInfo)
{
skip("No GetThemeParseErrorInfo found\n");
return;
}
hr = GetThemeParseErrorInfo(NULL);
ok_hex(hr, E_POINTER);
ZeroMemory(&Info, sizeof(Info));
hr = GetThemeParseErrorInfo(&Info);
ok_hex(hr, E_INVALIDARG);
ZeroMemory(&Info, sizeof(Info));
Info.cbSize = sizeof(Info);
hr = GetThemeParseErrorInfo(&Info);
ok_hex(hr, HRESULT_FROM_WIN32(ERROR_RESOURCE_NAME_NOT_FOUND));
FN_ParseThemeIniFile ParseThemeIniFile =
(FN_ParseThemeIniFile)GetProcAddress(GetModuleHandleW(L"uxtheme.dll"), MAKEINTRESOURCEA(11));
if (!ParseThemeIniFile)
{
skip("No ParseThemeIniFile found\n");
return;
}
FILE *fout = _wfopen(L"invalid.ini", L"wb");
fprintf(fout, "[InvalidKey]\n");
fprintf(fout, "InvalidValueName=InvalidValue\n");
fclose(fout);
hr = ParseThemeIniFile(L"invalid.ini", szPath, ParseThemeIniFileProc, NULL);
ok_hex(hr, HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY));
_wremove(L"invalid.ini");
ZeroMemory(&Info, sizeof(Info));
Info.cbSize = sizeof(Info);
Info.szDescription[0] = L'@';
Info.szDescription[MAX_PATH] = L'@';
Info.szFile[0] = L'@';
Info.szLine[0] = L'@';
hr = GetThemeParseErrorInfo(&Info);
ok_hex(hr, S_OK);
ok_int(Info.nID, 160);
ok(Info.szDescription[0] != UNICODE_NULL, "Info.szDescription was empty\n");
ok(Info.szDescription[0] != L'@', "Info.szDescription had no change\n");
trace("szDescription: %s\n", wine_dbgstr_w(Info.szDescription)); // "Must be Primitive, enum, or type: InvalidValueName"
ok_int(Info.szDescription[MAX_PATH], L'@');
ok_wstr(Info.szFile, L"invalid.ini");
ok_wstr(Info.szLine, L"InvalidValueName=InvalidValue");
ok_int(Info.nLineNo, 2);
}

View file

@ -5,6 +5,7 @@
extern void func_CloseThemeData(void); extern void func_CloseThemeData(void);
extern void func_DrawThemeParentBackground(void); extern void func_DrawThemeParentBackground(void);
extern void func_GetThemeParseErrorInfo(void);
extern void func_SetThemeAppProperties(void); extern void func_SetThemeAppProperties(void);
extern void func_SetWindowTheme(void); extern void func_SetWindowTheme(void);
@ -12,6 +13,7 @@ const struct test winetest_testlist[] =
{ {
{ "CloseThemeData", func_CloseThemeData }, { "CloseThemeData", func_CloseThemeData },
{ "DrawThemeParentBackground", func_DrawThemeParentBackground }, { "DrawThemeParentBackground", func_DrawThemeParentBackground },
{ "GetThemeParseErrorInfo", func_GetThemeParseErrorInfo },
{ "SetWindowTheme", func_SetWindowTheme }, { "SetWindowTheme", func_SetWindowTheme },
{ "SetThemeAppProperties", func_SetThemeAppProperties }, { "SetThemeAppProperties", func_SetThemeAppProperties },
{ 0, 0 } { 0, 0 }

View file

@ -1,7 +1,23 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef HANDLE HTHEMEFILE; typedef HANDLE HTHEMEFILE;
typedef struct tagPARSE_ERROR_INFO
{
DWORD cbSize;
UINT nID;
WCHAR szDescription[2 * MAX_PATH];
WCHAR szFile[MAX_PATH];
WCHAR szLine[MAX_PATH];
INT nLineNo;
} PARSE_ERROR_INFO, *PPARSE_ERROR_INFO;
HRESULT WINAPI GetThemeParseErrorInfo(_Inout_ PPARSE_ERROR_INFO pInfo);
/********************************************************************** /**********************************************************************
* ENUMTHEMEPROC * ENUMTHEMEPROC
* *
@ -118,3 +134,6 @@ BOOL WINAPI ThemeHooksInstall(VOID);
BOOL WINAPI ThemeHooksRemove(VOID); BOOL WINAPI ThemeHooksRemove(VOID);
#ifdef __cplusplus
} // extern "C"
#endif