Even to develop a simple application, the existing examples in Openthread are complex to refer. Can anybody provide a list of steps to use Openthread "mdt/fdt library" and develop a simple application, from where a CoAP message can be sent or received ? Following is what I have written, but it is not running properly and crashing at times. I have linked "fdt, posix, mbedtls, libcrypto" etc libraries and able to build the application successfully.
instance = otInstanceInitSingle();
otError err = otIp6SetEnabled(instance, true);
if(err == OT_ERROR_NONE)
{
err = otCoapStart(instance, OT_DEFAULT_COAP_PORT);
pthread_t thread_id;
pthread_create(&thread_id, NULL, OTProcessThread, NULL); // To call otTaskletsProcess(instance);
return OK;
}
else{
std::cout << "Init Status: " << err << "\n";
}
The thread looks like the following. I this is a sample code, so I have not given any sleep/signal in the thread at present.
void *OTProcessThread(void *vargp)
{
printf("\nOTProcessThread started..");
while (true)
{
otTaskletsProcess(instance);
//otSysProcessDrivers(instance);
}
}
With this initialization process, I am trying to send a message as follows. But after that the application is crashing somewhere inside the Openthread code.
message = otCoapNewMessage(instance, NULL);
otCoapMessageInit(message, coapType, coapCode);
otCoapMessageGenerateToken(message, 8);
otCoapMessageAppendUriPathOptions(message, uri.c_str());
//otMessageAppend(message, NULL, 0);
otError status = otCoapSendRequest(instance, message, &messageInfo, &HandleResponse, this);
Can somebody please let me know, what exactly I am missing ?
While I can't speak to your specific issue without greater visibility, here are some resources you may find helpful:
https://github.com/openthread/ot-rtos
https://codelabs.developers.google.com/codelabs/openthread-apis/
https://www.nordicsemi.com/Software-and-tools/Software/nRF5-SDK-for-Thread-and-Zigbee
Related
I'm trying to use the Leadtools API version 21 for automatically scanning some documents and here is a sudo code of what I have done (it runs in a secondary thread and the unlock has been done in the main thread):
void CheckRetCode(int rc)
{
if (SUCCESS != rc)
{
L_TCHAR errMsg[1024];
memset(errMsg, 0, sizeof(errMsg));
L_GetFriendlyErrorMessage(rc, errMsg, 1024, L_FALSE);
throw TLeadException(errMsg, rc);
}
}
void OnThreadExecute(void)
{
HTWAINSESSION hSession = nullptr;
APPLICATIONDATA appData;
L_INT nRet;
L_TCHAR pszTwnSourceName[1024];
LTWAINSOURCE sInfo;
memset(&appData, 0, sizeof(APPLICATIONDATA));
appData.uStructSize = sizeof(APPLICATIONDATA);
appData.hWnd = hWnd;// hWnd is valid handle of my main window
appData.uLanguage = TWLG_ENGLISH_USA;
appData.uCountry = TWCY_USA;
wcscpy(appData.szManufacturerName, L"MyCompanyName");
wcscpy(appData.szAppProductFamily, L"MyProductName");
wcscpy(appData.szAppName, appData.szAppProductFamily);
wcscpy(appData.szVersionInfo, L"Version 0.1.0.1");
nRet = L_TwainInitSession2(&hSession, &appData, LTWAIN_INIT_MULTI_THREADED);
CheckRetCode(nRet);// the exception gets catched elsewhere but no error reported here
memset(pszTwnSourceName, 0, sizeof(pszTwnSourceName));
wcscpy(pszTwnSourceName, L"EPSON Artisan837/PX830"); // the name of the scanner is verifyed
sInfo.uStructSize = sizeof(LTWAINSOURCE);
sInfo.pszTwainSourceName = pszTwnSourceName;
CheckRetCode(L_TwainSelectSource(hSession, &sInfo)); // No error reported here
CheckRetCode(L_TwainStartCapsNeg(hSession)); // in here I get the return value -84 which is reported as "TWAIN DS or DSM reported error, app shouldn't (no need for your app to report the error)."
// the rest of the code but we cannot get there since above code reports error
}
Can anyone tell me what I'm doing wrong? Is there a step that I'm missing here?
EditThe function L_TwainSelectSource() make no effort to make sure the supplied source is valid and does not even return an error. As result, if you set the selected source to a garbage name, it will act as if it accepted it. From that point on if you try to Get/Set anything or try to acquire an image, every function returns -84.
Thank you
Sam
To test your code, I put the main window’s handle in a global variable:
globalhWnd = hWnd;
And modified your function to use that handle like this:
void OnThreadExecute(void *)
{
...
appData.hWnd = globalhWnd; // hWnd is valid handle of my main window
...
}
Then created a thread for it from the main program like this:
globalhWnd = hWnd;
_beginthread(OnThreadExecute, 0, 0);
I tried this with 5 different Twain sources: 2 virtual and 3 physical scanners (one of them an old Epson). All 5 drivers returned SUCCESS when calling L_TwainStartCapsNeg() from within the thread.
Two possibilities come to mind:
The problem might be caused by something else in your code other than the thread function.
Or the problem could be specific to your Twain driver.
To rule out the first possibility, I suggest creating a small test project that only creates a similar thread and does nothing else and trying it with different scanners. If it causes the same problem with all scanners, send that test project (not your full application) to support#leadtools.com and our support engineers with test it for you.
If the problem only happens with a specific Twain driver, try contacting the scanner’s vendor to see if they have an updated driver.
I have a dilemma. My GUI-based C++ app requires to implement drag-and-drop functionality. At the same time, I'm converting this Win32 app to UWP to submit to Windows Store. But there's one issue:
To implement drag-and-drop I need to call these two methods:
OleInitialize(NULL);
//...
HRESULT hr = RegisterDragDrop(hMainWnd, pDropTarget);
and to init WinRT stuff to work with Windows Store, I need to call:
HRESULT hr = RoInitialize(RO_INIT_MULTITHREADED);
Unfortunately OleInitialize initialized COM as single-thread apartment and RoInitialize requires multi-threaded model, while RegisterDragDrop cannot function without calling OleInitialize.
Any idea how to resolve it? (apart from moving RoInitialize and all WinRT code into a worker thread, that will complicate things.)
Raymond Chen in his usual condescending way is pretty good at criticizing things but offers no fix to an existing problem. I'm posting this mostly for later self-reference and in case someone else stumbles upon the same issue as well. I just spent several days trying to resolve this bug, so maybe it will save time for someone else.
Problem
First off, this is a native Win32 code (no .NET or C++/CX.) It is C++ with a sprinkle of WRL for easier handling of WinRT/COM stuff.
In my case I have a Win32 GUI app that implements drag-and-drop of files into its main window. So to init it, one needs to do this from the main thread, right when the app starts:
OleInitialize(NULL);
//...
HRESULT hr = RegisterDragDrop(hMainWnd, pDropTarget);
The OleInitialize call above will initialize COM for the main thread to use single-thread apartment, which is required for RegisterDragDrop to succeed. Without it, the drag-and-drop function will not work.
Then, say you decide to convert this Win32 app to UWP using Microsoft's Project Centennial converter for inclusion into Windows 10 store.
When the app is converted and listed in the store under their trial-license scheme, you will employ the following logic to check if the user has a trial or an activated (i.e. purchased) copy of the app. You'll begin it as such:
//Init COM for WinRT
RoInitialize(RO_INIT_MULTITHREADED);
ComPtr<IStoreContextStatics> pStoreContextStatics;
if(SUCCEEDED(RoGetActivationFactory(
HStringReference(L"Windows.Services.Store.StoreContext").Get(),
__uuidof(pStoreContextStatics),
&pStoreContextStatics)) &&
pStoreContextStatics)
{
//Get store context for the app
ComPtr<IStoreContext> pStoreContext;
if(SUCCEEDED(pStoreContextStatics->GetDefault(&pStoreContext)) &&
pStoreContext)
{
//Got store context
//....
}
}
and then if you need to know trial vs. activated status of the app, using this logic, you'd call:
ComPtr<IAsyncOperation<StoreAppLicense*>> p_opAppLic;
if(SUCCEEDED(pStoreContext->GetAppLicenseAsync(p_opAppLic)) &&
p_opAppLic)
{
ComPtr<IAsyncOperationCompletedHandler<StoreAppLicense*>> p_onAppLicCallback =
Callback<Implements<RuntimeClassFlags<ClassicCom>, IAsyncOperationCompletedHandler<StoreAppLicense*>, FtmBase>>(
[](IAsyncOperation<StoreAppLicense*>* pOp, AsyncStatus status)
{
if (status == AsyncStatus::Completed)
{
ComPtr<IStoreAppLicense> pAppLicResult;
if(SUCCEEDED(pOp->GetResults(&pAppLicResult)) &&
pAppLicResult)
{
BYTE nActive = -1;
BYTE nTrial = -1;
pAppLicResult->get_IsActive(&nActive);
pAppLicResult->get_IsTrial(&nTrial);
//Get app's store ID with SKU
HString strStoreId;
pAppLicResult->get_SkuStoreId(strStoreId.GetAddressOf());
if(nActive == 1 &&
nTrial == 0)
{
//Activated, or purchased copy
}
else if(nActive == 1 &&
nTrial == 1)
{
//Trial copy
}
else
{
//Error -- store returned some gibberish
}
}
}
return S_OK;
});
if(SUCCEEDED(p_opAppLic->put_Completed(p_onAppLicCallback.Get())))
{
//Success initiating async call
}
}
So, if you do all this, your UWP-converted app will behave in a very strange way. Here's an example. Say a user purchases a license for the app thru Windows Store. In turn your app logic calls the code above to see if the app is activated, but what you get back is nActive=0 and nTrial=1. Then if you check strStoreId it will be your app store ID but without the SKU. WTF!?
I know, it's really confusing. As an aside, let me explain. When you first list your app in a Windows Store it will be assigned a Store ID. Something like: ABCDEFG12345. Then if you submit any follow-up update(s) to the first version of the same app, they will add a SKU number to it, that will make the whole app ID change to ABCDEFG12345/0010, then ABCDEFG12345/0011 for the next update, and so on.
Well, the WinRT code above would return my app store ID as ABCDEFG12345 without any SKU attached to it. Which was wrong, since it was a third or so update to the first version of the app. And thus any additional attributes for that app store ID were also wrong.
So that was the issue that I was faced with...
Cause
All the headache that I described above was caused by my omission to check the result code returned from the first RoInitialize call. I would be able to catch the problem much faster if I did this:
//Init COM for WinRT
if(FAILED(RoInitialize(RO_INIT_MULTITHREADED)))
{
//WinRT COM initialization failed
//Go scratch your head why....
}
In this case RoInitialize will fail with error code RPC_E_CHANGED_MODE. The documentation for it is as helpful as Windows Help (F1) option:
A previous call to RoInitialize specified the concurrency model for
this thread as multithread apartment (MTA). This could also indicate
that a change from neutral-threaded apartment to single-threaded
apartment has occurred.
What previous call? The only parameter anyone can call it with is RO_INIT_MULTITHREADED.
So I started digging deeper and by the process of elimination found that the OleInitialize call earlier was the reason why RoInitialize failed and caused the cascade of events that I described above.
Thus I was at the point of asking the question here.
Note on the side, that the bug ridden WinRT library (ref1, ref2, ref3, ref4, ref5) gave me no indications of a problem in all the calls following RoInitialize and somewhere internally silently failed to retrieve the app's SKU because of a single-thread apartment COM initialization.
Hack/Workaround
As was suggested by RbMm in the comments above, doing the following will work, but is a totally undocumented behavior:
if(SUCCEEDED(OleInitialize(0))
{
CoUninitialize();
}
CoInitializeEx(NULL, COINIT_MULTITHREADED);
So if you don't want your app to start crashing for no apparent reason, I would not use it.
Solution
My solution that I went with was to move all the WinRT COM stuff (code I listed above: 2nd and 3rd code segments) into a separate worker thread. It will work fine from there. The issue is marshalling calls between your main thread and this worker thread. It is doable, but requires some work, i.e. using mutexes and events for synchronized access, etc.
So if anyone finds an easier fix for this, please post your solution. I'll mark it as the answer.
solution to the IDsObjPicker crashes I mentioned in the comment ealier, quick code I wrote just now.
Use code below as:
TDsObjPicker lv_PickInfo;
memset(&lv_PickInfo, 0, sizeof(TDsObjPicker));
Sec_InitDsObjPicker(&lv_PickInfo, &lv_InitInfo);
Sec_InvokeDsObjPicker(&lv_PickInfo, 0, &lv_oData);
Solution is to run the dialog in another thread and init the thread without the Ole+Com combination:
// command codes
#define DSOPCMD_EXITTHREAD 1
#define DSOPCMD_INITIALIZE 2
#define DSOPCMD_INVOKE 3
// parameters of object picker via thread
typedef struct tagDsObjPicker
{
// thread handle
HANDLE hThread;
// events
HANDLE hCmdEvt;
HANDLE hRdyEvt;
// commands
UINT CmdCode;
HRESULT hResult;
// command parameters - DSOPCMD_INITIALIZE
DSOP_INIT_INFO *InitInfo;
// command parameters - DSOPCMD_INVOKE
HWND hWnd;
IDataObject **oData;
//
} TDsObjPicker;
DWORD CALLBACK _Sec_DsObjPickerThread(VOID *in_Param)
{
/* locals */
HRESULT lv_hCreateResult;
HRESULT lv_hResult;
TDsObjPicker *lv_PickInfo;
IDsObjectPicker *lv_oPicker;
// get info structure
lv_PickInfo = (TDsObjPicker*)in_Param;
// init COM
CoInitializeEx(NULL, COINIT_MULTITHREADED);
// preclear object pointer
lv_oPicker = NULL;
// create instance of picker
lv_hCreateResult = CoCreateInstance(
CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker, (VOID**)&lv_oPicker);
// while thread is not aborted
while (lv_PickInfo->CmdCode != DSOPCMD_EXITTHREAD)
{
// wait for command event
if (WaitForSingleObject(lv_PickInfo->hCmdEvt, INFINITE) == 0)
{
// what command?
switch (lv_PickInfo->CmdCode)
{
// call init
case DSOPCMD_INITIALIZE:
{
// call object
if (lv_hCreateResult)
lv_hResult = lv_hCreateResult;
else
lv_hResult = lv_oPicker->Initialize(lv_PickInfo->InitInfo);
// done
break;
}
// call invoke
case DSOPCMD_INVOKE:
{
// call object
if (lv_hCreateResult)
lv_hResult = lv_hCreateResult;
else
lv_hResult = lv_oPicker->InvokeDialog(lv_PickInfo->hWnd, lv_PickInfo->oData);
// done
break;
}
// other command codes
default:
lv_hResult = E_FAIL;
break;
}
// store result
lv_PickInfo->hResult = lv_hResult;
// notify caller
SetEvent(lv_PickInfo->hRdyEvt);
}
}
// destroy the picker object
if (lv_oPicker)
lv_oPicker->Release();
// cleanup COM
CoUninitialize();
// leave the thread
return 0;
}
VOID Sec_DoneDsObjPicker(TDsObjPicker *in_PickInfo)
{
// is thread created?
if (in_PickInfo->hThread)
{
// set command code
in_PickInfo->CmdCode = DSOPCMD_EXITTHREAD;
// trigger the thread to process the code
SetEvent(in_PickInfo->hCmdEvt);
// wait for thread to finish
WaitForSingleObject(in_PickInfo->hThread, INFINITE);
// close thread handle
CloseHandle(in_PickInfo->hThread);
}
// close event handles
if (in_PickInfo->hCmdEvt) CloseHandle(in_PickInfo->hCmdEvt);
if (in_PickInfo->hRdyEvt) CloseHandle(in_PickInfo->hRdyEvt);
// clear
memset(in_PickInfo, 0, sizeof(TDsObjPicker));
}
HRESULT Sec_InitDsObjPicker(TDsObjPicker *in_PickInfo, DSOP_INIT_INFO *in_InitInfo)
{
/* locals */
DWORD lv_TID;
// thread not yet created?
if (!in_PickInfo->hThread)
{
// create events
in_PickInfo->hCmdEvt = CreateEvent(0,0,0,0);
in_PickInfo->hRdyEvt = CreateEvent(0,0,0,0);
// if ok
if (in_PickInfo->hCmdEvt && in_PickInfo->hRdyEvt)
{
// create the thread
in_PickInfo->hThread = CreateThread(
0, 0, _Sec_DsObjPickerThread, in_PickInfo, 0, &lv_TID);
}
// failed?
if (!in_PickInfo->hThread)
{
// cleanup
Sec_DoneDsObjPicker(in_PickInfo);
// return with error
return E_OUTOFMEMORY;
}
}
// store parameter
in_PickInfo->InitInfo = in_InitInfo;
// set command code
in_PickInfo->CmdCode = DSOPCMD_INITIALIZE;
// trigger the thread to process the code
SetEvent(in_PickInfo->hCmdEvt);
// wait for result
WaitForSingleObject(in_PickInfo->hRdyEvt, INFINITE);
// return the result
return in_PickInfo->hResult;
}
HRESULT Sec_InvokeDsObjPicker(TDsObjPicker *in_PickInfo, HWND in_hWnd, IDataObject **out_oData)
{
/* locals */
MSG lv_Msg;
// thread not yet created?
if (!in_PickInfo->hThread)
return E_FAIL;
// store parameters
in_PickInfo->hWnd = in_hWnd;
in_PickInfo->oData = out_oData;
// set command
in_PickInfo->CmdCode = DSOPCMD_INVOKE;
// trigger the thread
SetEvent(in_PickInfo->hCmdEvt);
// process messages of this thread while picker runs in other thread until event
while (MsgWaitForMultipleObjects(1, &in_PickInfo->hRdyEvt, 0, INFINITE, QS_ALLINPUT) != 0)
{
// get next message
while (PeekMessage(&lv_Msg, 0,0,0, PM_REMOVE))
{
// translate/dispatch the message
TranslateMessage(&lv_Msg);
DispatchMessage(&lv_Msg);
}
}
// return the result
return in_PickInfo->hResult;
}
You asked why calling OleInitialize() first, followed by CoUnintialize and then reinit COM via CoInitializeEx works and is safe, look at the code of the rewritten OLE server in WINE, https://github.com/wine-mirror/wine/blob/master/dlls/ole32/ole2.c it comes pretty close to the "real thing". The OleInitialize calls CoInitializeEx itself with COINIT_APARTMENTTHREADED and fails before doing the OLE-specific initializations upon a fail of CoInitializeEx. There is no reason to fail as the OLE code can run as well in MULTITHREADED mode. Remember MULTITHREADED means the caller must take care of synchronisation/locking while with APARTMENTTHREADED the COM libray will handle it for the code. So if you make sure you do not call the OLE code like dragdrop and clipboard at the same time from multiple threads then there is no problem. Keeping all UI in the main thread will do that. As you should already write multithreaded-aware code yourself using the requested MULTITHREADED mode.
I have the problem with directshow filters/drivers which lock the process when COM is initialized with APARTMENTTHREADED even when directshow is called from a thread with THREADED while the main UI thread runs in APARTMENTTHREADED.
Uninitializing COM after initializing OLE, then re-inititializing COM with MULTITHREAED during startup in the main UI thread makes you bypass the failure in OleInitialize. It is the best solution to make sure all runs well.
I'm creating a Windows Add/Remove Programs application in Qt 5.4 and I'm becaming crazy to solve a little "puzzle":
My application (APP_0) runs another application (APP_1) and waits for this APP_1 until it terminates.
APP_1 is an uninstaller (i.e. uninstall.exe) and I've not the source code of the APP_1, just of my Qt APP_0.
APP_1, instead of doing the uninstall job, it simply copies itself somewhere in the filesystem (I saw as Au_.exe but other apps could use different names and locations), runs this copy of itself (APP_2) and terminates.
The APP_2 has a GUI and the job I'm waiting for (uninstall) is demanded to the final user of the running APP_2.
In this situation my application (APP_0) stops waiting for APP_1 pratically immediately (because it launches APP_1 and waits for APP_1). But to work properly, obviously, I need to know instead when APP_2 is terminated...
So the question is:
is there a way (using some techniques (hooking?)) to know if and when APP_2 terminates?
Note: Consider that the standard Windows Add/Remove Programs utility does the job successfully (it seems it waits for APP_2). You can test this, for example, installing Adobe Digital Edition. Its uninstaller (uninstall.exe) copies itself into a new folder in the User_Local_Temp folder as Au_.exe, runs it and terminates. But the OS utility successfully waits for Au_.exe and only after it terminates refreshes the list of installed programs.
If this kind of technique (uninstall.exe copies itself somewhere ALWAYS with THE SAME name (Au_.exe) ) the problem could be resolved, obviously, very simply. But I don't think that the name of the copied uninstaller is always the same and also I don't like to assume things I'm not sure are real.
Many thanks in advance
Thanks to IInspectable's suggestion (see his comment... and many thanks guy!) I created a function which solves my problems! I'll share here this function which could be useful to other people with the same (or similar) problem.
For my needs, the function receives as parameter the index of the item to be uninstalled (from a QList) and gets the uninstall string (for example: C:\ProgramFiles\MyApp\uninstall.exe).
Then with this uninstall string, I'll create a process (CreateProcess) and put its handle into a Job Object, so that my function will wait for all the processes ran by this process.
The function itself is pretty simple and can be improved.
Notice that the process MUST be created with the CREATE_BREAKAWAY_FROM_JOB option, otherwise the AssignProcessToJobObject will fail with a "Access Denied" error.
void MainWindow::uniButtonClick(int idx)
{
QMessageBox::StandardButton reply;
QMessageBox::StandardButton err;
reply = QMessageBox::question(this, "Uninstall/Change", "Uninstall " +
ip[idx].displayName +"?\r\n\r\n" + ip[idx].uninstallString,
QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes)
{
//QString s = "C:\\windows\\notepad.exe"; // Just to test Job assignment and createprocess
QString s = ip[idx].uninstallString; // the real uninstaller string
QString jobName = "MyJobObject";
try
{
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
PJOBOBJECT_BASIC_PROCESS_ID_LIST pList;
HANDLE hProcess;
BOOL bJobAllEnd;
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field
wchar_t* path;
path = (wchar_t*) malloc (sizeof(wchar_t)*s.length()+1);
s.toWCharArray(path);
path[s.length()]=0; // Null terminate the string
// Create the process with CREATE_BREAKAWAY_FROM_JOB to overcome the AccessDenied issue on AssignProcessToJobObject.
if(CreateProcess(NULL, path, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB|CREATE_SUSPENDED, NULL, NULL,&StartupInfo, &ProcessInfo))
{
pList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)GlobalAlloc(GMEM_FIXED, 10000);
HANDLE jobObj = CreateJobObject(NULL, (const wchar_t*)jobName.utf16());
if (AssignProcessToJobObject(jobObj, ProcessInfo.hProcess) != 0)
{
ResumeThread(ProcessInfo.hThread); // Process assigned to JobObjext, resume it now
do
{
QueryInformationJobObject(jobObj, JobObjectBasicProcessIdList, pList, 10000, NULL);
bJobAllEnd = TRUE;
for(DWORD i=0; i<pList->NumberOfProcessIdsInList; i++)
{
hProcess = OpenProcess(SYNCHRONIZE, FALSE, pList->ProcessIdList[i]);
if(hProcess != NULL)
{
CloseHandle(hProcess);
bJobAllEnd = FALSE;
}
}
Sleep(500);
} while(!bJobAllEnd);
}
else
qDebug() << "AssignProcess to Job failed: error = " << QString::number(GetLastError());
GlobalFree(pList);
CloseHandle(jobObj);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
}
}
catch(QString error)
{
QMessageBox::critical(this, "File not found!", "The requested uninstaller doesn't exists", QMessageBox::Ok);
}
// refresh list
handleButton();
}
}
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...
I am attempting to use a WaitableTimer in a Windows Service written in C++ to bring a Windows XP machine out of sleep/stand-by mode but I cannot seem to get it to work. I copy/pasted the code I am using in the service into a standalone app and that works fine. Is there a step I am missing to get this to work within a service?
The code I am using to set up the waitable timer is as follows (the call to UpdateWaitableTimer() happens within a thread that loops indefinitely):
void UpdateWaitableTimer(job_definition *jobdef)
{
HANDLE existingHandle;
try
{
if (jobdef->JobType == JOB_TYPE_SCAN)
{
char szTimerName[MAX_PATH];
sprintf_s(szTimerName, MAX_PATH, "Timer_%I64d", jobdef->JobID);
existingHandle = OpenWaitableTimer(TIMER_ALL_ACCESS, TRUE, szTimerName);
if (existingHandle != NULL)
{
// A timer handle already exists for this job, so cancel it
CancelWaitableTimer(existingHandle);
}
else
{
// No timer handle exists, create one
existingHandle = CreateWaitableTimer(NULL, TRUE, szTimerName);
}
if (jobdef->JobStatus != JOB_STATUS_SCHEDULED)
{
// This job was cancelled, so close the handle
CloseHandle(existingHandle);
}
else
{
time_t now = time(NULL);
time_t dt = jobdef->JobScheduleTime;
while(dt < now)
{
dt += 86400;
}
// Get a FILETIME one minute before
FILETIME utcFileTime = GetTimestamp(dt - 60);
// Convert to LARGE_INTEGER
LARGE_INTEGER dueTime;
dueTime.HighPart = utcFileTime.dwHighDateTime;
dueTime.LowPart = utcFileTime.dwLowDateTime;
SYSTEMTIME st;
FILETIME *ft = &utcFileTime;
FileTimeToSystemTime(ft, &st);
LogRelease(false, "Setting Timer for scheduled job: %02d/%02d/%d %02d:%02d:%02d", st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond);
if(SetWaitableTimer(existingHandle, &dueTime, 0, NULL, NULL, TRUE))
{
if(GetLastError() == ERROR_NOT_SUPPORTED)
{
LogRelease(false, "Resume from sleep/stand-by feature not supported on this operating system.");
}
}
else
{
LogError(false, "Could not create timer. Error: %d", GetLastError());
}
}
}
}
catch(...)
{
LogError(false, "An exception occured while updating waitable timer for job %I64d", jobdef->JobID);
}
LogRelease(false, "Finished Updating Waitable Timer [Job:%I64d]", jobdef->JobID);
}
If it works outside a service then your code is probably fine. There are really only two things I can think of that might cause it to behave differently:
Resuming might require the service to be able to "interact with the desktop." Try setting that option in the service manager under the log on tab, and restart your service.
Services running as LOCAL_SYSTEM might not have rights to resume from sleep. Try running the service as yourself, or create a service account specifically for the service to run from.
If you're already running the service as a specific user, then perhaps that user account has insufficient permissions.