How to encrypt data correctly? - c++

I have the following code. I'd like to add to this code a key BYTE[] and an IV BYTE[] too, to encrypt my data with. To do that i have to call CryptImportKey and CryptSetKeyParam.
So my questions are:
Where do i have to call theese two APIs? I think after CryptDeriveKey, and then use the output from CryptImportKey to encrypt my data. Am i right?
Can i somehow ensure that the result is correct encrypted? Should i make some other changes to make my code more secure?
#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);
}
Thanks in advance!

Related

How to get extended port information when enumerating ports using Windows API

I'm using some legacy code to enumerate ports on my machine:
#include <windows.h>
#include <devguid.h>
#include <setupapi.h>
#include <string>
#include <iostream>
#include <assert.h>
bool GetTextProperty( std::string& sProperty,
HDEVINFO dev,
_SP_DEVINFO_DATA* pDeviceInfoData,
DWORD prop )
{
char szBuf[MAX_PATH];
DWORD iPropertySize = 0;
if (SetupDiGetDeviceRegistryProperty(dev, pDeviceInfoData,
prop, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
{
sProperty = szBuf;
assert( iPropertySize >= sProperty.size() + 1 );
return true;
}
return false;
}
inline bool readRegistryKeyValue( HKEY hKey, const std::string& key, std::string& value )
{
bool res = false;
CHAR szBuffer[512];
DWORD dwBufferSize = sizeof(szBuffer);
ULONG nError = RegQueryValueEx(hKey, key.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
if (ERROR_SUCCESS == nError)
{
value = szBuffer;
res = true;
}
return res;
}
void ListPorts()
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, 0L, 0L, DIGCF_PRESENT);
if ( hDevInfo == INVALID_HANDLE_VALUE )
{
//Medoc_ReportError(MEDOC_ERROR_HARDWARE_DRIVER_API_FAILED,
// &hDevInfo, sizeof hDevInfo);
assert( false );
}
else
{
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData) != 0; i++)
{
char szBuf[MAX_PATH];
short wImageIdx = 0;
short wItem = 0;
DWORD iPropertySize;
if (SetupDiGetDeviceRegistryProperty(hDevInfo, &DeviceInfoData,
SPDRP_FRIENDLYNAME, 0L, (PBYTE) szBuf, MAX_PATH, &iPropertySize))
{
std::cout << "Smart name: " << szBuf << std::endl;
HKEY hKey = SetupDiOpenDevRegKey(
hDevInfo,
&DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_READ );
if ( hKey )
{
std::string portName;
readRegistryKeyValue( hKey, "PortName", portName );
std::cout << "Port name: " << szBuf << std::endl;
for ( DWORD prop = 0; prop != SPDRP_MAXIMUM_PROPERTY; ++prop )
{
std::string temp;
GetTextProperty( temp, hDevInfo, &DeviceInfoData, prop );
std::cout << prop << " : " << temp << std::endl;
}
RegCloseKey(hKey);
}
}
}
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
}
int main( int argc, char* argv[] )
{
ListPorts();
return 0;
}
Among other information, this gives me access to port name (COM*), type (FTDI for instance), VID and PID...
However, when I have many different devices based on a FTDI chip plugged, they all have the same information (SPDRP_HARDWAREID prperty reports FTDIBUS\COMPORT&VID_0403&PID_6015 or FTDIBUS\COMPORT&VID_0403&PID_6010). So I cannot discriminate who is who.
When I use a USB sniffer ("Device Monitoring Studio"), this one is able to report more relevant information withoutestablishing any connection to the ports:
Can this kind of extended information be accessed through Windows API to discriminate by name many devices using the same FTDI chip? Or must I use FTDI driver API to achieve this?
With the help of Ben Voigt and Simon Mourier, I could achieve this, here is the piece of code:
// More includes:
#include <initguid.h>
#include <devpkey.h>
#include <cfgmgr32.h>
// A new dependency:
#pragma comment (lib, "Cfgmgr32.lib")
bool GetDeviceProperty( const std::string& what,
DEVINST dev,
DEVPROPKEY prop )
{
char szDeviceBuf[MAX_PATH];
DEVPROPTYPE type;
ULONG iDevicePropertySize = MAX_PATH;
if ( CM_Get_DevNode_PropertyW(dev,
&prop,
&type,
(PBYTE) szDeviceBuf,
&iDevicePropertySize,
0) == CR_SUCCESS )
{
wchar_t* txt = (wchar_t*) szDeviceBuf;
std::wstring ws(txt);
std::cout << what << " : " << std::string(ws.begin(), ws.end()) << std::endl;
return true;
}
else
{
return false;
}
}
void ListPorts()
{
...
DEVINST devInstParent;
auto status = CM_Get_Parent(&devInstParent, DeviceInfoData.DevInst, 0);
if (status == CR_SUCCESS)
{
ShowDeviceProperty( "Bus reported device description", devInstParent, DEVPKEY_Device_BusReportedDeviceDesc );
ShowDeviceProperty( "Device description", devInstParent, DEVPKEY_Device_DeviceDesc );
}
else
{
continue;
}
...

Serial communication between pc and Arduino through USB

I have some C++ code that I need to use for serial communication between PC and Arduino. The file "Serial.cpp" is including a file called "stdafx.h" that doesn't exist in the project or anywhere on my computer, which obviously causes an error.
Other than that, I also get other errors, such as C2065 'CSerial': undeclared identifier.
Here are the three files that are in the project:
Serial.h
#ifndef __SERIAL_H__
#define __SERIAL_H__
#pragma once
#include <Windows.h>
#include <memory.h>
#define FC_DTRDSR 0x01
#define FC_RTSCTS 0x02
#define FC_XONXOFF 0x04
#define ASCII_BEL 0x07
#define ASCII_BS 0x08
#define ASCII_LF 0x0A
#define ASCII_CR 0x0D
#define ASCII_XON 0x11
#define ASCII_XOFF 0x13
class CSerial
{
public:
CSerial();
~CSerial();
BOOL Open( int nPort = 2, int nBaud = 9600 );
BOOL Close( void );
int ReadData( void *, int );
int SendData( const char *, int );
int ReadDataWaiting( void );
BOOL IsOpened( void ){ return( m_bOpened ); }
protected:
BOOL WriteCommByte( unsigned char );
HANDLE m_hIDComDev;
OVERLAPPED m_OverlappedRead, m_OverlappedWrite;
bool m_bOpened;
};
#endif
Serial.cpp
// Serial.cpp
#include "stdafx.h"
#include "Serial.h"
CSerial::CSerial()
{
memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );
m_hIDComDev = NULL;
m_bOpened = false;
}
CSerial::~CSerial()
{
Close();
}
BOOL CSerial::Open( int nPort, int nBaud )
{
if( m_bOpened ) return( TRUE );
wchar_t szPort[15];
wchar_t szComParams[50];
DCB dcb;
wsprintf( szPort, L"COM%d", nPort );
m_hIDComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
if( m_hIDComDev == NULL ) return( FALSE );
memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );
COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;
SetCommTimeouts( m_hIDComDev, &CommTimeOuts );
wsprintf( szComParams, L"COM%d:%d,n,8,1", nPort, nBaud );
m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
dcb.DCBlength = sizeof( DCB );
GetCommState( m_hIDComDev, &dcb );
dcb.BaudRate = nBaud;
dcb.ByteSize = 8;
unsigned char ucSet;
ucSet = (unsigned char) ( ( FC_RTSCTS & FC_DTRDSR ) != 0 );
ucSet = (unsigned char) ( ( FC_RTSCTS & FC_RTSCTS ) != 0 );
ucSet = (unsigned char) ( ( FC_RTSCTS & FC_XONXOFF ) != 0 );
if( !SetCommState( m_hIDComDev, &dcb ) ||
!SetupComm( m_hIDComDev, 10000, 10000 ) ||
m_OverlappedRead.hEvent == NULL ||
m_OverlappedWrite.hEvent == NULL ){
DWORD dwError = GetLastError();
if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent );
if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );
CloseHandle( m_hIDComDev );
return( FALSE );
}
m_bOpened = TRUE;
return( m_bOpened );
}
BOOL CSerial::Close( void )
{
if( !m_bOpened || m_hIDComDev == NULL ) return( TRUE );
if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent );
if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );
CloseHandle( m_hIDComDev );
m_bOpened = FALSE;
m_hIDComDev = NULL;
return( TRUE );
}
BOOL CSerial::WriteCommByte( unsigned char ucByte )
{
BOOL bWriteStat;
DWORD dwBytesWritten;
bWriteStat = WriteFile( m_hIDComDev, (LPSTR) &ucByte, 1, &dwBytesWritten, &m_OverlappedWrite );
if( !bWriteStat && ( GetLastError() == ERROR_IO_PENDING ) ){
if( WaitForSingleObject( m_OverlappedWrite.hEvent, 1000 ) ) dwBytesWritten = 0;
else{
GetOverlappedResult( m_hIDComDev, &m_OverlappedWrite, &dwBytesWritten, FALSE );
m_OverlappedWrite.Offset += dwBytesWritten;
}
}
return( TRUE );
}
int CSerial::SendData( const char *buffer, int size )
{
if( !m_bOpened || m_hIDComDev == NULL ) return( 0 );
DWORD dwBytesWritten = 0;
int i;
for( i=0; i<size; i++ ){
WriteCommByte( buffer[i] );
dwBytesWritten++;
}
return( (int) dwBytesWritten );
}
int CSerial::ReadDataWaiting( void )
{
if( !m_bOpened || m_hIDComDev == NULL ) return( 0 );
DWORD dwErrorFlags;
COMSTAT ComStat;
ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );
return( (int) ComStat.cbInQue );
}
int CSerial::ReadData( void *buffer, int limit )
{
if( !m_bOpened || m_hIDComDev == NULL ) return( 0 );
BOOL bReadStatus;
DWORD dwBytesRead, dwErrorFlags;
COMSTAT ComStat;
ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );
if( !ComStat.cbInQue ) return( 0 );
dwBytesRead = (DWORD) ComStat.cbInQue;
if( limit < (int) dwBytesRead ) dwBytesRead = (DWORD) limit;
bReadStatus = ReadFile( m_hIDComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead );
if( !bReadStatus ){
if( GetLastError() == ERROR_IO_PENDING ){
WaitForSingleObject( m_OverlappedRead.hEvent, 2000 );
return( (int) dwBytesRead );
}
return( 0 );
}
return( (int) dwBytesRead );
}
SerialExample.cpp
bool sendExample(int port, int baudRate)
{
char data[4];
CSerial* s = new CSerial();
if(!s->Open(port, baudRate))
{
std_out << _T("Could not open COM") << port << endl;
return false;
}
// Sending a string of 4 characters
data[0] = 0x31;
data[1] = 0x32;
data[2] = 0x33;
data[3] = 0x0D; // ASCII CR
s->SendData(data, 4);
s->Close();
delete s;
}
Does anyone know what I have to do?
stdafx.h is a precompiled header for Visual studio. so if you are not working in visual studio, you can just remove it and it should work just fine.
In regard to the compiler not recognizing the CSerial class -
I don't see where you include "CSerial.h" in SerialExample.cpp (i.e: #include "CSerial.h"), but if you do, this may also be a symptom of CSerial.cpp not compiling (less likely though)...
Hope this helps,
Lior

CryptDecrypt returns random characters at the end of decrxpted string?

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.

Terminating a process

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.

How to read registry correctly for multiple values in c?

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.