stricmp doesn't work in my code - c++

I'm cycling through a process snapshot of TlHelp32 and then comparing the names with stricmp to get the process handle. The problem is even though both values seem to be the same, they apparently are not since it doesn't return 0 . I don't know why though, I have tried writing the process name into the function as well.
HANDLE GetProcessValues(std::string ProcName)
{
const char* ProcNameChar = ProcName.c_str();
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 process;
ZeroMemory(&process, sizeof(process));
process.dwSize = sizeof(process);
if (Process32First(snapshot, &process))
{
do
{
if (_stricmp((char*)process.szExeFile,ProcNameChar)==0)
{
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
return hProc;
}
}while (Process32Next(snapshot,&process));
}
return 0;
}
I debugged it to see if the values fit:

The problem is that you are using the TCHAR versions of Process32First()/Process32Next(), and your debugger screnshot clearly shows that you are compiling your project for Unicode, so TCHAR maps to WCHAR and thus process.szExeFile is a WCHAR[] array. You are incorrectly type-casting that array to a char* pointer. You cannot directly compare a Unicode string to an Ansi string. You need to convert one string to the encoding of the other string before then comparing them.
You are also leaking the HANDLE returned by CreateToolhelp32Snapshot().
Since you are passing an Ansi std::string as input to your GetProcessValues() function, the easiest solution would be to use the Ansi versions of Process32First()/Process32Next() instead, so process.szExeFile is now a CHAR[] array, and thus no conversion is needed:
HANDLE GetProcessValues(std::string ProcName)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE)
return NULL;
PROCESSENTRY32A process;
ZeroMemory(&process, sizeof(process));
process.dwSize = sizeof(process);
const char* ProcNameChar = ProcName.c_str();
HANDLE hProc = NULL;
if (Process32FirstA(snapshot, &process))
{
do
{
if (_stricmp(process.szExeFile, ProcNameChar) == 0)
{
hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
break;
}
}
while (Process32NextA(snapshot, &process));
}
CloseHandle(snapshot);
return hProc;
}
However, you really should stay away from using Ansi APIs. Windows is a Unicode-based OS, and has been for a long time. Use Unicode APIs instead:
HANDLE GetProcessValues(std::wstring ProcName)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE)
return NULL;
PROCESSENTRY32W process;
ZeroMemory(&process, sizeof(process));
process.dwSize = sizeof(process);
const wchar_t* ProcNameChar = ProcName.c_str();
HANDLE hProc = NULL;
if (Process32FirstW(snapshot, &process))
{
do
{
if (_wcsicmp(process.szExeFile, ProcNameChar) == 0)
{
hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process.th32ProcessID);
break;
}
}
while (Process32NextW(snapshot, &process));
}
CloseHandle(snapshot);
return hProc;
}
If your ProcName parameter absolutely must be a std::string, then you can either:
convert ProcName to Unicode using MultiByteToWideChar(), std::wstring_convert, etc, and then compare that result to the strings returned by the Unicode API.
convert strings from the Unicode API to Ansi using WideCharToMultiByte(), std::wstring_convert, etc, and then compare those results to ProcName.

when dealing with wchar* data type, use _wcsicmp for comparison, and - if necessary - convert any involved char* data type into a wchar*-equivalent, e.g. using CStringW class. Confer microsoft _wcsicmp, and be also aware of using a correct locale. A similar problem, yet with wchar* constants, has been described at stack overflow

Related

argument of type "WCHAR *" is incompatible with parameter of type "LPCSTR" in c++

