WIN32_FIND_DATA Problems - cFileName - c++

i have a problem with my code ;)
hFind = FindFirstFileEx( szPath, FindExInfoMaxInfoLevel, &FindData, FindExSearchNameMatch, NULL , 0);
strncpy_s( pszFileName, 280, FindData.cFileName, strlen(FindData.cFileName));
everything seems fine but when i copy the executable to another computer (windows 2003) i get
But for pszFileName i get really strange output

Specifying FindExInfoMaxInfoLevel is incorrect. The MSDN Library says:
FindExInfoMaxInfoLevel
This value is used for validation. Supported values are less than this value.
In addition, from your usage of FindFirstFileEx, I cannot see why you do not use the simpler FindFirstFile function.

There's not enough code to diagnose the problem, especially without any evidence of error checking. However, there is something really smelly in what you posted. Your call to strncpy_s() says that pszFileName is a pointer to an array with 280 elements. Where did that number come from? Is it just a guess? It can never be more than 260 on Windows, why is it more? I suspect that when you make this a real number, like an argument passed to your function, instead of a guess that you'll fix the problem as well.

You shuold not use the output fields in FindData without first checking that hFind is valid. From the MSDN docs:
If the function fails or fails to
locate files from the search string in
the lpFileName parameter, the return
value is INVALID_HANDLE_VALUE and the
contents of lpFindFileData are
indeterminate.
Thus you should have (after fixing other problems in your API call described in the answers here):
hFind = FindFirstFileEx( szPath, /* replace FindExInfoMaxInfoLevel here */,
&FindData, FindExSearchNameMatch, NULL , 0);
if (hFind != INVALID_HANDLE_VALUE)
{
strncpy_s( pszFileName, 280, FindData.cFileName, strlen(FindData.cFileName));
}

Related

What does the BluetoothGATTSetCharacteristicValue ReliableWriteContext parameter actually do?

Using C++ VS2017 Win10...
I am testing some code to set a characteristic value on a BLE device. I had originally had the default function call
HRESULT hr = BluetoothGATTSetCharacteristicValue(
hBleService.get(),
_pGattCharacteristic,
gatt_value,
NULL,
BLUETOOTH_GATT_FLAG_NONE);
I had to switch the flag to BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE to get any sets to take place even though IsWritable and IsReadable were the only 2 properties set showing true but that is a different story and another topic.
Anyway, before I found the problem with the flag I had tried to use the ReliableWriteContext parameter so the code changed to
HANDLE hDevice = _bleDeviceContext.getBleDeviceHandle();
BTH_LE_GATT_RELIABLE_WRITE_CONTEXT ReliableWriteContext = NULL;
HRESULT hr1 = BluetoothGATTBeginReliableWrite(hDevice,
&ReliableWriteContext,
BLUETOOTH_GATT_FLAG_NONE);
HRESULT hr = BluetoothGATTSetCharacteristicValue(
hBleService.get(),
_pGattCharacteristic,
gatt_value,
ReliableWriteContext,
BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE);
if (NULL != ReliableWriteContext) {
BluetoothGATTEndReliableWrite(hDevice,
ReliableWriteContext,
BLUETOOTH_GATT_FLAG_NONE);
}
Once I fixed the flag issue my BluetoothGATTSetCharacteristicValue() function would work with either the NULL or the ReliableWriteContext parameters. No difference that I could see.
My question is,then, what does the ReliableWriteContext do exactly? MS docs only say:
The BluetoothGATTBeginReliableWrite function specifies that reliable
writes are about to begin.
Well that doesn't tell me anything. So should I keep the reliable writes because the word "Reliable" sure sounds like it is something that I want? Or do I not use it because it does not seem to be necessary>
Any insight would be appreciated.
Ed

How to tell if there's no default file extension association on OS post-Windows XP?

Going back to the days of Windows XP one could use the following code to tell if there's no file association existed for an extension:
TCHAR buffPath[MAX_PATH] = {0};
DWORD dwszBuffPath = MAX_PATH;
HRESULT hR = ::AssocQueryString(
ASSOCF_NOFIXUPS | ASSOCF_VERIFY,
ASSOCSTR_EXECUTABLE,
_T(".weirdassextension"),
NULL,
buffPath,
&dwszBuffPath);
if(hR != S_OK &&
hR != E_POINTER)
{
//Association does not exist
}
But since Windows 8, the AssocQueryString API returns S_OK and buffPath is set to something like C:\WINDOWS\system32\OpenWith.exe if it doesn't find anything.
Is there a better way now to determine that file extension has no Shell association?
PS. I do not want to just compare the file name to OpenWith.exe. What if there's a legit executable called just that... There must be a better way.
I think I got it. The trick was to use the correct flags. This seems to work from XP and up:
WCHAR wbuffPath[MAX_PATH] = {0};
DWORD dwszBuffPath = MAX_PATH;
HRESULT hR = ::AssocQueryStringW(ASSOCF_INIT_IGNOREUNKNOWN,
ASSOCSTR_EXECUTABLE,
L".weirdassextension",
NULL,
wbuffPath,
&dwszBuffPath);
if(hR == 0x80070483) // HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION)
{
//The association is missing
}
There's one other trick there, that took me some time to figure out -- DO NOT use AssocQueryStringA(). The shim for AssocQueryStringA() that converts its passed string parameters to Unicode has a bug in XP (and evidently in Vista as well) that will make that API fail on those OS. So, if you do your own ANSI-to-Unicode conversion and call AssocQueryStringW() the problem will go away (Evidently 14 years is not enough time for Microsoft to fix that bug?).

