'dim': identifier not found - c++

I am getting this error message:
error C3861: 'dim': identifier not found
Here are my includes:
#include "stdafx.h"
#include "HSMBTPrintX.h"
#include "HSMBTPrintXCtrl.h"
#include "HSMBTPrintXPropPage.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
Here is my function:
#define MSS_PORTS_BASE _T("Software\\Microsoft\\Bluetooth\\Serial\\Ports")
bool FindBluetoothPort(TCHAR name[16]) {
HKEY hKey, hRoot;
TCHAR szPort[20] = _T(""), szPortString[20];
DWORD len, dwIndex=0;
bool bFound=false;
INT i = 0, rc;
DWORD dwNSize;
DWORD dwCSize;
TCHAR szClass[256];
TCHAR szName[MAX_PATH];
FILETIME ft;
hRoot = HKEY_LOCAL_MACHINE;
if (RegOpenKeyEx (hRoot, MSS_PORTS_BASE, 0, 0, &hKey) != ERROR_SUCCESS) {
rc = GetLastError();
return 0;
}
dwNSize = dim(szName); <---- ~~ !! HERE IS THE LINE THAT ERRORS
dwCSize = dim(szClass); <---- HERE IS THE LINE THAT ERRORS !!
rc = RegEnumKeyEx (hKey, i, szName, &dwNSize, NULL, szClass, &dwCSize, &ft);
while (rc == ERROR_SUCCESS)
{
// how many children
TCHAR szCurrentKey[MAX_PATH];
wcscpy(szCurrentKey, MSS_PORTS_BASE);
wcscat(szCurrentKey, TEXT("\\"));
wcscat(szCurrentKey, szName);
wcscat(szCurrentKey, TEXT("\\"));
len = sizeof(szPort);
if(RegGetValue(hRoot, szCurrentKey, _T("Port"), NULL, (LPBYTE)szPort, &len)) {
wsprintf(szPortString, _T("%s:"), szPort);
bFound = true;
break;
}
dwNSize = dim(szName);
rc = RegEnumKeyEx(hKey, ++i, szName, &dwNSize, NULL, NULL, 0, &ft);
}
if(bFound)
_tcscpy(name, szPortString);
return bFound;
}
As you can see, the two lines that use this are:
dwNSize = dim(szName);
dwCSize = dim(szClass);
Why is that an error?

It looks like you are wanting sizeof:
dwNSize = sizeof(szName);
dwCSize = sizeof(szClass);
sizeof returns the number of bytes of the object/variable. However, I just looked at the documentation for the API RegEnumKeyEx, and it needs the number of characters. So I think it actually should divide by the size of a TCHAR (which will be 1 or 2 depending on if your are building for Unicode).
dwNSize = sizeof(szName) / sizeof(TCHAR);
dwCSize = sizeof(szClass) / sizeof(TCHAR);

You want sizeof.
If you originally learned dim, that was probably a macro that really calls sizeof behind the scenes.

I have in the past used the following macro:
#define DIM(x) (sizeof(x)/sizeof((x)[0]))
It is not provided by any of the standard includes, you have to define it for yourself.
You can also do a more modern version using a template function:
template<typename T, size_t N>
size_t dim(const T (& array)[N])
{
return N;
}

Related

RegCreateKeyEx always returns 5 ERROR_ACCESS_DENIED even when admin

I'm really stuck...I have a Windows program that I'm trying to simply write a value to the Registry.
The problem is RegCreateKeyEx() returns 5 (ERROR_ACCESS_DENIED).
My logon username belongs to the local Administrators group.
The lpdwDisposition parameter in RegCreateKeyEx() gets set to 2 (REG_OPENED_EXISTING_KEY), but RegCreateKeyEx() still returns ERROR_ACCESS_DENIED.
It's a 32-bit program, so I have the SAM set to KEY_WOW64_32KEY | KEY_WRITE
Here is minimal working example code:
#include <Windows.h>
#include <time.h>
#include <strsafe.h>
void GetCurrentDateAndTimeWithMs(WCHAR *sValueData, DWORD dwSizeValueData)
{
CONST INT iSize = 64;
WCHAR sDate[iSize] = {0};
WCHAR sTime[iSize] = {0};
SYSTEMTIME lt = {0};
GetLocalTime(&lt);
GetDateFormat(LOCALE_USER_DEFAULT, NULL, &lt, NULL, sDate, iSize);
GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &lt, NULL, sTime, iSize);
StringCchPrintf(sValueData, dwSizeValueData, L"%s %s.%u",sDate, sTime, lt.wMilliseconds);
}
DWORD SaveToRegistry(CONST WCHAR *sPath, CONST WCHAR *sValueName, CONST WCHAR *sValueData)
{
LSTATUS dwRV = 0;
HKEY hKey = NULL;
DWORD rv = 0;
DWORD dwType_Local = REG_SZ;
dwRV = RegCreateKeyExW(HKEY_LOCAL_MACHINE, sPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WOW64_32KEY | KEY_WRITE, NULL, &hKey, &rv);
if (dwRV == ERROR_SUCCESS)
{
DWORD dwLenData = (DWORD) wcslen(sValueData) +1;
dwRV = RegSetValueExW(hKey, sValueName, 0, dwType_Local, (LPBYTE) sValueData, dwLenData * sizeof(WCHAR));
}
RegCloseKey(hKey);
return dwRV;
}
int main()
{
WCHAR sDT[64] = {0};
GetCurrentDateAndTimeWithMs(sDT, 64);
SaveToRegistry(L"Software\\Company\\Product\\Settings", L"CurrentDateTime", sDT);
}