I know that there are lots of questions like this as it is a common error, I also know it is happening because I am using unicode. However, after reading through SO/microsoft docs and fixing the code, it still does not seem to work and I am stumped.
The code is as follows:
#include <Windows.h>
#include <Tlhelp32.h>
#include <string>
DWORD find_pid(const char* procname) {
// Dynamically resolve some functions
HMODULE kernel32 = GetModuleHandleA("Kernel32.dll");
using CreateToolhelp32SnapshotPrototype = HANDLE(WINAPI *)(DWORD, DWORD);
CreateToolhelp32SnapshotPrototype CreateToolhelp32Snapshot = (CreateToolhelp32SnapshotPrototype)GetProcAddress(kernel32, "CreateToolhelp32Snapshot");
using Process32FirstPrototype = BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32);
Process32FirstPrototype Process32First = (Process32FirstPrototype)GetProcAddress(kernel32, "Process32First");
using Process32NextPrototype = BOOL(WINAPI *)(HANDLE, LPPROCESSENTRY32);
Process32NextPrototype Process32Next = (Process32NextPrototype)GetProcAddress(kernel32, "Process32Next");
// Init some important local variables
HANDLE hProcSnap;
PROCESSENTRY32 pe32;
DWORD pid = 0;
pe32.dwSize = sizeof(PROCESSENTRY32);
// Find the PID now by enumerating a snapshot of all the running processes
hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap)
return 0;
if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}
while (Process32Next(hProcSnap, &pe32)) {
//--->here is offending code...
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}
// Cleanup
CloseHandle(hProcSnap);
return pid;
}
I changed the code to this:
if (strcmp(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
but still get the same error. Any ideas?
PROCESSENTRY32 uses wchars when you define UNICODE. The doc's are probably misleading.
Tlhelp32.h defines this:
#ifdef UNICODE
#define Process32First Process32FirstW
#define Process32Next Process32NextW
#define PROCESSENTRY32 PROCESSENTRY32W
#define PPROCESSENTRY32 PPROCESSENTRY32W
#define LPPROCESSENTRY32 LPPROCESSENTRY32W
#endif // !UNICODE
As you can see, PROCESSENTRY32 maps to PROCESSENTRY32W if UNICODE is defined.
pe32.szExeFile is a WCHAR szExeFile[MAX_PATH]; // Path
That is the reason why strcmp fails with the error you get. strcmp expects a char* but you pass pe32.szExeFile, which in your case is a WCHAR*.
Take real care to get the correct pointers to the helper functions. Are you getting the ANSI or UNICODE pointers? You are using a lot of C-style casts in the GetProcAddress calls. You can easily end up casting the return value to an ANSI style function, but using the UNICODE style pointer type.

how can I allocate an array on the stack if the size is not known at compile time?

I'm writing a c++ program with visual studio and I have written this code
DWORD GetProcIDByName(const char* procName) {
HANDLE hSnap;
BOOL done;
PROCESSENTRY32 procEntry;
ZeroMemory(&procEntry, sizeof(PROCESSENTRY32));
procEntry.dwSize = sizeof(PROCESSENTRY32);
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
done = Process32First(hSnap, &procEntry);
do {
/* here */ char file_str[sizeof(procEntry.szExeFile)];
int wc_convert = WideCharToMultiByte(CP_ACP, 0, procEntry.szExeFile, sizeof(procEntry.szExeFile), file_str, sizeof(file_str), NULL, NULL);
if (_strnicmp(file_str, procName, sizeof(file_str)) == 0) {
return procEntry.th32ProcessID;
}
} while (Process32Next(hSnap, &procEntry));
return 0;
}
in order to convert the value procEntry.szExeFile from a WCHAR* (wide unicode character array), to a standard char* to compare, I had to make a char* buffer for it. I wrote the line
char file_str[sizeof(procEntry.szExeFile)];
and realized later that I should use heap memory for this buffer that will change sizes depending on the process name, but I was surprised to see that my visual studio had no problem with this code and I was able to build it with no compiler errors. I haven't run it yet and I probably will not because I imagine if this runs there is a potential for buffer overflow and undefined behaviour
I don't have any issue, but I am curious about why I was able to write this code without getting a compiler error. If the process name is not known at compile time, how can I allocate this buffer on the stack?
The szExeFile field is not dynamic length. It is a fixed-length array of MAX_PATH characters, holding a null-terminated string.
Note that:
sizeof() reports a size in bytes
szExeFile is an array of wchar_t characters, in your case
wchar_t is 2 bytes in size on Windows.
So, when you declare your char[] array as char file_str[sizeof(procEntry.szExeFile)];, it will have a static compile-time size of MAX_PATH*2 chars. Which should be large enough to easily handle most conversions from wchar_t[] to char[] in this case.
BTW, your use of sizeof(procEntry.szExeFile) in the 4th parameter of WideCharToMultiByte() is wrong. That parameter expects a character count, not a byte count. Use lstrlenW(procEntry.szExeFile) or wcslen(procEntry.szExeFile) instead. Or just -1 to let WideCharToMultiByte() count the wide characters for you.
That being said, an easier solution is to use Process32FirstA()/Process32NextA() instead. Or, change your function to take a Unicode wchar_t string as input. Either way, then you won't have to convert the procEntry.szExeFile at all, just use it as-is.
Also, you are leaking the HANDLE from CreateToolhelp32Snapshot(), you need to call CloseHandle() when you are done using it.
Try this:
DWORD GetProcIDByName(const char* procName) {
DWORD dwProcessID = 0;
PROCESSENTRY32A procEntry = {};
procEntry.dwSize = sizeof(procEntry);
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE) {
BOOL ok = Process32FirstA(hSnap, &procEntry);
while (ok) {
if (_stricmp(procEntry.szExeFile, procName) == 0) {
dwProcessID = procEntry.th32ProcessID;
break;
}
ok = Process32NextA(hSnap, &procEntry);
}
CloseHandle(hSnap);
}
return dwProcessID;
}
Or this:
DWORD GetProcIDByName(const wchar_t* procName) {
DWORD dwProcessID = 0;
PROCESSENTRY32W procEntry = {};
procEntry.dwSize = sizeof(procEntry);
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE) {
BOOL ok = Process32FirstW(hSnap, &procEntry);
while (ok) {
if (_wcsicmp(procEntry.szExeFile, procName) == 0) {
dwProcessID = procEntry.th32ProcessID;
break;
}
ok = Process32NextW(hSnap, &procEntry);
}
CloseHandle(hSnap);
}
return dwProcessID;
}

Creating a file with the same name as registry

I want to create a text file with the same name as a registry.
Say, I get the variable valueName, and I want it's value to be the name of a .txt file in C:\ How can I do that?
Almost final code:
void EnumerateValues(HKEY hKey, DWORD numValues)
{
for (DWORD dwIndex = 0; dwIndex < numValues; dwIndex++)
{BOOL bErrorFlag = FALSE;
char valueName[64];
DWORD valNameLen = sizeof(valueName);
DWORD dataType;
DWORD dataSize = 0;
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, &dataType, NULL, &dataSize);
if (retval == ERROR_SUCCESS)
{//pregatesc calea
char* val = new char[strlen(valueName)];
sprintf(val, "C:\\%s.txt", valueName);
printf("S-a creat fisierul: %s\n", val);
//creez/suprascriu fisierul
HANDLE hFile;
hFile=CreateFile(val,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{ printf("Eroare la creat fisierul %s!\n",val);
}
//sciru in fisier
char str[] = "Example text testing WriteFile";
DWORD bytesWritten=0;
DWORD dwBytesToWrite = (DWORD)strlen(str);
bErrorFlag=WriteFile(hFile, str, dwBytesToWrite, &bytesWritten, NULL);
if (FALSE == bErrorFlag)
{
printf("Eroare la scriere in fisier\n");
}
//inchid fisierul
CloseHandle(hFile);
}
//eroare regenumv
else printf("\nError RegEnumValue");
}
}
The fundamental problem is that you seem to want to convert a registry key, HKEY into a path. And there's no API to do that. You will need to keep track of the path and pass it to the function in the question, along with the HKEY.
You are passing uninitialized values to RegEnumValue, specifically dataSize. Since you don't care about the data, don't ask for it. Pass NULL for the data pointer, and zero for data size.
Your call to new is not allocating enough memory. You need space for the directory name, the file extension, and the null-terminator.
These problems are exacerbated by your complete neglect for error checking. That might sound harsh, but frankly you need some shock treatment. In order to be able to fail gracefully you need to check for errors. More pressing for you, in order to be able to debug code, you need to check for errors.
You've tagged the code C++ but write as if it were C. If you really are using C++ then you can use standard containers, std::string, avoid raw memory allocation and the result leaks. Yes, you code leaks as it stands.
first of all your program is more C like than C++, but if you want to solve this in C++ you can use stringstream in the following way:
std::stringstream stream;
stream << "C:\\";
stream << valueName;
stream << ".txt";
std::string filename(stream.str());
HANDLE hFile=CreateFile(filename.c_str() ,GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_NEW , FILE_ATTRIBUTE_NORMAL,NULL);
Also you need a include:
#include <sstream>

LPCTSTR to LPCSTR conversion

I am trying to get information of existing file using GetFileInformationByHandle(). My function that performs the required task receives LPCTSTR Filename as argument. Here is the code:
getfileinfo(LPCTSTR Filename)
{
OFSTRUCT oo;
BY_HANDLE_FILE_INFORMATION lpFileInformation;
HFILE hfile=OpenFile((LPCSTR)Filename,&oo,OF_READ);
int err=GetLastError();
GetFileInfomationByHandle((HANDLE)hfile,&lpFileInformation);
}
Above code works fine if I declare Filename as LPCSTR but as per requirement of my function I receive the filename in LPCTSTR so if I use typecasting then openfile() cannot find the specified file and returns -1.
Can anyone tell me how to get file information if filename is LPCTSTR? Or how to convert LPCTSTR to LPCSTR.
Why is this typecasting not working? I believe this should work.
Just casting the pointer doesn't change the actual data (ie filename) that is being pointed to into eight-bit characters.
Reading the docs at MSDN suggests using CreateFile instead, which handles LPCTSTR filenames.
The solution to your immediate problem is to replace OpenFile() with CreateFile(), just like the OpenFile() documentation says to do:
Note This function has limited capabilities and is not recommended. For new application development, use the CreateFile function.
For example:
getfileinfo(LPCTSTR Filename)
{
HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
int err = GetLastError();
// handle error as needed ...
}
else
{
BY_HANDLE_FILE_INFORMATION FileInfo = {0};
BOOL ok = GetFileInformationByHandle(hFile, &FileInfo);
int err = GetLastError();
CloseHandle(hFile);
if (!ok)
{
// handle error as needed ...
}
else
{
// use FileInfo as needed...
}
}
}
That being said, a better solution is to not open the file at all. Most of the information that GetFileInformationByHandle() returns can be obtained using FindFirstFile() instead:
getfileinfo(LPCTSTR Filename)
{
WIN32_FIND_DATA FileData = {0};
HANDLE hFile = FindFirstFile(Filename, &FileData);
if (hFile == INVALID_HANDLE_VALUE)
{
int err = GetLastError();
// handle error as needed ...
}
else
{
FindClose(hFile);
// use FileData as needed ...
}
}
Have a look at Project Properties/Configuration Properties/General/Character Set. This is normally set to UNICODE. It can be changed to MBCS.
If it is set to MBCS, then the code does not need to be modified.
If it is set to Unicode, which I suspect it is otherwise you won't be asking this question, use widechartomultibyte to convert it from LPCTSTR (const wchar_t*) to LPSTR (const char*).

Unicode across the network to xml

I'm trying to figure out the safest way to retrieve unicode data in a unified method from remote computers and make sure that data stays consistent and readable.
Computer A: Chinese user, mixed English Windows 7, some registry values contain Chinese letters like L"您好"
Computer B: US English, no unicode values returned from my functions
Computer C: Introduces an agent to Computer A and B.
The agent: assesses the health and security of the computer from the inside. One unicode aware section is simply getting registry values i.e:
int Utilities::GetRegistryStringValue(HKEY h_sub_key, WCHAR* value_name, wstring &result)
{
DWORD cbData = 8;
LPDWORD type = NULL;
//Get the size and type of the key
long err = RegQueryValueEx(h_sub_key, value_name, NULL, type, NULL, &cbData);
if (err != ERROR_SUCCESS)
{
if (err != ERROR_FILE_NOT_FOUND)
debug->DebugMessage(Error::GetErrorMessageW(err));
return err;
}
result.resize(cbData / sizeof(WCHAR));
LPWSTR res = new WCHAR[(cbData + sizeof(L'\0')) / sizeof(WCHAR)];
err = RegQueryValueEx(h_sub_key, value_name, NULL, NULL, (LPBYTE) &res[0], &cbData);
if(err != ERROR_SUCCESS && err != ERROR_FILE_NOT_FOUND)
{
debug->DebugMessage(Error::GetErrorMessageW(err));
return err;
}
res[cbData / sizeof(WCHAR)] = L'\0';
result = wstring(res);
return ERROR_SUCCESS;
}
Those values will be stored in an XML file.
Should that XML file be in UTF16 or UTF8?
Am I going to need to pass the remote system's code page back for translation?
What other issues might I have?
UTF8 is more standard (for networking) because it does not have endian issues. For UTF16 you'll need to specify an endian-ness for the transmission. If you're using a unicode format, you do not need a code page.
You can do the translation with standard windows calls like WideCharToMultiByte if they're on windows machines.
std::wstring buffer_with_utf16;
const char DefaultChar = 1; //not null, but not normal either
bool had_conversion_error = false;
int alength = WideCharToMultiByte(CP_UTF8, 0,
buffer_with_utf16.cstr(), buffer_with_utf16.size(),
NULL, 0,
&DefaultChar, &had_conversion_error);
if (alength == 0)
throw std::logic_error("Bad UTF8 conversion"); //use GetLastError
std::string buffer_with_utf8(alength+1);
int error = WideCharToMultiByte(CP_UTF8, 0,
buffer_with_utf16.cstr(), buffer_with_utf16.size(),
&buffer_with_utf8[0], buffer_with_utf8.size(),
&DefaultChar, &had_conversion_error);
if (error == 0)
throw std::logic_error("Bad UTF8 conversion"); //use GetLastError