i have the following test code:
#define CMDLINE ".\\dummyFolder\\dummyProc.exe op1 op2 op3"
int main(int argc, char **argv) {
STARTUPINFO info;
info.cb = sizeof(STARTUPINFO);
info.lpReserved = NULL;
info.cbReserved2 = 0;
info.lpReserved2 = NULL;
PROCESS_INFORMATION processInfo;
SECURITY_ATTRIBUTES procAttr;
procAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
procAttr.lpSecurityDescriptor = NULL;
procAttr.bInheritHandle = false;
SECURITY_ATTRIBUTES threadAttr;
procAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
procAttr.lpSecurityDescriptor = NULL;
procAttr.bInheritHandle = false;
bool handlersInheritable = true;
char cmdLine2[sizeof(CMDLINE)];
strcpy(cmdLine2, CMDLINE);
char AppName[sizeof(".\\dummyFolder\\dummyProc.exe")];
strcpy(AppName, ".\\dummyFolder\\dummyProc.exe");
if (CreateProcess(AppName, cmdLine2, &procAttr, &threadAttr,
handlersInheritable, 0, NULL, NULL, &info, &processInfo)) {
//::WaitForMultipleObjects(procQty, handlers, waitForAll, waitInterval);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
CloseHandle(info.hStdError);
CloseHandle(info.hStdInput);
CloseHandle(info.hStdOutput);
} else {
std::cout << "Returned: " << GetLastError() << std::endl;
}
std::cout << "Exiting main process" << std::endl;
return 0;
}
This is just a test code for creating processes in windows. The problem is that when i launch "dummyProc.exe" i get a 0xc0000142 error.
The process dummyProc.exe runs fine from the command line, but not from within the code.
Here's the dummyProc code if it helps:
int main(int argc, char **argv) {
std::cout << "Working!!!!" << std::endl << "Receivedi: " << std::endl;
for (int i = 0; i < argc; ++i)
std::cout << argv[i] << std::endl;
return 0;
}
So, any ideas?
The most obvious thing that char cmdLine2[sizeof(CMDLINE)]; declares a string of length equal to your machine's pointer size. You need to use strlen(CMDLINE)+1 instead. Likewise for appName.
Note that the first parameter to CreateProcess does not need to be writeable. Just pass the string literal directly to it. No need for appName variable.
As for lpCommandLine which does need to be writeable it's easiest to do it like this:
char cmdline[] = "op1 op2 op3";
That gives you a writeable buffer. Note that you do not need to repeat the executable file name.
Another problem is that you have not initialized all the parameters to CreateProcess. For example the STARTUPINFO struct has 19 fields and you initialize only 3. You should initialize all your structs to 0 and then fill out any fields you need to be non-zero. Like this:
STARTUPINFO info = { 0 };
Do this for all the structs you pass.
You can, and should, pass NULL for the lpProcessAttributes and lpThreadAttributes parameters.
This answer is to relate another cause for 0xc0000142 - placed here (even though another answer was accepted for this question) because there is very little useful information on the intertubes about this error - and a shocking lack of any useful information on the subject from Microsoft - and so someone's internet search may get them here. (Well, mine did.)
So: You can get The application was unable to start correctly (0xc0000142) on starting a process written in C++ where you access though a null pointer in a constructor of a static object. (In my case it was in an initializer of a constructor of a static object.)
Your hint to this will be an event in the application log (event id 1000 source "Application Error") which has lines similar to the following:
Faulting module name: unknown, version: 0.0.0.0, time stamp: 0x00000000
Exception code: 0xc0000005
Fault offset: 0x0000000000000000
0xc0000005 is access violation, of course, and the offset of 0 (actually anything less than 0x10000 is a reference through a null pointer.
Anyway, the surprising thing (to me) is that evaluating statics happens before the debugger can attach (!!) so launching it with ImageFileExecutionOptions set or even directly within Visual Studio doesn't let you debug this thing!!
(And then of course you won't find 0xc0000142 in any Microsoft documentation whatsoever. Well done, NT team!)
Related
Greetings!
I have come today to ask a question about invoking a very specific IOCTL on Windows. I have some amount of driver development experience, but my experience with file system drivers is relatively limited.
The Goal
I am developing a tool that manages volumes/physical disks/partitions. For the purpose I am attempting to learn to invoke many of the Windows file system data set management (DSM) IOCTLs. Currently I am learning how to use IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES which is documented at https://learn.microsoft.com/en-us/windows/win32/api/winioctl/ni-winioctl-ioctl_storage_manage_data_set_attributes?redirectedfrom=MSDN.
However, I have had to intuit how to set up the call to the IOCTL myself. The MSDN article does not give fully detailed instructions on how to set up the input buffer, and specifically what values of the inputs are strictly required. I have uncertainty about how to call the IOCTL that has lead to a bug I cannot debug easily.
In order to reduce my uncertainty about proper invocation of the IOCTL I worked off a tool MS released a few years ago and copied some of their code: https://github.com/microsoft/StorScore/blob/7cbe261a7cad74f3a4f758c2b8a35ca552ba8dde/src/StorageTool/src/_backup.c
My Code
At first I tried:
#include <windows.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include <winnt.h>
#include <winternl.h>
#include <ntddstor.h>
int main(int argc, const char* argv[]) {
//My understanding is for this IOCTL I need to open the drive, not the object PartmgrControl device that the driver registers.
HANDLE hDevice = CreateFile(L"\\\\.\\Physicaldrive0",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
NULL);
int cf_error = 0;
cf_error = GetLastError();
if (hDevice == INVALID_HANDLE_VALUE) {
std::cout << "COULDN'T GET HANDLE";
return -1;
}
std::cout << "Device Handle error: " << cf_error << "\n";
std::cout << "Handle value: " << hDevice << "\n";
_DEVICE_MANAGE_DATA_SET_ATTRIBUTES attributes_struct;
LPDWORD BytesReturned = 0;
int inputbufferlength = 0;
inputbufferlength = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + sizeof(_DEVICE_DSM_OFFLOAD_WRITE_PARAMETERS) + sizeof(DEVICE_DATA_SET_RANGE);
PUCHAR inputbuffer = (PUCHAR)malloc(inputbufferlength);
PUCHAR outputbuffer = (PUCHAR)malloc(inputbufferlength);
//RtlZeroMemory(inputbuffer, inputBufferLength);
PDEVICE_MANAGE_DATA_SET_ATTRIBUTES dsmAttributes = (PDEVICE_MANAGE_DATA_SET_ATTRIBUTES)inputbuffer;
PDEVICE_DSM_OFFLOAD_WRITE_PARAMETERS offload_write_parameters = NULL;
dsmAttributes->Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES);
dsmAttributes->Action = DeviceDsmAction_OffloadWrite;
dsmAttributes->Flags = 0;
dsmAttributes->ParameterBlockOffset = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES);
dsmAttributes->ParameterBlockLength = sizeof(DEVICE_DSM_OFFLOAD_WRITE_PARAMETERS);
offload_write_parameters = (PDEVICE_DSM_OFFLOAD_WRITE_PARAMETERS)((PUCHAR)dsmAttributes + dsmAttributes->ParameterBlockOffset);
offload_write_parameters->Flags = 0;
offload_write_parameters->TokenOffset = 0;
dsmAttributes->DataSetRangesOffset = dsmAttributes->ParameterBlockOffset + dsmAttributes->ParameterBlockLength;
dsmAttributes->DataSetRangesLength = sizeof(DEVICE_DATA_SET_RANGE);
PDEVICE_DATA_SET_RANGE lbaRange = NULL;
lbaRange = (PDEVICE_DATA_SET_RANGE)((PUCHAR)dsmAttributes + dsmAttributes->DataSetRangesOffset);
lbaRange->StartingOffset = 0; // not sure about this one for now
lbaRange->LengthInBytes = 256 * 1024 * 1024;
int status = DeviceIoControl(
hDevice, // handle to device
IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES, // dwIoControlCode
inputbuffer, // input buffer
inputbufferlength, // size of the input buffer
outputbuffer, // output buffer
inputbufferlength, // size of the input buffer - modified to be too small!
BytesReturned, // number of bytes returned
0 //(LPOVERLAPPED) &overlapped_struct // OVERLAPPED structure
);
DWORD error_num = GetLastError();
CloseHandle(hDevice);
std::cout << "STATUS IS: " << status << "\n";
std::cout << "ERROR IS: " << error_num;
return 0;
}
But this returned error 87 ERROR_INVALID_PARAMETER when attempting to call it.
My instinct was to debug the IOCTL by placing a breakpoint on partmgr!PartitionIoctlDsm - I was under the impression the targeted IOCTL was throwing the error. However my breakpoint was not being hit. So, then I moved on to placing a breakpoint on the IOCTL dispatch table itself
bp partmgr!PartitionDeviceControl
But that BP is never hit either. So, something else before my driver is throwing the error.
The Question(s)
How should I go about debugging this? How do I figure which driver is throwing the error?
What is the correct way to invoke this driver without throwing errors?
Why Am I getting this error?
Additional information
To be absolutely clear, I am dead set on using this particular IOCTL function. This is a learning exercise, and I am not interested in using alternative/easier to use functionality to implement the same effect. My curiosity lies in figuring out why the IO manager wont let me call the function.
I am running this code as admin.
I am running this code in a virtual machine.
I am debugging with windbg preview over a COM port.
Through some sleuthing I believe this is a filter driver, and that other drivers can intercept and handle this request.
Let me know if there is any other information I can provide.
I am running a simple app and trying to read a specific offset within it's memory using Window's PSAPI.
when I run my debugger, I get the real value of the memory address, and the relative one to my ".exe" entry point.
yet, when I run the following code, the base module I get as an entry point together with my offset yields a different address(it's wrong, and off by a few (hexa)demical points).
what might be the problem?
ReadMemory is a template for ReadProcessMemory
HWND WINDOW_HANDLE;
HANDLE PROC_HANDLE;
DWORD PROC_ID;
DWORD address;
SIZE_T bytesRead;
int InitReadMemory(const char* windowClass,const char* caption, DWORD addressOffset)
{
DWORD cbNeeded;
DWORD dwdResult;
HMODULE mainModule;
BOOL enumResult;
//Get the window handle
WINDOW_HANDLE = FindWindow(windowClass, NULL);
if(WINDOW_HANDLE == NULL)
{
//Window was not foud
return 10;
}
//Get the process ID
dwdResult = GetWindowThreadProcessId(WINDOW_HANDLE, &PROC_ID);
if(dwdResult==0)
{
//Getting Process ID failed
return 20;
}
//Open the process
PROC_HANDLE = OpenProcess(PROCESS_ALL_ACCESS, false, PROC_ID);
if(PROC_HANDLE==NULL)
{
//Process failed to open
return 30;
}
/*
*Get the Main Module-
*first entry in the returned HMODULE array from
*EnumProcessModules
*/
enumResult = EnumProcessModules(PROC_HANDLE, &mainModule, sizeof(HMODULE), &cbNeeded);
if(enumResult != 0)
{
//Failed enumerating process modules
return 40;
}
//offset the requested memory address from the application's base address
address = (DWORD)((UINT_PTR)mainModule + addressOffset);
#ifdef DEBUG
using namespace std;
char filenameBuffer[64]="";
string number;
stringstream stristream;
stristream << address;
stristream >> number;
cout << number << "\r\n" << endl;
GetModuleFileNameEx(PROC_HANDLE, mainModule , filenameBuffer, 256);
cout << (byte)ReadMemory<byte>() << "\r\n" << number << "\r\n" << filenameBuffer << endl;
system("PAUSE");
#endif
return 1;}
thank you in advance :)
P.S. I'm mostly just looking for pointers ...
bah dum tsss
Update:
apparently, checking for GetLastError value, EnumProcessModules prompts a 299 error code after it is done. and debugging shows that mainModule holds nothing... yet EnumProcessModules returns 0 as in "no errors".
yesterday, I managed to get it AND get GetModuleFileName to work propery(same code, only added GetLastError).
Apparently, my problem was that I was running the tests with the snippet
enumResult = EnumProcessModules(PROC_HANDLE, &mainModule, sizeof(HMODULE), &cbNeeded)
if(enumResult != 0)
{
//Failed enumerating process modules
return 40;
}
and a successful run of EnumProcessModules yields a nonzero result! (thus causing me some confusion and faulted my whole debugging process)
after I figured this detail out, I ran some old tests again and found out that my target process is 64 bit, while I was running a 32 bit application.
changed to 64bit and now it works like a charm
Driver:
PIO_STACK_LOCATION pIoStackLocation = IoGetCurrentIrpStackLocation(pIrp);
PVOID pBuf = pIrp->AssociatedIrp.SystemBuffer;
switch (pIoStackLocation->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_TEST:
DbgPrint("IOCTL IOCTL_TEST.");
DbgPrint("int received : %i", pBuf);
break;
}
User-space App:
int test = 123;
int outputBuffer;
DeviceIoControl(hDevice, IOCTL_SET_PROCESS, &test, sizeof(test), &outputBuffer, sizeof(outputBuffer), &dwBytesRead, NULL);
std::cout << "Output reads as : " << outputBuffer << std::endl;
The user-space application prints out the correct value received back through the output buffer, but in debug view, the value printed out seems to be garbage (ie: "int received : 169642096")
What am I doing wrong?
As said by the previous user, you are printing the address of the variable, not the content.
I strongly suggest you to take a look to the following Driver Development tutorials:
http://www.opferman.com/Tutorials/
I need the base Address of the exe "tibia.exe". This is what I got so far but it doesn't work. It always returns 0.
What's wrong?
DWORD MainWindow::getBaseAddress(DWORD dwProcessIdentifier)
{
TCHAR lpszModuleName[] = {'t','i','b','i','a','.','e','x','e','\0'}; //tibia.exe
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
dwProcessIdentifier);
DWORD dwModuleBaseAddress = 0;
if(hSnapshot != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 ModuleEntry32;
ModuleEntry32.dwSize = sizeof(MODULEENTRY32);
if(Module32First(hSnapshot, &ModuleEntry32))
{
do
{
if( wcscmp(ModuleEntry32.szModule, lpszModuleName) == 0)
{
dwModuleBaseAddress = (DWORD)ModuleEntry32.modBaseAddr;
break;
}
}
while(Module32Next(hSnapshot, &ModuleEntry32));
}
CloseHandle(hSnapshot);
}
return dwModuleBaseAddress;
}
//Call it here
tibiaWindow = FindWindow( L"TibiaClient", NULL);
DWORD PID;
GetWindowThreadProcessId( tibiaWindow, &PID );
DWORD baseAddress = getBaseAddress( PID );
if( baseAddress == 0 )
return false ;
Perhaps it's just because I was using them before ToolHelp32 was available (at least on the NT-based operating systems), but I tend to use the PSAPI functions for this kind of task. Using them, the code would look like this:
#include <windows.h>
#include <string>
#include <psapi.h>
#include <iostream>
int main(int argc, char **argv) {
HANDLE process = GetCurrentProcess();
if (argc != 1)
process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, atoi(argv[1]));
HMODULE handles[2048];
DWORD needed;
EnumProcessModules(process, handles, sizeof(handles), &needed);
for (int i = 0; i < needed / sizeof(handles[0]); i++) {
MODULEINFO info;
char name[1024];
GetModuleBaseName(process, handles[i], name, sizeof(name));
if (std::string(name).find(".exe") != std::string::npos) {
GetModuleInformation(process, handles[i], &info, sizeof(info));
std::cout << name << ": " << info.lpBaseOfDll << "\n";
break;
}
}
}
As it stands right now, this will let you enter a process ID on the command line, and show the load address of the first module it finds in that process with a name that includes ".exe". If you don't specify a process ID, it'll search through its own process (demos how the functions work, but otherwise pretty much useless).
Using either ToolHelp32 or PSAPI, you end up with a similar limitation: you need to compile this into a 64-bit executable for it to be able to "see" other 64-bit processes (i.e., when compiled as 32-bit code, they see only other 32-bit processes).
There are also some processes (e.g., CSRSS.exe) that neither will be able to open/enumerate successfully. As far as I know, the same processes will succeed/fail with PSAPI vs. ToolHelp32.
PSAPI does have one bit of clumsiness compared to ToolHelp32: dealing (well) with processes that have lots of modules is clumsy (at best). You call EnumProcessModules, and if you haven't given room for enough modules, the "Needed" parameter will be set to the space needed for the number of modules it contains. There's a race condition though: between the time that returns and the time you call EnumProcessModules again, the process could have loaded more DLLs, so that second call could fail the same way.
For the moment, I've just assumed that no process will use more than 2048 modules. To be really correct, you should have a while loop (or maybe a do/while loop) that starts with zero space, calls EnumProcessModules to find out how much space is needed, allocate that (perhaps with a little extra in case it loads more DLLs) and repeat until it succeeds.
I think you are my last hope. I have got here a Bluetooth device (it is a sensor to be more precisely) which I want to connect to and read data from. The device offers SPP (Serial Port Profile). To avoid the problem of reliable mapping from Bluetooth addresses and virtual serial ports (COM Ports), I am going to use sockets.
Unfortunately the application always crashes before returning from WinAPI function connect(...) with: 0xC0000005: Access violation reading location 0x00000004, so I get no error code.
BUT, and that is weird, when I right-click on the Bluetooth System Tray Icon to to show available devices, my device shows up being authenticated and connected. This list was empty before, of course.
My OS is Windows 7 64 Bit, the IDE is Visual Studio 2010, Microsoft Bluetooth Stack. Code to find and connect to my only device:
#include <iostream>
#include <string>
#include <algorithm>
#include <cassert>
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <BluetoothAPIs.h>
#include <Winsock2.h>
#include <Ws2bth.h>
BOOL auth_callback_ex(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS authParams)
{
BLUETOOTH_AUTHENTICATE_RESPONSE response;
response.bthAddressRemote = authParams->deviceInfo.Address;
response.authMethod = authParams->authenticationMethod; // == BLUETOOTH_AUTHENTICATION_METHOD_LEGACY
UCHAR pin[] = "1234";
std::copy(pin, pin+sizeof(pin), response.pinInfo.pin);
response.pinInfo.pinLength = sizeof(pin)-1; //excluding '\0'
response.negativeResponse = false;
HRESULT err = BluetoothSendAuthenticationResponseEx(NULL, &response);
if (err)
{
std::cout << "BluetoothSendAuthenticationResponseEx error = " << err << std::endl;
}
return true;
}
int main()
{
BLUETOOTH_DEVICE_SEARCH_PARAMS btSearchParams;
btSearchParams.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
btSearchParams.cTimeoutMultiplier = 5; //5*1.28s search timeout
btSearchParams.fIssueInquiry = true; //new inquiry
//return all known and unknown devices
btSearchParams.fReturnAuthenticated = true;
btSearchParams.fReturnConnected = true;
btSearchParams.fReturnRemembered = true;
btSearchParams.fReturnUnknown = true;
btSearchParams.hRadio = NULL; //search on all local radios
BLUETOOTH_DEVICE_INFO btDeviceInfo;
ZeroMemory(&btDeviceInfo, sizeof(BLUETOOTH_DEVICE_INFO)); //"initialize"
btDeviceInfo.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
HBLUETOOTH_DEVICE_FIND btDeviceFindHandle = NULL;
btDeviceFindHandle = BluetoothFindFirstDevice(&btSearchParams, &btDeviceInfo);
if(btDeviceFindHandle)
{
HBLUETOOTH_AUTHENTICATION_REGISTRATION authCallbackHandle = NULL;
DWORD err = BluetoothRegisterForAuthenticationEx(&btDeviceInfo, &authCallbackHandle, &auth_callback_ex, NULL);
if (err != ERROR_SUCCESS)
{
DWORD err = GetLastError();
std::cout << "BluetoothRegisterForAuthentication Error" << err << std::endl;
}
/////////////// Socket
WSADATA wsaData;
err = WSAStartup(MAKEWORD(2,2), &wsaData);
if (err)
{
std::cout << "WSAStartup error = " << err << std::endl;
}
// create BT socket
SOCKET s = socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
assert(s != INVALID_SOCKET); //WSAGetLastError //throw // runtime check release?
SOCKADDR_BTH btSockAddr;
btSockAddr.addressFamily = AF_BTH;
btSockAddr.btAddr = btDeviceInfo.Address.ullLong;
btSockAddr.serviceClassId = RFCOMM_PROTOCOL_UUID; //SerialPortServiceClass_UUID (no difference)
btSockAddr.port = BT_PORT_ANY;
err = connect(s, reinterpret_cast<SOCKADDR*>(&btSockAddr), sizeof(SOCKADDR_BTH));
/* <--- never got so far --> */
if (err)
{
DWORD wsaErr = WSAGetLastError();
std::cout << "connect error = " << wsaErr << std::endl;
}
else
{
//err = shutdown(s, SD_BOTH);
err = closesocket(s);
if (err)
{
std::cout << "closesocket error = " << err << std::endl;
}
}
WSACleanup();
///////////////Socket
BOOL ok = BluetoothUnregisterAuthentication(authCallbackHandle);
if (!ok)
{
DWORD err = GetLastError();
std::cout << "BluetoothUnregisterAuthentication Error" << err << std::endl;
}
ok = BluetoothFindDeviceClose(btDeviceFindHandle);
if (!ok)
{
DWORD err = GetLastError();
std::cout << "BluetoothDeviceClose Error" << err << std::endl;
}
}
else
{
DWORD err = GetLastError();
std::cout << "BluetoothFindFirstDevice Error" << err << std::endl;
}
std::cin.get();
}
I have made some few more observations:
The authentication callback and the BluetoothSendAuthenticationResponseEx function are working fine, there is no error given back.
If I do not install the authentication callback (BluetoothRegisterForAuthenticationEx) and therefore have to manually enter the PIN (the UI shows up automatically while trying to connect), connect function returns properly and everything works fine, too. I even got data (the recv part is omitted in this snippet).
If I search and pair completely manually (Bluetooth Tray Icon -> Add Device), everything is fine, too. A service and a virtual serial port is installed. Data come via putty.
So somewhere between calling the authentication callback and end of the connect function something is going wrong. Maybe when trying to get a certain structure data via a pointer, which should not be NULL, plus offset.
Or am I doing something wrong? Is there something missing?
Thanks...
The problem is that your function is using the wrong calling convention. According to MSDN, you need to use the CALLBACK macro, as in:
BOOL CALLBACK auth_callback_ex(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS authParams)
Having the wrong calling convention will result in a stack mismatch on return, which could cause an access violation inside the MS Bluetooth code when it can't find its local variables.
Or it could result in the parameters to your function being all jumbled. If authParams and pvParam are swapped, because the cdecl calling convention expects args pushed from right to left and stdcall pushes them left to right, you'd get NULL in authParams, and then authParams->deviceInfo.Address will try to read address 0x04.
The compiler should have caught this. Compile with maximum warnings turned on (/W4). You'll have to ignore the warnings about unknown pragma, this is a bug in the header which I'm reporting to Microsoft (misspelled #pragma deprecated).
Unfortunately there's a second bug in the header, much more serious, of not specifying the calling convention explicitly, with the result that it will only work correctly on x86 (32-bit code) if /Gz is used. Yuck!
Followup: In the SDK headers shipped with VS2013, both issues are fixed.
You have a null-pointer access somewhere. "Access violation reading location 0x00000004" indicates that, as it is only 4 bytes away from zero.
I have a couple of thoughts to share with you, but be advised that these are hunches. I haven't compiled and debugged your code, although I commend you for posting a complete sample.
I think the crash may be within your authentication callback function, due to a '''NULL''' pointer dereference.
These lines:
response.bthAddressRemote = authParams->deviceInfo.Address;
response.authMethod = authParams->authenticationMethod; // == BLUETOOTH_AUTHENTICATION_METHOD_LEGACY
will cause the message you describe, if you are running on 32-bit Windows, and '''authParams''' may be '''NULL''' -- in that case, '''deviceInfo''' contributes a zero offset (it is at the beginning of the '''BLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS'''), and '''.Address''' does contribute an offset of 4 ('''NULL + 4 == 0x00000004'''), because it follows a '''DWORD''' and nothing else within the '''BLUETOOTH_DEVICE_INFO''' layout.
Is it possible that '''authParams''' is NULL when your callback is called?
As another poster has already mentioned, this could be due to incorrect calling convention (lack of '''CALLBACK''' macro) -- causing otherwise correct parameters to mis-align with the positions the compiled code is reading.
The second thought was:
BLUETOOTH_DEVICE_INFO btDeviceInfo;
ZeroMemory(&btDeviceInfo, sizeof(BLUETOOTH_DEVICE_INFO)); //"initialize"
btDeviceInfo.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
Can be represented by:
BLUETOOTH_DEVICE_INFO btDeviceInfo = {sizeof(BLUETOOTH_DEVICE_INFO)};
According to the standard, this will zero the other fields of '''btDeviceInfo'''.
Or write managed code and use my Bluetooth library 32feet.NET Super simple. http://32feet.codeplex.com/
Will it crash then -- if so there's something wrong on your PC...