Get a list of Handles of a process on windows [duplicate]

Is there any way how to enumerate process with given PID in windows, and get list of all his opened handles(locked files, etc.)?
EDIT: I dont care about language. If it is in .NET, I'd be glad, if in WinApi (C), it won't hurt. If in something else, I think I can rewrite it :-)
I did a deep googling and found this article.
This article gave a link to download source code:
I tried method in NtSystemInfoTest.cpp ( downloaded source code ) and it worked superbly.
void ListHandles( DWORD processID, LPCTSTR lpFilter )
The code has following declaimer:
// Written by Zoltan Csizmadia, zoltan_csizmadia#yahoo.com
// For companies(Austin,TX): If you would like to get my resume, send an email.
//
// The source is free, but if you want to use it, mention my name and e-mail address
//
//////////////////////////////////////////////////////////////////////////////////////
//
I hope this helps you.
The command-line 'Handle' tool from Sysinternals does this, if you just want a tool. This won't help you if you're looking for a code solution, though.
Here is an example using ZwQueryProcessInformation from the DDK. The DDK is now known as the "WDK" and is available with MSDN. If you don't have MSDN, apparantly, you can also get it from here.
I haven't tried it, I just googled your question.
#include "ntdll.h"
#include <stdlib.h>
#include <stdio.h>
#include "ntddk.h"
#define DUPLICATE_SAME_ATTRIBUTES 0x00000004
#pragma comment(lib,"ntdll.lib")
BOOL EnablePrivilege(PCSTR name)
{
TOKEN_PRIVILEGES priv = {1, {0, 0, SE_PRIVILEGE_ENABLED}};
LookupPrivilegeValue(0, name, &priv.Privileges[0].Luid);
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof priv, 0, 0);
BOOL rv = GetLastError() == ERROR_SUCCESS;
CloseHandle(hToken);
return rv;
}
int main(int argc, char *argv[])
{
if (argc == 1) return 0;
ULONG pid = strtoul(argv[1], 0, 0);
EnablePrivilege(SE_DEBUG_NAME);
HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
ULONG n = 0x1000;
PULONG p = new ULONG[n];
while (NT::ZwQuerySystemInformation(NT::SystemHandleInformation, p, n * sizeof *p, 0)
== STATUS_INFO_LENGTH_MISMATCH)
delete [] p, p = new ULONG[n *= 2];
NT::PSYSTEM_HANDLE_INFORMATION h = NT::PSYSTEM_HANDLE_INFORMATION(p + 1);
for (ULONG i = 0; i < *p; i++) {
if (h[i].ProcessId == pid) {
HANDLE hObject;
if (NT::ZwDuplicateObject(hProcess, HANDLE(h[i].Handle), NtCurrentProcess(), &hObject,
0, 0, DUPLICATE_SAME_ATTRIBUTES)
!= STATUS_SUCCESS) continue;
NT::OBJECT_BASIC_INFORMATION obi;
NT::ZwQueryObject(hObject, NT::ObjectBasicInformation, &obi, sizeof obi, &n);
printf("%p %04hx %6lx %2x %3lx %3ld %4ld ",
h[i].Object, h[i].Handle, h[i].GrantedAccess,
int(h[i].Flags), obi.Attributes,
obi.HandleCount - 1, obi.PointerCount - 2);
n = obi.TypeInformationLength + 2;
NT::POBJECT_TYPE_INFORMATION oti = NT::POBJECT_TYPE_INFORMATION(new CHAR[n]);
NT::ZwQueryObject(hObject, NT::ObjectTypeInformation, oti, n, &n);
printf("%-14.*ws ", oti[0].Name.Length / 2, oti[0].Name.Buffer);
n = obi.NameInformationLength == 0
? MAX_PATH * sizeof (WCHAR) : obi.NameInformationLength;
NT::POBJECT_NAME_INFORMATION oni = NT::POBJECT_NAME_INFORMATION(new CHAR[n]);
NTSTATUS rv = NT::ZwQueryObject(hObject, NT::ObjectNameInformation, oni, n, &n);
if (NT_SUCCESS(rv))
printf("%.*ws", oni[0].Name.Length / 2, oni[0].Name.Buffer);
printf("\n");
CloseHandle(hObject);
}
}
delete [] p;
CloseHandle(hProcess);
return 0;
}

GetFinalPathByHandle returns the same path for all handles returned by NtQuerySystemInformation

I want to retrieve all file paths that are accessed by processes in my OS.
List of processes is retrieved and those has correct handle values. So now I want to use GetFinalPathNameByHandle function to get path to those files, but Path variable is the same for all records. I need a hand here guys.
Source code is here: http://pastebin.com/nU26Vcsd or here if pastebin is not accessible http://hastebin.com/wahudogawa.avrasm
Line 66 is where I need help. Path is the same for each file handler of the tested process and is equal to the path where this program is executed( and not the process start folder).
I run it as: testprogram.exe | grep 5231 where 5231 is a PID of the process I need.
Results looks like:
PID: 5231 FileHandlePid: 44 The final path is: \Device\HarddiskVolume4\KillFileHandle\C++\Debug
While those should be like:
PID: 5231 FileHandlePid: 44 The final path is: \Device\HarddiskVolume2\Users\username\AppData\Roaming\testapp
Or correct me please if I am wrong in expected result.
Latest addition:
Thanks to #Raymond Chen comments I am trying to move forward and use DuplicateHandle() funtion. So far I've updated code (hardcoded pid for now, sorry) , added HandleValueTemp, trying to pass it to DuplicateHandle. The output is changed to nonprintable characters.
for (i = 0; i < hCount; ++i)
if ((hFirstEntry[i].ObjectType == 28))
{
HANDLE TargetHandleValueTemp = (HANDLE)hFirstEntry[i].HandleValue;
HANDLE SourceProcHandleTemp = OpenProcess(PROCESS_DUP_HANDLE, FALSE, hFirstEntry[i].OwnerPid);
if (!DuplicateHandle(SourceProcHandleTemp, (HANDLE)hFirstEntry[i].HandleValue, GetCurrentProcess(), &TargetHandleValueTemp, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
cout << "Error in DuplicateHandle"
}
CloseHandle(SourceProcHandleTemp);
TCHAR Path[MAX_PATH];
DWORD dwret = GetFinalPathNameByHandle(TargetHandleValueTemp, Path, MAX_PATH, 0);
_tprintf(TEXT("PID: %d\tFileHandle: %d\tThe final path is: %s\n"), hFirstEntry[i].OwnerPid, TargetHandleValueTemp, Path);
CloseHandle(TargetHandleValueTemp);
}
Digging further and looking in comments from time to time. Maybe this code can be useful to someone else here.
Thanks to #RaymondChen and #HarryJohnston comments in question I was able to get to working result. I leave it here for case when someone else needs that. The code is a bit crappy but further formatting is up to you. Remember to update OwnerPid in loop to your own when testing.
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#include <iostream>
#define START_ALLOC 0x1000
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
#define SystemHandleInformation 0x10
typedef long(__stdcall *NtQSI)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
typedef struct _SYSTEM_HANDLE_ENTRY {
ULONG OwnerPid;
BYTE ObjectType;
BYTE HandleFlags;
USHORT HandleValue;
PVOID ObjectPointer;
ACCESS_MASK AccessMask;
} SYSTEM_HANDLE_ENTRY, *PSYSTEM_HANDLE_ENTRY;
int main()
{
HMODULE hNtDll = NULL;
NtQSI pNtQSI = NULL;
PVOID pMem = NULL;
ULONG allocSize = START_ALLOC;
ULONG retVal = 0;
// --------------------------------
ULONG hCount = 0;
PSYSTEM_HANDLE_ENTRY hFirstEntry = NULL;
// --------------------------------
ULONG i;
hNtDll = LoadLibraryA("NTDLL.dll");
if (!hNtDll)
return 1;
pNtQSI = (NtQSI)GetProcAddress(hNtDll, "NtQuerySystemInformation");
if (!pNtQSI) {
FreeLibrary(hNtDll);
return 2;
}
pMem = malloc(allocSize);
while (pNtQSI(SystemHandleInformation, pMem, allocSize, &retVal)
== STATUS_INFO_LENGTH_MISMATCH) {
pMem = realloc(pMem, allocSize *= 2);
}
hCount = *(ULONG*)pMem;
hFirstEntry = (PSYSTEM_HANDLE_ENTRY)((PBYTE)pMem + 4);
for (i = 0; i < hCount; ++i)
if ((hFirstEntry[i].ObjectType == 30) && (hFirstEntry[i].OwnerPid == 5628))
{
HANDLE TargetHandleValueTemp = (HANDLE)hFirstEntry[i].HandleValue;
HANDLE SourceProcHandleTemp = OpenProcess(PROCESS_DUP_HANDLE, FALSE, hFirstEntry[i].OwnerPid);
if (!DuplicateHandle(SourceProcHandleTemp, (HANDLE)hFirstEntry[i].HandleValue, GetCurrentProcess(), &TargetHandleValueTemp, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
TargetHandleValueTemp = (HANDLE)hFirstEntry[i].HandleValue;
}
CloseHandle(SourceProcHandleTemp);
TCHAR Path[MAX_PATH];
DWORD dwret = GetFinalPathNameByHandle(TargetHandleValueTemp, Path, MAX_PATH, 0);
_tprintf(TEXT("PID: %d\tFileHandle: %d\tThe final path is: %s\n"), hFirstEntry[i].OwnerPid, TargetHandleValueTemp, Path);
CloseHandle(TargetHandleValueTemp);
}
free(pMem);
FreeLibrary(hNtDll);
}

RegSetValueEx and CHAR

consider the following code
addHash("hash");
bool addHash(char* hash) {
HKEY hKey = 0;
int code = RegOpenKey(HKEY_CURRENT_USER, subkey, &hKey);
const int length = strlen(hash)+1;
WCHAR whash[100];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, hash, strlen(hash), whash, 100);
LONG setRes = RegSetValueEx(hKey, L"hash", 0, REG_SZ, (LPBYTE)whash, strlen(hash)+1);
return true;
}
After code is compiled and executed "ha" is puted into registry. Can somebody tell me where the problem is?
Thank you in advance!
The last argument is the number of bytes, not the number of characters, that the second last argument points to.
So the first five bytes (strlen(hash) + 1) of whash will be stored in the registry. Change to:
LONG setRes = RegSetValueEx(hKey,
L"hash",
0,
REG_SZ,
(LPBYTE)whash,
(wcslen(whash) + 1) * sizeof(WCHAR));
You may also need to initialise whash (I don't think MultiByteToWideChar() adds a null terminator for you):
WCHAR whash[100] = { 0 };
I think this is what you are trying to do:
#include <tchar.h>
#include <Windows.h>
using namespace std;
bool addHash(wstring hash) {
const wchar_t* wHash = hash.c_str();
LONG ret = RegSetKeyValue(HKEY_CURRENT_USER, _T("Software\\aa\\test"), _T("hash"), REG_SZ, wHash, hash.length() * sizeof(wchar_t));
return (ret == ERROR_SUCCESS);
}
int main()
{
addHash(_T("A42B2094EDC43"));
return 0;
}
Hope this helps ;)

Determine path to registry key from HKEY handle in C++

Given a handle to a Windows Registry Key, such as the ones that are set by ::RegOpenKeyEx(), is it possible to determine the full path to that key?
I realize that in a simple application all you have to do is look up 5 or 10 lines and read... but in a complex app like the one I'm debugging, the key I'm interested in can be opened from a series of calls.
Use LoadLibrary and NtQueryKey exported function as in the following code snippet.
#include <windows.h>
#include <string>
typedef LONG NTSTATUS;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#ifndef STATUS_BUFFER_TOO_SMALL
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#endif
std::wstring GetKeyPathFromKKEY(HKEY key)
{
std::wstring keyPath;
if (key != NULL)
{
HMODULE dll = LoadLibrary(L"ntdll.dll");
if (dll != NULL) {
typedef DWORD (__stdcall *NtQueryKeyType)(
HANDLE KeyHandle,
int KeyInformationClass,
PVOID KeyInformation,
ULONG Length,
PULONG ResultLength);
NtQueryKeyType func = reinterpret_cast<NtQueryKeyType>(::GetProcAddress(dll, "NtQueryKey"));
if (func != NULL) {
DWORD size = 0;
DWORD result = 0;
result = func(key, 3, 0, 0, &size);
if (result == STATUS_BUFFER_TOO_SMALL)
{
size = size + 2;
wchar_t* buffer = new (std::nothrow) wchar_t[size/sizeof(wchar_t)]; // size is in bytes
if (buffer != NULL)
{
result = func(key, 3, buffer, size, &size);
if (result == STATUS_SUCCESS)
{
buffer[size / sizeof(wchar_t)] = L'\0';
keyPath = std::wstring(buffer + 2);
}
delete[] buffer;
}
}
}
FreeLibrary(dll);
}
}
return keyPath;
}
int _tmain(int argc, _TCHAR* argv[])
{
HKEY key = NULL;
LONG ret = ERROR_SUCCESS;
ret = RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft", &key);
if (ret == ERROR_SUCCESS)
{
wprintf_s(L"Key path for %p is '%s'.", key, GetKeyPathFromKKEY(key).c_str());
RegCloseKey(key);
}
return 0;
}
This will print the key path on the console:
Key path for 00000FDC is
'\REGISTRY\MACHINE\SOFTWARE\Microsoft'.
I was excited to find this article and its well liked solution.
Until I found that my system's NTDLL.DLL did not have NtQueryKeyType.
After some hunting around, I ran across ZwQueryKey in the DDK forums.
It is in C#, but here is the solution that works for me:
enum KEY_INFORMATION_CLASS
{
KeyBasicInformation, // A KEY_BASIC_INFORMATION structure is supplied.
KeyNodeInformation, // A KEY_NODE_INFORMATION structure is supplied.
KeyFullInformation, // A KEY_FULL_INFORMATION structure is supplied.
KeyNameInformation, // A KEY_NAME_INFORMATION structure is supplied.
KeyCachedInformation, // A KEY_CACHED_INFORMATION structure is supplied.
KeyFlagsInformation, // Reserved for system use.
KeyVirtualizationInformation, // A KEY_VIRTUALIZATION_INFORMATION structure is supplied.
KeyHandleTagsInformation, // Reserved for system use.
MaxKeyInfoClass // The maximum value in this enumeration type.
}
[StructLayout(LayoutKind.Sequential)]
public struct KEY_NAME_INFORMATION
{
public UInt32 NameLength; // The size, in bytes, of the key name string in the Name array.
public char[] Name; // An array of wide characters that contains the name of the key.
// This character string is not null-terminated.
// Only the first element in this array is included in the
// KEY_NAME_INFORMATION structure definition.
// The storage for the remaining elements in the array immediately
// follows this element.
}
[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int ZwQueryKey(IntPtr hKey, KEY_INFORMATION_CLASS KeyInformationClass, IntPtr lpKeyInformation, int Length, out int ResultLength);
public static String GetHKeyName(IntPtr hKey)
{
String result = String.Empty;
IntPtr pKNI = IntPtr.Zero;
int needed = 0;
int status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, IntPtr.Zero, 0, out needed);
if ((UInt32)status == 0xC0000023) // STATUS_BUFFER_TOO_SMALL
{
pKNI = Marshal.AllocHGlobal(sizeof(UInt32) + needed + 4 /*paranoia*/);
status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, pKNI, needed, out needed);
if (status == 0) // STATUS_SUCCESS
{
char[] bytes = new char[2 + needed + 2];
Marshal.Copy(pKNI, bytes, 0, needed);
// startIndex == 2 skips the NameLength field of the structure (2 chars == 4 bytes)
// needed/2 reduces value from bytes to chars
// needed/2 - 2 reduces length to not include the NameLength
result = new String(bytes, 2, (needed/2)-2);
}
}
Marshal.FreeHGlobal(pKNI);
return result;
}
I've only ever tried it while running as Administrator, which may be required.
The result is a bit oddly formatted: \REGISTRY\MACHINE\SOFTWARE\company\product for example, instead of HKEY_LOCAL_MACHINE\SOFTWARE\company\product.
Nominally no because it's just a handle and there is no API that I know of to let you do this in the normal Windows API's.
HOWEVER the Native API has lots of functions some of which can give you handles open for given files and the like so there maybe something similar for the Registry. That and RegMon by SysInternals may do something like this but you'll have to Google I'm afraid :/
You can use RegSaveKey and write it to a file, then look at the file.
Alternatively you can keep a global map of HKEYs to LPCWSTRs and add entries when you open them and do lookups whenever.
You may also be able to do something with the !reg command in WinDBG / NTSD, but you can't just give it the HKEY. You'll have to do some other trickery to get the info you want out of it.
Since std::wstring allows to construct string from pointer and count of characters, and the kernel string always return the count of bytes, it is not necessary to terminated the string with NUL. I do not suggest that to add size or to offset the pointer by constant number directly, it's better to use the real data type like the structure types instead, and std::vector<UCHAR> instead of new for dynamic memory allocating. I modified the code from highly upvoted answer as the followings.
The legacy way, obtaining the function pointer from ntdll.dll dynamically:
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#include <string>
#include <vector>
#define REG_KEY_PATH_LENGTH 1024
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
KeyLayerInformation,
MaxKeyInfoClass
} KEY_INFORMATION_CLASS;
typedef struct _KEY_NAME_INFORMATION {
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
typedef NTSTATUS (NTAPI *PFN_NtQueryKey)(
__in HANDLE /* KeyHandle */,
__in KEY_INFORMATION_CLASS /* KeyInformationClass */,
__out_opt PVOID /* KeyInformation */,
__in ULONG /* Length */,
__out ULONG * /* ResultLength */
);
std::wstring RegQueryKeyPath(HKEY hKey)
{
std::wstring keyPath;
if (hKey != NULL)
{
HMODULE hinstDLL = GetModuleHandleW(L"ntdll.dll");
if (hinstDLL != NULL)
{
FARPROC pfn = GetProcAddress(hinstDLL, "NtQueryKey");
if (pfn != NULL)
{
NTSTATUS Status;
std::vector<UCHAR> Buffer(FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + sizeof(WCHAR) * REG_KEY_PATH_LENGTH);
KEY_NAME_INFORMATION *pkni;
ULONG Length;
TryAgain:
Status = reinterpret_cast<PFN_NtQueryKey>(pfn)(hKey, KeyNameInformation, Buffer.data(), Buffer.size(), &Length);
switch (Status) {
case STATUS_BUFFER_TOO_SMALL:
case STATUS_BUFFER_OVERFLOW:
Buffer.resize(Length);
goto TryAgain;
case STATUS_SUCCESS:
pkni = reinterpret_cast<KEY_NAME_INFORMATION *>(Buffer.data());
keyPath.assign(pkni->Name, pkni->NameLength / sizeof(WCHAR));
default:
break;
}
}
}
}
return keyPath;
}
If you are using Visual Studio 2015 or above, ntdll.lib is included by default, so I suggest that linking to ntdll.dll statically:
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll")
#include <string>
#include <vector>
#define REG_KEY_PATH_LENGTH 1024
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
KeyLayerInformation,
MaxKeyInfoClass
} KEY_INFORMATION_CLASS;
typedef struct _KEY_NAME_INFORMATION {
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
EXTERN_C NTSYSAPI NTSTATUS NTAPI NtQueryKey(
__in HANDLE /* KeyHandle */,
__in KEY_INFORMATION_CLASS /* KeyInformationClass */,
__out_opt PVOID /* KeyInformation */,
__in ULONG /* Length */,
__out ULONG * /* ResultLength */
);
std::wstring RegQueryKeyPath(HKEY hKey)
{
std::wstring keyPath;
NTSTATUS Status;
std::vector<UCHAR> Buffer(FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + sizeof(WCHAR) * REG_KEY_PATH_LENGTH);
KEY_NAME_INFORMATION *pkni;
ULONG Length;
TryAgain:
Status = NtQueryKey(hKey, KeyNameInformation, Buffer.data(), Buffer.size(), &Length);
switch (Status) {
case STATUS_BUFFER_TOO_SMALL:
case STATUS_BUFFER_OVERFLOW:
Buffer.resize(Length);
goto TryAgain;
case STATUS_SUCCESS:
pkni = reinterpret_cast<KEY_NAME_INFORMATION *>(Buffer.data());
keyPath.assign(pkni->Name, pkni->NameLength / sizeof(WCHAR));
default:
break;
}
return keyPath;
}
Note that NtQueryKey returned STATUS_BUFFER_OVERFLOW but not STATUS_BUFFER_TOO_SMALL on Windows 10 if the supplied buffer is insufficient.
For ntsd/windbg:
!handle yourhandle 4