api: finish porting from wireguard-go
Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
c8bf62ac19
commit
7e3740018d
70
api/api.h
70
api/api.h
@ -6,6 +6,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <IPExport.h>
|
||||||
|
|
||||||
typedef _Return_type_success_(return == ERROR_SUCCESS) DWORD WINSTATUS;
|
typedef _Return_type_success_(return == ERROR_SUCCESS) DWORD WINSTATUS;
|
||||||
extern HINSTANCE ResourceModule;
|
extern HINSTANCE ResourceModule;
|
||||||
@ -37,6 +38,42 @@ NciInit();
|
|||||||
void
|
void
|
||||||
NciCleanup();
|
NciCleanup();
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryOpenKeyWait(
|
||||||
|
_In_ HKEY Key,
|
||||||
|
_In_z_count_c_(MAX_PATH) LPCWSTR Path,
|
||||||
|
_In_ DWORD Access,
|
||||||
|
_In_ DWORD Timeout,
|
||||||
|
_Out_ HKEY *KeyOut);
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryWaitForKey(_In_ HKEY Key, _In_z_count_c_(MAX_PATH) LPCWSTR Path, _In_ DWORD Timeout);
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryGetMultiString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ LPWSTR *Value);
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ LPWSTR *Value);
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value);
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value);
|
||||||
|
|
||||||
|
WINSTATUS WINAPI
|
||||||
|
WintunGetVersion(
|
||||||
|
_Out_ DWORD *DriverVersionMaj,
|
||||||
|
_Out_ DWORD *DriverVersionMin,
|
||||||
|
_Out_ DWORD *NdisVersionMaj,
|
||||||
|
_Out_ DWORD *NdisVersionMin);
|
||||||
|
|
||||||
#define MAX_POOL 256
|
#define MAX_POOL 256
|
||||||
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
|
#define MAX_INSTANCE_ID MAX_PATH /* TODO: Is MAX_PATH always enough? */
|
||||||
|
|
||||||
@ -53,4 +90,35 @@ VOID WINAPI
|
|||||||
WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
|
WintunFreeAdapter(_In_ WINTUN_ADAPTER *Adapter);
|
||||||
|
|
||||||
WINSTATUS WINAPI
|
WINSTATUS WINAPI
|
||||||
WintunGetAdapter(_In_z_count_c_(MAX_POOL) LPCWSTR Pool, _In_z_ LPCWSTR IfName, _Out_ WINTUN_ADAPTER **Adapter);
|
WintunGetAdapter(_In_z_count_c_(MAX_POOL) LPCWSTR Pool, _In_z_ LPCWSTR Name, _Out_ WINTUN_ADAPTER **Adapter);
|
||||||
|
|
||||||
|
WINSTATUS WINAPI
|
||||||
|
WintunGetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _Out_cap_c_(MAX_ADAPTER_NAME) LPWSTR Name);
|
||||||
|
|
||||||
|
WINSTATUS WINAPI
|
||||||
|
WintunSetAdapterName(_In_ const WINTUN_ADAPTER *Adapter, _In_z_count_c_(MAX_ADAPTER_NAME) LPCWSTR Name);
|
||||||
|
|
||||||
|
void WINAPI
|
||||||
|
WintunGetAdapterGUID(_In_ const WINTUN_ADAPTER *Adapter, _Out_ GUID *Guid);
|
||||||
|
|
||||||
|
void WINAPI
|
||||||
|
WintunGetAdapterLUID(_In_ const WINTUN_ADAPTER *Adapter, _Out_ LUID *Luid);
|
||||||
|
|
||||||
|
WINSTATUS WINAPI
|
||||||
|
WintunGetAdapterDeviceObject(_In_ const WINTUN_ADAPTER *Adapter, _Out_ HANDLE *Handle);
|
||||||
|
|
||||||
|
WINSTATUS WINAPI
|
||||||
|
WintunCreateAdapter(
|
||||||
|
_In_z_count_c_(MAX_POOL) LPCWSTR Pool,
|
||||||
|
_In_z_ LPCWSTR Name,
|
||||||
|
_In_opt_ const GUID *RequestedGUID,
|
||||||
|
_Out_ WINTUN_ADAPTER **Adapter,
|
||||||
|
_Inout_ BOOL *RebootRequired);
|
||||||
|
|
||||||
|
WINSTATUS WINAPI
|
||||||
|
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequired);
|
||||||
|
|
||||||
|
typedef BOOL(CALLBACK *WINTUN_ENUMPROC)(_In_ const WINTUN_ADAPTER *Adapter, _In_ LPARAM Param);
|
||||||
|
|
||||||
|
WINSTATUS WINAPI
|
||||||
|
WintunEnumAdapters(_In_z_count_c_(MAX_POOL) LPCWSTR Pool, _In_ WINTUN_ENUMPROC Func, _In_ LPARAM Param);
|
||||||
|
@ -120,7 +120,7 @@
|
|||||||
<AdditionalIncludeDirectories>..\$(WintunPlatform)\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\$(WintunPlatform)\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ResourceCompile>
|
</ResourceCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>Bcrypt.lib;Setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>Bcrypt.lib;Cfgmgr32.lib;Iphlpapi.lib;Setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
<ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
</Link>
|
</Link>
|
||||||
@ -162,6 +162,7 @@
|
|||||||
<ClCompile Include="devmgmt.c" />
|
<ClCompile Include="devmgmt.c" />
|
||||||
<ClCompile Include="namespace.c" />
|
<ClCompile Include="namespace.c" />
|
||||||
<ClCompile Include="nci.c" />
|
<ClCompile Include="nci.c" />
|
||||||
|
<ClCompile Include="registry.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
@ -42,5 +42,8 @@
|
|||||||
<ClCompile Include="nci.c">
|
<ClCompile Include="nci.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="registry.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
1084
api/devmgmt.c
1084
api/devmgmt.c
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,12 @@
|
|||||||
EXPORTS
|
EXPORTS
|
||||||
WintunFreeAdapter
|
WintunFreeAdapter
|
||||||
WintunGetAdapter
|
WintunGetAdapter
|
||||||
|
WintunGetAdapterName
|
||||||
|
WintunSetAdapterName
|
||||||
|
WintunGetAdapterGUID
|
||||||
|
WintunGetAdapterLUID
|
||||||
|
WintunGetAdapterDeviceObject
|
||||||
|
WintunGetVersion
|
||||||
|
WintunCreateAdapter
|
||||||
|
WintunDeleteAdapter
|
||||||
|
WintunEnumAdapters
|
||||||
|
411
api/registry.c
Normal file
411
api/registry.c
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "api.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
static WINSTATUS
|
||||||
|
OpenKeyWait(_In_ HKEY Key, _Inout_z_ LPWSTR Path, _In_ DWORD Access, _In_ ULONGLONG Deadline, _Out_ HKEY *KeyOut)
|
||||||
|
{
|
||||||
|
DWORD Result;
|
||||||
|
LPWSTR PathNext = wcschr(Path, L'\\');
|
||||||
|
if (PathNext)
|
||||||
|
*PathNext = 0;
|
||||||
|
|
||||||
|
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
|
if (!Event)
|
||||||
|
return GetLastError();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_NAME, Event, TRUE);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
HKEY Subkey;
|
||||||
|
Result = RegOpenKeyExW(Key, Path, 0, PathNext ? KEY_NOTIFY : Access, &Subkey);
|
||||||
|
if (Result == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if (PathNext)
|
||||||
|
{
|
||||||
|
Result = OpenKeyWait(Subkey, PathNext + 1, Access, Deadline, KeyOut);
|
||||||
|
RegCloseKey(Subkey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*KeyOut = Subkey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
|
||||||
|
break;
|
||||||
|
|
||||||
|
LONGLONG TimeLeft = Deadline - GetTickCount64();
|
||||||
|
if (TimeLeft < 0)
|
||||||
|
TimeLeft = 0;
|
||||||
|
if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CloseHandle(Event);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the specified registry key. It waits for the registry key to become available.
|
||||||
|
*
|
||||||
|
* @param Key Handle of the parent registry key. Must be opened with notify access.
|
||||||
|
*
|
||||||
|
* @param Path Subpath of the registry key to open
|
||||||
|
*
|
||||||
|
* @param Access A mask that specifies the desired access rights to the key to be opened
|
||||||
|
*
|
||||||
|
* @param Timeout Timeout to wait for the value in milliseconds
|
||||||
|
*
|
||||||
|
* @param KeyOut Pointer to a variable to receive the key handle
|
||||||
|
*
|
||||||
|
* @return ERROR_SUCCESS on success; WAIT_TIMEOUT on timeout; error code otherwise
|
||||||
|
*/
|
||||||
|
WINSTATUS
|
||||||
|
RegistryOpenKeyWait(
|
||||||
|
_In_ HKEY Key,
|
||||||
|
_In_z_count_c_(MAX_PATH) LPCWSTR Path,
|
||||||
|
_In_ DWORD Access,
|
||||||
|
_In_ DWORD Timeout,
|
||||||
|
_Out_ HKEY *KeyOut)
|
||||||
|
{
|
||||||
|
WCHAR Buf[MAX_PATH];
|
||||||
|
wcscpy_s(Buf, _countof(Buf), Path);
|
||||||
|
return OpenKeyWait(Key, Buf, Access, GetTickCount64() + Timeout, KeyOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
WINSTATUS
|
||||||
|
RegistryWaitForKey(_In_ HKEY Key, _In_z_count_c_(MAX_PATH) LPCWSTR Path, _In_ DWORD Timeout)
|
||||||
|
{
|
||||||
|
HKEY k;
|
||||||
|
DWORD Result = RegistryOpenKeyWait(Key, Path, KEY_NOTIFY, Timeout, &k);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
return Result;
|
||||||
|
RegCloseKey(k);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and/or sanitize string value read from registry.
|
||||||
|
*
|
||||||
|
* @param Buf On input, it contains pointer to pointer where the data is stored. The data must be
|
||||||
|
* allocated using HeapAlloc(GetProcessHeap(), 0).
|
||||||
|
* On output, it contains pointer to pointer where the sanitized data is stored. It must be
|
||||||
|
* released with HeapFree(GetProcessHeap(), 0, *Buf) after use.
|
||||||
|
*
|
||||||
|
* @param Len Length of data string in wide characters
|
||||||
|
*
|
||||||
|
* @param ValueType Type of data. Must be either REG_SZ or REG_EXPAND_SZ. REG_MULTI_SZ is treated like REG_SZ; only
|
||||||
|
* the first string of a multi-string is to be used.
|
||||||
|
*
|
||||||
|
* @return ERROR_SUCCESS on success; Win32 error code otherwise
|
||||||
|
*/
|
||||||
|
WINSTATUS
|
||||||
|
RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
||||||
|
{
|
||||||
|
HANDLE Heap = GetProcessHeap();
|
||||||
|
|
||||||
|
if (wcsnlen(*Buf, Len) >= Len)
|
||||||
|
{
|
||||||
|
/* String is missing zero-terminator. */
|
||||||
|
LPWSTR BufZ = HeapAlloc(Heap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
||||||
|
if (!BufZ)
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
wmemcpy(BufZ, *Buf, Len);
|
||||||
|
BufZ[Len] = 0;
|
||||||
|
HeapFree(Heap, 0, *Buf);
|
||||||
|
*Buf = BufZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ValueType != REG_EXPAND_SZ)
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
|
||||||
|
/* ExpandEnvironmentStringsW() returns strlen on success or 0 on error. Bail out on empty input strings to
|
||||||
|
* disambiguate. */
|
||||||
|
if (!(*Buf)[0])
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
|
||||||
|
Len = Len * 2 + 64;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
LPWSTR Expanded = HeapAlloc(Heap, 0, Len * sizeof(WCHAR));
|
||||||
|
if (!Expanded)
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
|
||||||
|
if (!Result)
|
||||||
|
{
|
||||||
|
Result = GetLastError();
|
||||||
|
HeapFree(Heap, 0, Expanded);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
if (Result > Len)
|
||||||
|
{
|
||||||
|
HeapFree(Heap, 0, Expanded);
|
||||||
|
Len = Result;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
HeapFree(Heap, 0, *Buf);
|
||||||
|
*Buf = Expanded;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate and/or sanitize multi-string value read from registry.
|
||||||
|
*
|
||||||
|
* @param Buf On input, it contains pointer to pointer where the data is stored. The data must be
|
||||||
|
* allocated using HeapAlloc(GetProcessHeap(), 0).
|
||||||
|
* On output, it contains pointer to pointer where the sanitized data is stored. It must be
|
||||||
|
* released with HeapFree(GetProcessHeap(), 0, *Buf) after use.
|
||||||
|
*
|
||||||
|
* @param Len Length of data string in wide characters
|
||||||
|
*
|
||||||
|
* @param ValueType Type of data. Must be one of REG_MULTI_SZ, REG_SZ or REG_EXPAND_SZ.
|
||||||
|
*
|
||||||
|
* @return ERROR_SUCCESS on success; Win32 error code otherwise
|
||||||
|
*/
|
||||||
|
WINSTATUS
|
||||||
|
RegistryGetMultiString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType)
|
||||||
|
{
|
||||||
|
HANDLE Heap = GetProcessHeap();
|
||||||
|
|
||||||
|
if (ValueType == REG_MULTI_SZ)
|
||||||
|
{
|
||||||
|
for (size_t i = 0;; i += wcsnlen(*Buf + i, Len - i) + 1)
|
||||||
|
{
|
||||||
|
if (i > Len)
|
||||||
|
{
|
||||||
|
/* Missing string and list terminators. */
|
||||||
|
LPWSTR BufZ = HeapAlloc(Heap, 0, ((size_t)Len + 2) * sizeof(WCHAR));
|
||||||
|
if (!BufZ)
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
wmemcpy(BufZ, *Buf, Len);
|
||||||
|
BufZ[Len] = 0;
|
||||||
|
BufZ[Len + 1] = 0;
|
||||||
|
HeapFree(Heap, 0, *Buf);
|
||||||
|
*Buf = BufZ;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
if (i == Len)
|
||||||
|
{
|
||||||
|
/* Missing list terminator. */
|
||||||
|
LPWSTR BufZ = HeapAlloc(Heap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
||||||
|
if (!BufZ)
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
wmemcpy(BufZ, *Buf, Len);
|
||||||
|
BufZ[Len] = 0;
|
||||||
|
HeapFree(Heap, 0, *Buf);
|
||||||
|
*Buf = BufZ;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
if (!(*Buf)[i])
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanitize REG_SZ/REG_EXPAND_SZ and append a list terminator to make a multi-string. */
|
||||||
|
DWORD Result = RegistryGetString(Buf, Len, ValueType);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
return Result;
|
||||||
|
Len = (DWORD)wcslen(*Buf) + 1;
|
||||||
|
LPWSTR BufZ = HeapAlloc(Heap, 0, ((size_t)Len + 1) * sizeof(WCHAR));
|
||||||
|
if (!BufZ)
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
wmemcpy(BufZ, *Buf, Len);
|
||||||
|
BufZ[Len] = 0;
|
||||||
|
HeapFree(Heap, 0, *Buf);
|
||||||
|
*Buf = BufZ;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the type and data for the specified value name associated with an open registry key.
|
||||||
|
*
|
||||||
|
* @param Key Handle of the registry key to read from. Must be opened with read
|
||||||
|
* access.
|
||||||
|
*
|
||||||
|
* @param Name Name of the value to read
|
||||||
|
*
|
||||||
|
* @param ValueType A pointer to a variable that receives a code indicating the type of data stored in the specified
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @param Buf Pointer to a pointer to retrieve registry value. The buffer must be released with
|
||||||
|
* HeapFree(GetProcessHeap(), 0, *Buf) after use.
|
||||||
|
*
|
||||||
|
* @param BufLen On input, a hint of expected registry value size in bytes; on output, actual registry value size
|
||||||
|
* in bytes.
|
||||||
|
*
|
||||||
|
* @return ERROR_SUCCESS on success; Win32 error code otherwise
|
||||||
|
*/
|
||||||
|
static WINSTATUS
|
||||||
|
RegistryQuery(
|
||||||
|
_In_ HKEY Key,
|
||||||
|
_In_opt_z_ LPCWSTR Name,
|
||||||
|
_Out_opt_ DWORD *ValueType,
|
||||||
|
_Out_ void **Buf,
|
||||||
|
_Inout_ DWORD *BufLen)
|
||||||
|
{
|
||||||
|
HANDLE Heap = GetProcessHeap();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
*Buf = HeapAlloc(Heap, 0, *BufLen);
|
||||||
|
if (!*Buf)
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
LSTATUS Result = RegQueryValueExW(Key, Name, NULL, ValueType, (BYTE *)*Buf, BufLen);
|
||||||
|
if (Result == ERROR_SUCCESS)
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
HeapFree(Heap, 0, *Buf);
|
||||||
|
if (Result != ERROR_MORE_DATA)
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads string value from registry key.
|
||||||
|
*
|
||||||
|
* @param Key Handle of the registry key to read from. Must be opened with read
|
||||||
|
* access.
|
||||||
|
*
|
||||||
|
* @param Name Name of the value to read
|
||||||
|
*
|
||||||
|
* @param Value Pointer to string to retrieve registry value. If the value type is
|
||||||
|
* REG_EXPAND_SZ the value is expanded using ExpandEnvironmentStrings(). If the value type is
|
||||||
|
* REG_MULTI_SZ, only the first string from the multi-string is returned.
|
||||||
|
* The string must be released with HeapFree(GetProcessHeap(), 0, Value) after use.
|
||||||
|
*
|
||||||
|
* @return ERROR_SUCCESS on success; Win32 error code otherwise
|
||||||
|
*/
|
||||||
|
WINSTATUS
|
||||||
|
RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ LPWSTR *Value)
|
||||||
|
{
|
||||||
|
DWORD ValueType, Size = 256 * sizeof(WCHAR);
|
||||||
|
DWORD Result = RegistryQuery(Key, Name, &ValueType, Value, &Size);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
return Result;
|
||||||
|
switch (ValueType)
|
||||||
|
{
|
||||||
|
case REG_SZ:
|
||||||
|
case REG_EXPAND_SZ:
|
||||||
|
case REG_MULTI_SZ:
|
||||||
|
Result = RegistryGetString(Value, Size / sizeof(WCHAR), ValueType);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
HeapFree(GetProcessHeap(), 0, *Value);
|
||||||
|
return Result;
|
||||||
|
default:
|
||||||
|
HeapFree(GetProcessHeap(), 0, *Value);
|
||||||
|
return ERROR_INVALID_DATATYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads string value from registry key. It waits for the registry value to become available.
|
||||||
|
*
|
||||||
|
* @param Key Handle of the registry key to read from. Must be opened with read and notify
|
||||||
|
* access.
|
||||||
|
*
|
||||||
|
* @param Name Name of the value to read
|
||||||
|
*
|
||||||
|
* @param Timeout Timeout to wait for the value in milliseconds
|
||||||
|
*
|
||||||
|
* @param Value Pointer to string to retrieve registry value. If the value type is
|
||||||
|
* REG_EXPAND_SZ the value is expanded using ExpandEnvironmentStrings().
|
||||||
|
* The string must be released with HeapFree(GetProcessHeap(), 0, Value)
|
||||||
|
* after use.
|
||||||
|
*
|
||||||
|
* @return ERROR_SUCCESS on success; Win32 error code otherwise
|
||||||
|
*/
|
||||||
|
WINSTATUS
|
||||||
|
RegistryQueryStringWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ LPWSTR *Value)
|
||||||
|
{
|
||||||
|
DWORD Result;
|
||||||
|
ULONGLONG Deadline = GetTickCount64() + Timeout;
|
||||||
|
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
|
if (!Event)
|
||||||
|
return GetLastError();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
Result = RegistryQueryString(Key, Name, Value);
|
||||||
|
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
|
||||||
|
break;
|
||||||
|
LONGLONG TimeLeft = Deadline - GetTickCount64();
|
||||||
|
if (TimeLeft < 0)
|
||||||
|
TimeLeft = 0;
|
||||||
|
if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CloseHandle(Event);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a 32-bit DWORD value from registry key.
|
||||||
|
*
|
||||||
|
* @param Key Handle of the registry key to read from. Must be opened with read
|
||||||
|
* access.
|
||||||
|
*
|
||||||
|
* @param Name Name of the value to read
|
||||||
|
*
|
||||||
|
* @param Value Pointer to DWORD to retrieve registry value
|
||||||
|
*
|
||||||
|
* @return ERROR_SUCCESS on success; Win32 error code otherwise
|
||||||
|
*/
|
||||||
|
WINSTATUS
|
||||||
|
RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value)
|
||||||
|
{
|
||||||
|
DWORD ValueType, Size = sizeof(DWORD);
|
||||||
|
DWORD Result = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
return Result;
|
||||||
|
if (ValueType != REG_DWORD)
|
||||||
|
return ERROR_INVALID_DATATYPE;
|
||||||
|
if (Size != sizeof(DWORD))
|
||||||
|
return ERROR_INVALID_DATA;
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a 32-bit DWORD value from registry key. It waits for the registry value to become available.
|
||||||
|
*
|
||||||
|
* @param Key Handle of the registry key to read from. Must be opened with read
|
||||||
|
* access.
|
||||||
|
*
|
||||||
|
* @param Name Name of the value to read
|
||||||
|
*
|
||||||
|
* @param Timeout Timeout to wait for the value in milliseconds
|
||||||
|
*
|
||||||
|
* @param Value Pointer to DWORD to retrieve registry value
|
||||||
|
*
|
||||||
|
* @return ERROR_SUCCESS on success; Win32 error code otherwise
|
||||||
|
*/
|
||||||
|
WINSTATUS
|
||||||
|
RegistryQueryDWORDWait(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ DWORD Timeout, _Out_ DWORD *Value)
|
||||||
|
{
|
||||||
|
DWORD Result;
|
||||||
|
ULONGLONG Deadline = GetTickCount64() + Timeout;
|
||||||
|
HANDLE Event = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||||
|
if (!Event)
|
||||||
|
return GetLastError();
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
Result = RegNotifyChangeKeyValue(Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, Event, TRUE);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
Result = RegistryQueryDWORD(Key, Name, Value);
|
||||||
|
if (Result != ERROR_FILE_NOT_FOUND && Result != ERROR_PATH_NOT_FOUND)
|
||||||
|
break;
|
||||||
|
LONGLONG TimeLeft = Deadline - GetTickCount64();
|
||||||
|
if (TimeLeft < 0)
|
||||||
|
TimeLeft = 0;
|
||||||
|
if (WaitForSingleObject(Event, (DWORD)TimeLeft) != WAIT_OBJECT_0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CloseHandle(Event);
|
||||||
|
return Result;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user