Remote thread is failing on call to LoadLibrary with error 87

I am tring to create a Remote thread that will load a DLL I wrote, and run a function from it.
The DLL is working fine (Checked) but from some reason, the Remote thread fails and the proccess in which it was created stop responding.
I used ollyDebug to try and see what is going wrong and I noticed two things...
My strings (dll name and function name) are passed to the remote thread correctly
The thread fails on LoadLibrary with lasterror code 87 "ERROR_INVALID_PARAMETER"
My best guess is that somehow, The remote thread can't find LoadLibrary (Is this because the linker is done with repspect to my proccess???, Just a guess...)
What am I doing wrong?
This is the code to the remote function:
static DWORD WINAPI SetRemoteHook (DATA *data)
{
HINSTANCE dll;
HHOOK WINAPI hook;
HOOK_PROC hookAdress;
dll = LoadLibrary(data->dll);
hookAdress = (HOOK_PROC) GetProcAddress(dll,data->func);
if (hookAdress != NULL)
{
(hookAdress)();
}
return 1;
}
Edit:
This is the part in which I allocate the memory to the remote proccess:
typedef struct
{
char* dll;
char* func;
} DATA;
char* dllName = "C:\\Windows\\System32\\cptnhook.dll";
char* funcName = "SetHook";
char* targetPrgm = "mspaint.exe";
Data lData;
lData.dll = (char*) VirtualAllocEx( explorer, 0, sizeof(char)*strlen(dllName), MEM_COMMIT, PAGE_READWRITE );
lData.func = (char*) VirtualAllocEx( explorer, 0, sizeof(char)*strlen(funcName), MEM_COMMIT, PAGE_READWRITE );
WriteProcessMemory( explorer, lData.func, funcName, sizeof(char)*strlen(funcName), &v );
WriteProcessMemory( explorer, lData.dll, dllName, sizeof(char)*strlen(dllName), &v );
rDataP = (DATA*) VirtualAllocEx( explorer, 0, sizeof(DATA), MEM_COMMIT, PAGE_READWRITE );
WriteProcessMemory( explorer, rDataP, &lData, sizeof(DATA), NULL );
Edit:
It looks like the problem is that the remote thread is calling a "garbage" address
instead of LoadLibrary base address. Is there a possibily Visual studio linked
the remote proccess LoadLibrary address wrong?
Edit:
when I try to run the same exact code as a local thread (I use a handle to the current procces in CreateRemoteThread) the entire thing works just fine. What can cause this?
Should I add the calling function code? It seems to be doing its job as
the code is being executed in the remote thread with the correct parameters...
The code is compiled under VS2010.
data is a simple struct with char* 's to the names. (As explicetly writing the strings in code would lead to pointers to my original proccess).
What am I doing wrong?
Failing with ERROR_INVALID_PARAMETER indicates that there is a problem with the parameters passed.
So one should look at data->dll which represents the only parameter in question.
It is initialised here:
lData.dll = VirtualAllocEx(explorer, 0, sizeof(char) * (strlen(dllName) + 1), MEM_COMMIT, PAGE_READWRITE);
So let's add a check whether the allocation of the memory which's reference should be store into lData.dll really succeded.
if (!lData.dll) {
// do some error logging/handling/whatsoever
}
Having done so, you might have detected that the call as implemented failed because (verbatim from MSDN for VirtualAllocEx()):
The function fails if you attempt to commit a page that has not been
reserved. The resulting error code is ERROR_INVALID_ADDRESS.
So you might like to modifiy the fourth parameter of the call in question as recommended (again verbatim from MSDN):
To reserve and commit pages in one step, call VirtualAllocEx with
MEM_COMMIT | MEM_RESERVE.
PS: Repeat this exercise for the call to allocate lData.func. ;-)
It's possible that LoadLibrary is actually aliasing LoadLibraryW (depending on project settings), which is the Unicode version. Whenever you use the Windows API with "char" strings instead of "TCHAR", you should explicitly use ANSI version names. This will prevent debugging hassles when the code is written, and also in the future for you or somebody else in case the project ever flips to Unicode.
So, in addition to fixing that horrible unterminated string problem, make sure to use:
LoadLibraryA(data->dll);

