How to write process memory with multilevel pointer with c++? - c++

I'm trying to make a cheat for RE2. I found memory's with pointer-scan with cheat engine. My code is not working :(
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
int newValue = 10 ;
HWND hwnd = FindWindowA(NULL, "RESIDENT EVIL 2");
if ( hwnd == NULL )
{
cout << endl << "Process handle not found !" << endl;
return 0 ;
} else {
DWORD pId;
GetWindowThreadProcessId(hwnd, &pId);
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
if(!hProc) {
cerr << "Cannot open process !" << endl ;
} else {
int c = WriteProcessMemory(hProc, (LPVOID)0x707B6D0 + 0x80 + 0x78 + 0x98 + 0x50 + 0x18, &newValue, (DWORD)sizeof(newValue), NULL);
if (c>0) {
clog << "yes" << endl ;
} else {
clog << "no" << endl ;
}
CloseHandle(hProc);
}
}
return 0;
}

You are misinterpreting what Cheat Engine is showing you.
In your code, 0x707B6D0 + 0x80 + 0x78 + 0x98 + 0x50 + 0x18 equals 0x707B8C8, which is NOWHERE even close to the value of 0x0EC1A3F0 that you are trying to reach.
What you need to do instead is:
First, read a pointer that is stored at the base address 0x707B6D0 (the value read is 0x128BFBB0).
Then, add 0x18 to that pointer (0x128BFBB0 + 0x18 = 0x128BFBC8) and read a new pointer at that address (the value read is 0x128564D0).
Then, add 0x50 to that pointer (0x128564D0 + 0x50 = 0x12856520) and read a new pointer at that address (the value read is 0x0F2EC940).
Then, add 0x98 to that pointer (0x0F2EC940 + 0x98 = 0x0F2EC9D8) and read a new pointer at that address (the value read is 0x0F2EB2B0).
Then, add 0x78 to that pointer (0x0F2EB2B0 + 0x78 = 0x0F2EB328) and read a new pointer at that address (the value read is 0x0EC1A370).
Then, add 0x80 to that pointer (0x0EC1A370 + 0x80 = 0x0EC1A3F0), and write your data to that address.
Try something more like this:
#include <iostream>
#include <stdexcept>
#include <memory>
#include <windows.h>
DWORD_PTR readPointerFromProc(HANDLE hProc, DWORD_PTR baseAddr)
{
DWORD ptr;
if (!ReadProcessMemory(hProc, reinterpret_cast<LPVOID>(baseAddr), &ptr, sizeof(ptr), NULL);
throw std::runtime_error("Cannot read from process !");
return ptr;
}
void WriteIntToProc(HANDLE hProc, DWORD_PTR baseAddr, int value)
{
if (!WriteProcessMemory(hProc, reinterpret_cast<LPVOID>(baseAddr), &value, sizeof(value), NULL);
throw std::runtime_error("Cannot write to process !");
}
struct HandleDeleter
{
typedef HANDLE pointer;
void operator()(HANDLE handle) const { CloseHandle(handle); }
};
int main()
{
int newValue = 10;
try
{
HWND hwnd = FindWindowA(NULL, "RESIDENT EVIL 2");
if (!hwnd)
throw std::runtime_error("Process window not found !");
DWORD pId = 0;
GetWindowThreadProcessId(hwnd, &pId);
HANDLE hProc = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pId);
if (!hProc)
throw std::runtime_error("Cannot open process !");
std::unique_ptr<HANDLE, HandleDeleter> hProc_deleter(hProc);
DWORD_PTR ptr = readPointerFromProc(hProc, 0x707B6D0);
ptr = readPointerFromProc(hProc, ptr + 0x18);
ptr = readPointerFromProc(hProc, ptr + 0x50);
ptr = readPointerFromProc(hProc, ptr + 0x98);
ptr = readPointerFromProc(hProc, ptr + 0x78);
writeIntToProc(hProc, ptr + 0x80, newValue);
}
catch (const std::exception &e)
{
std::cerr << e.what() << std::endl;
return 0;
}
std::cout << "Success !" << std::endl;
return 0;
}

You need to de-reference between each offset so that you are following the pointer chain. Just adding the offsets is not enough.
Here is a function that does this for you, please keep in mind there is no error checking:
uintptr_t FindDMAAddy(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets)
{
uintptr_t addr = ptr;
for (unsigned int i = 0; i < offsets.size(); ++i)
{
ReadProcessMemory(hProc, (BYTE*)addr, &addr, sizeof(addr), 0);
addr += offsets[i];
}
return addr;
}
Calling the function would look like:
uintptr_t ammoAddr = FindDMAAddy(hProcess, dynamicPtrBaseAddr, { 0x374, 0x14, 0x0 });
It does not de-reference the last offset, which is ideal.
After that, call WriteProcessMemory using the return from that function as the lpBaseAddress argument.

Related

c++ memory write bytes to address with Windows kernel driver

so I will explain what im trying to do and i wanna understand why its not working for me,
I found an Address from CE : which is: 0x04013118 with value an array of bytes: DC 04 00 00 04 02 00 00
What im trying to do is write memory with kernel driver to this address a new value which is also an array of bytes :
DC 04 00 00 00 00 00 00
Here is most of the function im trying to use , but most of the parameters are defined in other classes i cannot provide all of them but i think part of the code ( just im going to put here ) is already enough,
this is part of the MemoryManager.cpp and also BypassMemory.cpp:
void MemoryManager::readMemory(PVOID BaseAddress, PVOID Buffer, SIZE_T BufferSize){
if(!allIsWell)
return;
struct{
HANDLE ProcessHandle;
PVOID BaseAddress;
PVOID Buffer;
SIZE_T BufferSize;
PSIZE_T NumberOfBytesRead;
} input = { processHandle, BaseAddress, Buffer, BufferSize, NumberOfBytes };
IO_STATUS_BLOCK ioStatusBlock;
NtDeviceIoControlFile(m_hDriver, nullptr, nullptr, nullptr, &ioStatusBlock, MM_READVIRTUALMEMORY, &input, sizeof(input), nullptr, 0);
}
void MemoryManager::writeMemory(PVOID BaseAddress, PVOID Buffer, SIZE_T BufferSize) {
if (!allIsWell)
return;
struct {
HANDLE ProcessHandle;
PVOID BaseAddress;
PVOID Buffer;
SIZE_T BufferSize;
PSIZE_T NumberOfBytesWritten;
} input = { processHandle, BaseAddress, Buffer, BufferSize, NumberOfBytesWrite };
IO_STATUS_BLOCK ioStatusBlock;
NtDeviceIoControlFile(m_hDriver, nullptr, nullptr, nullptr, &ioStatusBlock, MM_WRITEVIRTUALMEMORY, &input, sizeof(input), nullptr, 0);
}
bool MemoryManager::search(BYTE * bSearchData, int nSearchSize, DWORD_PTR dwStartAddr, DWORD_PTR dwEndAddr, BOOL bIsCurrProcess, int iSearchMode, std::vector<DWORD_PTR> &vRet){
MEMORY_BASIC_INFORMATION mbi;
std::vector<MEMORY_REGION> m_vMemoryRegion;
mbi.RegionSize = 0x400;
DWORD dwAddress = dwStartAddr;
MEMORY_REGION memSectorList[1000];
int memSectorIndex = 0;
while(VirtualQueryEx(processHandle, (LPCVOID)dwAddress, &mbi, sizeof(mbi)) && (dwAddress < dwEndAddr) && ((dwAddress + mbi.RegionSize) > dwAddress)){
if(
(mbi.State == MEM_COMMIT) &&
((mbi.Protect & PAGE_GUARD) == 0) &&
(mbi.Protect != PAGE_NOACCESS) &&
((mbi.AllocationProtect & PAGE_NOCACHE) != PAGE_NOCACHE)
){
MEMORY_REGION mData = { 0 };
mData.dwBaseAddr = (DWORD_PTR)mbi.BaseAddress;
mData.dwMemorySize = mbi.RegionSize;
m_vMemoryRegion.push_back(mData);
memSectorList[memSectorIndex] = mData;
memSectorIndex++;
}
dwAddress = (DWORD)mbi.BaseAddress + mbi.RegionSize;
}
std::vector<MEMORY_REGION>::iterator it;
int memSectorCount = memSectorIndex;
memSectorIndex = 0;
DWORD_PTR curAddr = dwStartAddr;
while(curAddr < dwEndAddr){
VirtualQueryEx(processHandle, (LPCVOID)curAddr, &mbi, sizeof(mbi));
long regionSizeOrg = mbi.RegionSize;
long regionSize = mbi.RegionSize;
if(regionSize > 10){
BYTE* pCurrMemoryData = new BYTE[regionSize];
ZeroMemory(pCurrMemoryData, regionSize);
writeMemory((PVOID)curAddr, (PVOID*)pCurrMemoryData, regionSize);
DWORD_PTR dwOffset = 0;
int iOffset = find(pCurrMemoryData, regionSize, bSearchData, nSearchSize);
while(iOffset != -1){
dwOffset += iOffset;
vRet.push_back(dwOffset + curAddr);
dwOffset += nSearchSize;
iOffset = find(pCurrMemoryData + dwOffset, regionSize - dwOffset - nSearchSize, bSearchData, nSearchSize);
}
delete[] pCurrMemoryData;
}
memSectorIndex++;
curAddr = curAddr + (DWORD_PTR)regionSizeOrg;
continue;
}
return TRUE;
}
int MemoryManager::find(BYTE *buffer, int dwBufferSize, BYTE *bstr, DWORD dwStrLen){
if(dwBufferSize < 0){
return -1;
}
DWORD i, j;
for(i = 0; i < dwBufferSize; i++){
for(j = 0; j < dwStrLen; j++){
if(buffer[i + j] != bstr[j] && bstr[j] != '?')
break;
}
if(j == dwStrLen)
return i;
}
return -1;
}
DWORD MemoryManager::dRead(DWORD base){
readMemory((PVOID)base, &_d, 4);
return _d;
}
void MemoryManager::dWrite(DWORD base){
writeMemory((PVOID)base, &_d, 4);
}
/* these are in bypassmemory.cpp */
void BypassMemory::init(){
viewWordBase = getAddr(); // = works and gets Addrs = 0x04013118
if(viewWordBase){
std::cout << "found addr : " << termcolor::green << std::hex << viewWordBase << std::dec << termcolor::reset << "\n";
} else{
std::cout << termcolor::red << "View World Not Found ! \n" << termcolor::reset;
return;
}
// so basiclly my addres = 0x04013118 and value of it = DC 04 00 00 04 02 00 00
BYTE writePattern[] = { 0xDC, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
//const char* writePtr = "DC 04 00 00 00 00 00 00"; // i tried also this but didn't work
MemoryManager->writeMemory((PVOID)bypassAddr1, &writePattern, sizeof(writePattern)); // i write to the base addres ( 0x04013118, new val = DC 04 00 00 00 00 00 00)
//MemoryManager->writeMemory((PVOID)bypassAddr1, &writePtr, sizeof(writePtr));
}
DWORD BypassMemory::getAddr(){
BYTE pattern[] = { 0xDC, 0x04, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00 };
std::vector<DWORD_PTR> foundedBases;
MemoryManager->search(pattern, sizeof(pattern), 0x04000000, 0x05000000, false, 0, foundedBases);
std::cout << "founded bases size: " << termcolor::green << std::hex << foundedBases.size() << std::dec << termcolor::reset << "\n";
for(int i = 0; i < foundedBases.size(); i++){
DWORD cand = dGet(foundedBases[i]); // this reads inside the address purpose to check
std::cout << "founded bases addr: " << termcolor::green << std::hex << foundedBases[i] << std::dec << termcolor::reset << "\n";
return foundedBases[i];
}
return 0;
}
int main()
{
int Pid = ProcManager::getAowProcID();
pMemoryManager->init(Pid, true);
BypassMemory->init();
return 0;
}
this is the MemoryManager.h: ( if someone interested )
#define MM_DEVICE_TYPE 0x9999
#define MM_CTL_CODE(x) CTL_CODE(MM_DEVICE_TYPE, 0x800 + x, METHOD_NEITHER, FILE_ANY_ACCESS)
#define MM_READVIRTUALMEMORY MM_CTL_CODE(56)
#define MM_WRITEVIRTUALMEMORY MM_CTL_CODE(57)
typedef struct _MEMORY_REGION{
DWORD_PTR dwBaseAddr;
DWORD_PTR dwMemorySize;
}MEMORY_REGION;
class MemoryManager{
public:
MemoryManager();
~MemoryManager();
HANDLE m_hDriver = nullptr;
HANDLE processHandle;
int processId = 0;
bool allIsWell = false;
PSIZE_T NumberOfBytes = nullptr;
PSIZE_T NumberOfBytesWrite = nullptr; // created by oday
DWORD _d;
float _f;
int _i;
BYTE* _b = new BYTE[1];
int _dw = 1245; // created by oday
void init(int pid, bool debug);
bool connectToDriver(std::string m_strDeviceName);
void readMemory(PVOID BaseAddress, PVOID Buffer, SIZE_T BufferSize);
void writeMemory(PVOID BaseAddress, PVOID Buffer, SIZE_T BufferSize); // created by oday
bool search(BYTE * bSearchData, int nSearchSize, DWORD_PTR dwStartAddr, DWORD_PTR dwEndAddr, BOOL bIsCurrProcess, int iSearchMode, std::vector<DWORD_PTR>& vRet);
int find(BYTE * buffer, int dwBufferSize, BYTE * bstr, DWORD dwStrLen);
void dWrite(DWORD base); // created by oday
DWORD dRead(DWORD base);
float fRead(DWORD base);
int iRead(DWORD base);
BYTE* bRead(DWORD base);
};
extern MemoryManager* pMemoryManager;
The interesting part lays in this:
BYTE writePattern[] = { 0xDC, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
pMemoryManager->writeMemory((PVOID)bypassAddr1, &writePattern, sizeof(writePattern));
I successfully read the address at 0x04013118 from the search function from the current pattern, and everything is fine, but when i try to write to this address with this what i mentioned here up
nothing happens in the memory, and the value doesn't change, does anybody have an idea why nothing happens and the memory doesn't change? im pretty sure my kernel driver has nothing to do with this because its vuln and it has permissions to read and write.
I will draw a short conclusion for others having the same problem.
The main problem was that the author was unable to write to a specific memory location within a processes memory.
With the help of the windows API function VirtualProtectEx the author was able to change the virtual memory page access bits to allow writing to the memory page of the desired memory address.
The procedure includes:
Calling VirtualProtectEx to enable writing to the memory page
Writing to the specific memory location within that page
Reset the page access bits with another call to VirtualProtectEx

Read REG_RESOURCE_LIST memory values - Incorrect value

I am trying to read the physical memory values in Hardware\ResourceMap\System Resources\Physical Memory using the following code:
#include <iostream>
#include <conio.h>
#include <windows.h>
#include <string>
#include <stdlib.h>
using namespace std;
int main()
{
HKEY hKey = NULL;
LPCTSTR pszSubKey = L"Hardware\\ResourceMap\\System Resources\\Physical Memory";
LPCTSTR pszValueName = L".Translated";
if (! RegOpenKey(HKEY_LOCAL_MACHINE, pszSubKey, &hKey) == ERROR_SUCCESS)
{
cout << "RegOpenKey failed" << endl;
return 0;
}
DWORD dwType = 0;
LPBYTE lpData = NULL;
DWORD dwLength = 0;
if (! RegQueryValueEx(hKey, pszValueName, 0, &dwType, NULL, &dwLength) == ERROR_SUCCESS)
{
cout << "RegOpenKey failed" << endl;
return 0;
}
lpData = new BYTE[dwLength];
RegQueryValueEx(hKey, pszValueName, 0, &dwType, lpData, &dwLength);
RegCloseKey(hKey);
DWORD dwResourceCount = *(DWORD*)(lpData + 16);
auto pmi = lpData + 24;
for (int dwIndex = 0; dwIndex < dwResourceCount; dwIndex++)
{
auto start = *(uint64_t*)(pmi + 0);
cout << "-> 0x" << hex << start;
auto length = *(uint64_t*)(pmi + 8);
cout << "\t + 0x" << hex << length;
auto endaddr = start + length;
cout << "\t0x" << hex << endaddr << endl;
pmi += 20;
}
delete[]lpData;
}
A sample output:
-> 0x1000 + 0x57000 0x58000
-> 0x59000 + 0x46000 0x9f000
-> 0x100000 + 0xc855f000 0xc865f000
-> 0xc8666000 + 0xbf3000 0xc9259000
-> 0xc9759000 + 0x13779000 0xdced2000
-> 0xdd0d8000 + 0x3c000 0xdd114000
-> 0xddfff000 + 0x1000 0xde000000
-> 0x100000000 + 0x41f0000 0x1041f0000
The problem is that the last length value is incorrect.
Instead of 0x41f0000, the Registry editor shows 0x41f000000 to be the correct value:
I have been researching this issue for the past few days, but cannot figure out why I get a false value here.
Can anyone with more experience using the Win32 API help me?
if value type is REG_RESOURCE_LIST value data is CM_RESOURCE_LIST structure. need use it instead of *(DWORD*)(lpData + 16);, lpData + 24. anyway your code is incorrect in case Count != 1. what you try print is CM_PARTIAL_RESOURCE_DESCRIPTOR structures. but you not check the Type member of CM_PARTIAL_RESOURCE_DESCRIPTOR. but it cab be different. can be CmResourceTypeMemory but also can be CmResourceTypeMemoryLarge - you not take this in account. in case CmResourceTypeMemoryLarge need check Flags for
CM_RESOURCE_MEMORY_LARGE_40
CM_RESOURCE_MEMORY_LARGE_48
CM_RESOURCE_MEMORY_LARGE_64
and
you say:
Instead of 0x41f0000 the regeditor shows 0x41f000000
but 0x41f000000 is shifted on 8 bit 0x41f0000. based on this obvious that you really have here CmResourceTypeMemoryLarge with CM_RESOURCE_MEMORY_40 flag.
in this case need use Length40 member:
The high 32 bits of the 40-bit length, in bytes, of the range of
allocated memory addresses. The lowest 8 bits are treated as zero.
so code for dump CM_RESOURCE_LIST must be next:
BOOL Memory(PCM_RESOURCE_LIST pcrl, ULONG size)
{
if (size < FIELD_OFFSET(CM_RESOURCE_LIST, List))
{
return FALSE;
}
size -= FIELD_OFFSET(CM_RESOURCE_LIST, List);
if (ULONG Count = pcrl->Count)
{
PCM_FULL_RESOURCE_DESCRIPTOR List = pcrl->List;
do
{
if (size < FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors))
{
return FALSE;
}
size -= FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
DbgPrint("InterfaceType=%x BusNumber=%u\n", List->InterfaceType, List->BusNumber);
if (ULONG n = List->PartialResourceList.Count)
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors = List->PartialResourceList.PartialDescriptors;
do
{
if (size < sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))
{
return FALSE;
}
size -= sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
ULONG64 Length = PartialDescriptors->u.Memory.Length;
switch (PartialDescriptors->Type)
{
case CmResourceTypeMemoryLarge:
switch (PartialDescriptors->Flags & (CM_RESOURCE_MEMORY_LARGE_40|
CM_RESOURCE_MEMORY_LARGE_48|CM_RESOURCE_MEMORY_LARGE_64))
{
case CM_RESOURCE_MEMORY_LARGE_40:
Length <<= 8;
break;
case CM_RESOURCE_MEMORY_LARGE_48:
Length <<= 16;
break;
case CM_RESOURCE_MEMORY_LARGE_64:
Length <<= 32;
break;
default:
DbgPrint("unknown mamory type\n");
continue;
}
case CmResourceTypeMemory:
DbgPrint("%016I64x %I64x\n",
PartialDescriptors->u.Memory.Start.QuadPart, Length);
break;
}
} while (PartialDescriptors++, --n);
}
} while (List++, --Count);
}
return size == 0;
}
also when we get it data - need not forget close key handle even on error (you not do this when RegQueryValueEx fail) and use RegOpenKeyExW instead RegOpenKey for ability specify the desired access rights to the key. the use 2 sequential calls to RegQueryValueEx (with 0 buffer and allocated once buffer) also not the best. because in theory buffer size can changed (some change value) between this 2 calls and you can fail got data on second call RegQueryValueExtoo. also we can already on first call allocate reasonable memory space, and only if it will be not enough - reallocate on next call. so better call this in loop until we got ERROR_MORE_DATA and first time call with already not empty buffer:
ULONG Memory()
{
HKEY hKey;
ULONG dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"Hardware\\ResourceMap\\System Resources\\Physical Memory",
0, KEY_READ, &hKey);
if (dwError == NOERROR)
{
ULONG cb = 0x100;
do
{
dwError = ERROR_NO_SYSTEM_RESOURCES;
union {
PVOID buf;
PBYTE pb;
PCM_RESOURCE_LIST pcrl;
};
if (buf = LocalAlloc(0, cb))
{
ULONG dwType;
if ((dwError = RegQueryValueExW(hKey, L".Translated",
0, &dwType, pb, &cb)) == NOERROR)
{
if (dwType == REG_RESOURCE_LIST)
{
if (!Memory(pcrl, cb))
{
DbgPrint("error parsing resource list\n");
}
}
else
{
dwError = ERROR_INVALID_DATATYPE;
}
}
LocalFree(buf);
}
} while (dwError == ERROR_MORE_DATA);
RegCloseKey(hKey);
}
return dwError;
}

