https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1b5f6c2dc0bb62228a7e3…
commit 1b5f6c2dc0bb62228a7e329510ec392563380932
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Jan 28 21:05:40 2025 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Jan 28 21:05:40 2025 +0900
[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.
---
dll/win32/uxtheme/CMakeLists.txt | 1 +
dll/win32/uxtheme/errinfo.c | 150 +++++++++++++++++++++
dll/win32/uxtheme/main.c | 7 +-
dll/win32/uxtheme/system.c | 15 +++
dll/win32/uxtheme/uxtheme.spec | 2 +-
dll/win32/uxtheme/uxthemep.h | 40 ++++++
modules/rostests/apitests/uxtheme/CMakeLists.txt | 1 +
.../apitests/uxtheme/GetThemeParseErrorInfo.c | 92 +++++++++++++
modules/rostests/apitests/uxtheme/testlist.c | 2 +
sdk/include/reactos/uxundoc.h | 19 +++
10 files changed, 327 insertions(+), 2 deletions(-)
diff --git a/dll/win32/uxtheme/CMakeLists.txt b/dll/win32/uxtheme/CMakeLists.txt
index 92a6f0cb292..44ac0cd0eb4 100644
--- a/dll/win32/uxtheme/CMakeLists.txt
+++ b/dll/win32/uxtheme/CMakeLists.txt
@@ -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
diff --git a/dll/win32/uxtheme/errinfo.c b/dll/win32/uxtheme/errinfo.c
new file mode 100644
index 00000000000..40abe56e802
--- /dev/null
+++ b/dll/win32/uxtheme/errinfo.c
@@ -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(a)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;
+}
diff --git a/dll/win32/uxtheme/main.c b/dll/win32/uxtheme/main.c
index 4eb6eb33761..9c86347e2bc 100644
--- a/dll/win32/uxtheme/main.c
+++ b/dll/win32/uxtheme/main.c
@@ -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;
diff --git a/dll/win32/uxtheme/system.c b/dll/win32/uxtheme/system.c
index eaf8faf924c..c998be4f120 100644
--- a/dll/win32/uxtheme/system.c
+++ b/dll/win32/uxtheme/system.c
@@ -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;
}
/***********************************************************************
diff --git a/dll/win32/uxtheme/uxtheme.spec b/dll/win32/uxtheme/uxtheme.spec
index 632cfe84a00..17d90eef273 100644
--- a/dll/win32/uxtheme/uxtheme.spec
+++ b/dll/win32/uxtheme/uxtheme.spec
@@ -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)
diff --git a/dll/win32/uxtheme/uxthemep.h b/dll/win32/uxtheme/uxthemep.h
index 5a047d7fcdd..71c4da68aaa 100644
--- a/dll/win32/uxtheme/uxthemep.h
+++ b/dll/win32/uxtheme/uxthemep.h
@@ -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_ */
diff --git a/modules/rostests/apitests/uxtheme/CMakeLists.txt
b/modules/rostests/apitests/uxtheme/CMakeLists.txt
index ccb67069779..0af75394767 100644
--- a/modules/rostests/apitests/uxtheme/CMakeLists.txt
+++ b/modules/rostests/apitests/uxtheme/CMakeLists.txt
@@ -2,6 +2,7 @@
list(APPEND SOURCE
CloseThemeData.c
DrawThemeParentBackground.c
+ GetThemeParseErrorInfo.c
SetWindowTheme.c
SetThemeAppProperties.c
../include/msgtrace.c
diff --git a/modules/rostests/apitests/uxtheme/GetThemeParseErrorInfo.c
b/modules/rostests/apitests/uxtheme/GetThemeParseErrorInfo.c
new file mode 100644
index 00000000000..4d54c226ea7
--- /dev/null
+++ b/modules/rostests/apitests/uxtheme/GetThemeParseErrorInfo.c
@@ -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(a)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);
+}
diff --git a/modules/rostests/apitests/uxtheme/testlist.c
b/modules/rostests/apitests/uxtheme/testlist.c
index 0ecc2b98943..c3260d8499e 100644
--- a/modules/rostests/apitests/uxtheme/testlist.c
+++ b/modules/rostests/apitests/uxtheme/testlist.c
@@ -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 }
diff --git a/sdk/include/reactos/uxundoc.h b/sdk/include/reactos/uxundoc.h
index ed3ed4368ff..2c6e23cb22b 100644
--- a/sdk/include/reactos/uxundoc.h
+++ b/sdk/include/reactos/uxundoc.h
@@ -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