Signed-off-by: Paul Gofman <pgofman(a)codeweavers.com>
---
Avoids crash in Edge Webview embedded in Forza Horizon 5.
Technically it is enough just to fake success from these stubs
but PerfCreateInstance returns a documented (albeit wrongly)
structure and it looks better to return correcly layed out data.
dlls/advapi32/tests/Makefile.in | 1 +
dlls/advapi32/tests/perf.c | 100 ++++++++++++++++++++++++++++++++
dlls/kernelbase/main.c | 49 +++++++++++++---
include/perflib.h | 4 ++
4 files changed, 146 insertions(+), 8 deletions(-)
create mode 100644 dlls/advapi32/tests/perf.c
diff --git a/dlls/advapi32/tests/Makefile.in b/dlls/advapi32/tests/Makefile.in
index 12583e59f57..2e9b007a91f 100644
--- a/dlls/advapi32/tests/Makefile.in
+++ b/dlls/advapi32/tests/Makefile.in
@@ -10,6 +10,7 @@ C_SRCS = \
crypt_sha.c \
eventlog.c \
lsa.c \
+ perf.c \
registry.c \
security.c \
service.c
diff --git a/dlls/advapi32/tests/perf.c b/dlls/advapi32/tests/perf.c
new file mode 100644
index 00000000000..34fedd2b645
--- /dev/null
+++ b/dlls/advapi32/tests/perf.c
@@ -0,0 +1,100 @@
+/*
+ * Unit tests for Perflib functions
+ *
+ * Copyright (c) 2021 Paul Gofman for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "perflib.h"
+
+#include "wine/test.h"
+
+static ULONG WINAPI test_provider_callback(ULONG code, void *buffer, ULONG size)
+{
+ ok(0, "Provider callback called.\n");
+ return ERROR_SUCCESS;
+}
+
+void test_provider_init(void)
+{
+ static GUID test_guid = {0xdeadbeef, 0x0001, 0x0002, {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00 ,0x0a}};
+ PERF_PROVIDER_CONTEXT prov_context;
+ HANDLE prov, prov2;
+ ULONG ret;
+ BOOL bret;
+
+ prov = (HANDLE)0xdeadbeef;
+ ret = PerfStartProvider(NULL, test_provider_callback, &prov);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret);
+ ok(prov == (HANDLE)0xdeadbeef, "Got unexpected prov %p.\n", prov);
+
+ prov = (HANDLE)0xdeadbeef;
+ ret = PerfStartProvider(&test_guid, test_provider_callback, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret);
+ ok(prov == (HANDLE)0xdeadbeef, "Got unexpected prov %p.\n", prov);
+
+ prov = (HANDLE)0xdeadbeef;
+ ret = PerfStartProvider(&test_guid, test_provider_callback, &prov);
+ ok(!ret, "Got unexpected ret %u.\n", ret);
+ ok(prov != (HANDLE)0xdeadbeef, "Provider handle is not set.\n");
+
+ prov2 = prov;
+ ret = PerfStartProvider(&test_guid, test_provider_callback, &prov2);
+ ok(!ret, "Got unexpected ret %u.\n", ret);
+ ok(prov2 != prov, "Got the same provider handle.\n");
+
+ ret = PerfStopProvider(prov2);
+ ok(!ret, "Got unexpected ret %u.\n", ret);
+
+ if (0)
+ {
+ /* Access violation on Windows. */
+ PerfStopProvider(prov2);
+ }
+
+ /* Provider handle is a pointer and not a kernel object handle. */
+ bret = DuplicateHandle(GetCurrentProcess(), prov, GetCurrentProcess(), &prov2, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ ok(!bret && GetLastError() == ERROR_INVALID_HANDLE, "Got unexpected bret %d, err %u.\n", bret, GetLastError());
+ bret = IsBadWritePtr(prov, 8);
+ ok(!bret, "Handle does not point to the data.\n");
+
+ ret = PerfStopProvider(prov);
+ ok(!ret, "Got unexpected ret %u.\n", ret);
+
+ memset( &prov_context, 0, sizeof(prov_context) );
+ prov = (HANDLE)0xdeadbeef;
+ ret = PerfStartProviderEx( &test_guid, &prov_context, &prov );
+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret);
+ ok(prov == (HANDLE)0xdeadbeef, "Got unexpected prov %p.\n", prov);
+
+ prov_context.ContextSize = sizeof(prov_context) + 1;
+ ret = PerfStartProviderEx( &test_guid, &prov_context, &prov );
+ ok(!ret, "Got unexpected ret %u.\n", ret);
+ ok(prov != (HANDLE)0xdeadbeef, "Provider handle is not set.\n");
+
+ ret = PerfStopProvider(prov);
+ ok(!ret, "Got unexpected ret %u.\n", ret);
+}
+
+START_TEST(perf)
+{
+ test_provider_init();
+}
diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c
index e6cf892a4dc..d468c84f619 100644
--- a/dlls/kernelbase/main.c
+++ b/dlls/kernelbase/main.c
@@ -154,6 +154,17 @@ LONG WINAPI AppPolicyGetWindowingModel(HANDLE token, AppPolicyWindowingModel *po
return ERROR_SUCCESS;
}
+struct perf_provider
+{
+ GUID guid;
+ PERFLIBREQUEST callback;
+};
+
+static struct perf_provider *perf_provider_from_handle(HANDLE prov)
+{
+ return (struct perf_provider *)prov;
+}
+
/***********************************************************************
* PerfCreateInstance (KERNELBASE.@)
*/
@@ -195,19 +206,37 @@ ULONG WINAPI PerfSetCounterRefValue(HANDLE provider, PPERF_COUNTERSET_INSTANCE i
/***********************************************************************
* PerfStartProvider (KERNELBASE.@)
*/
-ULONG WINAPI PerfStartProvider(GUID *guid, PERFLIBREQUEST callback, HANDLE *provider)
+ULONG WINAPI PerfStartProvider( GUID *guid, PERFLIBREQUEST callback, HANDLE *provider )
{
- FIXME("%s %p %p: stub\n", debugstr_guid(guid), callback, provider);
- return ERROR_CALL_NOT_IMPLEMENTED;
+ PERF_PROVIDER_CONTEXT ctx;
+
+ FIXME( "guid %s, callback %p, provider %p semi-stub.\n", debugstr_guid(guid), callback, provider );
+
+ memset( &ctx, 0, sizeof(ctx) );
+ ctx.ContextSize = sizeof(ctx);
+ ctx.ControlCallback = callback;
+
+ return PerfStartProviderEx( guid, &ctx, provider );
}
/***********************************************************************
* PerfStartProviderEx (KERNELBASE.@)
*/
-ULONG WINAPI PerfStartProviderEx(GUID *guid, PPERF_PROVIDER_CONTEXT context, HANDLE *provider)
+ULONG WINAPI PerfStartProviderEx( GUID *guid, PERF_PROVIDER_CONTEXT *context, HANDLE *provider )
{
- FIXME("%s %p %p: stub\n", debugstr_guid(guid), context, provider);
- return ERROR_CALL_NOT_IMPLEMENTED;
+ struct perf_provider *prov;
+
+ FIXME( "guid %s, context %p, provider %p semi-stub.\n", debugstr_guid(guid), context, provider );
+
+ if (!guid || !context || !provider) return ERROR_INVALID_PARAMETER;
+ if (context->ContextSize < sizeof(*context)) return ERROR_INVALID_PARAMETER;
+
+ if (!(prov = heap_alloc_zero( sizeof(*prov) ))) return ERROR_OUTOFMEMORY;
+ memcpy( &prov->guid, guid, sizeof(prov->guid) );
+ prov->callback = context->ControlCallback;
+ *provider = prov;
+
+ return STATUS_SUCCESS;
}
/***********************************************************************
@@ -215,8 +244,12 @@ ULONG WINAPI PerfStartProviderEx(GUID *guid, PPERF_PROVIDER_CONTEXT context, HAN
*/
ULONG WINAPI PerfStopProvider(HANDLE handle)
{
- FIXME("%p: stub\n", handle);
- return ERROR_CALL_NOT_IMPLEMENTED;
+ struct perf_provider *prov = perf_provider_from_handle( handle );
+
+ TRACE( "handle %p.\n", handle );
+
+ heap_free( prov );
+ return STATUS_SUCCESS;
}
/***********************************************************************
diff --git a/include/perflib.h b/include/perflib.h
index 2d3f6efb419..47bc0716541 100644
--- a/include/perflib.h
+++ b/include/perflib.h
@@ -51,6 +51,10 @@ typedef struct _PROVIDER_CONTEXT {
LPVOID pMemContext;
} PERF_PROVIDER_CONTEXT, * PPERF_PROVIDER_CONTEXT;
+ULONG WINAPI PerfStartProvider(GUID *, PERFLIBREQUEST, HANDLE *);
+ULONG WINAPI PerfStartProviderEx(GUID *, PERF_PROVIDER_CONTEXT *, HANDLE *);
+ULONG WINAPI PerfStopProvider(HANDLE);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
--
2.33.1