Construct own object from return value of MapViewOfFile()

I want to 'cast' the return value of MapViewOfFile (as far as I know a pointer to void) to my own class, so that I am able work with this object. I know how the memory is structured. The headerSize resides at byte number 4 to byte number 8, a hex value is written in the byte for example hex 47, so the size should be 71 bytes. I want to get 71 as the value of my attribute 'headerSize'. What code has to replace 'TODO' in my snippet? I do not know how to read the bytes and how to create the attributes.
Code in main.cpp:
// MapViewOfFile return a pointer to void, so you need to cast it to a suitable structure
pBuf = (FILE*) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
// create object
JobaShm jobaShm(pBuf);
int headerSize = jobaShm.getHeaderSize();
std::cout << " HeaderSize " << headerSize << ";\n";
Code in jobashm.h
#ifndef JOBASHM_H
#define JOBASHM
class JobaShm {
public:
JobaShm(FILE* handle);
int getHeaderSize();
private:
int headerSize;
};
#endif
Code in jobashm.cpp
#include <stdio.h>
#include "jobashm.h"
JobaShm::JobaShm(FILE* handle){
// TODO
}
int JobaShm::getHeaderSize(){
return headerSize;
}
UPDATE: Due to this tutorial http://www.cplusplus.com/forum/general/54381/ I am trying to cast the return value of MapViewOfFile in my own struct.
main.cpp
struct Shm {
int firstByte;
};
int main(void){
std::cout << "*** Start SharedMemory ***\n";
HANDLE hMapFile;
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szName);
if (hMapFile == NULL){
MessageBox(NULL, TEXT("Could not open file mapping object"), TEXT("ERROR"), MB_OK);
return 1;
}
Shm * pBuf = (Shm *) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE); // ggf. besser size_of Shm, statt BUF_SIZE
std::cout << " Debug " << pBuf->firstByte << ";\n";
UnmapViewOfFile(&pBuf);
CloseHandle(hMapFile);
std::cout << "*** close app by typing a number. ***\n";
int a = 0;
cin >> a;
return 0;
}
I think you have to read more about MapViewOfFile.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366551(v=vs.85).aspx
It returns a pointer to the data.
LPCTSTR pBuf;
pBuf = (LPTSTR) MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
JobaShm(pBuf)
Then since you know what the data is you should create a structure for it and cast it.
struct FileData {
int space;
int headerSize;
// etc...
}
JobaShm::JobaShm(LPTSTR* pBuf) {
FileData fd;
CopyMemory((PVOID)pBuf, &fd, sizeof(fd));
headerSize = fd.headerSize;
}

