I write filtering system and use Winsock2 LSP.
In WSPConnect I need to compare executable filename of process with harcoded Unicode String.
I do:
LPWSTR moduleName = {0};
GetModuleFileNameEx (GetCurrentProcess(),0,moduleName,_MAX_FNAME );
LPWSTR mn = L"redirect.exe";
if (lstrcmp (moduleName, mn) == 0){ ...some code there...}
What I am doing wrong?
You should compare "case-insensitive": lstrcmpi
You need to pass a correct char array...
Also you should always check the result values of function calls!
Also you should not use the TCHAR version of GetModuleFileNameEx if you explicit use wchar_t => GetModuleFileNameExW!
Also you should use the method GetModuleFileNameW if you want to get the name of the current process! This is more reliable!
ALso you should use MAX_PATH instead of _MAX_FNAME, because the method might also return the full path!
Also be sure that your string is correctly NUL-terminated!
Also you must be aware that the returned path might contain the full path, so comparing with the process name does never match...
Also you must be aware that the path might contion the short file name! (not in your case, because the name is not longer than 8 characters; but if you compare it with "MyExecutable.exe" you also must compare with the short file name; see GetShortPathName
The code part should now look like:
WCHAR moduleName[MAX_PATH+1];
if (GetModuleFileNameW (NULL, moduleName, MAX_PATH) != 0)
{
moduleName[MAX_PATH] = 0;
LPWSTR mn = L"redirect.exe";
int len = lstrlen(moduleName);
int lenmn = lstrlen(mn);
if (len > lenmn)
{
if (lstrcmpi (&moduleName[len-lenmn], mn) == 0){ ...some code there...}
}
}
You need to declare storage space, just a pointer is not enough
LPWSTR moduleName = {0};
GetModuleFileNameEx (GetCurrentProcess(),0,moduleName,_MAX_FNAME );
should be
TCHAR moduleName[_MAX_PATH];
GetModuleFileNameEx(GetCurrentProcess(), 0, moduleName, _countof(moduleName));
and use case-insensitive lstrcmpi().
Related
I'm developing an application and would like to know if there's a way to get it's executable path automatically and run alongside Windows startup by adding it to the registry.
This is my function so far:
void Open(){
HKEY hKey;
WCHAR path[MAX_PATH]; //to store the directory
DWORD size = GetModuleFileNameW(NULL, path, MAX_PATH);
const char* StartName = "MyApplication";
LONG lnRes = RegOpenKeyEx( HKEY_CURRENT_USER,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
0 , KEY_WRITE,
&hKey);
if( ERROR_SUCCESS == lnRes )
{
lnRes = RegSetValueEx( hKey,
StartName,
0,
REG_SZ,
(LPBYTE)path,
size );
}
RegCloseKey(hKey);
}
I'm using GetModuleFileName to get the path, but it returns me the path with a single backslash and in the registry it only recognizes the "D" drive. For example: D:\Usuario\Desktop\log\mariobros.exe
https://prnt.sc/vondsi (Here's a print from my registry)
I suspect that the problem is that for the code to be recognized as a single backslash it needs to have a double backslash. This is how I think it should've need to be: D:\\Usuario\\Desktop\\log\\mariobros.exe
Does anyone know what could I do here?
Thanks in advance.
You are clearly compiling with UNICODE undefined in your project, which means RegOpenKeyEx() and RegSetValueEx() are actually calling the ANSI functions RegOpenKeyExA() and RegSetValueExA(), respectively (as evident by you being able to pass char* strings to them without compiler errors).
But, you are retrieving the file path as a Unicode UTF-16 string and passing it as-is to RegSetValueExA(), so you end up with embedded nul characters written to the Registry when RegSetValueExA() misinterprets your UTF-16 string as an ANSI string and re-encodes each of its bytes individually to Unicode characters. Unicode characters in the ASCII range have nul bytes in them.
Since you are using a Unicode function to retrieve the file path, and because the Registry internally stores strings in Unicode form only, you should use the Registry's Unicode functions to match that same encoding.
Also, note that the return value of GetModuleFileName(A|W) does not include the null terminator in the output string's length, but RegSetValueEx(A|W) expects the cbSize parameter to include enough bytes for a null terminator for REG_(EXPAND_|MULTI_)SZ value types.
Try this:
void Open()
{
WCHAR path[MAX_PATH]; //to store the directory
DWORD size = GetModuleFileNameW(NULL, path, MAX_PATH);
if ((size > 0) && (size < MAX_PATH))
{
HKEY hKey;
LONG lnRes = RegOpenKeyExW(HKEY_CURRENT_USER,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
0, KEY_SET_VALUE,
&hKey);
if( ERROR_SUCCESS == lnRes )
{
lnRes = RegSetValueExW(hKey,
L"MyApplication",
0,
REG_SZ,
(LPBYTE)path,
(size + 1) * sizeof(WCHAR) );
RegCloseKey(hKey);
}
}
}
This looks like you are passing a wide string, while promising that it is a narrow string (evident by your C-style cast).
The second byte in a wide string is 0, and this terminates your narrow string.
Suggestion: use wide strings only while dealing with Win API.
I created a simple function:
std::wstring GetRegKey(const std::string& location, const std::string& name){
const int valueLength = 10240;
auto platformFlag = KEY_WOW64_64KEY;
HKEY key;
TCHAR value[valueLength];
DWORD bufLen = valueLength*sizeof(TCHAR);
long ret;
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, location.c_str(), 0, KEY_READ | platformFlag, &key);
if( ret != ERROR_SUCCESS ){
return std::wstring();
}
ret = RegQueryValueExA(key, name.c_str(), NULL, NULL, (LPBYTE) value, &bufLen);
RegCloseKey(key);
if ( (ret != ERROR_SUCCESS) || (bufLen > valueLength*sizeof(TCHAR)) ){
return std::wstring();
}
std::wstring stringValue(value, (size_t)bufLen - 1);
size_t i = stringValue.length();
while( i > 0 && stringValue[i-1] == '\0' ){
--i;
}
return stringValue;
}
And I call it like auto result = GetRegKey("SOFTWARE\\Microsoft\\Cryptography", "MachineGuid");
yet string looks like
㤴ㄷ㤵戰㌭㉣ⴱ㔴㍥㤭慣ⴹ㍥摢㘵〴㉡ㄵ\0009ca9-e3bd5640a251
not like RegEdit
4971590b-3c21-45e3-9ca9-e3bd5640a251
So I wonder what shall be done to get a correct representation of MachineGuid in C++?
RegQueryValueExA is an ANSI wrapper around the Unicode version since Windows NT. When building on a Unicode version of Windows, it not only converts the the lpValueName to a LPCWSTR, but it will also convert the lpData retrieved from the registry to an LPWSTR before returning.
MSDN has the following to say:
If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, and
the ANSI version of this function is used (either by explicitly
calling RegQueryValueExA or by not defining UNICODE before including
the Windows.h file), this function converts the stored Unicode string
to an ANSI string before copying it to the buffer pointed to by
lpData.
Your problem is that you are populating the lpData, which holds TCHARs (WCHAR on Unicode versions of Windows) with an ANSI string.
The garbled string that you see is a result of 2 ANSI chars being used to populate a single wchar_t. That explains the Asian characters. The portion that looks like the end of the GUID is because the print function blew past the terminating null since it was only one byte and began printing what is probably a portion of the buffer that was used by RegQueryValueExA before converting to ANSI.
To solve the problem, either stick entirely to Unicode, or to ANSI (if you are brave enough to continue using ANSI in the year 2014), or be very careful about your conversions. I would change GetRegKey to accept wstrings and use RegQueryValueExW instead, but that is a matter of preference and what sort of code you plan on using this in.
(Also, I would recommend you have someone review this code since there are a number of oddities in the error checking, and a hard coded buffer size.)
I want to get the install date of product:
DWORD max = 255;
WCHAR buffer[255];
std::wstring guidWString = S::WstrToStr(subKeys[i]); //from array of std::string
LPCWSTR guid = guidWString.c_str();
int err = MsiGetProductInfo(guid, INSTALLPROPERTY_INSTALLDATE, buffer, &max);
if(err == ERROR_SUCCESS){ //never success :(
info.date = S::WstrToStr(std::wstring(buffer));
}
But I always get the error code 87 (*ERROR_INVALID_PARAMETER*).
I don't see anything "invalid" here, according to the documentation:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa370130%28v=vs.85%29.aspx
I have checked that:
All variables are of good types, buffer size (DWORD max) is not null, equal to the size of my buffer.
I use a function to convert std::string (I have my GUID in std::string) to std::wstring (under debugger, all looks good, conversion works in many other places in code that use WinAPI and std::wstring).
I have tried with different GUID, all of them exists and works for asking register "manually". MsiGetProductInfo() returns that error ALWAYS.
I have also tried to just write GUID in code (L"{GUID-GO-EXACTLY-HERE}"), with the same result.
I just don't know where the problem is?
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to compare strings
I want to Compare to registry string values and if they were the same an messagebox appears
Currently I'm using this functions , It returns the value correctly but whenever I want to compare them, The compare result is always wrong
char* GetRegistry(char* StringName)
{
DWORD dwType = REG_SZ;
HKEY hKey = 0;
char value[1024];
DWORD value_length = 1024;
const char* subkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\MCI\\Player";
RegOpenKey(HKEY_LOCAL_MACHINE,subkey,&hKey);
RegQueryValueEx(hKey, StringName, NULL, &dwType, (LPBYTE)&value, &value_length);
return value;
}
I use this to compare them
if (GetRegistry("First") == GetRegistry("Second"))
{
MessageBox(NULL,":|",":|",1);
}
But the MessageBox appears how ever The values are different
Any help is appreciated.
By using std::string, comparison would behave as you expected. Also that would fix another bug that the function returns a pointer to a local buffer.
std::string GetRegistry(const char* StringName)
{
....
return std::string(value);
}
GetRegistry() returns a char*, so you are actually comparing pointers with operator==.
You should use strcmp() to do raw C-like char* string comparisons, or better use a robust C++ string class, like CString or std::[w]string.
Here is a possible rewrite of your function using ATL's CString:
#include <atlbase.h>
#include <atlstr.h>
CString GetRegistry(LPCTSTR pszValueName)
{
// Try open registry key
HKEY hKey = NULL;
LPCTSTR pszSubkey = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\MCI Extensions");
if ( RegOpenKey(HKEY_LOCAL_MACHINE, pszSubkey, &hKey) != ERROR_SUCCESS )
{
// Error:
// throw an exception or something...
//
// (In production code a custom C++ exception
// derived from std::runtime_error could be used)
AtlThrowLastWin32();
}
// Buffer to store string read from registry
TCHAR szValue[1024];
DWORD cbValueLength = sizeof(szValue);
// Query string value
if ( RegQueryValueEx(
hKey,
pszValueName,
NULL,
NULL,
reinterpret_cast<LPBYTE>(&szValue),
&cbValueLength)
!= ERROR_SUCCESS )
{
// Error
// throw an exception or something...
AtlThrowLastWin32();
}
// Create a CString from the value buffer
return CString(szValue);
}
And then you can call it like this:
if ( GetRegistry(_T("First")) == GetRegistry(_T("Second")) )
...
Note that this code will compile in both ANSI/MBCS and Unicode builds (it's based on Win32 TCHAR model).
You have a couple of problems with this source code.
First of all you have a function with a local variable, a variable on the stack, which is returning the address of that variable yet when the function returns, the variable disappears and the address is no longer valid.
The next problem is that you are not comparing the character strings. You are instead comparing the address returned by the function and if you get lucky, the address could be the same. Since you are calling the function twice in succession, you are getting lucky so the address is the same.
I suggest you do the following: (1) create two local character strings in your function which is calling the function GetRegistry() and (2) modify the GetRegistry() function so that it uses those buffers rather than its own. So the code would look something like:
char registryEntryOne[1024];
char registryEntryTwo[1024];
DWORD dwRegistryEntryOneLen;
DWORD dwRegistryEntryTwoLen;
registryEntryOne[0] = 0; // init the registry entry to zero length string
registryEntryTwo[0] = 0;
dwRegistryEntryOneLen = sizeof(registryEntryOne);
GetRegistry ("First", registryEntryOne, &dwRegistryEntryOneLen);
dwRegistryEntryTwoLen = sizeof(registryEntryTwo);
GetRegistry ("Second", registryEntryTwo, &dwRegistryEntryTwoLen);
// two strings are equal if:
// the lengths are the same
// at least one of the lengths is non-zero
// the bytes are the same in the same order
if (dwRegistryEntryOneLen && dwRegistryEntryOneLen == dwRegistryEntryTwoLen && memcmp (registryEntryOne, registryEntryTwo, dwRegistryEntryOneLen) == 0) {
// strings are equal
} else {
// strings are not equal
}
The GetRegistry() function would look something like:
char* GetRegistry(char* StringName, char *valueBuffer, DWORD *value_length)
{
DWORD dwType = REG_SZ;
HKEY hKey = 0;
const char* subkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\MCI\\Player";
RegOpenKey(HKEY_LOCAL_MACHINE,subkey,&hKey);
RegQueryValueEx(hKey, StringName, NULL, &dwType, (LPBYTE)valueBuffer, value_length);
return valueBuffer;
}
I am implementing a custom action for a WindowsCE CAB file, and I need to concat a LPCTSTR to get a proper path to an exe.
My custom action receives a LPCTSTR as an argument.
So (pseudocode):
extern "C" codeINSTALL_EXIT MYCUSTOMACTION_API Install_Exit(
HWND hwndParent,
LPCTSTR pszInstallDir,
WORD cFailedDirs,
WORD cFailedFiles,
WORD cFailedRegKeys,
WORD cFailedRegVals,
WORD cFailedShortcuts
)
{
if (FALSE == LaunchApp(pszInstallDir + "\\MyApp.exe"))
::MessageBox(hwndParent, L"Could not launch app!", L"Setup", MB_ICONINFORMATION );
return codeINSTALL_EXIT_DONE;
}
This is using the imaginary "+" operator, that I would use in my standard language, C#.
I have relatively little experience in C++. What is the proper way to append a LPCTSTR for my purposes? The LaunchApp method uses this type as an argument.
Also if I want to display the resulting path (for debugging purposes) in a MessageBox, is there a quick way to convert to a LPCWSTR?
For concatenation use StringCchCat
TCHAR pszDest[260] = _T("");
StringCchCat(pszDest, 260, pszInstallDir);
StringCchCat(pszDest, 260, _T("\\MyApp.exe"));
LaunchApp(pszDest);
You need to allocate a new buffer to assemble the combined string in and then copy both parts into it. You can either pick a fixed, large buffer size
TCHAR fullPath[MAX_PATH + 11]; // 11 = length of "\MyApp.exe" + nul in characters
_sntprintf_s(fullPath, MAX_PATH + 11, _T("%s\\MyApp.exe"), pszInstallDir);
or allocate it dynamically to fit:
size_t installDirLen = tcslen(pszInstallDir);
size_t bufferLen = installDirLen + 11; // again 11 = len of your string
LPWSTR fullPath = new TCHAR[bufferLen];
// if you're paranoid, check allocation succeeded: fullPath != null
tcsncpy_s(fullPath, bufferLen, pszInstallDir);
tcsncat_s(fullPath, bufferLen, _T"\\MyApp.exe");
// use it
delete fullPath;
If you're in Unicode mode then LPCTSTR == LPCWSTR (in MBCS mode == LPCSTR instead). Either way the MessageBox macro should work for you - it'll choose between MessageBoxA or MessageBoxW as appropriate.
As ctacke points out below, this in on Windows CE and I can't assume you're going to have the _s functions. I think in the second case it's OK to use the non _s variants since we know the buffer is big enough, but in the first _sntprintf does not guarantee a trailing null on the output string (as the _s version does) and so we need to initialise the buffer ourselves first:
size_t bufferLen = MAX_PATH + 11;
TCHAR fullPath[bufferLen];
// zero the buffer out first
memset(fullPath, 0, sizeof(TCHAR) * bufferLen);
// only write up to bufferLen - 1, i.e. ensure the last character is left zero
_sntprintf(fullPath, bufferLen - 1, _T("%s\\MyApp.exe"), pszInstallDir);
(It might also be possible to do this by omitting the memset and using _sntprintf's return value to find the end of the combined generated string and nul the next character.)
AFAICR Windows CE is Unicode only and so LPCTSTR == LPCWSTR always.
You can use string to be concatenated and then cast the result to LPCTSTR using ATL helpers like CA2T:
std::string filePath = "\\\\user\\Home\\";
std::string fileName = "file.ex";
std::string fullPath = filePath + fileName;
CA2T t(fullPath.c_str());
LPCTSTR lpctsrFullPath = t;