diff --git a/patches/advapi32-Performance_Counters/0001-advapi32-tests-Add-more-tests-for-performance-counte.patch b/patches/advapi32-Performance_Counters/0001-advapi32-tests-Add-more-tests-for-performance-counte.patch new file mode 100644 index 00000000..ebff6a62 --- /dev/null +++ b/patches/advapi32-Performance_Counters/0001-advapi32-tests-Add-more-tests-for-performance-counte.patch @@ -0,0 +1,267 @@ +From e950724c38a4f81efb97bb9595dc59c5fb925da0 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 12 Apr 2017 12:33:31 +0800 +Subject: advapi32/tests: Add more tests for performance counters. + +--- + dlls/advapi32/tests/registry.c | 196 ++++++++++++++++++++++++++++++++++++++++- + include/winreg.h | 2 + + 2 files changed, 194 insertions(+), 4 deletions(-) + +diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c +index 846f1c49628..d850f6a3aa7 100644 +--- a/dlls/advapi32/tests/registry.c ++++ b/dlls/advapi32/tests/registry.c +@@ -3520,35 +3520,73 @@ static void test_RegNotifyChangeKeyValue(void) + CloseHandle(event); + } + ++static const char *dbgstr_longlong(ULONGLONG ll) ++{ ++ static char buf[16][64]; ++ static int idx; ++ ++ idx &= 0x0f; ++ ++ if (sizeof(ll) > sizeof(unsigned long) && ll >> 32) ++ sprintf(buf[idx], "0x%lx%08lx", (unsigned long)(ll >> 32), (unsigned long)ll); ++ else ++ sprintf(buf[idx], "0x%08lx", (unsigned long)ll); ++ ++ return buf[idx++]; ++} ++ ++#define cmp_li(a, b, c) cmp_li_real(a, b, c, __LINE__) ++static void cmp_li_real(LARGE_INTEGER *l1, LARGE_INTEGER *l2, LONGLONG slack, int line) ++{ ++ LONGLONG diff = l2->QuadPart - l1->QuadPart; ++ if (diff < 0) diff = -diff; ++ ok_(__FILE__, line)(diff <= slack, "values don't match: %s/%s\n", ++ dbgstr_longlong(l1->QuadPart), dbgstr_longlong(l2->QuadPart)); ++} ++ + static void test_RegQueryValueExPerformanceData(void) + { +- DWORD cbData, len; ++ static const WCHAR globalW[] = { 'G','l','o','b','a','l',0 }; ++ static const WCHAR dummyW[5] = { 'd','u','m','m','y' }; ++ static const char * const names[] = { NULL, "", "Global", "2" "invalid counter name" }; ++ DWORD cbData, len, i, type; + BYTE *value; + DWORD dwret; + LONG limit = 6; + PERF_DATA_BLOCK *pdb; ++ HKEY hkey; ++ BYTE buf[256 + sizeof(PERF_DATA_BLOCK)]; + + /* Test with data == NULL */ + dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, NULL, &cbData ); + todo_wine ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); + ++ dwret = RegQueryValueExW( HKEY_PERFORMANCE_DATA, globalW, NULL, NULL, NULL, &cbData ); ++ todo_wine ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); ++ + /* Test ERROR_MORE_DATA, start with small buffer */ + len = 10; + value = HeapAlloc(GetProcessHeap(), 0, len); + cbData = len; +- dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, value, &cbData ); ++ type = 0xdeadbeef; ++ dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, &type, value, &cbData ); + todo_wine ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); ++todo_wine ++ ok(type == REG_BINARY, "got %u\n", type); + while( dwret == ERROR_MORE_DATA && limit) + { + len = len * 10; + value = HeapReAlloc( GetProcessHeap(), 0, value, len ); + cbData = len; +- dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, value, &cbData ); ++ type = 0xdeadbeef; ++ dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, &type, value, &cbData ); + limit--; + } + ok(limit > 0, "too many times ERROR_MORE_DATA returned\n"); + + todo_wine ok(dwret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", dwret); ++todo_wine ++ ok(type == REG_BINARY, "got %u\n", type); + + /* Check returned data */ + if (dwret == ERROR_SUCCESS) +@@ -3565,8 +3603,158 @@ static void test_RegQueryValueExPerformanceData(void) + } + + HeapFree(GetProcessHeap(), 0, value); +-} + ++ for (i = 0; i < sizeof(names)/sizeof(names[0]); i++) ++ { ++ cbData = 0xdeadbeef; ++ dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, names[i], NULL, NULL, NULL, &cbData); ++todo_wine ++ ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret); ++ ok(cbData == 0, "got %u\n", cbData); ++ ++ cbData = 0; ++ dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, names[i], NULL, NULL, NULL, &cbData); ++todo_wine ++ ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret); ++ ok(cbData == 0, "got %u\n", cbData); ++ ++ cbData = 0xdeadbeef; ++ dwret = RegQueryValueExA(HKEY_PERFORMANCE_TEXT, names[i], NULL, NULL, NULL, &cbData); ++todo_wine ++ ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret); ++ ok(cbData == 0, "got %u\n", cbData); ++ ++ cbData = 0; ++ dwret = RegQueryValueExA(HKEY_PERFORMANCE_TEXT, names[i], NULL, NULL, NULL, &cbData); ++todo_wine ++ ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret); ++ ok(cbData == 0, "got %u\n", cbData); ++ ++ cbData = 0xdeadbeef; ++ dwret = RegQueryValueExA(HKEY_PERFORMANCE_NLSTEXT, names[i], NULL, NULL, NULL, &cbData); ++todo_wine ++ ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret); ++ ok(cbData == 0, "got %u\n", cbData); ++ ++ cbData = 0; ++ dwret = RegQueryValueExA(HKEY_PERFORMANCE_NLSTEXT, names[i], NULL, NULL, NULL, &cbData); ++todo_wine ++ ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret); ++ ok(cbData == 0, "got %u\n", cbData); ++ } ++ ++ memset(buf, 0x77, sizeof(buf)); ++ type = 0xdeadbeef; ++ cbData = sizeof(buf); ++ dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "invalid counter name", NULL, &type, buf, &cbData); ++todo_wine ++ ok(dwret == ERROR_SUCCESS, "got %u\n", dwret); ++todo_wine ++ ok(type == REG_BINARY, "got %u\n", type); ++ if (dwret == ERROR_SUCCESS) ++ { ++ SYSTEMTIME st; ++ WCHAR sysname[MAX_COMPUTERNAME_LENGTH + 1]; ++ DWORD sysname_len; ++ LARGE_INTEGER counter, freq, ftime; ++ ++ GetSystemTime(&st); ++ GetSystemTimeAsFileTime((FILETIME *)&ftime); ++ QueryPerformanceCounter(&counter); ++ QueryPerformanceFrequency(&freq); ++ ++ sysname_len = MAX_COMPUTERNAME_LENGTH + 1; ++ GetComputerNameW(sysname, &sysname_len); ++ ++ pdb = (PERF_DATA_BLOCK *)buf; ++ ok(pdb->Signature[0] == 'P', "got '%c'\n", pdb->Signature[0]); ++ ok(pdb->Signature[1] == 'E', "got '%c'\n", pdb->Signature[1]); ++ ok(pdb->Signature[2] == 'R', "got '%c'\n", pdb->Signature[2]); ++ ok(pdb->Signature[3] == 'F', "got '%c'\n", pdb->Signature[3]); ++ ++ ok(pdb->LittleEndian == 1, "got %u\n", pdb->LittleEndian); ++ ok(pdb->Version == 1, "got %u\n", pdb->Version); ++ ok(pdb->Revision == 1, "got %u\n", pdb->Revision); ++ len = (sizeof(*pdb) + pdb->SystemNameLength + 7) & ~7; ++ ok(pdb->TotalByteLength == len, "got %u vs %u\n", pdb->TotalByteLength, len); ++ ok(pdb->HeaderLength == pdb->TotalByteLength, "got %u\n", pdb->HeaderLength); ++ ok(pdb->NumObjectTypes == 0, "got %u\n", pdb->NumObjectTypes); ++ ok(pdb->DefaultObject != 0, "got %u\n", pdb->DefaultObject); ++ ok(pdb->SystemTime.wYear == st.wYear, "got %u\n", pdb->SystemTime.wYear); ++ ok(pdb->SystemTime.wMonth == st.wMonth, "got %u\n", pdb->SystemTime.wMonth); ++ ok(pdb->SystemTime.wDayOfWeek == st.wDayOfWeek, "got %u\n", pdb->SystemTime.wDayOfWeek); ++ ok(pdb->SystemTime.wDay == st.wDay, "got %u\n", pdb->SystemTime.wDay); ++ if (U(pdb->PerfTime).LowPart != 0x77777777) /* TestBot is broken */ ++ cmp_li(&pdb->PerfTime, &counter, freq.QuadPart); ++ if (U(pdb->PerfFreq).LowPart != 0x77777777) /* TestBot is broken */ ++ cmp_li(&pdb->PerfFreq, &freq, 0); ++ cmp_li(&pdb->PerfTime100nSec, &ftime, 200000); /* TestBot needs huge slack value */ ++ ok(pdb->SystemNameLength == (sysname_len + 1) * sizeof(WCHAR), "expected %u, got %u\n", ++ (sysname_len + 1) * sizeof(WCHAR), pdb->SystemNameLength); ++ ok(pdb->SystemNameOffset == sizeof(*pdb), "got %u\n", pdb->SystemNameOffset); ++ ok(!lstrcmpW(sysname, (LPCWSTR)(pdb + 1)), "%s != %s\n", ++ wine_dbgstr_w(sysname), wine_dbgstr_w((LPCWSTR)(pdb + 1))); ++ ++ len = pdb->TotalByteLength - (sizeof(*pdb) + pdb->SystemNameLength); ++ if (len) ++ { ++ BYTE remainder[8], *p; ++ ++ memset(remainder, 0x77, sizeof(remainder)); ++ p = buf + sizeof(*pdb) + pdb->SystemNameLength; ++ ok(!memcmp(p, remainder, len), "remainder: %02x,%02x...\n", p[0], p[1]); ++ } ++ } ++ ++ dwret = RegOpenKeyA(HKEY_PERFORMANCE_DATA, NULL, &hkey); ++todo_wine ++ ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret); ++ ++ dwret = RegOpenKeyA(HKEY_PERFORMANCE_DATA, "Global", &hkey); ++todo_wine ++ ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret); ++ ++ dwret = RegOpenKeyExA(HKEY_PERFORMANCE_DATA, "Global", 0, KEY_READ, &hkey); ++todo_wine ++ ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret); ++ ++ dwret = RegQueryValueA(HKEY_PERFORMANCE_DATA, "Global", NULL, (LONG *)&cbData); ++todo_wine ++ ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret); ++ ++ dwret = RegSetValueA(HKEY_PERFORMANCE_DATA, "Global", REG_SZ, "dummy", 4); ++todo_wine ++ ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret); ++ ++ dwret = RegSetValueExA(HKEY_PERFORMANCE_DATA, "Global", 0, REG_SZ, (const BYTE *)"dummy", 40); ++todo_wine ++ ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret); ++ ++ cbData = sizeof(buf); ++ dwret = RegEnumKeyA(HKEY_PERFORMANCE_DATA, 0, (LPSTR)buf, cbData); ++todo_wine ++ ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret); ++ ++ cbData = sizeof(buf); ++ dwret = RegEnumValueA(HKEY_PERFORMANCE_DATA, 0, (LPSTR)buf, &cbData, NULL, NULL, NULL, NULL); ++todo_wine ++ ok(dwret == ERROR_MORE_DATA, "got %u\n", dwret); ++todo_wine ++ ok(cbData == sizeof(buf), "got %u\n", cbData); ++ ++ dwret = RegEnumValueA(HKEY_PERFORMANCE_DATA, 0, NULL, &cbData, NULL, NULL, NULL, NULL); ++ ok(dwret == ERROR_INVALID_PARAMETER, "got %u\n", dwret); ++ ++ if (pRegSetKeyValueW) ++ { ++ dwret = pRegSetKeyValueW(HKEY_PERFORMANCE_DATA, NULL, globalW, REG_SZ, dummyW, sizeof(dummyW)); ++todo_wine ++ ok(dwret == ERROR_INVALID_HANDLE, "got %u\n", dwret); ++ } ++ ++ dwret = RegCloseKey(HKEY_PERFORMANCE_DATA); ++ ok(dwret == ERROR_SUCCESS, "got %u\n", dwret); ++} + + START_TEST(registry) + { +diff --git a/include/winreg.h b/include/winreg.h +index 42b77251ae4..ddbd9293783 100644 +--- a/include/winreg.h ++++ b/include/winreg.h +@@ -32,6 +32,8 @@ extern "C" { + #define HKEY_PERFORMANCE_DATA ((HKEY)(LONG_PTR)(LONG)0x80000004) + #define HKEY_CURRENT_CONFIG ((HKEY)(LONG_PTR)(LONG)0x80000005) + #define HKEY_DYN_DATA ((HKEY)(LONG_PTR)(LONG)0x80000006) ++#define HKEY_PERFORMANCE_TEXT ((HKEY)(LONG_PTR)(LONG)0x80000050) ++#define HKEY_PERFORMANCE_NLSTEXT ((HKEY)(LONG_PTR)(LONG)0x80000060) + + /* + * registry provider structs +-- +2.13.1 + diff --git a/patches/advapi32-Performance_Counters/0002-include-Add-more-definitions-for-performance-counter.patch b/patches/advapi32-Performance_Counters/0002-include-Add-more-definitions-for-performance-counter.patch new file mode 100644 index 00000000..67048b70 --- /dev/null +++ b/patches/advapi32-Performance_Counters/0002-include-Add-more-definitions-for-performance-counter.patch @@ -0,0 +1,139 @@ +From f72de28ee3a7a3cb25165f0aaee0c7e17eb7e6d7 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 12 Apr 2017 12:48:29 +0800 +Subject: include: Add more definitions for performance counters. + +--- + include/winperf.h | 113 ++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 97 insertions(+), 16 deletions(-) + +diff --git a/include/winperf.h b/include/winperf.h +index dce1a6d648d..113bfbae40f 100644 +--- a/include/winperf.h ++++ b/include/winperf.h +@@ -67,25 +67,106 @@ + #define PERF_DETAIL_EXPERT 300 + #define PERF_DETAIL_WIZARD 400 + ++#include ++ + /* Performance data structure header + * returned in answer to HKEY_PERFORMANCE_DATA request + */ + +-typedef struct _PERF_DATA_BLOCK { +- WCHAR Signature[4]; +- DWORD LittleEndian; +- DWORD Version; +- DWORD Revision; +- DWORD TotalByteLength; +- DWORD HeaderLength; +- DWORD NumObjectTypes; +- DWORD DefaultObject; +- SYSTEMTIME SystemTime; +- LARGE_INTEGER PerfTime; +- LARGE_INTEGER PerfFreq; +- LARGE_INTEGER PerfTime100nSec; +- DWORD SystemNameLength; +- DWORD SystemNameOffset; +-} PERF_DATA_BLOCK, *PPERF_DATA_BLOCK, *LPPERF_DATA_BLOCK; ++#define PERF_DATA_VERSION 1 ++#define PERF_DATA_REVISION 1 ++ ++typedef struct _PERF_DATA_BLOCK ++{ ++ WCHAR Signature[4]; ++ DWORD LittleEndian; ++ DWORD Version; ++ DWORD Revision; ++ DWORD TotalByteLength; ++ DWORD HeaderLength; ++ DWORD NumObjectTypes; ++ DWORD DefaultObject; ++ SYSTEMTIME SystemTime; ++ LARGE_INTEGER PerfTime; ++ LARGE_INTEGER PerfFreq; ++ LARGE_INTEGER PerfTime100nSec; ++ DWORD SystemNameLength; ++ DWORD SystemNameOffset; ++} PERF_DATA_BLOCK, *PPERF_DATA_BLOCK; ++ ++#define PERF_NO_INSTANCES -1 ++ ++typedef struct _PERF_OBJECT_TYPE ++{ ++ DWORD TotalByteLength; ++ DWORD DefinitionLength; ++ DWORD HeaderLength; ++ DWORD ObjectNameTitleIndex; ++#ifdef _WIN64 ++ DWORD ObjectNameTitle; ++#else ++ LPWSTR ObjectNameTitle; ++#endif ++ DWORD ObjectHelpTitleIndex; ++#ifdef _WIN64 ++ DWORD ObjectHelpTitle; ++#else ++ LPWSTR ObjectHelpTitle; ++#endif ++ DWORD DetailLevel; ++ DWORD NumCounters; ++ LONG DefaultCounter; ++ LONG NumInstances; ++ DWORD CodePage; ++ LARGE_INTEGER PerfTime; ++ LARGE_INTEGER PerfFreq; ++} PERF_OBJECT_TYPE, *PPERF_OBJECT_TYPE; ++ ++typedef struct _PERF_COUNTER_DEFINITION ++{ ++ DWORD ByteLength; ++ DWORD CounterNameTitleIndex; ++#ifdef _WIN64 ++ DWORD CounterNameTitle; ++#else ++ LPWSTR CounterNameTitle; ++#endif ++ DWORD CounterHelpTitleIndex; ++#ifdef _WIN64 ++ DWORD CounterHelpTitle; ++#else ++ LPWSTR CounterHelpTitle; ++#endif ++ LONG DefaultScale; ++ DWORD DetailLevel; ++ DWORD CounterType; ++ DWORD CounterSize; ++ DWORD CounterOffset; ++} PERF_COUNTER_DEFINITION, *PPERF_COUNTER_DEFINITION; ++ ++#define PERF_NO_UNIQUE_ID -1 ++ ++typedef struct _PERF_INSTANCE_DEFINITION ++{ ++ DWORD ByteLength; ++ DWORD ParentObjectTitleIndex; ++ DWORD ParentObjectInstance; ++ LONG UniqueID; ++ DWORD NameOffset; ++ DWORD NameLength; ++} PERF_INSTANCE_DEFINITION, *PPERF_INSTANCE_DEFINITION; ++ ++typedef struct _PERF_COUNTER_BLOCK ++{ ++ DWORD ByteLength; ++} PERF_COUNTER_BLOCK, *PPERF_COUNTER_BLOCK; ++ ++ ++#include ++ ++typedef DWORD (APIENTRY PM_OPEN_PROC)(LPWSTR); ++typedef DWORD (APIENTRY PM_COLLECT_PROC)(LPWSTR,LPVOID *,LPDWORD,LPDWORD); ++typedef DWORD (APIENTRY PM_CLOSE_PROC)(void); ++typedef DWORD (APIENTRY PM_QUERY_PROC)(LPDWORD,LPVOID *,LPDWORD,LPDWORD); + + #endif /* _WINPERF_ */ +-- +2.13.1 + diff --git a/patches/advapi32-Performance_Counters/0003-advapi32-Add-initial-support-for-querying-performanc.patch b/patches/advapi32-Performance_Counters/0003-advapi32-Add-initial-support-for-querying-performanc.patch new file mode 100644 index 00000000..b4a969aa --- /dev/null +++ b/patches/advapi32-Performance_Counters/0003-advapi32-Add-initial-support-for-querying-performanc.patch @@ -0,0 +1,376 @@ +From cba7fd4c248a70be8ce180f66809f1802328514f Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 12 Apr 2017 13:59:20 +0800 +Subject: advapi32: Add initial support for querying performance counters data. + +--- + dlls/advapi32/registry.c | 241 ++++++++++++++++++++++++++++++++++++++++- + dlls/advapi32/tests/registry.c | 17 +-- + 2 files changed, 246 insertions(+), 12 deletions(-) + +diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c +index 7a26fffc55e..a6e5c7903cf 100644 +--- a/dlls/advapi32/registry.c ++++ b/dlls/advapi32/registry.c +@@ -2,6 +2,7 @@ + * Registry management + * + * Copyright (C) 1999 Alexandre Julliard ++ * Copyright (C) 2017 Dmitry Timoshkov + * + * Based on misc/registry.c code + * Copyright (C) 1996 Marcus Meissner +@@ -36,6 +37,7 @@ + #include "winreg.h" + #include "winerror.h" + #include "winternl.h" ++#include "winperf.h" + #include "winuser.h" + #include "sddl.h" + #include "advapi32_misc.h" +@@ -1482,6 +1484,231 @@ LONG WINAPI RegSetKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name, DWORD type, + return ret; + } + ++struct perf_provider ++{ ++ HMODULE perflib; ++ PM_OPEN_PROC *pOpen; ++ PM_CLOSE_PROC *pClose; ++ PM_COLLECT_PROC *pCollect; ++}; ++ ++static void *get_provider_entry(HKEY perf, HMODULE perflib, const char *name) ++{ ++ char buf[MAX_PATH]; ++ DWORD err, type, len; ++ ++ len = sizeof(buf) - 1; ++ err = RegQueryValueExA(perf, name, NULL, &type, (BYTE *)buf, &len); ++ if (err != ERROR_SUCCESS || type != REG_SZ) ++ return NULL; ++ ++ buf[len] = 0; ++ TRACE("Loading function pointer for %s: %s\n", name, debugstr_a(buf)); ++ ++ return GetProcAddress(perflib, buf); ++} ++ ++static BOOL load_provider(HKEY root, const WCHAR *name, struct perf_provider *provider) ++{ ++ static const WCHAR performanceW[] = { 'P','e','r','f','o','r','m','a','n','c','e',0 }; ++ static const WCHAR libraryW[] = { 'L','i','b','r','a','r','y',0 }; ++ WCHAR buf[MAX_PATH], buf2[MAX_PATH]; ++ DWORD err, type, len; ++ HKEY service, perf; ++ ++ err = RegOpenKeyExW(root, name, 0, KEY_READ, &service); ++ if (err != ERROR_SUCCESS) ++ return FALSE; ++ ++ err = RegOpenKeyExW(service, performanceW, 0, KEY_READ, &perf); ++ RegCloseKey(service); ++ if (err != ERROR_SUCCESS) ++ return FALSE; ++ ++ len = sizeof(buf) - sizeof(WCHAR); ++ err = RegQueryValueExW(perf, libraryW, NULL, &type, (BYTE *)buf, &len); ++ if (err != ERROR_SUCCESS || !(type == REG_SZ || type == REG_EXPAND_SZ)) ++ goto error; ++ ++ buf[len / sizeof(WCHAR)] = 0; ++ if (type == REG_EXPAND_SZ) ++ { ++ len = ExpandEnvironmentStringsW(buf, buf2, MAX_PATH); ++ if (!len || len > MAX_PATH) goto error; ++ strcpyW(buf, buf2); ++ } ++ ++ if (!(provider->perflib = LoadLibraryW(buf))) ++ { ++ WARN("Failed to load %s\n", debugstr_w(buf)); ++ goto error; ++ } ++ ++ GetModuleFileNameW(provider->perflib, buf, MAX_PATH); ++ TRACE("Loaded provider %s\n", wine_dbgstr_w(buf)); ++ ++ provider->pOpen = get_provider_entry(perf, provider->perflib, "Open"); ++ provider->pClose = get_provider_entry(perf, provider->perflib, "Close"); ++ provider->pCollect = get_provider_entry(perf, provider->perflib, "Collect"); ++ if (provider->pOpen && provider->pClose && provider->pCollect) ++ return TRUE; ++ ++ TRACE("Provider is missing required exports\n"); ++ FreeLibrary(provider->perflib); ++ ++error: ++ RegCloseKey(perf); ++ return FALSE; ++} ++ ++static DWORD collect_data(struct perf_provider *provider, const WCHAR *query, void **data, DWORD *size, DWORD *obj_count) ++{ ++ DWORD err; ++ ++ err = provider->pOpen(NULL); ++ if (err != ERROR_SUCCESS) ++ { ++ TRACE("Open error %u (%#x)\n", err, err); ++ return err; ++ } ++ ++ *obj_count = 0; ++ err = provider->pCollect((WCHAR *)query, data, size, obj_count); ++ if (err != ERROR_SUCCESS) ++ { ++ TRACE("Collect error %u (%#x)\n", err, err); ++ *obj_count = 0; ++ } ++ ++ provider->pClose(); ++ return err; ++} ++ ++#define MAX_SERVICE_NAME 260 ++ ++static DWORD query_perf_data(const WCHAR *query, DWORD *type, void *data, DWORD *ret_size) ++{ ++ static const WCHAR SZ_SERVICES_KEY[] = { 'S','y','s','t','e','m','\\', ++ 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', ++ 'S','e','r','v','i','c','e','s',0 }; ++ DWORD err, i, data_size; ++ HKEY root; ++ PERF_DATA_BLOCK *pdb; ++ ++ if (!ret_size) ++ return ERROR_INVALID_PARAMETER; ++ ++ data_size = *ret_size; ++ *ret_size = 0; ++ ++ if (type) ++ *type = REG_BINARY; ++ ++ if (!data || data_size < sizeof(*pdb)) ++ return ERROR_MORE_DATA; ++ ++ pdb = data; ++ ++ pdb->Signature[0] = 'P'; ++ pdb->Signature[1] = 'E'; ++ pdb->Signature[2] = 'R'; ++ pdb->Signature[3] = 'F'; ++#ifdef WORDS_BIGENDIAN ++ pdb->LittleEndian = FALSE; ++#else ++ pdb->LittleEndian = TRUE; ++#endif ++ pdb->Version = PERF_DATA_VERSION; ++ pdb->Revision = PERF_DATA_REVISION; ++ pdb->TotalByteLength = 0; ++ pdb->HeaderLength = sizeof(*pdb); ++ pdb->NumObjectTypes = 0; ++ pdb->DefaultObject = 0; ++ QueryPerformanceCounter(&pdb->PerfTime); ++ QueryPerformanceFrequency(&pdb->PerfFreq); ++ ++ data = pdb + 1; ++ pdb->SystemNameOffset = sizeof(*pdb); ++ pdb->SystemNameLength = (data_size - sizeof(*pdb)) / sizeof(WCHAR); ++ if (!GetComputerNameW(data, &pdb->SystemNameLength)) ++ return ERROR_MORE_DATA; ++ ++ pdb->SystemNameLength++; ++ pdb->SystemNameLength *= sizeof(WCHAR); ++ ++ pdb->HeaderLength += pdb->SystemNameLength; ++ ++ /* align to 8 bytes */ ++ if (pdb->SystemNameLength & 7) ++ pdb->HeaderLength += 8 - (pdb->SystemNameLength & 7); ++ ++ if (data_size < pdb->HeaderLength) ++ return ERROR_MORE_DATA; ++ ++ pdb->TotalByteLength = pdb->HeaderLength; ++ ++ data_size -= pdb->HeaderLength; ++ data = (char *)data + pdb->HeaderLength; ++ ++ err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, SZ_SERVICES_KEY, 0, KEY_READ, &root); ++ if (err != ERROR_SUCCESS) ++ return err; ++ ++ i = 0; ++ for (;;) ++ { ++ DWORD collected_size = data_size, obj_count = 0; ++ struct perf_provider provider; ++ WCHAR name[MAX_SERVICE_NAME]; ++ void *collected_data = data; ++ ++ err = RegEnumKeyW(root, i++, name, MAX_SERVICE_NAME); ++ if (err == ERROR_NO_MORE_ITEMS) ++ { ++ err = ERROR_SUCCESS; ++ break; ++ } ++ ++ if (err != ERROR_SUCCESS) ++ continue; ++ ++ if (!load_provider(root, name, &provider)) ++ continue; ++ ++ err = collect_data(&provider, query, &collected_data, &collected_size, &obj_count); ++ FreeLibrary(provider.perflib); ++ ++ if (err == ERROR_MORE_DATA) ++ break; ++ ++ if (err == ERROR_SUCCESS) ++ { ++ PERF_OBJECT_TYPE *obj = (PERF_OBJECT_TYPE *)data; ++ ++ TRACE("Collect: obj->TotalByteLength %u, collected_size %u\n", ++ obj->TotalByteLength, collected_size); ++ ++ data_size -= collected_size; ++ data = collected_data; ++ ++ pdb->TotalByteLength += collected_size; ++ pdb->NumObjectTypes += obj_count; ++ } ++ } ++ ++ RegCloseKey(root); ++ ++ if (err == ERROR_SUCCESS) ++ { ++ *ret_size = pdb->TotalByteLength; ++ ++ GetSystemTime(&pdb->SystemTime); ++ GetSystemTimeAsFileTime((FILETIME *)&pdb->PerfTime100nSec); ++ } ++ ++ return err; ++} ++ + /****************************************************************************** + * RegQueryValueExW [ADVAPI32.@] + * +@@ -1502,6 +1729,10 @@ LSTATUS WINAPI RegQueryValueExW( HKEY hkey, LPCWSTR name, LPDWORD reserved, LPDW + (count && data) ? *count : 0 ); + + if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; ++ ++ if (hkey == HKEY_PERFORMANCE_DATA) ++ return query_perf_data(name, type, data, count); ++ + if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; + + RtlInitUnicodeString( &name_str, name ); +@@ -1592,7 +1823,8 @@ LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWO + hkey, debugstr_a(name), reserved, type, data, count, count ? *count : 0 ); + + if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; +- if (!(hkey = get_special_root_hkey( hkey, 0 ))) return ERROR_INVALID_HANDLE; ++ if (hkey != HKEY_PERFORMANCE_DATA && !(hkey = get_special_root_hkey( hkey, 0 ))) ++ return ERROR_INVALID_HANDLE; + + if (count) datalen = *count; + if (!data && count) *count = 0; +@@ -1604,6 +1836,13 @@ LSTATUS WINAPI DECLSPEC_HOTPATCH RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWO + if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE ))) + return RtlNtStatusToDosError(status); + ++ if (hkey == HKEY_PERFORMANCE_DATA) ++ { ++ DWORD ret = query_perf_data( nameW.Buffer, type, data, count ); ++ RtlFreeUnicodeString( &nameW ); ++ return ret; ++ } ++ + status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, + buffer, sizeof(buffer), &total_size ); + if (status && status != STATUS_BUFFER_OVERFLOW) goto done; +diff --git a/dlls/advapi32/tests/registry.c b/dlls/advapi32/tests/registry.c +index d850f6a3aa7..d7a25eb8c6b 100644 +--- a/dlls/advapi32/tests/registry.c ++++ b/dlls/advapi32/tests/registry.c +@@ -3559,10 +3559,10 @@ static void test_RegQueryValueExPerformanceData(void) + + /* Test with data == NULL */ + dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, NULL, &cbData ); +- todo_wine ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); ++ ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); + + dwret = RegQueryValueExW( HKEY_PERFORMANCE_DATA, globalW, NULL, NULL, NULL, &cbData ); +- todo_wine ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); ++ ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); + + /* Test ERROR_MORE_DATA, start with small buffer */ + len = 10; +@@ -3570,8 +3570,7 @@ static void test_RegQueryValueExPerformanceData(void) + cbData = len; + type = 0xdeadbeef; + dwret = RegQueryValueExA( HKEY_PERFORMANCE_DATA, "Global", NULL, &type, value, &cbData ); +- todo_wine ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); +-todo_wine ++ ok( dwret == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", dwret ); + ok(type == REG_BINARY, "got %u\n", type); + while( dwret == ERROR_MORE_DATA && limit) + { +@@ -3584,14 +3583,13 @@ todo_wine + } + ok(limit > 0, "too many times ERROR_MORE_DATA returned\n"); + +- todo_wine ok(dwret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", dwret); +-todo_wine ++ ok(dwret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", dwret); + ok(type == REG_BINARY, "got %u\n", type); + + /* Check returned data */ + if (dwret == ERROR_SUCCESS) + { +- todo_wine ok(len >= sizeof(PERF_DATA_BLOCK), "got size %d\n", len); ++ ok(len >= sizeof(PERF_DATA_BLOCK), "got size %d\n", len); + if (len >= sizeof(PERF_DATA_BLOCK)) { + pdb = (PERF_DATA_BLOCK*) value; + ok(pdb->Signature[0] == 'P', "expected Signature[0] = 'P', got 0x%x\n", pdb->Signature[0]); +@@ -3608,13 +3606,11 @@ todo_wine + { + cbData = 0xdeadbeef; + dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, names[i], NULL, NULL, NULL, &cbData); +-todo_wine + ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret); + ok(cbData == 0, "got %u\n", cbData); + + cbData = 0; + dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, names[i], NULL, NULL, NULL, &cbData); +-todo_wine + ok(dwret == ERROR_MORE_DATA, "%u/%s: got %u\n", i, names[i], dwret); + ok(cbData == 0, "got %u\n", cbData); + +@@ -3647,9 +3643,7 @@ todo_wine + type = 0xdeadbeef; + cbData = sizeof(buf); + dwret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "invalid counter name", NULL, &type, buf, &cbData); +-todo_wine + ok(dwret == ERROR_SUCCESS, "got %u\n", dwret); +-todo_wine + ok(type == REG_BINARY, "got %u\n", type); + if (dwret == ERROR_SUCCESS) + { +@@ -3679,6 +3673,7 @@ todo_wine + ok(pdb->TotalByteLength == len, "got %u vs %u\n", pdb->TotalByteLength, len); + ok(pdb->HeaderLength == pdb->TotalByteLength, "got %u\n", pdb->HeaderLength); + ok(pdb->NumObjectTypes == 0, "got %u\n", pdb->NumObjectTypes); ++todo_wine + ok(pdb->DefaultObject != 0, "got %u\n", pdb->DefaultObject); + ok(pdb->SystemTime.wYear == st.wYear, "got %u\n", pdb->SystemTime.wYear); + ok(pdb->SystemTime.wMonth == st.wMonth, "got %u\n", pdb->SystemTime.wMonth); +-- +2.13.1 + diff --git a/patches/advapi32-Performance_Counters/0004-winspool.drv-Add-performance-counters-service-stubs.patch b/patches/advapi32-Performance_Counters/0004-winspool.drv-Add-performance-counters-service-stubs.patch new file mode 100644 index 00000000..636ffdac --- /dev/null +++ b/patches/advapi32-Performance_Counters/0004-winspool.drv-Add-performance-counters-service-stubs.patch @@ -0,0 +1,93 @@ +From efdcec40d501c6b27e3f3460ad0ad5fe26643e9d Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 12 Apr 2017 15:04:03 +0800 +Subject: winspool.drv: Add performance counters service stubs. + +--- + dlls/winspool.drv/info.c | 29 +++++++++++++++++++++++++++++ + dlls/winspool.drv/winspool.drv.spec | 6 +++--- + loader/wine.inf.in | 7 +++++++ + 3 files changed, 39 insertions(+), 3 deletions(-) + +diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c +index f09745d1e6b..330ce236b45 100644 +--- a/dlls/winspool.drv/info.c ++++ b/dlls/winspool.drv/info.c +@@ -8681,3 +8681,32 @@ HRESULT WINAPI UploadPrinterDriverPackageW( LPCWSTR server, LPCWSTR path, LPCWST + flags, hwnd, dst, dstlen); + return E_NOTIMPL; + } ++ ++/***************************************************************************** ++ * PerfOpen [WINSPOOL.@] ++ */ ++DWORD WINAPI PerfOpen(LPWSTR context) ++{ ++ FIXME("%s: stub\n", debugstr_w(context)); ++ return ERROR_SUCCESS; ++} ++ ++/***************************************************************************** ++ * PerfClose [WINSPOOL.@] ++ */ ++DWORD WINAPI PerfClose(void) ++{ ++ FIXME("stub\n"); ++ return ERROR_SUCCESS; ++} ++ ++/***************************************************************************** ++ * PerfCollect [WINSPOOL.@] ++ */ ++DWORD WINAPI PerfCollect(LPWSTR query, LPVOID *data, LPDWORD size, LPDWORD obj_count) ++{ ++ FIXME("%s,%p,%p,%p: stub\n", debugstr_w(query), data, size, obj_count); ++ *size = 0; ++ *obj_count = 0; ++ return ERROR_SUCCESS; ++} +diff --git a/dlls/winspool.drv/winspool.drv.spec b/dlls/winspool.drv/winspool.drv.spec +index 58dc60bcc9f..a23ea2ced99 100644 +--- a/dlls/winspool.drv/winspool.drv.spec ++++ b/dlls/winspool.drv/winspool.drv.spec +@@ -2,9 +2,9 @@ + 101 stub -noname ClusterSplOpen + 102 stub -noname ClusterSplClose + 103 stub -noname ClusterSplIsAlive +-104 stub PerfClose +-105 stub PerfCollect +-106 stub PerfOpen ++104 stdcall PerfClose() ++105 stdcall PerfCollect(wstr ptr ptr ptr) ++106 stdcall PerfOpen(wstr) + 201 stdcall GetDefaultPrinterA(ptr ptr) + 202 stdcall SetDefaultPrinterA(str) + 203 stdcall GetDefaultPrinterW(ptr ptr) +diff --git a/loader/wine.inf.in b/loader/wine.inf.in +index 176647b8beb..a83cc209a96 100644 +--- a/loader/wine.inf.in ++++ b/loader/wine.inf.in +@@ -3353,6 +3353,7 @@ StartType=3 + ErrorControl=1 + + [SpoolerService] ++AddReg=SpoolerServiceKeys + Description="Loads files to memory for later printing" + DisplayName="Print Spooler" + ServiceBinary="%11%\spoolsv.exe" +@@ -3361,6 +3362,12 @@ StartType=3 + ErrorControl=1 + LoadOrderGroup="SpoolerGroup" + ++[SpoolerServiceKeys] ++HKLM,"System\CurrentControlSet\Services\Spooler\Performance","Library",,"winspool.drv" ++HKLM,"System\CurrentControlSet\Services\Spooler\Performance","Open",,"PerfOpen" ++HKLM,"System\CurrentControlSet\Services\Spooler\Performance","Close",,"PerfClose" ++HKLM,"System\CurrentControlSet\Services\Spooler\Performance","Collect",,"PerfCollect" ++ + [TerminalServices] + Description="Remote desktop access" + DisplayName="Terminal Services" +-- +2.13.1 + diff --git a/patches/advapi32-Performance_Counters/0005-advapi32-Performance-providers-Open-expects-to-see-t.patch b/patches/advapi32-Performance_Counters/0005-advapi32-Performance-providers-Open-expects-to-see-t.patch new file mode 100644 index 00000000..6652ff1c --- /dev/null +++ b/patches/advapi32-Performance_Counters/0005-advapi32-Performance-providers-Open-expects-to-see-t.patch @@ -0,0 +1,72 @@ +From ea1f7f191b65313ed472e660a10d75e609a31dfc Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Fri, 14 Apr 2017 16:39:21 +0800 +Subject: advapi32: Performance providers' Open() expects to see the configured + name as its parameter. + +--- + dlls/advapi32/registry.c | 23 +++++++++++++++++++++-- + 1 file changed, 21 insertions(+), 2 deletions(-) + +diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c +index a6e5c7903cf..37462380c40 100644 +--- a/dlls/advapi32/registry.c ++++ b/dlls/advapi32/registry.c +@@ -1487,6 +1487,7 @@ LONG WINAPI RegSetKeyValueA( HKEY hkey, LPCSTR subkey, LPCSTR name, DWORD type, + struct perf_provider + { + HMODULE perflib; ++ WCHAR linkage[MAX_PATH]; + PM_OPEN_PROC *pOpen; + PM_CLOSE_PROC *pClose; + PM_COLLECT_PROC *pCollect; +@@ -1512,6 +1513,8 @@ static BOOL load_provider(HKEY root, const WCHAR *name, struct perf_provider *pr + { + static const WCHAR performanceW[] = { 'P','e','r','f','o','r','m','a','n','c','e',0 }; + static const WCHAR libraryW[] = { 'L','i','b','r','a','r','y',0 }; ++ static const WCHAR linkageW[] = { 'L','i','n','k','a','g','e',0 }; ++ static const WCHAR exportW[] = { 'E','x','p','o','r','t',0 }; + WCHAR buf[MAX_PATH], buf2[MAX_PATH]; + DWORD err, type, len; + HKEY service, perf; +@@ -1520,6 +1523,21 @@ static BOOL load_provider(HKEY root, const WCHAR *name, struct perf_provider *pr + if (err != ERROR_SUCCESS) + return FALSE; + ++ provider->linkage[0] = 0; ++ err = RegOpenKeyExW(service, linkageW, 0, KEY_READ, &perf); ++ if (err == ERROR_SUCCESS) ++ { ++ len = sizeof(buf) - sizeof(WCHAR); ++ err = RegQueryValueExW(perf, exportW, NULL, &type, (BYTE *)buf, &len); ++ if (err == ERROR_SUCCESS && (type == REG_SZ || type == REG_MULTI_SZ)) ++ { ++ memcpy(provider->linkage, buf, len); ++ provider->linkage[len / sizeof(WCHAR)] = 0; ++ TRACE("Export: %s\n", debugstr_w(provider->linkage)); ++ } ++ RegCloseKey(perf); ++ } ++ + err = RegOpenKeyExW(service, performanceW, 0, KEY_READ, &perf); + RegCloseKey(service); + if (err != ERROR_SUCCESS) +@@ -1563,12 +1581,13 @@ error: + + static DWORD collect_data(struct perf_provider *provider, const WCHAR *query, void **data, DWORD *size, DWORD *obj_count) + { ++ WCHAR *linkage = provider->linkage[0] ? provider->linkage : NULL; + DWORD err; + +- err = provider->pOpen(NULL); ++ err = provider->pOpen(linkage); + if (err != ERROR_SUCCESS) + { +- TRACE("Open error %u (%#x)\n", err, err); ++ TRACE("Open(%s) error %u (%#x)\n", debugstr_w(linkage), err, err); + return err; + } + +-- +2.13.1 + diff --git a/patches/advapi32-Performance_Counters/0006-advapi32-If-the-query-is-not-specified-the-default-q.patch b/patches/advapi32-Performance_Counters/0006-advapi32-If-the-query-is-not-specified-the-default-q.patch new file mode 100644 index 00000000..df81d4fa --- /dev/null +++ b/patches/advapi32-Performance_Counters/0006-advapi32-If-the-query-is-not-specified-the-default-q.patch @@ -0,0 +1,31 @@ +From f734e1d94b068a78cc10600c190bb2d527ab4866 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Fri, 14 Apr 2017 16:40:43 +0800 +Subject: advapi32: If the query is not specified the default query is + "Global". + +--- + dlls/advapi32/registry.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c +index 37462380c40..0aa38c5b9b3 100644 +--- a/dlls/advapi32/registry.c ++++ b/dlls/advapi32/registry.c +@@ -1581,9 +1581,13 @@ error: + + static DWORD collect_data(struct perf_provider *provider, const WCHAR *query, void **data, DWORD *size, DWORD *obj_count) + { ++ static const WCHAR globalW[] = { 'G','l','o','b','a','l',0 }; + WCHAR *linkage = provider->linkage[0] ? provider->linkage : NULL; + DWORD err; + ++ if (!query || !query[0]) ++ query = globalW; ++ + err = provider->pOpen(linkage); + if (err != ERROR_SUCCESS) + { +-- +2.13.1 + diff --git a/patches/advapi32-Performance_Counters/0007-advapi32-Read-the-configured-object-list-for-the-per.patch b/patches/advapi32-Performance_Counters/0007-advapi32-Read-the-configured-object-list-for-the-per.patch new file mode 100644 index 00000000..2688cda7 --- /dev/null +++ b/patches/advapi32-Performance_Counters/0007-advapi32-Read-the-configured-object-list-for-the-per.patch @@ -0,0 +1,53 @@ +From de80831314ecb76ac22b19b249467a600129a9e3 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Fri, 14 Apr 2017 16:43:31 +0800 +Subject: advapi32: Read the configured object list for the performance + provider. + +FIXME: it's not currently used, but the queries should be matched +against the configured object lists, and the providers should be +loaded and called only in case of a match. +--- + dlls/advapi32/registry.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/dlls/advapi32/registry.c b/dlls/advapi32/registry.c +index 0aa38c5b9b3..5af8128748b 100644 +--- a/dlls/advapi32/registry.c ++++ b/dlls/advapi32/registry.c +@@ -1488,6 +1488,7 @@ struct perf_provider + { + HMODULE perflib; + WCHAR linkage[MAX_PATH]; ++ WCHAR objects[MAX_PATH]; + PM_OPEN_PROC *pOpen; + PM_CLOSE_PROC *pClose; + PM_COLLECT_PROC *pCollect; +@@ -1511,6 +1512,7 @@ static void *get_provider_entry(HKEY perf, HMODULE perflib, const char *name) + + static BOOL load_provider(HKEY root, const WCHAR *name, struct perf_provider *provider) + { ++ static const WCHAR object_listW[] = { 'O','b','j','e','c','t',' ','L','i','s','t',0 }; + static const WCHAR performanceW[] = { 'P','e','r','f','o','r','m','a','n','c','e',0 }; + static const WCHAR libraryW[] = { 'L','i','b','r','a','r','y',0 }; + static const WCHAR linkageW[] = { 'L','i','n','k','a','g','e',0 }; +@@ -1543,6 +1545,16 @@ static BOOL load_provider(HKEY root, const WCHAR *name, struct perf_provider *pr + if (err != ERROR_SUCCESS) + return FALSE; + ++ provider->objects[0] = 0; ++ len = sizeof(buf) - sizeof(WCHAR); ++ err = RegQueryValueExW(perf, object_listW, NULL, &type, (BYTE *)buf, &len); ++ if (err == ERROR_SUCCESS && (type == REG_SZ || type == REG_MULTI_SZ)) ++ { ++ memcpy(provider->objects, buf, len); ++ provider->objects[len / sizeof(WCHAR)] = 0; ++ TRACE("Object List: %s\n", debugstr_w(provider->objects)); ++ } ++ + len = sizeof(buf) - sizeof(WCHAR); + err = RegQueryValueExW(perf, libraryW, NULL, &type, (BYTE *)buf, &len); + if (err != ERROR_SUCCESS || !(type == REG_SZ || type == REG_EXPAND_SZ)) +-- +2.13.1 + diff --git a/patches/advapi32-Performance_Counters/definition b/patches/advapi32-Performance_Counters/definition new file mode 100644 index 00000000..64281726 --- /dev/null +++ b/patches/advapi32-Performance_Counters/definition @@ -0,0 +1 @@ +Fixes: [33037] Add support for querying performance counters data diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index bd668f03..a34d6308 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -90,6 +90,7 @@ patch_enable_all () enable_advapi32_BuildSecurityDescriptor="$1" enable_advapi32_GetExplicitEntriesFromAclW="$1" enable_advapi32_LsaLookupSids="$1" + enable_advapi32_Performance_Counters="$1" enable_advapi32_SetSecurityInfo="$1" enable_advapi32_WinBuiltinAnyPackageSid="$1" enable_api_ms_win_Stub_DLLs="$1" @@ -514,6 +515,9 @@ patch_enable () advapi32-LsaLookupSids) enable_advapi32_LsaLookupSids="$2" ;; + advapi32-Performance_Counters) + enable_advapi32_Performance_Counters="$2" + ;; advapi32-SetSecurityInfo) enable_advapi32_SetSecurityInfo="$2" ;; @@ -3047,6 +3051,34 @@ if test "$enable_advapi32_LsaLookupSids" -eq 1; then ) >> "$patchlist" fi +# Patchset advapi32-Performance_Counters +# | +# | This patchset fixes the following Wine bugs: +# | * [#33037] Add support for querying performance counters data +# | +# | Modified files: +# | * dlls/advapi32/registry.c, dlls/advapi32/tests/registry.c, dlls/winspool.drv/info.c, dlls/winspool.drv/winspool.drv.spec, +# | include/winperf.h, include/winreg.h, loader/wine.inf.in +# | +if test "$enable_advapi32_Performance_Counters" -eq 1; then + patch_apply advapi32-Performance_Counters/0001-advapi32-tests-Add-more-tests-for-performance-counte.patch + patch_apply advapi32-Performance_Counters/0002-include-Add-more-definitions-for-performance-counter.patch + patch_apply advapi32-Performance_Counters/0003-advapi32-Add-initial-support-for-querying-performanc.patch + patch_apply advapi32-Performance_Counters/0004-winspool.drv-Add-performance-counters-service-stubs.patch + patch_apply advapi32-Performance_Counters/0005-advapi32-Performance-providers-Open-expects-to-see-t.patch + patch_apply advapi32-Performance_Counters/0006-advapi32-If-the-query-is-not-specified-the-default-q.patch + patch_apply advapi32-Performance_Counters/0007-advapi32-Read-the-configured-object-list-for-the-per.patch + ( + printf '%s\n' '+ { "Dmitry Timoshkov", "advapi32/tests: Add more tests for performance counters.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "include: Add more definitions for performance counters.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "advapi32: Add initial support for querying performance counters data.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "winspool.drv: Add performance counters service stubs.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "advapi32: Performance providers'\'' Open() expects to see the configured name as its parameter.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "advapi32: If the query is not specified the default query is \"Global\".", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "advapi32: Read the configured object list for the performance provider.", 1 },'; + ) >> "$patchlist" +fi + # Patchset advapi32-SetSecurityInfo # | # | This patchset fixes the following Wine bugs: