|
|
/*****************************************************************************
* * (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; }
|