[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
buffer.c
draw.c
errinfo.c
main.c
metric.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)
{
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);
break;
case DLL_PROCESS_DETACH:
UXTHEME_UnInitSystem(hInstDLL);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
UXTHEME_DeleteParseErrorInfo();
break;
}
return TRUE;

View file

@ -24,6 +24,8 @@
#include <winreg.h>
#include <uxundoc.h>
DWORD gdwErrorInfoTlsIndex = TLS_OUT_OF_INDEXES;
/***********************************************************************
* Defines and global variables
*/
@ -588,6 +590,19 @@ void UXTHEME_InitSystem(HINSTANCE hInst)
RtlInitializeHandleTable(0xFFF, sizeof(UXTHEME_HANDLE), &g_UxThemeHandleTable);
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)
46 stdcall -noname ClassicAdjustWindowRectEx(ptr long long long)
47 stdcall DrawThemeBackgroundEx(ptr ptr long long ptr ptr)
48 stub -noname GetThemeParseErrorInfo
48 stdcall -noname GetThemeParseErrorInfo(ptr)
49 stdcall GetThemeAppProperties()
50 stdcall GetThemeBackgroundContentRect(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;
} 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 _UXTHEME_HANDLE
@ -276,6 +286,7 @@ extern ATOM atWndContext;
extern BOOL g_bThemeHooksActive;
void UXTHEME_InitSystem(HINSTANCE hInst);
void UXTHEME_UnInitSystem(HINSTANCE hInst);
void UXTHEME_LoadTheme(BOOL bLoad);
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 */
#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_ */

View file

@ -2,6 +2,7 @@
list(APPEND SOURCE
CloseThemeData.c
DrawThemeParentBackground.c
GetThemeParseErrorInfo.c
SetWindowTheme.c
SetThemeAppProperties.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_DrawThemeParentBackground(void);
extern void func_GetThemeParseErrorInfo(void);
extern void func_SetThemeAppProperties(void);
extern void func_SetWindowTheme(void);
@ -12,6 +13,7 @@ const struct test winetest_testlist[] =
{
{ "CloseThemeData", func_CloseThemeData },
{ "DrawThemeParentBackground", func_DrawThemeParentBackground },
{ "GetThemeParseErrorInfo", func_GetThemeParseErrorInfo },
{ "SetWindowTheme", func_SetWindowTheme },
{ "SetThemeAppProperties", func_SetThemeAppProperties },
{ 0, 0 }

View file

@ -1,7 +1,23 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
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
*
@ -118,3 +134,6 @@ BOOL WINAPI ThemeHooksInstall(VOID);
BOOL WINAPI ThemeHooksRemove(VOID);
#ifdef __cplusplus
} // extern "C"
#endif