These functions are used by Visual Studio 2019, when opening or converting some projects.
Signed-off-by: Lorenzo Ferrillo lorenzofersteam@live.it
-- v19: kernelbase: Check for PERF_SIZE_LARGE in PerfSetULongLongCounterValue and PerfSetULongCounterValue kernelbase : Check for PERF_ATTRIB_BY_REFERENCE attribute in PerfSetCounterRefValue advapi32/test: Add Test For PerfSetULongLongCounterValue advapi32/tests: Create Tests for PerfSetULongCounterValue. advapi32: Forward PerfSetULongCounterValue and PerfSetULongLongCounterValue to kernelbase kernelbase: Add implementation for PerfSetULongLongCounterValue kernelbase: Add implementation of PerfSetULongCounterValue kernelbase: factor out common functionality for performance counter functions
From: Lorenzo Ferrillo lorenzofersteam@live.it
--- dlls/kernelbase/main.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-)
diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index 60173ba6513..4c373f06e57 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -301,6 +301,29 @@ ULONG WINAPI PerfSetCounterSetInfo( HANDLE handle, PERF_COUNTERSET_INFO *templat return STATUS_SUCCESS; }
+ +static unsigned int get_performance_counter_index(PERF_COUNTERSET_INSTANCE *instance, ULONG counter_id, struct counterset_template ** out_template,struct counterset_instance ** out_instance) +{ + unsigned int i; + struct counterset_template *template; + struct counterset_instance *inst; + + inst = CONTAINING_RECORD(instance, struct counterset_instance, instance); + template = inst->template; + + *out_instance = inst; + *out_template = template; + + for (i = 0; i < template->counterset.NumCounters; ++i) + if (template->counter[i].CounterId == counter_id) return i; + return template->counterset.NumCounters; +} + +static BYTE* get_performance_counter_address(struct counterset_template* template, struct counterset_instance* instance, unsigned int counter_index) +{ + return (BYTE*) &instance->instance + sizeof(PERF_COUNTERSET_INSTANCE) + template->counter[counter_index].Offset; +} + /*********************************************************************** * PerfSetCounterRefValue (KERNELBASE.@) */ @@ -310,21 +333,17 @@ ULONG WINAPI PerfSetCounterRefValue(HANDLE provider, PERF_COUNTERSET_INSTANCE *i struct perf_provider *prov = perf_provider_from_handle( provider ); struct counterset_template *template; struct counterset_instance *inst; - unsigned int i; + unsigned int counter_index;;
FIXME( "provider %p, instance %p, counterid %lu, address %p semi-stub.\n", provider, instance, counterid, address );
if (!prov || !instance || !address) return ERROR_INVALID_PARAMETER;
- inst = CONTAINING_RECORD(instance, struct counterset_instance, instance); - template = inst->template; - - for (i = 0; i < template->counterset.NumCounters; ++i) - if (template->counter[i].CounterId == counterid) break; + counter_index = get_performance_counter_index(instance, counterid, &template, &inst);
- if (i == template->counterset.NumCounters) return ERROR_NOT_FOUND; - *(void **)((BYTE *)&inst->instance + sizeof(PERF_COUNTERSET_INSTANCE) + template->counter[i].Offset) = address; + if (counter_index== template->counterset.NumCounters) return ERROR_NOT_FOUND; + *(void **)(get_performance_counter_address(template,inst, counter_index)) = address;
return STATUS_SUCCESS; }
From: Lorenzo Ferrillo lorenzofersteam@live.it
--- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/main.c | 26 ++++++++++++++++++++++++++ include/perflib.h | 1 + 3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index d11a4417d48..fa6858a893a 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1195,7 +1195,7 @@ # @ stub PerfQueryInstance @ stdcall PerfSetCounterRefValue(long ptr long ptr) @ stdcall PerfSetCounterSetInfo(long ptr long) -# @ stub PerfSetULongCounterValue +@ stdcall PerfSetULongCounterValue(long ptr long long) # @ stub PerfSetULongLongCounterValue @ stdcall PerfStartProvider(ptr ptr ptr) @ stdcall PerfStartProviderEx(ptr ptr ptr) diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index 4c373f06e57..c50fb193178 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -348,6 +348,32 @@ ULONG WINAPI PerfSetCounterRefValue(HANDLE provider, PERF_COUNTERSET_INSTANCE *i return STATUS_SUCCESS; }
+/*********************************************************************** + * PerfSetULongCounterValue (KERNELBASE.@) + */ +ULONG WINAPI PerfSetULongCounterValue(HANDLE provider, PERF_COUNTERSET_INSTANCE *instance, + ULONG counterid, ULONG value) +{ + struct perf_provider *prov = perf_provider_from_handle( provider ); + struct counterset_template *template; + struct counterset_instance *inst; + unsigned int counter_index; + + TRACE( "provider %p, instance %p, counterid %lu, address %lu semi-stub.\n", + provider, instance, counterid, value ); + + if (!prov || !instance) return ERROR_INVALID_PARAMETER; + + counter_index = get_performance_counter_index(instance, counterid, &template, &inst); + + if (counter_index == template->counterset.NumCounters) return ERROR_NOT_FOUND; + if (template->counter[counter_index].Attrib & PERF_ATTRIB_BY_REFERENCE) return ERROR_INVALID_PARAMETER; + + *(ULONG*)(get_performance_counter_address(template,inst, counter_index)) = value; + + return STATUS_SUCCESS; +} + /*********************************************************************** * PerfStartProvider (KERNELBASE.@) */ diff --git a/include/perflib.h b/include/perflib.h index 188f26e3e74..53c17f9efe8 100644 --- a/include/perflib.h +++ b/include/perflib.h @@ -106,6 +106,7 @@ typedef struct _PERF_DATA_HEADER { PERF_COUNTERSET_INSTANCE WINAPI *PerfCreateInstance(HANDLE, const GUID *, const WCHAR *, ULONG); ULONG WINAPI PerfDeleteInstance(HANDLE, PERF_COUNTERSET_INSTANCE *); ULONG WINAPI PerfSetCounterRefValue(HANDLE, PERF_COUNTERSET_INSTANCE *, ULONG, void *); +ULONG WINAPI PerfSetULongCounterValue(HANDLE, PERF_COUNTERSET_INSTANCE *, ULONG, ULONG); ULONG WINAPI PerfSetCounterSetInfo(HANDLE, PERF_COUNTERSET_INFO *, ULONG); ULONG WINAPI PerfStartProvider(GUID *, PERFLIBREQUEST, HANDLE *); ULONG WINAPI PerfStartProviderEx(GUID *, PERF_PROVIDER_CONTEXT *, HANDLE *);
From: Lorenzo Ferrillo lorenzofersteam@live.it
--- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/main.c | 26 ++++++++++++++++++++++++++ include/perflib.h | 1 + 3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index fa6858a893a..daab63e85e2 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1196,7 +1196,7 @@ @ stdcall PerfSetCounterRefValue(long ptr long ptr) @ stdcall PerfSetCounterSetInfo(long ptr long) @ stdcall PerfSetULongCounterValue(long ptr long long) -# @ stub PerfSetULongLongCounterValue +@ stdcall PerfSetULongLongCounterValue(long ptr long int64) @ stdcall PerfStartProvider(ptr ptr ptr) @ stdcall PerfStartProviderEx(ptr ptr ptr) @ stdcall PerfStopProvider(long) diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index c50fb193178..1b3b450cfff 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -374,6 +374,32 @@ ULONG WINAPI PerfSetULongCounterValue(HANDLE provider, PERF_COUNTERSET_INSTANCE return STATUS_SUCCESS; }
+/*********************************************************************** + * PerfSetULongLongCounterValue (KERNELBASE.@) + */ +ULONG WINAPI PerfSetULongLongCounterValue(HANDLE provider, PERF_COUNTERSET_INSTANCE *instance, + ULONG counterid, ULONGLONG value) +{ + struct perf_provider *prov = perf_provider_from_handle( provider ); + struct counterset_template *template; + struct counterset_instance *inst; + unsigned int counter_index; + + TRACE( "provider %p, instance %p, counterid %lu, address %I64u semi-stub.\n", + provider, instance, counterid, value ); + + if (!prov || !instance) return ERROR_INVALID_PARAMETER; + + counter_index = get_performance_counter_index(instance, counterid, &template, &inst); + + if (counter_index == template->counterset.NumCounters) return ERROR_NOT_FOUND; + if (template->counter[counter_index].Attrib & PERF_ATTRIB_BY_REFERENCE) return ERROR_INVALID_PARAMETER; + + *(ULONGLONG*)(get_performance_counter_address(template,inst, counter_index)) = value; + + return STATUS_SUCCESS; +} + /*********************************************************************** * PerfStartProvider (KERNELBASE.@) */ diff --git a/include/perflib.h b/include/perflib.h index 53c17f9efe8..6d14daffc4d 100644 --- a/include/perflib.h +++ b/include/perflib.h @@ -107,6 +107,7 @@ PERF_COUNTERSET_INSTANCE WINAPI *PerfCreateInstance(HANDLE, const GUID *, const ULONG WINAPI PerfDeleteInstance(HANDLE, PERF_COUNTERSET_INSTANCE *); ULONG WINAPI PerfSetCounterRefValue(HANDLE, PERF_COUNTERSET_INSTANCE *, ULONG, void *); ULONG WINAPI PerfSetULongCounterValue(HANDLE, PERF_COUNTERSET_INSTANCE *, ULONG, ULONG); +ULONG WINAPI PerfSetULongLongCounterValue(HANDLE, PERF_COUNTERSET_INSTANCE *, ULONG, ULONGLONG); ULONG WINAPI PerfSetCounterSetInfo(HANDLE, PERF_COUNTERSET_INFO *, ULONG); ULONG WINAPI PerfStartProvider(GUID *, PERFLIBREQUEST, HANDLE *); ULONG WINAPI PerfStartProviderEx(GUID *, PERF_PROVIDER_CONTEXT *, HANDLE *);
From: Lorenzo Ferrillo lorenzofersteam@live.it
VS2019 call these functions from kernelbase --- dlls/advapi32/advapi32.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec index 79b64df8abb..e4b6c5a981a 100644 --- a/dlls/advapi32/advapi32.spec +++ b/dlls/advapi32/advapi32.spec @@ -577,8 +577,8 @@ # @ stub PerfRegSetValue @ stdcall -import PerfSetCounterRefValue(long ptr long ptr) @ stdcall -import PerfSetCounterSetInfo(long ptr long) -# @ stub PerfSetULongCounterValue -# @ stub PerfSetULongLongCounterValue +@ stdcall -import PerfSetULongCounterValue(long ptr long long) +@ stdcall -import PerfSetULongLongCounterValue(long ptr long int64) @ stdcall -import PerfStartProvider(ptr ptr ptr) @ stdcall -import PerfStartProviderEx(ptr ptr ptr) @ stdcall -import PerfStopProvider(long)
From: Lorenzo Ferrillo lorenzofersteam@live.it
Also add tests showing that PerfSetCounterRefValue cannot be used without BYREF counters --- dlls/advapi32/tests/perf.c | 77 +++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 6 deletions(-)
diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index 7481020dd4e..f8b29662d7c 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -54,17 +54,18 @@ static ULONG WINAPI test_provider_callback(ULONG code, void *buffer, ULONG size) return ERROR_SUCCESS; }
+struct template +{ + PERF_COUNTERSET_INFO counterset; + PERF_COUNTER_INFO counter[2]; +}; + void test_provider_init(void) { static GUID test_set_guid = {0xdeadbeef, 0x0002, 0x0003, {0x0f, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; static GUID test_set_guid2 = {0xdeadbeef, 0x0003, 0x0003, {0x0f, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; static GUID test_guid = {0xdeadbeef, 0x0001, 0x0002, {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}}; - static struct - { - PERF_COUNTERSET_INFO counterset; - PERF_COUNTER_INFO counter[2]; - } - pc_template = + struct template pc_template = { {{0}}, { @@ -74,6 +75,16 @@ void test_provider_init(void) PERF_DETAIL_NOVICE, 0, 0xdeadbeef}, }, }; + struct template pc_template_val = + { + {{0}}, + { + {1, PERF_COUNTER_COUNTER, 0, sizeof(PERF_COUNTER_INFO), + PERF_DETAIL_NOVICE, 0, 0xdeadbeef}, + {2, PERF_COUNTER_COUNTER, 0, sizeof(PERF_COUNTER_INFO), + PERF_DETAIL_NOVICE, 0, 0xdeadbeef}, + }, + };
PERF_COUNTERSET_INSTANCE *instance; PERF_PROVIDER_CONTEXT prov_context; @@ -187,6 +198,60 @@ void test_provider_init(void) ok(*(void **)((BYTE *)instance + sizeof(*instance) + sizeof(UINT64)) == &counter2, "Got unexpected counter value %p.\n", *(void **)(instance + 1));
+ /*Counter defined as BYREF error if modified with SetValue functions*/ + ret = PerfSetULongCounterValue(prov, instance, 1, 666L); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongCounterValue(prov, instance, 2, 900000L); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + ret = PerfSetULongCounterValue(prov, instance, 0, 42L); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %lu.\n", ret); + + ret = PerfDeleteInstance(prov, instance); + ok(!ret, "Got unexpected ret %lu.\n", ret); + ret = PerfStopProvider(prov); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + ret = PerfStartProvider(&test_guid, test_provider_callback, &prov); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + pc_template_val.counterset.CounterSetGuid = test_set_guid; + pc_template_val.counterset.ProviderGuid = test_guid; + pc_template_val.counterset.NumCounters = 2; + pc_template_val.counterset.InstanceType = PERF_COUNTERSET_SINGLE_INSTANCE; + ret = PerfSetCounterSetInfo(prov, &pc_template_val.counterset, sizeof(pc_template_val)); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + instance = PerfCreateInstance(prov, &test_set_guid, L"11", 1); + ok(!!instance, "Got NULL instance.\n"); + ok(instance->InstanceId == 1, "Got unexpected InstanceId %lu.\n", instance->InstanceId); + ok(instance->InstanceNameSize == 6, "Got unexpected InstanceNameSize %lu.\n", instance->InstanceNameSize); + ok(IsEqualGUID(&instance->CounterSetGuid, &test_set_guid), "Got unexpected guid %s.\n", + debugstr_guid(&instance->CounterSetGuid)); + + ret = PerfSetULongCounterValue(prov, instance, 1, 666L); + ok(!ret, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongCounterValue(prov, instance, 2, 900000L); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + ret = PerfSetULongCounterValue(prov, instance, 0, 42); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %lu.\n", ret); + + ok(*(ULONG *)(instance + 1) == 666L, "Got unexpected counter value %lu.\n", + *(ULONG *)(instance + 1)); + ok(*(ULONG *)((BYTE *)instance + sizeof(*instance) + sizeof(UINT64)) == 900000L, + "Got unexpected counter value %lu.\n", *(ULONG *)(instance + 1)); + + ret = PerfSetULongCounterValue(prov, instance, 1, 55L); + ok(!ret, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongCounterValue(prov, instance, 2, 9000L); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + ret = PerfSetCounterRefValue(prov, instance, 1, &counter1); + todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ret = PerfSetCounterRefValue(prov, instance, 2, &counter2); + todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ret = PerfDeleteInstance(prov, instance); ok(!ret, "Got unexpected ret %lu.\n", ret);
From: Lorenzo Ferrillo lorenzofersteam@live.it
--- dlls/advapi32/tests/perf.c | 67 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)
diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index f8b29662d7c..82114449c66 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -85,6 +85,16 @@ void test_provider_init(void) PERF_DETAIL_NOVICE, 0, 0xdeadbeef}, }, }; + struct template pc_template_val_long = + { + {{0}}, + { + {1, (PERF_COUNTER_COUNTER & ~PERF_SIZE_DWORD) | PERF_SIZE_LARGE, 0, sizeof(PERF_COUNTER_INFO), + PERF_DETAIL_NOVICE, 0, 0xdeadbeef}, + {2, (PERF_COUNTER_COUNTER & ~PERF_SIZE_DWORD) | PERF_SIZE_LARGE, 0, sizeof(PERF_COUNTER_INFO), + PERF_DETAIL_NOVICE, 0, 0xdeadbeef}, + }, + };
PERF_COUNTERSET_INSTANCE *instance; PERF_PROVIDER_CONTEXT prov_context; @@ -203,9 +213,15 @@ void test_provider_init(void) ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); ret = PerfSetULongCounterValue(prov, instance, 2, 900000L); ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongLongCounterValue(prov, instance, 1, 666L); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongLongCounterValue(prov, instance, 2, 900000L); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret);
ret = PerfSetULongCounterValue(prov, instance, 0, 42L); ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongLongCounterValue(prov, instance, 0, 42L); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %lu.\n", ret);
ret = PerfDeleteInstance(prov, instance); ok(!ret, "Got unexpected ret %lu.\n", ret); @@ -247,6 +263,15 @@ void test_provider_init(void) ret = PerfSetULongCounterValue(prov, instance, 2, 9000L); ok(!ret, "Got unexpected ret %lu.\n", ret);
+ /* Cannot be used with PERF_SIZE_DWORD */ + ret = PerfSetULongLongCounterValue(prov, instance, 1, 900000L); + todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongLongCounterValue(prov, instance, 2, 666L); + todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + ret = PerfSetULongLongCounterValue(prov, instance, 0, 42); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %lu.\n", ret); + ret = PerfSetCounterRefValue(prov, instance, 1, &counter1); todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); ret = PerfSetCounterRefValue(prov, instance, 2, &counter2); @@ -258,6 +283,48 @@ void test_provider_init(void) ret = PerfStopProvider(prov); ok(!ret, "Got unexpected ret %lu.\n", ret);
+ ret = PerfStartProvider(&test_guid, test_provider_callback, &prov); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + pc_template_val_long.counterset.CounterSetGuid = test_set_guid; + pc_template_val_long.counterset.ProviderGuid = test_guid; + pc_template_val_long.counterset.NumCounters = 2; + pc_template_val_long.counterset.InstanceType = PERF_COUNTERSET_SINGLE_INSTANCE; + ret = PerfSetCounterSetInfo(prov, &pc_template_val_long.counterset, sizeof(pc_template_val_long)); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + instance = PerfCreateInstance(prov, &test_set_guid, L"11", 1); + ok(!!instance, "Got NULL instance.\n"); + ok(instance->InstanceId == 1, "Got unexpected InstanceId %lu.\n", instance->InstanceId); + ok(instance->InstanceNameSize == 6, "Got unexpected InstanceNameSize %lu.\n", instance->InstanceNameSize); + ok(IsEqualGUID(&instance->CounterSetGuid, &test_set_guid), "Got unexpected guid %s.\n", + debugstr_guid(&instance->CounterSetGuid)); + + ret = PerfSetULongLongCounterValue(prov, instance, 1, 900000L); + ok(!ret, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongLongCounterValue(prov, instance, 2, 666L); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + ret = PerfSetULongLongCounterValue(prov, instance, 0, 42); + ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %lu.\n", ret); + + ok(*(ULONGLONG *)(instance + 1) == 900000L, "Got unexpected counter value %I64u.\n", + *(ULONGLONG *)(instance + 1)); + ok(*(ULONGLONG *)((BYTE *)instance + sizeof(*instance) + sizeof(UINT64)) == 666L, + "Got unexpected counter value %I64u.\n", *(ULONGLONG *)(instance + 1)); + + /* Don't work on PERF_SIZE_LARGE */ + ret = PerfSetULongCounterValue(prov, instance, 1, 666L); + todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ret = PerfSetULongCounterValue(prov, instance, 2, 900000L); + todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + + ret = PerfDeleteInstance(prov, instance); + ok(!ret, "Got unexpected ret %lu.\n", ret); + + ret = PerfStopProvider(prov); + ok(!ret, "Got unexpected ret %lu.\n", ret); + memset( &prov_context, 0, sizeof(prov_context) ); prov = (HANDLE)0xdeadbeef; ret = PerfStartProviderEx( &test_guid, &prov_context, &prov );
From: Lorenzo Ferrillo lorenzofersteam@live.it
Tests shown that counters that have this attribute not set should be rejected in the SetCounterRefValue function --- dlls/advapi32/tests/perf.c | 4 ++-- dlls/kernelbase/main.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index 82114449c66..409ebff95d5 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -273,9 +273,9 @@ void test_provider_init(void) ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %lu.\n", ret);
ret = PerfSetCounterRefValue(prov, instance, 1, &counter1); - todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); ret = PerfSetCounterRefValue(prov, instance, 2, &counter2); - todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret);
ret = PerfDeleteInstance(prov, instance); ok(!ret, "Got unexpected ret %lu.\n", ret); diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index 1b3b450cfff..e478e2ab919 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -343,6 +343,8 @@ ULONG WINAPI PerfSetCounterRefValue(HANDLE provider, PERF_COUNTERSET_INSTANCE *i counter_index = get_performance_counter_index(instance, counterid, &template, &inst);
if (counter_index== template->counterset.NumCounters) return ERROR_NOT_FOUND; + if (!(template->counter[counter_index].Attrib & PERF_ATTRIB_BY_REFERENCE)) return ERROR_INVALID_PARAMETER; + *(void **)(get_performance_counter_address(template,inst, counter_index)) = address;
return STATUS_SUCCESS;
From: Lorenzo Ferrillo lorenzofersteam@live.it
Should be setted for SetULongULong function and unsetted fo SetULong one, as test shown. --- dlls/advapi32/tests/perf.c | 8 ++++---- dlls/kernelbase/main.c | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c index 409ebff95d5..f46eca1397a 100644 --- a/dlls/advapi32/tests/perf.c +++ b/dlls/advapi32/tests/perf.c @@ -265,9 +265,9 @@ void test_provider_init(void)
/* Cannot be used with PERF_SIZE_DWORD */ ret = PerfSetULongLongCounterValue(prov, instance, 1, 900000L); - todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); ret = PerfSetULongLongCounterValue(prov, instance, 2, 666L); - todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret);
ret = PerfSetULongLongCounterValue(prov, instance, 0, 42); ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %lu.\n", ret); @@ -315,9 +315,9 @@ void test_provider_init(void)
/* Don't work on PERF_SIZE_LARGE */ ret = PerfSetULongCounterValue(prov, instance, 1, 666L); - todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); ret = PerfSetULongCounterValue(prov, instance, 2, 900000L); - todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret); + ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %lu.\n", ret);
ret = PerfDeleteInstance(prov, instance); ok(!ret, "Got unexpected ret %lu.\n", ret); diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c index e478e2ab919..c000413e900 100644 --- a/dlls/kernelbase/main.c +++ b/dlls/kernelbase/main.c @@ -26,6 +26,7 @@ #include "shlwapi.h" #include "perflib.h" #include "winternl.h" +#include "winperf.h"
#include "wine/debug.h" #include "kernelbase.h" @@ -370,6 +371,7 @@ ULONG WINAPI PerfSetULongCounterValue(HANDLE provider, PERF_COUNTERSET_INSTANCE
if (counter_index == template->counterset.NumCounters) return ERROR_NOT_FOUND; if (template->counter[counter_index].Attrib & PERF_ATTRIB_BY_REFERENCE) return ERROR_INVALID_PARAMETER; + if (template->counter[counter_index].Type & PERF_SIZE_LARGE) return ERROR_INVALID_PARAMETER;
*(ULONG*)(get_performance_counter_address(template,inst, counter_index)) = value;
@@ -396,6 +398,7 @@ ULONG WINAPI PerfSetULongLongCounterValue(HANDLE provider, PERF_COUNTERSET_INSTA
if (counter_index == template->counterset.NumCounters) return ERROR_NOT_FOUND; if (template->counter[counter_index].Attrib & PERF_ATTRIB_BY_REFERENCE) return ERROR_INVALID_PARAMETER; + if (!(template->counter[counter_index].Type & PERF_SIZE_LARGE)) return ERROR_INVALID_PARAMETER;
*(ULONGLONG*)(get_performance_counter_address(template,inst, counter_index)) = value;
v2: Added 2 function to share common code for various PerfSet...Counter functions, extracted from the already existing PerfSetCounterRefValue Reimplemented new functions using these common functions
The address calculation was extracted, but the value write itself was kept in the function proper, as the values to write were of different types and size.
Do you think this is enough @julliard ? Or do you have some ideas to make the code better?
On Mon Apr 7 07:55:52 2025 +0000, Lorenzo Ferrillo wrote:
v2: Added 2 function to share common code for various PerfSet...Counter functions, extracted from the already existing PerfSetCounterRefValue Reimplemented new functions using these common functions The address calculation was extracted, but the value write itself was kept in the function proper, as the values to write were of different types and size. Do you think this is enough @julliard ? Or do you have some ideas to make the code better? EDIT: for some reason, having moved the counter address calculation into a function is causing a strange error in 64bit build. (I didn't catch locally, becouse I forgot to build with Werror). I will try to fix shortly.
It looks good, you could probably improve it by returning a counter pointer instead of an index. Also you could have a set function doing a memcpy instead of returning a pointer and casting it.
On Mon Apr 7 07:55:52 2025 +0000, Alexandre Julliard wrote:
It looks good, you could probably improve it by returning a counter pointer instead of an index. Also you could have a set function doing a memcpy instead of returning a pointer and casting it.
Hi, I did try your suggestions, and I like returning the pointer directly more. However It seems I'm not able to make the setter works:
I did try this:
``` static void set_performance_counter_value(PERF_COUNTER_INFO* counter, struct counterset_instance* instance, void* new_value, size_t size) { void* address = ((BYTE*) &instance->instance + sizeof(PERF_COUNTERSET_INSTANCE) + counter->Offset); memcpy(address, new_value, size); } ``` However compilation is still failing with ../wine/dlls/kernelbase/main.c:325:5: error: writing 8 bytes into a region of size 0 [-Werror=stringop-overflow=] 325 | memcpy(address, new_value, size);
Using memcpy, this error happens in all cases, while using the direct assignment with casting, it seems to happen only when the byte pointer is calculated inside an inner function (if I put pointer calculation and assignment inside the top function works) Do you have any idea? @julliard