Using RegQueryInfoKey

I am new to programming, I would like to know the number of entries in a registry key. I think entries are called subkeys but I am not sure. I am trying to use RegQueryInfoKey() but I don't fully understand the MSDN webpage since I am beginner.
HKEY hKey = HKEY_LOCAL_MACHINE;
char regpath[] = "SOFTWARE\\MyApplication\\"
LPDWORD numberofEntries;
RegOpenKeyEx(hKey, regpath, 0, KEY_READ, &hKey);
RegQueryInfoKey(hKey, NULL, NULL, NULL, numberofEntries, NULL);
then I would like to printf the number of entries in this key. The code above doesn't work, the app crash.
How is it done?
Thank you
RegQueryInfoKey has 12 parameters. You are only passing 6. I can't understand how that even compiles—perhaps you are providing your own definition of RegQueryInfoKey rather than the one from the windows header files.
Perhaps you are getting confused by the fact that many of the parameters to RegQueryInfoKey are marked as optional. This only means that you can pass NULL into the function and not that you can omit the parameters altogether.

CreateFile Win32 API Call with OPEN_ALWAYS failed in an Odd Way

We had a line of code
if( !CreateFile( m_hFile, szFile, GENERIC_READ|GENERIC_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL ) )
{
DWORD dwErr = GetLastError();
CString czInfo;
czInfo.Format ("CMemoryMapFile::OpenAppend SetFilePointer call failed - GetLastError returned %d", dwErr);
LOG(czInfo);
return false;
}
This code worked great for many years. A few weeks ago, we had a customer with a problem. Turns out, the problem could be traced to this line of code, where the function would return a INVALID_HANDLE_VALUE handle and GetLastError() returned ERROR_FILE_NOT_FOUND(2).
Now, this is very confusing to us. OPEN_ALWAYS should direct the file to be created if it does not exist. So, why are we getting a ERROR_FILE_NOT_FOUND?
More confusion: For this customer, this only happened on one network share point (we were using a UNC path). Other UNC paths to other machines for this customer worked. Local paths worked. All our other customers (10000+ installs) have no problem at all.
The customer was using XP as the client OS, and the servers were running what appeared to be standard Windows Server 2003 (I think the Small Business Server version). We could not replicate their errors in our test lab using the same OS's. They could repeat the problem with several XP clients, but the problem was only on one server (other Server 2003 servers did not exhibit the problem).
We fixed the problem by nesting two CreateFile calls, the first with OPEN_EXISTING, and the second with CREATE_ALWAYS if OPEN_EXISTING failed. So, we have no immediate need for a fix.
My question: Does anyone have any idea why this API call would fail in this particular way? We are puzzled.
Addendum:
The CreateFile function above is a wrapper on the Windows API function. Here's the code:
bool CMemoryMapFile::CreateFile( HANDLE & hFile, LPCSTR szFile, DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes )
{
hFile = ::CreateFile (szFile, dwDesiredAccess, dwShareMode, NULL,
dwCreationDisposition, dwFlagsAndAttributes, NULL);
return (hFile != INVALID_HANDLE_VALUE)
}
First, you should always check for success of the CreateFile() API like this:
if (CreateFile(...) == INVALID_HANDLE_VALUE)
{
// handle the error
}
because CreateFile() doesn't return !=0 in case of success, but anything other than INVALID_HANDLE_VALUE (which is -1).
Then, the CreateFile() can fail in the situation you described if either the directory doesn't exist where you want to create/open the file in, or it can fail if the user has the rights to open and write files in that directory, but no rights to create new files.
Maybe the directory you wanted to create the file in did not exist?
Are you sure you fixed it by using 2 CreateFile calls? Or did you just not reproduce it?
We have also seen this problem when a file is accessed by a UNC share. None of the ideas and suggestions applied in our case - the directory always exists, the parameters to CreateFile are correct, we are checking the return correctly.
We believe this to be a shares issue. We solved the problem with a simple retry loop:
If a CreateFile with OPEN_ALWAYS fails with ERROR_FILE_NOT_FOUND, we simply sleep for a few ms and try again. It always works second time (if it failed first time).
If CreateFile fails, it will return INVALID_HANDLE_VALUE which is non-zero (I think it's negative 1). So CreateFile might be succeeding and returning zero as the handle.
It's only safe to check GetLastError() after a function fails but it looks like you might be checking the last error when CreateFile has succeeded (returned zero).
According to this article, some functions set the "last error" if they succeed:
My guesses would be something server related like the server not implementing support correctly for that filesystem operation. Maybe a linux server compared to a windows server?
Your arguments to create file are incorrect, so I assume that this is some sort of CreateFile helper function.
A call to CreateFile should look like:
m_hFile = CreateFile( szFile, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 );
if(m_hFile == INVALID_HANDLE_VALUE)