in the handler of SetUnhandledExceptionFilter how to print a stacktrace?

When unhandled exception occured i want to print a stacktrace instead of just terminating. I've tried to do that using SetUnhandledExceptionFilter:
SetUnhandledExceptionFilter(UnhandledException);
...
LONG WINAPI UnhandledException(LPEXCEPTION_POINTERS exceptionInfo)
{
printf("An exception occurred which wasn't handled!\nCode: 0x%08X\nAddress: 0x%08X",
exceptionInfo->ExceptionRecord->ExceptionCode,
exceptionInfo->ExceptionRecord->ExceptionAddress);
return EXCEPTION_EXECUTE_HANDLER;
}
This code, i've found, works fine. However there are no addition information because ExceptionCode and ExceptionAddress are printed in system "Event Viewer" anyway.
If it is possible to print a full stack trace so I can determine the exact point where exception occured?
I've found this code https://code.google.com/p/m0d-s0beit-sa/source/browse/src/main.cpp?r=9ceb4fec21d647b169c72851d7882bef2b9c5a8a It partly solves my problem. Only method where exception occured is printed. But type of exception and line number is not printed.
Here's some stack-walk code for Windows I wrote some years ago. Here's the kind of output it produces:
Walking stack.
0 DebugBreak
1 ThreadFunc2 e:\c\source\stackwalk2a.cpp(72)
2 ThreadFunc1 e:\c\source\stackwalk2a.cpp(79)
3 TargetThread e:\c\source\stackwalk2a.cpp(86)
4 BaseThreadInitThunk
5 RtlUserThreadStart
End of stack walk.
The main thing that's missing is anything about the exception type. If you're talking about a native structured/vectored exception, I'm pretty sure that should be retrievable too. Retrieving types of C++ exceptions might be a little more difficult (but I'm not really sure -- it might be pretty easy).
#include <windows.h>
#include <winnt.h>
#include <string>
#include <vector>
#include <Psapi.h>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <iterator>
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "dbghelp.lib")
// Some versions of imagehlp.dll lack the proper packing directives themselves
// so we need to do it.
#pragma pack( push, before_imagehlp, 8 )
#include <imagehlp.h>
#pragma pack( pop, before_imagehlp )
struct module_data {
std::string image_name;
std::string module_name;
void *base_address;
DWORD load_size;
};
typedef std::vector<module_data> ModuleList;
HANDLE thread_ready;
bool show_stack(std::ostream &, HANDLE hThread, CONTEXT& c);
DWORD __stdcall TargetThread( void *arg );
void ThreadFunc1();
void ThreadFunc2();
DWORD Filter( EXCEPTION_POINTERS *ep );
void *load_modules_symbols( HANDLE hProcess, DWORD pid );
int main( void ) {
DWORD thread_id;
thread_ready = CreateEvent( NULL, false, false, NULL );
HANDLE thread = CreateThread( NULL, 0, TargetThread, NULL, 0, &thread_id );
WaitForSingleObject( thread_ready, INFINITE );
CloseHandle(thread_ready);
return 0;
}
// if you use C++ exception handling: install a translator function
// with set_se_translator(). In the context of that function (but *not*
// afterwards), you can either do your stack dump, or save the CONTEXT
// record as a local copy. Note that you must do the stack dump at the
// earliest opportunity, to avoid the interesting stack-frames being gone
// by the time you do the dump.
DWORD Filter(EXCEPTION_POINTERS *ep) {
HANDLE thread;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &thread, 0, false, DUPLICATE_SAME_ACCESS);
std::cout << "Walking stack.";
show_stack(std::cout, thread, *(ep->ContextRecord));
std::cout << "\nEnd of stack walk.\n";
CloseHandle(thread);
return EXCEPTION_EXECUTE_HANDLER;
}
void ThreadFunc2() {
__try { DebugBreak(); }
__except (Filter(GetExceptionInformation())) { }
SetEvent(thread_ready);
}
void ThreadFunc1(void (*f)()) {
f();
}
// We'll do a few levels of calls from our thread function so
// there's something on the stack to walk...
//
DWORD __stdcall TargetThread(void *) {
ThreadFunc1(ThreadFunc2);
return 0;
}
class SymHandler {
HANDLE p;
public:
SymHandler(HANDLE process, char const *path=NULL, bool intrude = false) : p(process) {
if (!SymInitialize(p, path, intrude))
throw(std::logic_error("Unable to initialize symbol handler"));
}
~SymHandler() { SymCleanup(p); }
};
#ifdef _M_X64
STACKFRAME64 init_stack_frame(CONTEXT c) {
STACKFRAME64 s;
s.AddrPC.Offset = c.Rip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Rsp;
s.AddrStack.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Rbp;
s.AddrFrame.Mode = AddrModeFlat;
return s;
}
#else
STACKFRAME64 init_stack_frame(CONTEXT c) {
STACKFRAME64 s;
s.AddrPC.Offset = c.Eip;
s.AddrPC.Mode = AddrModeFlat;
s.AddrStack.Offset = c.Esp;
s.AddrStack.Mode = AddrModeFlat;
s.AddrFrame.Offset = c.Ebp;
s.AddrFrame.Mode = AddrModeFlat;
return s;
}
#endif
void sym_options(DWORD add, DWORD remove=0) {
DWORD symOptions = SymGetOptions();
symOptions |= add;
symOptions &= ~remove;
SymSetOptions(symOptions);
}
class symbol {
typedef IMAGEHLP_SYMBOL64 sym_type;
sym_type *sym;
static const int max_name_len = 1024;
public:
symbol(HANDLE process, DWORD64 address) : sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) {
memset(sym, '\0', sizeof(*sym) + max_name_len);
sym->SizeOfStruct = sizeof(*sym);
sym->MaxNameLength = max_name_len;
DWORD64 displacement;
if (!SymGetSymFromAddr64(process, address, &displacement, sym))
throw(std::logic_error("Bad symbol"));
}
std::string name() { return std::string(sym->Name); }
std::string undecorated_name() {
std::vector<char> und_name(max_name_len);
UnDecorateSymbolName(sym->Name, &und_name[0], max_name_len, UNDNAME_COMPLETE);
return std::string(&und_name[0], strlen(&und_name[0]));
}
};
bool show_stack(std::ostream &os, HANDLE hThread, CONTEXT& c) {
HANDLE process = GetCurrentProcess();
int frame_number=0;
DWORD offset_from_symbol=0;
IMAGEHLP_LINE64 line = {0};
SymHandler handler(process);
sym_options(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
void *base = load_modules_symbols(process, GetCurrentProcessId());
STACKFRAME64 s = init_stack_frame(c);
line.SizeOfStruct = sizeof line;
IMAGE_NT_HEADERS *h = ImageNtHeader(base);
DWORD image_type = h->FileHeader.Machine;
do {
if (!StackWalk64(image_type, process, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
return false;
os << std::setw(3) << "\n" << frame_number << "\t";
if ( s.AddrPC.Offset != 0 ) {
std::cout << symbol(process, s.AddrPC.Offset).undecorated_name();
if (SymGetLineFromAddr64( process, s.AddrPC.Offset, &offset_from_symbol, &line ) )
os << "\t" << line.FileName << "(" << line.LineNumber << ")";
}
else
os << "(No Symbols: PC == 0)";
++frame_number;
} while (s.AddrReturn.Offset != 0);
return true;
}
class get_mod_info {
HANDLE process;
static const int buffer_length = 4096;
public:
get_mod_info(HANDLE h) : process(h) {}
module_data operator()(HMODULE module) {
module_data ret;
char temp[buffer_length];
MODULEINFO mi;
GetModuleInformation(process, module, &mi, sizeof(mi));
ret.base_address = mi.lpBaseOfDll;
ret.load_size = mi.SizeOfImage;
GetModuleFileNameEx(process, module, temp, sizeof(temp));
ret.image_name = temp;
GetModuleBaseName(process, module, temp, sizeof(temp));
ret.module_name = temp;
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
return ret;
}
};
void *load_modules_symbols(HANDLE process, DWORD pid) {
ModuleList modules;
DWORD cbNeeded;
std::vector<HMODULE> module_handles(1);
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
module_handles.resize(cbNeeded/sizeof(HMODULE));
EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process));
return modules[0].base_address;
}

How to read a value from the Windows registry

Given the key for some registry value (e.g. HKEY_LOCAL_MACHINE\blah\blah\blah\foo) how can I:
Safely determine that such a key exists.
Programmatically (i.e. with code) get its value.
I have absolutely no intention of writing anything back to the registry (for the duration of my career if I can help it). So we can skip the lecture about every molecule in my body exploding at the speed of light if I write to the registry incorrectly.
Prefer answers in C++, but mostly just need to know what the special Windows API incantation to get at the value is.
Here is some pseudo-code to retrieve the following:
If a registry key exists
What the default value is for that registry key
What a string value is
What a DWORD value is
Example code:
Include the library dependency: Advapi32.lib
HKEY hKey;
LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Perl", 0, KEY_READ, &hKey);
bool bExistsAndSuccess (lRes == ERROR_SUCCESS);
bool bDoesNotExistsSpecifically (lRes == ERROR_FILE_NOT_FOUND);
std::wstring strValueOfBinDir;
std::wstring strKeyDefaultValue;
GetStringRegKey(hKey, L"BinDir", strValueOfBinDir, L"bad");
GetStringRegKey(hKey, L"", strKeyDefaultValue, L"bad");
LONG GetDWORDRegKey(HKEY hKey, const std::wstring &strValueName, DWORD &nValue, DWORD nDefaultValue)
{
nValue = nDefaultValue;
DWORD dwBufferSize(sizeof(DWORD));
DWORD nResult(0);
LONG nError = ::RegQueryValueExW(hKey,
strValueName.c_str(),
0,
NULL,
reinterpret_cast<LPBYTE>(&nResult),
&dwBufferSize);
if (ERROR_SUCCESS == nError)
{
nValue = nResult;
}
return nError;
}
LONG GetBoolRegKey(HKEY hKey, const std::wstring &strValueName, bool &bValue, bool bDefaultValue)
{
DWORD nDefValue((bDefaultValue) ? 1 : 0);
DWORD nResult(nDefValue);
LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult, nDefValue);
if (ERROR_SUCCESS == nError)
{
bValue = (nResult != 0) ? true : false;
}
return nError;
}
LONG GetStringRegKey(HKEY hKey, const std::wstring &strValueName, std::wstring &strValue, const std::wstring &strDefaultValue)
{
strValue = strDefaultValue;
WCHAR szBuffer[512];
DWORD dwBufferSize = sizeof(szBuffer);
ULONG nError;
nError = RegQueryValueExW(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
if (ERROR_SUCCESS == nError)
{
strValue = szBuffer;
}
return nError;
}
const CString REG_SW_GROUP_I_WANT = _T("SOFTWARE\\My Corporation\\My Package\\Group I want");
const CString REG_KEY_I_WANT= _T("Key Name");
CRegKey regKey;
DWORD dwValue = 0;
if(ERROR_SUCCESS != regKey.Open(HKEY_LOCAL_MACHINE, REG_SW_GROUP_I_WANT))
{
m_pobLogger->LogError(_T("CRegKey::Open failed in Method"));
regKey.Close();
goto Function_Exit;
}
if( ERROR_SUCCESS != regKey.QueryValue( dwValue, REG_KEY_I_WANT))
{
m_pobLogger->LogError(_T("CRegKey::QueryValue Failed in Method"));
regKey.Close();
goto Function_Exit;
}
// dwValue has the stuff now - use for further processing
Since Windows >=Vista/Server 2008, RegGetValue is available, which is a safer function than RegQueryValueEx. No need for RegOpenKeyEx, RegCloseKey or NUL termination checks of string values (REG_SZ, REG_MULTI_SZ, REG_EXPAND_SZ).
#include <iostream>
#include <string>
#include <exception>
#include <windows.h>
/*! \brief Returns a value from HKLM as string.
\exception std::runtime_error Replace with your error handling.
*/
std::wstring GetStringValueFromHKLM(const std::wstring& regSubKey, const std::wstring& regValue)
{
size_t bufferSize = 0xFFF; // If too small, will be resized down below.
std::wstring valueBuf; // Contiguous buffer since C++11.
valueBuf.resize(bufferSize);
auto cbData = static_cast<DWORD>(bufferSize * sizeof(wchar_t));
auto rc = RegGetValueW(
HKEY_LOCAL_MACHINE,
regSubKey.c_str(),
regValue.c_str(),
RRF_RT_REG_SZ,
nullptr,
static_cast<void*>(valueBuf.data()),
&cbData
);
while (rc == ERROR_MORE_DATA)
{
// Get a buffer that is big enough.
cbData /= sizeof(wchar_t);
if (cbData > static_cast<DWORD>(bufferSize))
{
bufferSize = static_cast<size_t>(cbData);
}
else
{
bufferSize *= 2;
cbData = static_cast<DWORD>(bufferSize * sizeof(wchar_t));
}
valueBuf.resize(bufferSize);
rc = RegGetValueW(
HKEY_LOCAL_MACHINE,
regSubKey.c_str(),
regValue.c_str(),
RRF_RT_REG_SZ,
nullptr,
static_cast<void*>(valueBuf.data()),
&cbData
);
}
if (rc == ERROR_SUCCESS)
{
cbData /= sizeof(wchar_t);
valueBuf.resize(static_cast<size_t>(cbData - 1)); // remove end null character
return valueBuf;
}
else
{
throw std::runtime_error("Windows system error code: " + std::to_string(rc));
}
}
int main()
{
std::wstring regSubKey;
#ifdef _WIN64 // Manually switching between 32bit/64bit for the example. Use dwFlags instead.
regSubKey = L"SOFTWARE\\WOW6432Node\\Company Name\\Application Name\\";
#else
regSubKey = L"SOFTWARE\\Company Name\\Application Name\\";
#endif
std::wstring regValue(L"MyValue");
std::wstring valueFromRegistry;
try
{
valueFromRegistry = GetStringValueFromHKLM(regSubKey, regValue);
}
catch (std::exception& e)
{
std::cerr << e.what();
}
std::wcout << valueFromRegistry;
}
Its parameter dwFlags supports flags for type restriction, filling the value buffer with zeros on failure (RRF_ZEROONFAILURE) and 32/64bit registry access (RRF_SUBKEY_WOW6464KEY, RRF_SUBKEY_WOW6432KEY) for 64bit programs.
The pair RegOpenKey and RegQueryKeyEx will do the trick.
If you use MFC CRegKey class is even more easier solution.
RegQueryValueEx
This gives the value if it exists, and returns an error code ERROR_FILE_NOT_FOUND if the key doesn't exist.
(I can't tell if my link is working or not, but if you just google for "RegQueryValueEx" the first hit is the msdn documentation.)
Typically the register key and value are constants in the program. If so, here is an example how to read a DWORD registry value Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled:
#include <windows.h>
DWORD val;
DWORD dataSize = sizeof(val);
if (ERROR_SUCCESS == RegGetValueA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\FileSystem", "LongPathsEnabled", RRF_RT_DWORD, nullptr /*type not required*/, &val, &dataSize)) {
printf("Value is %i\n", val);
// no CloseKey needed because it is a predefined registry key
}
else {
printf("Error reading.\n");
}
To adapt for other value types, see https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluea for complete spec.
This console app will list all the values and their data from a registry key for most of the potential registry values. There's some weird ones not often used. If you need to support all of them, expand from this example while referencing this Registry Value Type documentation.
Let this be the registry key content you can import from a .reg file format:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\added\subkey]
"String_Value"="hello, world!"
"Binary_Value"=hex:01,01,01,01
"Dword value"=dword:00001224
"QWord val"=hex(b):24,22,12,00,00,00,00,00
"multi-line val"=hex(7):4c,00,69,00,6e,00,65,00,20,00,30,00,00,00,4c,00,69,00,\
6e,00,65,00,20,00,31,00,00,00,4c,00,69,00,6e,00,65,00,20,00,32,00,00,00,00,\
00
"expanded_val"=hex(2):25,00,55,00,53,00,45,00,52,00,50,00,52,00,4f,00,46,00,49,\
00,4c,00,45,00,25,00,5c,00,6e,00,65,00,77,00,5f,00,73,00,74,00,75,00,66,00,\
66,00,00,00
The console app itself:
#include <Windows.h>
#include <iostream>
#include <string>
#include <locale>
#include <vector>
#include <iomanip>
int wmain()
{
const auto hKey = HKEY_CURRENT_USER;
constexpr auto lpSubKey = TEXT("added\\subkey");
auto openedKey = HKEY();
auto status = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &openedKey);
if (status == ERROR_SUCCESS) {
auto valueCount = static_cast<DWORD>(0);
auto maxNameLength = static_cast<DWORD>(0);
auto maxValueLength = static_cast<DWORD>(0);
status = RegQueryInfoKey(openedKey, NULL, NULL, NULL, NULL, NULL, NULL,
&valueCount, &maxNameLength, &maxValueLength, NULL, NULL);
if (status == ERROR_SUCCESS) {
DWORD type = 0;
DWORD index = 0;
std::vector<wchar_t> valueName = std::vector<wchar_t>(maxNameLength + 1);
std::vector<BYTE> dataBuffer = std::vector<BYTE>(maxValueLength);
for (DWORD index = 0; index < valueCount; index++) {
DWORD charCountValueName = static_cast<DWORD>(valueName.size());
DWORD charBytesData = static_cast<DWORD>(dataBuffer.size());
status = RegEnumValue(openedKey, index, valueName.data(), &charCountValueName,
NULL, &type, dataBuffer.data(), &charBytesData);
if (type == REG_SZ) {
const auto reg_string = reinterpret_cast<wchar_t*>(dataBuffer.data());
std::wcout << L"Type: REG_SZ" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData : " << reg_string << std::endl;
}
else if (type == REG_EXPAND_SZ) {
const auto casted = reinterpret_cast<wchar_t*>(dataBuffer.data());
TCHAR buffer[32000];
ExpandEnvironmentStrings(casted, buffer, 32000);
std::wcout << L"Type: REG_EXPAND_SZ" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData: " << buffer << std::endl;
}
else if (type == REG_MULTI_SZ) {
std::vector<std::wstring> lines;
const auto str = reinterpret_cast<wchar_t*>(dataBuffer.data());
auto line = str;
lines.emplace_back(line);
for (auto i = 0; i < charBytesData / sizeof(wchar_t) - 1; i++) {
const auto c = str[i];
if (c == 0) {
line = str + i + 1;
const auto new_line = reinterpret_cast<wchar_t*>(line);
if (wcsnlen_s(new_line, 1024) > 0)
lines.emplace_back(new_line);
}
}
std::wcout << L"Type: REG_MULTI_SZ" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData: " << std::endl;
for (size_t i = 0; i < lines.size(); i++) {
std::wcout << L"\t\tLine[" << i + 1 << L"]: " << lines[i] << std::endl;
}
}
if (type == REG_DWORD) {
const auto dword_value = reinterpret_cast<unsigned long*>(dataBuffer.data());
std::wcout << L"Type: REG_DWORD" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData : " << std::to_wstring(*dword_value) << std::endl;
}
else if (type == REG_QWORD) {
const auto qword_value = reinterpret_cast<unsigned long long*>(dataBuffer.data());
std::wcout << L"Type: REG_DWORD" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData : " << std::to_wstring(*qword_value) << std::endl;
}
else if (type == REG_BINARY) {
std::vector<uint16_t> bins;
for (auto i = 0; i < charBytesData; i++) {
bins.push_back(static_cast<uint16_t>(dataBuffer[i]));
}
std::wcout << L"Type: REG_BINARY" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData:";
for (size_t i = 0; i < bins.size(); i++) {
std::wcout << L" " << std::uppercase << std::hex << \
std::setw(2) << std::setfill(L'0') << std::to_wstring(bins[i]);
}
std::wcout << std::endl;
}
}
}
}
RegCloseKey(openedKey);
return 0;
}
Expected console output:
Type: REG_SZ
Name: String_Value
Data : hello, world!
Type: REG_BINARY
Name: Binary_Value
Data: 01 01 01 01
Type: REG_DWORD
Name: Dword value
Data : 4644
Type: REG_DWORD
Name: QWord val
Data : 1188388
Type: REG_MULTI_SZ
Name: multi-line val
Data:
Line[1]: Line 0
Line[2]: Line 1
Line[3]: Line 2
Type: REG_EXPAND_SZ
Name: expanded_val
Data: C:\Users\user name\new_stuff
#include <windows.h>
#include <map>
#include <string>
#include <stdio.h>
#include <string.h>
#include <tr1/stdint.h>
using namespace std;
void printerr(DWORD dwerror) {
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwerror,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
if (isOut) {
fprintf(fout, "%s\n", lpMsgBuf);
} else {
printf("%s\n", lpMsgBuf);
}
// Free the buffer.
LocalFree(lpMsgBuf);
}
bool regreadSZ(string& hkey, string& subkey, string& value, string& returnvalue, string& regValueType) {
char s[128000];
map<string,HKEY> keys;
keys["HKEY_CLASSES_ROOT"]=HKEY_CLASSES_ROOT;
keys["HKEY_CURRENT_CONFIG"]=HKEY_CURRENT_CONFIG; //DID NOT SURVIVE?
keys["HKEY_CURRENT_USER"]=HKEY_CURRENT_USER;
keys["HKEY_LOCAL_MACHINE"]=HKEY_LOCAL_MACHINE;
keys["HKEY_USERS"]=HKEY_USERS;
HKEY mykey;
map<string,DWORD> valuetypes;
valuetypes["REG_SZ"]=REG_SZ;
valuetypes["REG_EXPAND_SZ"]=REG_EXPAND_SZ;
valuetypes["REG_MULTI_SZ"]=REG_MULTI_SZ; //probably can't use this.
LONG retval=RegOpenKeyEx(
keys[hkey], // handle to open key
subkey.c_str(), // subkey name
0, // reserved
KEY_READ, // security access mask
&mykey // handle to open key
);
if (ERROR_SUCCESS != retval) {printerr(retval); return false;}
DWORD slen=128000;
DWORD valuetype = valuetypes[regValueType];
retval=RegQueryValueEx(
mykey, // handle to key
value.c_str(), // value name
NULL, // reserved
(LPDWORD) &valuetype, // type buffer
(LPBYTE)s, // data buffer
(LPDWORD) &slen // size of data buffer
);
switch(retval) {
case ERROR_SUCCESS:
//if (isOut) {
// fprintf(fout,"RegQueryValueEx():ERROR_SUCCESS:succeeded.\n");
//} else {
// printf("RegQueryValueEx():ERROR_SUCCESS:succeeded.\n");
//}
break;
case ERROR_MORE_DATA:
//what do I do now? data buffer is too small.
if (isOut) {
fprintf(fout,"RegQueryValueEx():ERROR_MORE_DATA: need bigger buffer.\n");
} else {
printf("RegQueryValueEx():ERROR_MORE_DATA: need bigger buffer.\n");
}
return false;
case ERROR_FILE_NOT_FOUND:
if (isOut) {
fprintf(fout,"RegQueryValueEx():ERROR_FILE_NOT_FOUND: registry value does not exist.\n");
} else {
printf("RegQueryValueEx():ERROR_FILE_NOT_FOUND: registry value does not exist.\n");
}
return false;
default:
if (isOut) {
fprintf(fout,"RegQueryValueEx():unknown error type 0x%lx.\n", retval);
} else {
printf("RegQueryValueEx():unknown error type 0x%lx.\n", retval);
}
return false;
}
retval=RegCloseKey(mykey);
if (ERROR_SUCCESS != retval) {printerr(retval); return false;}
returnvalue = s;
return true;
}