Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
903de9b6
Commit
903de9b6
authored
Jul 11, 2018
by
Dmitry Timoshkov
Committed by
Alexandre Julliard
Jul 12, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
advapi32: Add initial support for querying performance counters data.
Signed-off-by:
Dmitry Timoshkov
<
dmitry@baikal.ru
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
4adfa3dc
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
249 additions
and
12 deletions
+249
-12
registry.c
dlls/advapi32/registry.c
+243
-1
registry.c
dlls/advapi32/tests/registry.c
+6
-11
No files found.
dlls/advapi32/registry.c
View file @
903de9b6
...
...
@@ -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"
...
...
@@ -1480,6 +1482,234 @@ 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
)
{
RegCloseKey
(
perf
);
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.@]
*
...
...
@@ -1500,6 +1730,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
);
...
...
@@ -1590,7 +1824,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
;
...
...
@@ -1602,6 +1837,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
;
...
...
dlls/advapi32/tests/registry.c
View file @
903de9b6
...
...
@@ -3637,10 +3637,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
;
...
...
@@ -3648,8 +3648,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
)
{
...
...
@@ -3662,14 +3661,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
]);
...
...
@@ -3686,13 +3684,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
);
...
...
@@ -3725,9 +3721,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
)
{
...
...
@@ -3757,6 +3751,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
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment