You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
715 lines
20 KiB
715 lines
20 KiB
/*****************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORPORATION, 1999-2000
|
|
*
|
|
* TITLE: WiaLink.cpp
|
|
*
|
|
* VERSION: 1.0
|
|
*
|
|
* AUTHOR: OrenR
|
|
*
|
|
* DATE: 2000/11/06
|
|
*
|
|
* DESCRIPTION: Establishes link between WiaVideo and the WiaVideo Driver
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// These generate 2 event names which are created in the wia video
|
|
// driver found in wia\drivers\video\usd. If you must change
|
|
// these, they MUST change in the video driver as well. Be warned,
|
|
// changing these without knowing what you are doing will lead to problems.
|
|
//
|
|
const TCHAR* EVENT_PREFIX_GLOBAL = TEXT("Global\\");
|
|
const TCHAR* EVENT_SUFFIX_TAKE_PICTURE = TEXT("_TAKE_PICTURE");
|
|
const TCHAR* EVENT_SUFFIX_PICTURE_READY = TEXT("_PICTURE_READY");
|
|
const UINT THREAD_EXIT_TIMEOUT = 1000 * 5; // 5 seconds
|
|
|
|
///////////////////////////////
|
|
// CWiaLink Constructor
|
|
//
|
|
CWiaLink::CWiaLink() :
|
|
m_pWiaVideo(NULL),
|
|
m_hTakePictureEvent(NULL),
|
|
m_hPictureReadyEvent(NULL),
|
|
m_hTakePictureThread(NULL),
|
|
m_bExitThread(FALSE),
|
|
m_bEnabled(FALSE),
|
|
m_dwWiaItemCookie(0),
|
|
m_dwPropertyStorageCookie(0)
|
|
{
|
|
DBG_FN("CWiaLink::CWiaLink");
|
|
}
|
|
|
|
///////////////////////////////
|
|
// CWiaLink Constructor
|
|
//
|
|
CWiaLink::~CWiaLink()
|
|
{
|
|
DBG_FN("CWiaLink::~CWiaLink");
|
|
|
|
if (m_bEnabled)
|
|
{
|
|
Term();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////
|
|
// Init
|
|
//
|
|
HRESULT CWiaLink::Init(const CSimpleString *pstrWiaDeviceID,
|
|
CWiaVideo *pWiaVideo)
|
|
{
|
|
DBG_FN("CWiaLink::Init");
|
|
|
|
HRESULT hr = S_OK;
|
|
CComPtr<IWiaDevMgr> pDevMgr;
|
|
CComPtr<IWiaItem> pRootItem;
|
|
|
|
ASSERT(pstrWiaDeviceID != NULL);
|
|
ASSERT(pWiaVideo != NULL);
|
|
|
|
if ((pstrWiaDeviceID == NULL) ||
|
|
(pWiaVideo == NULL))
|
|
{
|
|
hr = E_POINTER;
|
|
CHECK_S_OK2(hr, ("CWiaLink::Init, received NULL params"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
m_pWiaVideo = pWiaVideo;
|
|
m_strDeviceID = *pstrWiaDeviceID;
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CAccessLock::Init(&m_csLock);
|
|
}
|
|
|
|
//
|
|
// Create the WiaDevMgr so we can create the Wia Root Item
|
|
//
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CWiaUtil::CreateWiaDevMgr(&pDevMgr);
|
|
|
|
CHECK_S_OK2(hr, ("CWiaLink::Init, failed to Create WiaDevMgr"));
|
|
}
|
|
|
|
//
|
|
// This ensures that the WIA Video Driver is initialized and in the
|
|
// correct state.
|
|
//
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CWiaUtil::CreateRootItem(pDevMgr, pstrWiaDeviceID, &pRootItem);
|
|
|
|
CHECK_S_OK2(hr, ("CWiaLink::Init, failed to create the WIA "
|
|
"Device Root Item for WIA Device ID '%ls'",
|
|
CSimpleStringConvert::WideString(*pstrWiaDeviceID)));
|
|
}
|
|
|
|
//
|
|
// Create a Global Interface Table object. This will enable us to use
|
|
// the root item (IWiaItem pRootItem) above across any thread we wish.
|
|
// This is required because if we receive async images (as a result of a
|
|
// hardware button event), a random thread will be calling the
|
|
// WriteMultiple function on the IWiaItem object.
|
|
//
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IGlobalInterfaceTable,
|
|
(void **)&m_pGIT);
|
|
|
|
CHECK_S_OK2(hr, ("CWiaUtil::Init, failed to create "
|
|
"StdGlobalInterfaceTable used to use the IWiaItem "
|
|
"root device item across multiple threads"));
|
|
}
|
|
|
|
//
|
|
// Register the WiaItem pointer in a apartment neutral way.
|
|
//
|
|
if (hr == S_OK)
|
|
{
|
|
//
|
|
// This will AddRef the pointer so no need to add a reference
|
|
// to it.
|
|
//
|
|
hr = m_pGIT->RegisterInterfaceInGlobal(pRootItem,
|
|
IID_IWiaItem,
|
|
&m_dwWiaItemCookie);
|
|
|
|
}
|
|
|
|
//
|
|
// Register the IWiaPropertyStorage pointer in an apartment neutral way.
|
|
//
|
|
if (hr == S_OK)
|
|
{
|
|
CComQIPtr<IWiaPropertyStorage, &IID_IWiaPropertyStorage>
|
|
pProp(pRootItem);
|
|
|
|
if (pProp)
|
|
{
|
|
hr = m_pGIT->RegisterInterfaceInGlobal(
|
|
pProp,
|
|
IID_IPropertyStorage,
|
|
&m_dwPropertyStorageCookie);
|
|
}
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
m_bEnabled = TRUE;
|
|
}
|
|
|
|
//
|
|
// If we failed in initializing, cleanup anything that we created
|
|
//
|
|
if (hr != S_OK)
|
|
{
|
|
Term();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// Term
|
|
//
|
|
HRESULT CWiaLink::Term()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DBG_FN("CWiaLink::Term");
|
|
|
|
StopMonitoring();
|
|
|
|
m_strDeviceID = TEXT("");
|
|
m_bEnabled = FALSE;
|
|
|
|
|
|
if (m_pGIT)
|
|
{
|
|
CAccessLock Lock(&m_csLock);
|
|
|
|
hr = m_pGIT->RevokeInterfaceFromGlobal(m_dwWiaItemCookie);
|
|
CHECK_S_OK2(hr,
|
|
("CWiaLink::Term, failed to RevokeInterfaceFromGlobal "
|
|
"for WiaItemCookie = '%lu'",
|
|
m_dwWiaItemCookie));
|
|
|
|
hr = m_pGIT->RevokeInterfaceFromGlobal(m_dwPropertyStorageCookie);
|
|
CHECK_S_OK2(hr,
|
|
("CWiaLink::Term, failed to RevokeInterfaceFromGlobal "
|
|
"for PropertyStorageCookie = '%lu'",
|
|
m_dwPropertyStorageCookie));
|
|
}
|
|
|
|
m_pGIT = NULL;
|
|
m_dwWiaItemCookie = 0;
|
|
m_dwPropertyStorageCookie = 0;
|
|
|
|
CAccessLock::Term(&m_csLock);
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// StartMonitoring
|
|
//
|
|
HRESULT CWiaLink::StartMonitoring()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_hTakePictureEvent != NULL)
|
|
{
|
|
DBG_WRN(("CWiaLink::StartMonitoring was called but it is already "
|
|
"monitoring TAKE_PICTURE events. Why was it called again, "
|
|
"prior to 'StopMonitoring' being called?"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
m_bExitThread = FALSE;
|
|
|
|
//
|
|
// create the event that will be opened by the WIA video driver.
|
|
//
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CreateWiaEvents(&m_hTakePictureEvent,
|
|
&m_hPictureReadyEvent);
|
|
|
|
CHECK_S_OK2(hr,
|
|
("CWiaLink::Init, failed to Create WIA Take "
|
|
"Picture Events"));
|
|
}
|
|
|
|
//
|
|
// Tell the WIA driver to enable the TAKE_PICTURE command.
|
|
//
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
CComPtr<IWiaItem> pRootItem;
|
|
|
|
hr = GetDevice(&pRootItem);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
CComPtr<IWiaItem> pUnused;
|
|
|
|
hr = pRootItem->DeviceCommand(0,
|
|
&WIA_CMD_ENABLE_TAKE_PICTURE,
|
|
&pUnused);
|
|
|
|
CHECK_S_OK2(hr, ("CWiaLink::StartMonitoring, failed to send "
|
|
"ENABLE_TAKE_PICTURE command to Wia Video "
|
|
"Driver"));
|
|
}
|
|
}
|
|
|
|
// Start the thread, waiting on the "TakePicture" event.
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
DWORD dwThreadID = 0;
|
|
|
|
DBG_TRC(("CWiaLink::Init, creating TAKE_PICTURE thread..."));
|
|
|
|
m_hTakePictureThread = CreateThread(NULL,
|
|
0,
|
|
CWiaLink::StartThreadProc,
|
|
reinterpret_cast<void*>(this),
|
|
0,
|
|
&dwThreadID);
|
|
|
|
if (m_hTakePictureThread == NULL)
|
|
{
|
|
hr = E_FAIL;
|
|
CHECK_S_OK2(hr,
|
|
("CWiaLink::Init, failed to create thread to wait "
|
|
"for take picture events from the wia video "
|
|
"driver, last error = %lu", GetLastError()));
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// StopMonitoring
|
|
//
|
|
HRESULT CWiaLink::StopMonitoring()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (m_hTakePictureThread)
|
|
{
|
|
DWORD dwThreadResult = 0;
|
|
|
|
m_bExitThread = TRUE;
|
|
SetEvent(m_hTakePictureEvent);
|
|
|
|
dwThreadResult = WaitForSingleObject(m_hTakePictureThread,
|
|
THREAD_EXIT_TIMEOUT);
|
|
|
|
if (dwThreadResult != WAIT_OBJECT_0)
|
|
{
|
|
DBG_WRN(("CWiaLink::Term, timed out waiting for take picture "
|
|
"thread to terminate, continuing anyway..."));
|
|
}
|
|
|
|
//
|
|
// Tell the WIA driver to disable the TAKE_PICTURE command.
|
|
//
|
|
if (m_dwWiaItemCookie)
|
|
{
|
|
CComPtr<IWiaItem> pRootItem;
|
|
|
|
hr = GetDevice(&pRootItem);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
CComPtr<IWiaItem> pUnused;
|
|
|
|
hr = pRootItem->DeviceCommand(0,
|
|
&WIA_CMD_DISABLE_TAKE_PICTURE,
|
|
&pUnused);
|
|
|
|
CHECK_S_OK2(hr, ("CWiaLink::StopMonitoring, failed to send "
|
|
"DISABLE_TAKE_PICTURE command to Wia Video "
|
|
"Driver"));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close the Take Picture Event Handles.
|
|
//
|
|
if (m_hTakePictureEvent)
|
|
{
|
|
CloseHandle(m_hTakePictureEvent);
|
|
m_hTakePictureEvent = NULL;
|
|
}
|
|
|
|
if (m_hPictureReadyEvent)
|
|
{
|
|
CloseHandle(m_hPictureReadyEvent);
|
|
m_hPictureReadyEvent = NULL;
|
|
}
|
|
|
|
if (m_hTakePictureThread)
|
|
{
|
|
CloseHandle(m_hTakePictureThread);
|
|
m_hTakePictureThread = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////
|
|
// CreateWiaEvents
|
|
//
|
|
HRESULT CWiaLink::CreateWiaEvents(HANDLE *phTakePictureEvent,
|
|
HANDLE *phPictureReadyEvent)
|
|
{
|
|
DBG_FN("CWiaLink::CreateWiaEvents");
|
|
|
|
HRESULT hr = S_OK;
|
|
CSimpleString strTakePictureEvent;
|
|
CSimpleString strPictureReadyEvent;
|
|
|
|
ASSERT(phTakePictureEvent != NULL);
|
|
ASSERT(phPictureReadyEvent != NULL);
|
|
|
|
if ((phTakePictureEvent == NULL) ||
|
|
(phPictureReadyEvent == NULL))
|
|
{
|
|
hr = E_POINTER;
|
|
CHECK_S_OK2(hr, ("CWiaLink::CreateWiaEvents received a NULL Param"));
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
INT iPosition = 0;
|
|
CSimpleString strModifiedDeviceID;
|
|
|
|
// Change the device ID from {6B...}\xxxx, to {6B...}_xxxx
|
|
|
|
iPosition = m_strDeviceID.ReverseFind('\\');
|
|
strModifiedDeviceID = m_strDeviceID.MakeUpper();
|
|
strModifiedDeviceID.SetAt(iPosition, '_');
|
|
|
|
//
|
|
// Generate the event names. These names contain the Device ID in
|
|
// them so that they are unique across devices.
|
|
//
|
|
strTakePictureEvent = EVENT_PREFIX_GLOBAL;
|
|
strTakePictureEvent += strModifiedDeviceID;
|
|
strTakePictureEvent += EVENT_SUFFIX_TAKE_PICTURE;
|
|
|
|
strPictureReadyEvent = EVENT_PREFIX_GLOBAL;
|
|
strPictureReadyEvent += strModifiedDeviceID;
|
|
strPictureReadyEvent += EVENT_SUFFIX_PICTURE_READY;
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
*phTakePictureEvent = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE,
|
|
FALSE,
|
|
strTakePictureEvent);
|
|
|
|
if (*phTakePictureEvent == NULL)
|
|
{
|
|
hr = E_FAIL;
|
|
CHECK_S_OK2(hr,
|
|
("CWiaLink::CreateWiaEvents, failed to create the "
|
|
"WIA event '%s', last error = %lu",
|
|
strTakePictureEvent.String(), GetLastError()));
|
|
}
|
|
else
|
|
{
|
|
DBG_TRC(("CWiaLink::CreateWiaEvents, created event '%ls'",
|
|
strTakePictureEvent.String()));
|
|
}
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
*phPictureReadyEvent = OpenEvent(EVENT_MODIFY_STATE | SYNCHRONIZE,
|
|
FALSE,
|
|
strPictureReadyEvent);
|
|
|
|
if (*phPictureReadyEvent == NULL)
|
|
{
|
|
hr = E_FAIL;
|
|
CHECK_S_OK2(hr,
|
|
("CWiaLink::CreateWiaEvents, failed to create the "
|
|
"WIA event '%s', last error = %lu",
|
|
strPictureReadyEvent.String(), GetLastError()));
|
|
}
|
|
else
|
|
{
|
|
DBG_TRC(("CWiaLink::CreateWiaEvents, created event '%ls'",
|
|
strPictureReadyEvent.String()));
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// ThreadProc
|
|
//
|
|
HRESULT CWiaLink::ThreadProc(void *pArgs)
|
|
{
|
|
DBG_FN("CWiaLink::ThreadProc");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
DBG_TRC(("CWiaLink::ThreadProc, starting TakePicture thread..."));
|
|
|
|
while (!m_bExitThread)
|
|
{
|
|
DWORD dwResult = 0;
|
|
|
|
//
|
|
// Reset our HRESULT. Just because we may have failed before,
|
|
// does not mean we will fail again.
|
|
//
|
|
hr = S_OK;
|
|
|
|
dwResult = WaitForSingleObject(m_hTakePictureEvent, INFINITE);
|
|
|
|
if (!m_bExitThread)
|
|
{
|
|
//
|
|
// The only error we can get from WaitForSingle object is
|
|
// something unexpected, since we can't timeout since we
|
|
// are waiting infinitely.
|
|
//
|
|
if (dwResult != WAIT_OBJECT_0)
|
|
{
|
|
hr = E_FAIL;
|
|
m_bExitThread = TRUE;
|
|
CHECK_S_OK2(hr,
|
|
("CWiaLink::ThreadProc, received '%lu' result "
|
|
"from WaitForSingleObject, unexpected error, "
|
|
"thread is exiting...",
|
|
dwResult));
|
|
}
|
|
else if (m_pWiaVideo == NULL)
|
|
{
|
|
hr = E_FAIL;
|
|
m_bExitThread = TRUE;
|
|
CHECK_S_OK2(hr,
|
|
("CWiaLink::ThreadProc, m_pWiaVideo is NULL, "
|
|
"cannot take picture unexpected error, thread "
|
|
"is exiting...", dwResult));
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
BSTR bstrNewImageFileName = NULL;
|
|
|
|
hr = m_pWiaVideo->TakePicture(&bstrNewImageFileName);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
CSimpleStringWide strNewImageFileName(
|
|
bstrNewImageFileName);
|
|
|
|
if (strNewImageFileName.Length() > 0)
|
|
{
|
|
SignalNewImage(
|
|
&(CSimpleStringConvert::NaturalString(
|
|
strNewImageFileName)));
|
|
}
|
|
}
|
|
|
|
if (bstrNewImageFileName)
|
|
{
|
|
SysFreeString(bstrNewImageFileName);
|
|
bstrNewImageFileName = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set this event, regardless of an error because the driver
|
|
// will be waiting for this event (with a timeout of course) to
|
|
// indicate that it can return from the TAKE_PICTURE request.
|
|
//
|
|
SetEvent(m_hPictureReadyEvent);
|
|
|
|
}
|
|
|
|
DBG_TRC(("CWiaLink::ThreadProc exiting..."));
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// StartThreadProc
|
|
//
|
|
// Static Fn.
|
|
//
|
|
DWORD WINAPI CWiaLink::StartThreadProc(void *pArgs)
|
|
{
|
|
DBG_FN("CWiaLink::StartThreadProc");
|
|
|
|
DWORD dwReturn = 0;
|
|
|
|
if (pArgs)
|
|
{
|
|
CWiaLink *pWiaLink = reinterpret_cast<CWiaLink*>(pArgs);
|
|
|
|
if (pWiaLink)
|
|
{
|
|
pWiaLink->ThreadProc(pArgs);
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("CWiaLink::StartThreadProc, invalid value for pArgs, "
|
|
"this should be the 'this' pointer, unexpected error"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG_ERR(("CWiaLink::StartThreadProc, received NULL pArgs, this "
|
|
"should be the 'this' pointer, unexpected error"));
|
|
}
|
|
|
|
return dwReturn;
|
|
|
|
}
|
|
|
|
///////////////////////////////
|
|
// SignalNewImage
|
|
//
|
|
HRESULT CWiaLink::SignalNewImage(const CSimpleString *pstrNewImageFileName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DBG_FN("CWiaLink::SignalNewImage");
|
|
|
|
//
|
|
// It is possible that this gets called by the Still Image processor if
|
|
// we get an unsolicited image (happens when you press external
|
|
// hardware button and capture filter has still pin on it).
|
|
// However, if user initialized WiaVideo so that it doesn't use
|
|
// WIA, simply ignore this request and return.
|
|
//
|
|
if (!m_bEnabled)
|
|
{
|
|
DBG_WRN(("CWiaLink::SignalNewImage was called, but WiaLink is NOT "
|
|
"enabled"));
|
|
return hr;
|
|
}
|
|
|
|
if (pstrNewImageFileName == NULL)
|
|
{
|
|
hr = E_FAIL;
|
|
CHECK_S_OK2(hr, ("CWiaLink::SignalNewImage, received NULL new image "
|
|
"file name"));
|
|
}
|
|
else if (m_dwWiaItemCookie == 0)
|
|
{
|
|
hr = E_FAIL;
|
|
CHECK_S_OK2(hr, ("CWiaLink::SignalNewImage, received WIA root "
|
|
"item not available."));
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
CComPtr<IWiaPropertyStorage> pStorage;
|
|
|
|
hr = GetDeviceStorage(&pStorage);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
hr = CWiaUtil::SetProperty(pStorage,
|
|
WIA_DPV_LAST_PICTURE_TAKEN,
|
|
pstrNewImageFileName);
|
|
|
|
CHECK_S_OK2(hr, ("CWiaLink::SignalNewImage, failed to set Last "
|
|
"Picture Taken property for Wia Video Driver"));
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// GetDevice
|
|
//
|
|
HRESULT CWiaLink::GetDevice(IWiaItem **ppWiaRootItem)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(ppWiaRootItem != NULL);
|
|
ASSERT(m_pGIT != NULL);
|
|
|
|
if ((ppWiaRootItem == NULL) ||
|
|
(m_pGIT == NULL))
|
|
{
|
|
hr = E_POINTER;
|
|
CHECK_S_OK2(hr, ("CWiaLink::GetDevice, received NULL params"));
|
|
return hr;
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
CAccessLock Lock(&m_csLock);
|
|
|
|
hr = m_pGIT->GetInterfaceFromGlobal(
|
|
m_dwWiaItemCookie,
|
|
IID_IWiaItem,
|
|
reinterpret_cast<void**>(ppWiaRootItem));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// GetDeviceStorage
|
|
//
|
|
HRESULT CWiaLink::GetDeviceStorage(IWiaPropertyStorage **ppPropertyStorage)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(ppPropertyStorage != NULL);
|
|
ASSERT(m_pGIT != NULL);
|
|
|
|
if ((ppPropertyStorage == NULL) ||
|
|
(m_pGIT == NULL))
|
|
{
|
|
hr = E_POINTER;
|
|
CHECK_S_OK2(hr, ("CWiaLink::GetDeviceStorage, received NULL params"));
|
|
return hr;
|
|
}
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
CAccessLock Lock(&m_csLock);
|
|
|
|
hr = m_pGIT->GetInterfaceFromGlobal(
|
|
m_dwPropertyStorageCookie,
|
|
IID_IWiaPropertyStorage,
|
|
reinterpret_cast<void**>(ppPropertyStorage));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|