Related
I have the following problem:
I want to keep track of the running processes by using CreateToolhelp32Snapshot and Process32First/Next. However I want to use the Unicode charset by default.
bool active( const std::wstring& process_name )
{
HANDLE snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if ( snapshot == INVALID_HANDLE_VALUE )
return false;
PROCESSENTRY32 entry;
if ( Process32First( snapshot, &entry ) )
{
if ( process_name.compare( entry.szExeFile ) == 0 )
{
CloseHandle( snapshot );
return true;
}
}
while ( Process32Next( snapshot, &entry ) )
{
if ( process_name.compare( entry.szExeFile ) == 0 )
{
CloseHandle( snapshot );
return true;
}
}
CloseHandle( snapshot );
return false;
}
int main( )
{
SetConsoleTitle( L"Lel" );
if ( active( L"notepad++.exe" ) )
std::cout << "Hello" << std::endl;
else
std::cout << ":(" << std::endl;
}
However, if I use multibyte-charset everything's working fine.
You must initialize entry and set dwSize value. dwSize value is Windows's idea of version control and is required:
PROCESSENTRY32 entry = { 0 };
entry.dwSize = sizeof(PROCESSENTRY32);
Comparison should not be case sensitive:
while (Process32Next(snapshot, &entry))
{
if (_wcsicmp(process_name.c_str(), entry.szExeFile) == 0)
{
CloseHandle(snapshot);
return true;
}
}
I am trying to make a simple application which encrypts a string and then decrypts it.
So far my code:
int main( int argc, char* argv[] )
{
char test[ 32 ] = { 0 };
strcpy( test, "This is a sample string." );
BYTE buf = NULL;
DWORD len = strlen( test );
EncryptData( lpszPassword, test, &len );
return 0;
}
void EncryptData( TCHAR *lpszPassword, char *pbBuffer, DWORD *dwCount )
{
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTHASH hHash = 0;
LPWSTR wszPassword = lpszPassword;
DWORD cbPassword = ( wcslen( wszPassword ) + 1 )*sizeof( WCHAR );
if ( !CryptAcquireContext( &hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT ) )
{
printf( "Error %x during CryptAcquireContext!\n", GetLastError() );
goto Cleanup;
}
if ( !CryptCreateHash( hProv, CALG_SHA_256, 0, 0, &hHash ) )
{
printf( "Error %x during CryptCreateHash!\n", GetLastError() );
goto Cleanup;
}
if ( !CryptHashData( hHash, ( PBYTE )wszPassword, cbPassword, 0 ) )
{
printf( "Error %x during CryptHashData!\n", GetLastError() );
goto Cleanup;
}
if ( !CryptDeriveKey( hProv, CALG_AES_256, hHash, CRYPT_EXPORTABLE, &hKey ) )//hKey
{
printf( "Error %x during CryptDeriveKey!\n", GetLastError() );
goto Cleanup;
}
DWORD size = ( DWORD )strlen( pbBuffer ) / sizeof( char );
printf( "\nLength of string = %d", size );
if ( !CryptEncrypt( hKey, 0, TRUE, 0, ( LPBYTE )pbBuffer, &size, BLOCK_SIZE ) )
{
printf( "Error %x during CryptEncrypt!\n", GetLastError() );
goto Cleanup;
}
printf( "\nEncrypted bytes = %d", size );
printf( "\nEncrypted text = %s", pbBuffer );
if ( !CryptDecrypt( hKey, 0, TRUE, 0, ( LPBYTE )pbBuffer, &size ) )
{
printf( "Error %x during CryptDecrypt!\n", GetLastError() );
goto Cleanup;
}
printf( "\nDecrypted bytes = %d", size );
printf( "\nDecrypted text = %s", pbBuffer );
Cleanup:
if ( hKey )
{
CryptDestroyKey( hKey );
}
if ( hHash )
{
CryptDestroyHash( hHash );
}
if ( hProv )
{
CryptReleaseContext( hProv, 0 );
}
}
This produces the output:
Length of string = 24
Encrypted bytes = 32
Encrypted text = ╨é╖·ç┤╠├ó br.≡·►;╜K/┤E(↓)╫%┤Cà¡╩╠╠╠╠╘)Ñ°♀·L
Decrypted bytes = 24
Decrypted text = This is a sample string.)╫%┤Cà¡╩╠╠╠╠╘)Ñ°♀·L
So basicly it is almost working, but at the and of the encrypted string there are characters left from the encrypted string.
So my question is, am i doing something wrong or am i just missing something?
Thanks in advance!
The printf function when given "%s" requires a NULL terminated string. Obviously the string is not NULL terminated (actually, the NULL is located who-knows-where, but printf() found it long after the valid portion of the data is printed).
Use the size value you retrieved for the decrypted text. That is the real number of bytes that are valid.
Here is a solution that not only corrects the size and decrypted data issue, but also the issue with usage of goto.
#include <string>
#include <iostream>
using namespace std;
struct CryptStuff
{
HCRYPTPROV* hProv;
HCRYPTKEY* hKey;
HCRYPTHASH* hHash;
CryptStuff(HCRYPTPROV* hprov, HCRYPTKEY* hkey, HCRYPTHASH* hash) :
hProv(hprov), hKey(hkey), hHash(hash) {}
~CryptStuff()
{
if ( *hKey ) CryptDestroyKey( *hKey );
if ( *hHash ) CryptDestroyHash( *hHash );
if ( *hProv ) CryptReleaseContext( *hProv, 0 );
}
};
void EncryptData( TCHAR *lpszPassword, char *pbBuffer, DWORD *dwCount )
{
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTHASH hHash = 0;
// create an instance of CryptStuff. This will cleanup the data on return
CryptStuff cs(&hProv, &hKey, &hHash);
LPWSTR wszPassword = lpszPassword;
DWORD cbPassword = ( wcslen( wszPassword ) + 1 )*sizeof( WCHAR );
if ( !CryptAcquireContext( &hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
CRYPT_VERIFYCONTEXT ) )
{
return;
}
if ( !CryptCreateHash( hProv, CALG_SHA_256, 0, 0, &hHash ) )
{
return;
}
if ( !CryptHashData( hHash, ( PBYTE )wszPassword, cbPassword, 0 ) )
{
return;
}
if ( !CryptDeriveKey( hProv, CALG_AES_256, hHash, CRYPT_EXPORTABLE, &hKey ) )
{
return;
}
DWORD size = ( DWORD )strlen( pbBuffer ) / sizeof( char );
cout << "\nLength of string = " << size;
if ( !CryptEncrypt( hKey, 0, TRUE, 0, ( LPBYTE )pbBuffer, &size, BLOCK_SIZE ) )
{
return;
}
cout << "\nEncrypted bytes = " << size;
cout << "\nEncrypted text = ";
cout.write(pbBuffer, size);
if ( !CryptDecrypt( hKey, 0, TRUE, 0, ( LPBYTE )pbBuffer, &size ) )
{
return;
}
cout << "\nDecrypted bytes = " << size;
cout << "\nDecrypted text = ";
cout.write(pbBuffer, size);
}
I wrote this without a compiler handy, so forgive any typos. I also removed the error output for brevity.
The code above first corrects the issue of the decrypted data by using cout.write to output the proper number of characters (denoted by the size value). This guarantees we get the characters outputted that we want. I used cout.write, since it is perfectly acceptable for unencrypted data to contain embedded NULL's, and we don't want to stop on the first NULL that shows up in the string. We want to stop once we hit size number of characters that are outputted.
The next thing that was done was to use a technique called RAII (Resource Acquisition Is Initialization) to remove the goto. Note how this was done:
We first created a struct called CryptStuff that contains pointers to the 3 items we want to clean up. In this struct, we have a destructor that cleans up these items. To utilize this struct, we create an instance of it called cs inside of EncryptData, and give the instance on construction the address of the 3 items.
So basically, when EncryptData returns, that cs instance will have its destructor called automatically, which means that we get our handles cleaned up. This is much more advantageous than using things such as goto (practically anything is better than goto) or tricky, redundant coding to clean up the handles. The reason why is that the clean up is automatic -- regardless of the reason for the return of EncryptData, i.e. a return or some function causes an exception to be thrown, we get to clean up the handles.
Also, if at a later time, the code gets more complex, there is no need to remember to "add a goto" or "write that clean up code" over and over again for each new return scenario. Note that the error conditions do a simple return without need for goto.
RAII info can be found here:
What is meant by Resource Acquisition is Initialization (RAII)?
It is an important part in writing C++ code that has to manage resources that are created and must be destroyed consistently.
We have an application that has 3 processes as shown in the image below.
What I wanted to do is to terminate these processes. After reading a few tutorials, I was able to collate these codes. However, it's not working properly. The output is shown after the code.
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
pe32.dwSize = sizeof( PROCESSENTRY32 );
std::string message = "";
int processCounter = 0;
while( Process32Next( hProcessSnap, &pe32 ) ) {
char ch[260];
char DefChar = ' ';
WideCharToMultiByte(CP_ACP,0,pe32.szExeFile,-1, ch,260,&DefChar, NULL);
//A std:string using the char* constructor.
std::string process(ch);
if( process == "bridge.exe" ) {
std::wstring stemp = std::wstring(process.begin(), process.end());
LPCWSTR sw = stemp.c_str();
HWND windowHandle = FindWindowW( NULL, sw );
DWORD* dwProcessId = new DWORD;
GetWindowThreadProcessId( windowHandle, dwProcessId );
message.append( process );
message.append( "-" );
std::ostringstream converter;
converter << *dwProcessId;
message.append( converter.str() );
message.append( "-" );
DWORD dwDesiredAccess = PROCESS_TERMINATE;
BOOL bInheritHandle = FALSE;
HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, *dwProcessId);
if( hProcess == NULL ) {
BOOL result = TerminateProcess(hProcess, 0);
message.append( "NULL" );
}
message.append( "\n" );
CloseHandle(hProcess);
}
}
This is the output:
bridge.exe-4597928-NULL
bridge.exe-4597568-NULL
bridge.exe-4587524-NULL
hProcess returns NULL. What did I miss? Thanks.
My goal is to get the full command line of a 64 bit process programmatically. I have understood and written this code where I do a process walk of all the currently running processes and get each of their details. But the issue is that this code fails to do the same for a 64 bit process (one that is not running under WOW64).
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <iostream>
#include <cstdio>
#include <fstream>
using namespace std;
BOOL GetProcessList( FILE *f);
BOOL ListProcessModules( DWORD dwPID, FILE *f);
BOOL ListProcessThreads( DWORD dwOwnerPID, FILE *f );
void printError( TCHAR* msg, FILE *f );
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
BOOL IsWow64(HANDLE processHandle)
{
BOOL bIsWow64 = FALSE;
//IsWow64Process is not available on all supported versions of Windows.
//Use GetModuleHandle to get a handle to the DLL that contains the function
//and GetProcAddress to get a pointer to the function if available.
fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
if(fnIsWow64Process != NULL)
{
if (!fnIsWow64Process(processHandle, &bIsWow64))
{
//handle error
}
}
return bIsWow64;
}
int main( void )
{
FILE *f = fopen("file_.txt", "w");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
GetProcessList(f);
return 0;
}
BOOL GetProcessList( FILE *f)
{
HANDLE hProcessSnap;
HANDLE hProcess;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass;
fprintf(f, "start writing:\n");
/*
myfile.open ("example.txt");
myfile << "writing starts here..." << endl;
*/
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
printError( TEXT("CreateToolhelp32Snapshot (of processes)"), f);
return( FALSE );
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first process,
// and exit if unsuccessful
if( !Process32First( hProcessSnap, &pe32 ) )
{
printError( TEXT("Process32First"), f ); // show cause of failure
CloseHandle( hProcessSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
_tprintf( TEXT("\n\n=====================================================" ));
_tprintf( TEXT("\nPROCESS NAME: %s"), pe32.szExeFile );
_tprintf( TEXT("\n-------------------------------------------------------" ));
fprintf(f, "\n\n=====================================================");
fprintf(f, "\nPROCESS NAME: %s", pe32.szExeFile );
fprintf(f, "\n------------------------------------------------------------");
/*
myfile << "\n\n=====================================================";
myfile << "\nPROCESS NAME " << pe32.szExeFile;
myfile << "\n-----------------------------------------------------------";
*/
// Retrieve the priority class.
dwPriorityClass = 0;
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
//is hProcess the handle to the process?
if( hProcess == NULL )
printError( TEXT("OpenProcess"), f );
else
{
if(IsWow64(hProcess)){
_tprintf(TEXT("\nThe process is running under WOW64.\n"));
fprintf(f, "\nThe process is running under WOW64.\n");
//myfile << "\nThe process is running under WOW64.\n";
}
else{
_tprintf(TEXT("\nThe process is not running under WOW64.\n"));
fprintf(f, "\nThe process is not running under WOW64.\n");
//myfile << "\nThe process is not running under WOW64.\n";
}
dwPriorityClass = GetPriorityClass( hProcess );
if( !dwPriorityClass )
printError( TEXT("GetPriorityClass"), f );
CloseHandle( hProcess );
}
_tprintf( TEXT("\n Process ID = 0x%08X"), pe32.th32ProcessID );
_tprintf( TEXT("\n Thread count = %d"), pe32.cntThreads );
_tprintf( TEXT("\n Parent process ID = 0x%08X"), pe32.th32ParentProcessID );
_tprintf( TEXT("\n Priority base = %d"), pe32.pcPriClassBase );
fprintf(f, "\n Process ID = 0x%08X", pe32.th32ProcessID);
fprintf(f, "\n Thread count = %d", pe32.cntThreads );
fprintf(f, "\n Parent process ID = 0x%08X", pe32.th32ParentProcessID );
fprintf(f, "\n Priority base = %d", pe32.pcPriClassBase );
if( dwPriorityClass )
_tprintf( TEXT("\n Priority class = %d"), dwPriorityClass );
// List the modules and threads associated with this process
ListProcessModules( pe32.th32ProcessID,f );
ListProcessThreads( pe32.th32ProcessID,f );
char *cmd_line = NULL;
//get_cmdline_from_pid(pe32.th32ProcessID, cmd_line);
} while( Process32Next( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap );
return( TRUE );
}
BOOL ListProcessModules( DWORD dwPID,FILE *f )
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
printError( TEXT("CreateToolhelp32Snapshot (of modules)"), f );
return( FALSE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
printError( TEXT("Module32First"), f ); // show cause of failure
CloseHandle( hModuleSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the module list of the process,
// and display information about each module
do
{
_tprintf( TEXT("\n\n MODULE NAME: %s"), me32.szModule );
_tprintf( TEXT("\n Executable = %s"), me32.szExePath );
_tprintf( TEXT("\n Process ID = 0x%08X"), me32.th32ProcessID );
_tprintf( TEXT("\n Ref count (g) = 0x%04X"), me32.GlblcntUsage );
_tprintf( TEXT("\n Ref count (p) = 0x%04X"), me32.ProccntUsage );
_tprintf( TEXT("\n Base address = 0x%08X"), (DWORD) me32.modBaseAddr );
_tprintf( TEXT("\n Base size = %d"), me32.modBaseSize );
fprintf(f, "\n\n MODULE NAME: %s", me32.szModule );
fprintf(f, "\n Executable = %s", me32.szExePath );
fprintf(f, "\n Process ID = 0x%08X", me32.th32ProcessID );
fprintf(f, "\n Ref count (g) = 0x%04X", me32.GlblcntUsage );
fprintf(f, "\n Ref count (p) = 0x%04X", me32.ProccntUsage );
fprintf(f, "\n Base address = 0x%08X", (DWORD) me32.modBaseAddr );
fprintf(f, "\n Base size = %d", me32.modBaseSize );
} while( Module32Next( hModuleSnap, &me32 ) );
CloseHandle( hModuleSnap );
return( TRUE );
}
BOOL ListProcessThreads( DWORD dwOwnerPID,FILE *f )
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
return( FALSE );
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32);
// Retrieve information about the first thread,
// and exit if unsuccessful
if( !Thread32First( hThreadSnap, &te32 ) )
{
printError( TEXT("Thread32First"), f ); // show cause of failure
CloseHandle( hThreadSnap ); // clean the snapshot object
return( FALSE );
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if( te32.th32OwnerProcessID == dwOwnerPID )
{
_tprintf( TEXT("\n\n THREAD ID = 0x%08X"), te32.th32ThreadID );
_tprintf( TEXT("\n Base priority = %d"), te32.tpBasePri );
_tprintf( TEXT("\n Delta priority = %d"), te32.tpDeltaPri );
_tprintf( TEXT("\n"));
fprintf(f, "\n\n THREAD ID = 0x%08X", te32.th32ThreadID);
fprintf(f, "\n Base priority = %d", te32.tpBasePri );
fprintf(f, "\n Delta priority = %d", te32.tpDeltaPri );
fprintf(f, "\n");
}
} while( Thread32Next(hThreadSnap, &te32 ) );
CloseHandle( hThreadSnap );
return( TRUE );
}
void printError( TCHAR* msg, FILE *f )
{
DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;
eNum = GetLastError( );
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL );
// Trim the end of the line and terminate it with a null
p = sysMsg;
while( ( *p > 31 ) || ( *p == 9 ) )
++p;
do { *p-- = 0; } while( ( p >= sysMsg ) &&
( ( *p == '.' ) || ( *p < 33 ) ) );
// Display the message
_tprintf( TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
fprintf(f, "\n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg);
}
It gives me the ERROR CODE 299, which indicates that it could not read or write memory from the process, and thus does not provide me the executable command for any 64 bit process.
=====================================================
PROCESS NAME: taskhostex.exe
------------------------------------------------------------
The process is not running under WOW64.
Process ID = 0x00001954
Thread count = 10
Parent process ID = 0x000003BC
Priority base = 8
WARNING: CreateToolhelp32Snapshot (of modules) failed with error 299 (Only part of a ReadProcessMemory or WriteProcessMemory request was completed)
Could anyone please help me out with getting around this issue?
Thanks.
This is not possible. From the documentation:
If the specified process is a 64-bit process and the caller is a
32-bit process, this function fails and the last error code is
ERROR_PARTIAL_COPY (299).
You need to compile your code as 64-bit.
Here more about this issue: How to enum modules in a 64bit process from a 32bit WOW process.
I created a .dll which should work like the RunAs command. The only difference is, that it should read from registry. My problem is, that i need to reed 3 values from the registry, but i can't. It reads the first, than it fails at the second one (Password) with error code 2, which means "The system cannot find the file specified". If i query only for domain and username then it is ok, if i query only for password then it it still succeeds, but if i want to query all three then it fails. Can someone tell me, what i am doing wrong?
Heres my code:
HKEY hKey = 0;
DWORD dwType = REG_SZ;
DWORD dwBufSize = sizeof(buf);
TCHAR szMsg [MAX_PATH + 32];
HANDLE handle;
LPVOID lpMsgBuf;
if( RegOpenKeyEx( HKEY_CURRENT_USER, TEXT("SOFTWARE\\Kampi Corporation\\RunAs!"), 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS )
{
if( RegQueryValueEx( hKey, TEXT("Username"), 0, &dwType, (LPBYTE)buf, &dwBufSize ) == ERROR_SUCCESS )
{
memset( szMsg, 0, sizeof( szMsg ) );
wsprintf ( szMsg, _T("%s"), buf );
mbstowcs( wuser, szMsg, 255 );
RegCloseKey( hKey );
}
else
{
MessageBox ( pCmdInfo->hwnd, "Can not query for Username key value!", _T("RunAs!"), MB_ICONERROR );
RegCloseKey( hKey );
return -1;
}
}
else
{
CSimpleShlExt::showerror( GetLastError(), pCmdInfo->hwnd, "RegOpenKeyEx failed for Username with error code :: " );
return -1;
}
if( RegOpenKeyEx( HKEY_CURRENT_USER, TEXT("SOFTWARE\\Kampi Corporation\\RunAs!"), 0, KEY_QUERY_VALUE ,&hKey ) == ERROR_SUCCESS )
{
if( RegQueryValueEx( hKey, TEXT("Password"), 0, &dwType, (LPBYTE)buf, &dwBufSize ) == ERROR_SUCCESS )
{
memset( szMsg, 0, sizeof( szMsg ) );
wsprintf ( szMsg, _T("%s"), buf );
mbstowcs( wpass, szMsg, 255 );
RegCloseKey( hKey );
}
else
{
char test[200];
sprintf(test,"Can not query for Password key value! EC: %d",GetLastError() );
MessageBox ( pCmdInfo->hwnd, test, _T("RunAs!"), MB_ICONERROR );
RegCloseKey( hKey );
return -1;
}
}
else
{
CSimpleShlExt::showerror( GetLastError(), pCmdInfo->hwnd, "RegOpenKeyEx failed for Password with error code :: " );
return -1;
}
if( RegOpenKeyEx( HKEY_CURRENT_USER, TEXT("SOFTWARE\\Kampi Corporation\\RunAs!"), 0, KEY_QUERY_VALUE ,&hKey ) == ERROR_SUCCESS )
{
if( RegQueryValueEx( hKey, TEXT("Domain"), 0, &dwType, (LPBYTE)buf, &dwBufSize ) == ERROR_SUCCESS )
{
memset( szMsg, 0, sizeof( szMsg ) );
wsprintf ( szMsg, _T("%s"), buf );
mbstowcs( wdomain, szMsg, 255 );
RegCloseKey( hKey );
}
else
{
sprintf(test,"Can not query for Password key value! EC: %d",GetLastError() );
MessageBox ( pCmdInfo->hwnd, test, _T("RunAs!"), MB_ICONERROR );
RegCloseKey( hKey );
return -1;
}
}
else
{
CSimpleShlExt::showerror( GetLastError(), pCmdInfo->hwnd, "RegOpenKeyEx failed for Domain with error code :: " );
return -1;
}
Though it doesn't directly relate to the problem you're asking about, I think the first step toward diagnosing the problem is to get rid of some of the duplication in your code. Right now, it's almost impossible to be sure that all the queries even work the same way. A good example of why it would probably be better if programming editors didn't have cut or (particularly) paste commands at all. I think I'd start with code more like this:
#include <windows.h>
#include <string>
#include <sstream>
#include <iostream>
#include <exception>
#include <iterator>
namespace {
void check(DWORD value, char const *op) {
if (value != ERROR_SUCCESS) {
std::ostringstream buf;
buf << op << " failed error code = " << value;
throw std::logic_error(buf.str().c_str());
}
}
class reg_key {
HKEY key;
public:
reg_key(wchar_t const *path, HKEY topkey = HKEY_CURRENT_USER, DWORD q=KEY_QUERY_VALUE) {
check(RegOpenKeyExW(topkey, path, 0, q, &key), "RegOpenKeyExW");
}
operator HKEY() { return key; }
~reg_key() { RegCloseKey(key); }
};
}
template <class outIt>
void read_reg(wchar_t const *path, wchar_t const *name, outIt out) {
static const int buf_size = 256;
wchar_t buffer[buf_size];
DWORD size = buf_size, type = REG_SZ;
reg_key key(path);
check(RegQueryValueExW(key, name, 0, &type, (LPBYTE)buffer, &size), "RegQueryValueExW");
std::copy(buffer, buffer+wcslen(buffer), out);
}
#ifdef TEST
int main() {
std::wstring code_page, font;
try {
read_reg(L"Software\\Microsoft\\CharMap", L"CodePage", std::back_inserter(code_page));
read_reg(L"Software\\Microsoft\\CharMap", L"Font", std::back_inserter(font));
std::wcout << "Code Page: " << code_page << "\n";
std::wcout << "Font: " << font << std::endl;
}
catch (std::exception &e) {
MessageBox(NULL, e.what(), "Reading Registry failed", MB_ICONERROR);
}
return 0;
}
#endif
I've tried this with a number of different paths/items in my registry, and haven't been able to duplicate the problem you ask about. I'm not sure whether that means the code works better or not though -- I don't have the same registry entries you're looking at since I don't have that particular software installed.
I think I can see why. You need to initialize dwBufSize each time before you call RegQueryValueEx. This function returns the number bytes copied to buf.
You will find the function returns ERROR_MORE_DATA. You've made the mistake of using GetLastError(). Don't do that. The Reg functions return an error code directly.