📄 obex.cpp
字号:
pTemp = pTemp->pNext;
}
VariantClear(&varDev1Address);
*isCorpse = bHasBeenCorpsed;
return S_OK;
}
HRESULT
CObex::UpdateDevices(IObexTransport *pTransport, CLSID *pclsid, DEVICE_LIST *pMatchedDeviceList)
{
CObexDevice *pObexDevice = NULL;
HRESULT hRes = S_OK;
while(pMatchedDeviceList)
{
SVSUTIL_ASSERT(gpSynch->IsLocked());
DEVICE_LIST *pDel = pMatchedDeviceList;
pObexDevice = pMatchedDeviceList->pDevice;
pMatchedDeviceList = pMatchedDeviceList->pNext;
delete pDel;
PREFAST_ASSERT(pObexDevice);
//because we are here, this device still exists
pObexDevice->SetPresent(TRUE);
IPropertyBag *pDeviceBag = pObexDevice->GetPropertyBag();
VARIANT varCorpse;
VariantInit(&varCorpse);
BOOL fIsCorpse = FALSE;
if(SUCCEEDED(pDeviceBag->Read(L"Corpse", &varCorpse, NULL)))
{
if(varCorpse.lVal == 1)
fIsCorpse = TRUE;
VariantClear(&varCorpse);
}
// finish updating the device
// (but only if it needs updating...)
if(!fIsCorpse && 0xFFFFFFFF != pObexDevice->GetUpdateStatus())
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumIndividualDevicesThread - finishing update \n"));
HRESULT hr;
SVSUTIL_ASSERT(pDeviceBag);
//go update the devices properties.. this will go out
// and preform the (possible) time consuming chore
// of figuring out if OBEX is supported on the device
// as well as build the human name
IPropertyBagEnum *pNewBagEnum = NULL;
UINT uiUpdateStatus;
UINT uiPrevStatus = pObexDevice->GetUpdateStatus();
BOOL fAborted = FALSE;
ReleaseLock();
hr = pTransport->UpdateDeviceProperties(pDeviceBag, &pNewBagEnum, FALSE, &uiUpdateStatus);
if (! GetLock ())
{
hRes = E_FAIL;
pObexDevice->Release();
goto done;
}
//if we succeeded, progress has been made (or could have been)
// so notify the client and possibly SetModified
if(SUCCEEDED(hr))
{
if(S_OK != hr)
pObexDevice->SetUpdateStatus(uiUpdateStatus);
else
pObexDevice->SetUpdateStatus(0xFFFFFFFF);
//special case this to maintain bkwrds compat with ppc2002
if(!(g_dwObexCaps & SEND_DEVICE_UPDATES))
{
if(uiUpdateStatus != uiPrevStatus && (S_OK == hr))
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumIndividualDevicesThread - sending update message - status (before/after) = (0x%x/0x%x)\n", uiUpdateStatus, uiPrevStatus));
pObexDevice->SetModified(TRUE);
if (!g_pObex->_bStopEnum)
g_pObex->_pConnPt->Notify(OE_DEVICE_ARRIVAL, pDeviceBag, NULL);
}
else if(uiUpdateStatus != uiPrevStatus && S_OK == hr)
{
pObexDevice->SetModified(TRUE);
}
else
{
pObexDevice->SetModified(FALSE);
}
}
else
{
if(uiUpdateStatus != uiPrevStatus)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumIndividualDevicesThread - sending update message - status (before/after) = (0x%x/0x%x)\n", uiUpdateStatus, uiPrevStatus));
pObexDevice->SetModified(TRUE);
if (!g_pObex->_bStopEnum)
g_pObex->_pConnPt->Notify(OE_DEVICE_UPDATE, pDeviceBag, NULL);
}
else
{
pObexDevice->SetModified(FALSE);
}
}
}
//if we have failed, or if we havent been modified in a while
// corpse the device
if(E_ABORT != hr && (FAILED(hr) || (!(uiUpdateStatus & CAN_CONNECT) && !pObexDevice->GetModified())))
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumIndividualDevicesThread - device doesnt support OBEX -- making it a corpse\n"));
//if an error occured, mark the device as a corpse in its bag
VARIANT varCorpseWrite;
VariantInit(&varCorpseWrite);
varCorpseWrite.vt = VT_I4;
varCorpseWrite.lVal = 1;
hr = pDeviceBag->Write(L"Corpse", &varCorpseWrite);
SVSUTIL_ASSERT(SUCCEEDED(hr));
VariantClear(&varCorpseWrite);
pObexDevice->Release();
pObexDevice=NULL;
break;
}
//
// If devices were discovered while updating a previous device
// they will be cloned and will have information.
// so place them into the list of devices and send
// a NOTIFY to any Sink
//
if(pNewBagEnum)
{
pNewBagEnum->Reset();
ULONG ulFetched = 0;
LPPROPERTYBAG2 pNewDeviceBag = NULL;
while(SUCCEEDED(pNewBagEnum->Next(1, &pNewDeviceBag, &ulFetched)) && ulFetched)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumIndividualDevicesThread - New device found during Update of prev found device!!\n"));
//create a new device with our clsid and propertybag (this marks it
// updated and present)
CObexDevice *pNewDevice = new CObexDevice(pNewDeviceBag, *pclsid);
if (!pNewDevice)
{
pNewBagEnum->Release();
pObexDevice->Release();
hRes = E_FAIL;
goto done;
}
//insert it into the device list
hr = g_pObex->_pDevices->Insert(pNewDevice);
SVSUTIL_ASSERT(SUCCEEDED(hr));
//if all went okay, notify any connection points
// <-- dont send arrival here on PPC2002
if ((g_dwObexCaps & SEND_DEVICE_UPDATES) && SUCCEEDED(hr))
{
if (!g_pObex->_bStopEnum)
g_pObex->_pConnPt->Notify(OE_DEVICE_ARRIVAL, pNewDeviceBag, NULL);
}
pNewDeviceBag->Release();
pNewDevice->Release();
pNewDevice = NULL;
}
pNewBagEnum->Release();
pNewBagEnum = NULL;
}
}
else if(!fIsCorpse)
{
SVSUTIL_ASSERT(pObexDevice);
pObexDevice->SetModified(TRUE);
}
pObexDevice->Release();
pObexDevice=NULL;
}
done:
// safety net -- clean up memory (only will happen on bad error)
while(pMatchedDeviceList)
{
DEVICE_LIST *pDel = pMatchedDeviceList;
pMatchedDeviceList->pDevice->Release();
pMatchedDeviceList = pMatchedDeviceList->pNext;
delete pDel;
}
return hRes;
}
HRESULT
CObex::PauseEnumIfRequired()
{
HRESULT hr = E_FAIL;
SVSUTIL_ASSERT(!gpSynch->IsLocked());
//
// Handle pausing
// this is done by first getting the lock, then if we were
// told to pause, we decrement the pause thread count (the number
// of instances of EnumIndividualDeviceThread running) and then
// if 0 we wake up the initiating Pause() function -- then
// we wait for a pauseEvent
if (!GetLock())
goto Done;
if(TRUE == g_pObex->_fPause) {
g_pObex->_uiRunningENumThreadCnt --;
if(0==g_pObex->_uiRunningENumThreadCnt)
SetEvent(g_pObex->_hEnumPauseEvent_UnlockPauseFunction);
}
ReleaseLock();
//note: this is a manual reset event!!
if(WAIT_FAILED == WaitForSingleObject(g_pObex->_hEnumPauseEvent, INFINITE)) {
ASSERT(FALSE);
goto Done;
}
hr = S_OK;
Done:
return hr;
}
//
// Note: because we monitor the number of instances of this
// thread that are running (via _uiRunningEnumThreadCnt)
// on *EVERY* exit (return) we have to first decrement
// the _uiRunninEnumThreadCnt (while under the main lock -- this is important)
// THEN once we have left that lock we MUST call PauseEnumIfRequired
// so that we wont race
//
DWORD WINAPI
CObex::EnumIndividualDeviceThread(LPVOID lpvParam)
{
PREFAST_ASSERT(g_pObex);
IObexTransport *pTransport = NULL;
ULONG ulFetched = 0;
HRESULT hr = E_FAIL;
CLSID clsid;
VARIANT var;
BOOL bOK;
LPPROPERTYBAG2 pBag = NULL;
DEVICE_PROPBAG_LIST *pDeviceCorpses = NULL;
IObexAbortTransportEnumeration *pAbortEnum = NULL;
//we are GIVEN the propery bag for the device, DO NOT ref count it!
LPPROPERTYBAG2 pPropBag = (LPPROPERTYBAG2) lpvParam;
PREFAST_ASSERT(pPropBag);
//init the COM library
if (FAILED(CoInitializeEx(NULL,COINIT_MULTITHREADED)))
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumDevicesThread - CANT CoInitializeEx\n"));
g_pObex->Release();
//
// Because we are leaving the thread, the # of running threads
// must be decremented--- and because this has to be dec'ed
// we must call PauseEnumIfRequired
if (!GetLock())
goto done;
//decrement the # of threads running
g_pObex->_uiRunningENumThreadCnt --;
ReleaseLock();
g_pObex->PauseEnumIfRequired();
return E_FAIL;
}
//fetch the GUID from the prop bag, if it doesnt exist, quit
VariantInit(&var);
bOK = ( (SUCCEEDED(pPropBag->Read(L"GUID", &var, 0))) && (SUCCEEDED(CLSIDFromString(var.bstrVal, &clsid))) );
if (!bOK)
goto done;
VariantClear(&var);
//get a transport (for seeing what devices are up)
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IObexTransport,
(void **)&pTransport);
if ( (FAILED(hr)) || (!pTransport) )
{
pTransport = NULL;
goto done;
}
// make sure the transport is not in the abort state
if(SUCCEEDED(pTransport->QueryInterface(IID_IObexAbortTransportEnumeration, (LPVOID *)&pAbortEnum))) {
pAbortEnum->Resume();
pAbortEnum->Release();
}
if(FAILED(g_pObex->AddActiveTransport(pTransport))) {
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumIndividualDevicesThread - Cant add active transport to list! -- can continue w/o this but enumeration stopping may be slow\n"));
}
for(;;)
{
SVSUTIL_ASSERT(pTransport && g_pObex && g_pObex->_pDevices);
// pause enumeration if required
if(FAILED(g_pObex->PauseEnumIfRequired()))
goto done;
//if we are told to stop... do so
if (!GetLock())
goto done;
if (g_pObex->_bStopEnum)
{
ReleaseLock();
goto done;
}
//start an enumeration run for all devices that are of the
// transport from 'clsid'... this mean the SetPresent flag is
// set false -- thus the credits go down by 1. if they go to
// 0 the device is deleted (well, marked as a corpse)
g_pObex->_pDevices->StartEnumRun(clsid);
ReleaseLock();
//
//get all the devices on a particular transport (pTransport)
//
LPPROPERTYBAGENUM pPropBagEnum = NULL;
if( (SUCCEEDED(pTransport->EnumDevices(&pPropBagEnum))) && (pPropBagEnum))
{
//
// quick check to see if we've been stopped.
//
if (g_pObex->_bStopEnum)
{
pPropBagEnum->Release();
goto done;
}
//look through each discoverd device, creating devices and inserting them into the
// device enumerator
ulFetched = 0;
pPropBagEnum->Reset();
//
// Loop through all devices discovered, find devices that might match
// (-- if they share addresses) and then figure out if multiple 'devices'
// live under that one device (1 BT device + multiple SDP records)
while(SUCCEEDED(pPropBagEnum->Next(1, &pBag, &ulFetched) ) && ulFetched == 1)
{
if (! GetLock ())
{
pBag->Release();
pBag = NULL;
pPropBagEnum->Release();
goto done;
}
//quick check to see if we've been stopped.
if (g_pObex->_bStopEnum)
{
pBag->Release();
pBag = NULL;
pPropBagEnum->Release();
ReleaseLock();
goto done;
}
//
// Check to see if this device has been found to be a corpse
// if it has, skip it
//
BOOL fIsCorpse = FALSE;
if(FAILED(g_pObex->IsCorpse(pDeviceCorpses,pBag,&fIsCorpse)))
{
ReleaseLock();
pBag->Release();
pBag = NULL;
pPropBagEnum->Release();
goto done;
}
else if(fIsCorpse)
{
SVSUTIL_ASSERT(gpSynch->IsLocked());
ulFetched = 0;
ReleaseLock();
pBag->Release();
pBag = NULL;
continue;
}
//
// Hunt out the obex device with the passed in property bag
// if it exists, set its present flag
DEVICE_LIST *pMatchedDeviceList = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -