📄 obex.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//
// Obex.cpp: implementation of the CObex class.
//
//////////////////////////////////////////////////////////////////////
#include "common.h"
#include "ObexDevice.h"
#include "CObex.h"
#include "DeviceEnum.h"
#include "conpoint.h"
#include "ObexIRDATransport.h"
#include "ObexBTHTransport.h"
#include "PropertyBag.h"
#include "PropertyBagEnum.h"
#include "HeaderEnum.h"
#include "HeaderCollection.h"
#include "ObexTCPTransport.h"
#include "ObexTransportConnection.h"
#include "ObexStream.h"
#include <olectl.h>
#include "ObexStrings.h"
extern UINT g_uiIRDAMaxRetries;
#if defined(DEBUG) || defined(_DEBUG)
DWORD dwData = 'OBEX';
void *operator new(UINT size)
{
return g_funcAlloc(size, &dwData);
}
void operator delete(void *pVoid)
{
if (pVoid)
g_funcFree(pVoid, &dwData);
}
#endif
/*----------globals----------------*/
//g_TransportSocketCS locks the internal structures of the
// transport socket (for example the linked list of
// transport connections)
CRITICAL_SECTION g_TransportSocketCS;
CRITICAL_SECTION g_PropBagCS;
CSynch *gpSynch = NULL;
CObex *g_pObex = NULL;
DWORD g_dwObexCaps = 0;
UINT g_uiMaxFileChunk;
int g_iCredits = OBEX_INQUIRY_FAILURES;
const LPCTSTR k_szRegTransportKey = TEXT("Software\\Microsoft\\Obex\\Transports");
const LPCTSTR k_szRegObex = TEXT("Software\\Microsoft\\Obex");
BOOL setKeyAndValue(const WCHAR * pszPath, const WCHAR * szSubkey, const WCHAR * szValue);
BOOL setValueInKey(const WCHAR * szKey, const WCHAR * szNamedValue, const WCHAR * szValue);
HRESULT CLSIDtochar(REFCLSID clsid, WCHAR * szCLSID, unsigned int length);
LONG recursiveDeleteKey(HKEY hKeyParent, const WCHAR * szKeyChild);
HRESULT RegisterServer(const WCHAR * szModuleName, // DLL module handle
REFCLSID clsid, // Class ID
const WCHAR * szFriendlyName, // Friendly Name
const WCHAR * szVerIndProgID, // Programmatic
const WCHAR * szProgID, // IDs
const WCHAR * szThreadingModel); // ThreadingModel
LONG UnregisterServer(REFCLSID clsid, // Class ID
const WCHAR * szVerIndProgID, // Programmatic
const WCHAR * szProgID); // IDs
const int CLSID_STRING_SIZE = 39;
static CObexIRDATransport *g_pIRDATransport = 0;
static CObexBTHTransport *g_pBTHTransport = 0;
long g_cComponents = 0;
long g_cServerLocks = 0;
BOOL GetLock()
{
PREFAST_ASSERT(gpSynch);
SVSUTIL_ASSERT(!gpSynch->IsLocked());
gpSynch->Lock();
if ((!g_pObex) || (!g_pObex->IsInitialized()))
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"GetLock::No valid IObex interface\n"));
gpSynch->Unlock();
return FALSE;
}
return TRUE;
}
void ReleaseLock()
{
SVSUTIL_ASSERT(gpSynch);
SVSUTIL_ASSERT(gpSynch->IsLocked());
gpSynch->Unlock();
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CObex::CObex() : _refCount(1)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::CObex()\n"));
InterlockedIncrement (&g_cComponents);
_bStopEnum = FALSE;
_pDevices = NULL;
_pConnPt = NULL;
_stage = Stopped;
_fPause = FALSE;
_pActiveTransports = NULL;
//enumeration thead
_uiRunningENumThreadCnt = 0; //<-- num of STILL running enum threads
_uiEnumThreadCnt = 0; //<--total enum threads (some might have exited)
_hEnumPauseEvent = NULL;
_hEnumPauseEvent_UnlockPauseFunction = NULL;
//number of times enumeration has been requested
_uiDeviceEnumCnt = 0;
//number of times we've been inited
_uiInitCnt = 0;
}
CObex::~CObex()
{
SVSUTIL_ASSERT(_refCount == 0);
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::~CObex()\n"));
PREFAST_ASSERT(gpSynch);
SVSUTIL_ASSERT(NULL == _pActiveTransports);
gpSynch->Lock();
if (g_pBTHTransport)
{
g_pBTHTransport->Release();
g_pBTHTransport = NULL;
}
if (g_pIRDATransport)
{
g_pIRDATransport->Release();
g_pIRDATransport = NULL;
}
if (_pDevices)
{
_pDevices->Release();
_pDevices = NULL;
}
g_pObex = NULL;
gpSynch->Unlock();
InterlockedDecrement (&g_cComponents);
}
HRESULT STDMETHODCALLTYPE
CObex::SetCaps(DWORD dwCaps)
{
g_dwObexCaps = dwCaps;
return S_OK;
}
HRESULT STDMETHODCALLTYPE
CObex::Initialize()
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::Initialize()\n"));
HRESULT hr = E_FAIL;
SVSUTIL_ASSERT(!gpSynch->IsLocked());
gpSynch->Lock();
if (_stage == ShuttingDown)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::Initialize FAILS....ShuttingDown()\n"));
return E_FAIL; //<--dont goto Done since that will clean up memory!
}
if (_stage == Initialized)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::Initialize....Already Initialized\n"));
//inc the initialization ref count
_uiInitCnt++;
hr = S_OK;
goto Done;
}
// load the # of times to retry IRDA from the registry
g_uiIRDAMaxRetries = 3;
HKEY hk;
if (ERROR_SUCCESS == RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"software\\microsoft\\obex", 0, KEY_READ, &hk)) {
DWORD dw = 0;
DWORD dwType = REG_DWORD;
DWORD dwSize = sizeof(dw);
if (ERROR_SUCCESS == RegQueryValueEx (hk, L"IRDARetries", NULL, &dwType, (LPBYTE)&dw, &dwSize)) {
if ((dwType == REG_DWORD) && (dwSize == sizeof(dw)) && (dw > 0) && (((int)dw) > 0)) {
g_uiIRDAMaxRetries = (UINT)dw;
}
}
RegCloseKey (hk);
}
ASSERT(NULL == _hEnumPauseEvent);
if(NULL == (_hEnumPauseEvent = CreateEvent(NULL, TRUE, TRUE, NULL))) {
hr = E_FAIL;
goto Done;
}
ASSERT(NULL == _hEnumPauseEvent_UnlockPauseFunction);
if(NULL == (_hEnumPauseEvent_UnlockPauseFunction = CreateEvent(NULL, FALSE, FALSE, NULL))) {
hr = E_FAIL;
goto Done;
}
SVSUTIL_ASSERT(_pConnPt == NULL);
if (NULL == (_pConnPt = new CConnectionPoint((IConnectionPointContainer *)this)))
{
hr = E_OUTOFMEMORY;
goto Done;
}
SVSUTIL_ASSERT(_uiEnumThreadCnt == NULL);
SVSUTIL_ASSERT(_bStopEnum == FALSE);
//inc the initialization ref count, set stage
_stage = Initialized;
_uiInitCnt++;
hr = S_OK;
Done:
if(FAILED(hr)) {
if(_pConnPt)
_pConnPt->Release();
if(_hEnumPauseEvent)
CloseHandle(_hEnumPauseEvent);
if(_hEnumPauseEvent_UnlockPauseFunction)
CloseHandle(_hEnumPauseEvent_UnlockPauseFunction);
_pConnPt = NULL;
_hEnumPauseEvent = NULL;
}
//unlock and return
SVSUTIL_ASSERT(gpSynch->IsLocked());
gpSynch->Unlock();
return hr;
}
HRESULT STDMETHODCALLTYPE
CObex::Shutdown()
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::Shutdown()\n"));
//make sure we are not paused
PauseDeviceEnum(FALSE);
gpSynch->Lock();
if (_stage != Initialized)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::Shutdown:ERROR_SERVICE_NOT_ACTIVE()\n"));
gpSynch->Unlock();
return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WINDOWS, ERROR_SERVICE_NOT_ACTIVE);
}
//dec the increment ref count
_uiInitCnt --;
//if we are still referenced, dont delete! just return OK
if(_uiInitCnt)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::Shutdown: initilization refcount(%d)\n", _uiInitCnt));
gpSynch->Unlock();
return S_OK;
}
//if we are no longer referenced, start the shutdown process
_stage = ShuttingDown;
if (_uiEnumThreadCnt)
{
_bStopEnum = TRUE;
gpSynch->Unlock();
//
//wait for all threads to exit (they get the _bStopEnum flag and quit)
//
for(UINT i=0; i<_uiEnumThreadCnt; i++)
{
DWORD waitRet = WaitForSingleObject(_hEnumThreadArray[i], INFINITE);
CloseHandle(_hEnumThreadArray[i]);
SVSUTIL_ASSERT(WAIT_FAILED != waitRet);
if(WAIT_FAILED == waitRet)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::WaitForMultipleObject on thread failed: %x\n", GetLastError()));
return E_FAIL;
}
else
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::WaitForMultipleObject thread %d down\n", i));
}
}
gpSynch->Lock();
_uiEnumThreadCnt = 0;
}
//kill the pause event (think of a cattle gate)
ASSERT(_hEnumPauseEvent);
if(_hEnumPauseEvent) {
CloseHandle(_hEnumPauseEvent);
_hEnumPauseEvent = NULL;
}
ASSERT(_hEnumPauseEvent_UnlockPauseFunction);
if(_hEnumPauseEvent_UnlockPauseFunction) {
CloseHandle(_hEnumPauseEvent_UnlockPauseFunction);
_hEnumPauseEvent_UnlockPauseFunction = NULL;
}
PREFAST_ASSERT(_pConnPt);
_pConnPt->ContainerReleased();
((IConnectionPoint*)_pConnPt)->Release();
_pConnPt = NULL;
if (_pDevices)
{
_pDevices->Release();
_pDevices = NULL;
}
_stage = Stopped;
gpSynch->Unlock();
return S_OK;
}
HRESULT
CObex::IsCorpse(DEVICE_PROPBAG_LIST *pDeviceCorpses, LPPROPERTYBAG2 pBag, BOOL *isCorpse)
{
//
// See if this device has already been found not to have OBEX
//
HRESULT hr;
DEVICE_PROPBAG_LIST *pTemp = pDeviceCorpses;
VARIANT varDev1Address;
VARIANT varDev2Address;
VariantInit(&varDev1Address);
VariantInit(&varDev2Address);
hr = pBag->Read(c_szDevicePropAddress, &varDev1Address, NULL);
if(FAILED(hr))
{
return hr;
}
BOOL bHasBeenCorpsed = FALSE;
while(pTemp)
{
PREFAST_ASSERT(pTemp->pBag);
if(FAILED((hr = pTemp->pBag->Read(c_szDevicePropAddress, &varDev2Address, NULL))))
{
VariantClear(&varDev1Address);
return hr;
}
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumIndividualDevicesThread -- checking for corpse!\n"));
if(varDev1Address.vt == varDev2Address.vt && varDev1Address.vt == VT_BSTR)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L" Checking: %s to %s\n", varDev1Address.bstrVal, varDev2Address.bstrVal));
}
bHasBeenCorpsed =
(
((varDev1Address.vt == VT_I4) && (varDev1Address.vt == varDev2Address.vt) && (varDev1Address.lVal == varDev2Address.lVal)) ||
((varDev1Address.vt == VT_BSTR) && (varDev1Address.vt == varDev2Address.vt) && (0 == wcscmp(varDev1Address.bstrVal, varDev2Address.bstrVal)))
);
DEBUGMSG(OBEX_COBEX_ZONE,(L" %s\n", bHasBeenCorpsed ? L"CORPSE" : L"NOT CORPSE"));
VariantClear(&varDev2Address);
//if a corpse has been found, skip this device
if(bHasBeenCorpsed)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CObex::EnumIndividualDevicesThread - Corpse found for device -- skipping!\n"));
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -