/******************************************************************************* * * (C) COPYRIGHT MICROSOFT CORP., 1998 * * TITLE: IDrvItem.Cpp * * VERSION: 2.0 * * AUTHOR: marke * * DATE: 30 Aug, 1998 * * DESCRIPTION: * Implementation of the WIA test camera item methods. * *******************************************************************************/ #include "precomp.h" #include "stiexe.h" #include "linklist.h" #include "wiamindr.h" #include "ienumitm.h" #include "helpers.h" #include "lockmgr.h" VOID WINAPI FreeDrvItemContextCallback(VOID *pData); VOID WINAPI ReleaseDrvItemCallback(VOID *pData); /**************************************************************************\ * CWiaDrvItem::QueryInterface * * Standard COM method. * * Arguments: * * iid - Interface ID to query * ppv - Pointer to returned interface. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::QueryInterface(const IID& iid, void** ppv) { *ppv = NULL; if ((iid == IID_IUnknown) || (iid == IID_IWiaDrvItem)) { *ppv = (IWiaDrvItem*) this; } else { return E_NOINTERFACE; } AddRef(); return (S_OK); } ULONG _stdcall CWiaDrvItem::AddRef() { InterlockedIncrement((long*) &m_cRef); return m_cRef; } ULONG _stdcall CWiaDrvItem::Release() { ULONG ulRefCount = m_cRef - 1; if (InterlockedDecrement((long*) &m_cRef) == 0) { delete this; return 0; } return ulRefCount; } /**************************************************************************\ * CWiaDrvItem * * CWiaDrvItem constructor. * * Arguments: * * None * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ CWiaDrvItem::CWiaDrvItem() { m_ulSig = CWIADRVITEM_SIG; m_cRef = 0; m_pbDrvItemContext = NULL; m_pIWiaMiniDrv = NULL; m_pCWiaTree = NULL; m_pActiveDevice = NULL; InitializeListHead(&m_leAppItemListHead); } /**************************************************************************\ * Initialize * * Initializ a new CWiaDrvItem. * * Arguments: * * lFlags - Object flags for new item. * bstrItemName - Item name. * bstrFullItemName - Full item name, including path. * pIWiaMiniDrv - Pointer to the device object. * cbDevSpecContext - Number of bytes to allocate for device * specific context. * ppDevSpecContext - Pointer to returned device specific context. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::Initialize( LONG lFlags, BSTR bstrItemName, BSTR bstrFullItemName, IWiaMiniDrv *pIWiaMiniDrv, LONG cbDevSpecContext, BYTE **ppDevSpecContext ) { DBG_FN(CWiaDrvItem::Initialize); DBG_TRC(("CWiaDrvItem::Initialize: 0x%08X, %S", this, bstrItemName)); HRESULT hr = S_OK; if (pIWiaMiniDrv == NULL) { DBG_ERR(("CWiaDrvItem::Initialize, bad pIWiaMiniDrv parameter")); return E_INVALIDARG; } m_pCWiaTree = new CWiaTree; if (m_pCWiaTree) { hr = m_pCWiaTree->Initialize(lFlags, bstrItemName, bstrFullItemName, (void*)this); if (SUCCEEDED(hr)) { m_pIWiaMiniDrv = pIWiaMiniDrv; // // alloc device specific context // if (cbDevSpecContext > 0) { hr = AllocDeviceSpecContext(cbDevSpecContext, ppDevSpecContext); } } if (FAILED(hr)) { delete m_pCWiaTree; m_pCWiaTree = NULL; } } else { DBG_ERR(("CWiaDrvItem::Initialize, new CWiaTree failed")); hr = E_OUTOFMEMORY; } return hr; } /**************************************************************************\ * ~CWiaDrvItem * * CWiaDrvItem destructor * * Arguments: * * None * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ CWiaDrvItem::~CWiaDrvItem() { DBG_TRC(("CWiaDrvItem::~CWiaDrvItem, (destroy)")); // // Release the backing tree item. // if (m_pCWiaTree) { delete m_pCWiaTree; m_pCWiaTree = NULL; } // // free device driver references // if (m_pbDrvItemContext != NULL) { FreeDrvItemContextCallback((VOID*)this); // DBG_ERR(("CWiaDrvItem destroy, device specific context not empty")); } // // Unlink the app item list. // LIST_ENTRY *pEntry; PAPP_ITEM_LIST_EL pElem; while (!IsListEmpty(&m_leAppItemListHead)) { pEntry = RemoveHeadList(&m_leAppItemListHead); if (pEntry) { pElem = CONTAINING_RECORD( pEntry, APP_ITEM_LIST_EL, ListEntry ); if (pElem) { LocalFree(pElem); } } } // // clear all members // if (m_pActiveDevice) { // // If the ACTIVE_DEVICE is pointing to us, make sure // we set its Driver Item pointer to NULL since we're going away... // if (m_pActiveDevice->m_pRootDrvItem == this) { m_pActiveDevice->SetDriverItem(NULL); } m_pActiveDevice = NULL; } m_ulSig = 0; m_pbDrvItemContext = NULL; m_pIWiaMiniDrv = NULL; } /**************************************************************************\ * CWiaDrvItem::AddItemToFolder * * Add a CWiaDrvItem to the driver item tree. * * Arguments: * * pIParent - Parent of the driver item. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::AddItemToFolder(IWiaDrvItem *pIParent) { DBG_FN(CWiaDrvItem::AddItemToFolder); HRESULT hr = S_OK; if (!pIParent) { DBG_ERR(("CWiaDrvItem::AddItemToFolder, NULL parent")); return E_INVALIDARG; } // // Get temporary parent object. // CWiaDrvItem *pParent = (CWiaDrvItem *)pIParent; // // Use tree method to add item. // hr = m_pCWiaTree->AddItemToFolder(pParent->m_pCWiaTree); if (SUCCEEDED(hr)) { // // Inc ref count of this (child) item since we're giving out // a reference for it to parent. // this->AddRef(); // // If the parent of this drv item has corresponding app items, // run down the list and add a new child app item to each tree. // { CWiaCritSect CritSect(&g_semDeviceMan); PLIST_ENTRY pEntry = pParent->m_leAppItemListHead.Flink; while (pEntry != &pParent->m_leAppItemListHead) { PAPP_ITEM_LIST_EL pElem; pElem = CONTAINING_RECORD(pEntry, APP_ITEM_LIST_EL, ListEntry); CWiaItem *pCWiaItem = pElem->pCWiaItem; hr = pCWiaItem->UpdateWiaItemTree(ADD_ITEM, this); if (FAILED(hr)) { break; } pEntry = pEntry->Flink; } } } return hr; } /**************************************************************************\ * RemoveItemFromFolder * * Remove a CWiaDrvItem from the driver item tree and mark it so that * no device access can be done through it. * * Arguments: * * lReason - Reason for removal of CWiaDrvItem. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::RemoveItemFromFolder(LONG lReason) { DBG_FN(CWiaDrvItem::RemoveItemFromFolder); HRESULT hr = S_OK; // // Use tree method to remove item. // hr = m_pCWiaTree->RemoveItemFromFolder(lReason); if (SUCCEEDED(hr)) { // // If this drv item has corresponding app items, run down the // list and unlink the app item from each tree. // { CWiaCritSect CritSect(&g_semDeviceMan); PLIST_ENTRY pEntry = m_leAppItemListHead.Flink; while (pEntry != &m_leAppItemListHead) { PAPP_ITEM_LIST_EL pElem; pElem = CONTAINING_RECORD(pEntry, APP_ITEM_LIST_EL, ListEntry); CWiaItem *pCWiaItem = pElem->pCWiaItem; pCWiaItem->UpdateWiaItemTree(DELETE_ITEM, this); pEntry = pEntry->Flink; } } // // Free device specific context. // FreeDrvItemContextCallback((VOID*)this); } // // release reference // this->Release(); return S_OK; } HRESULT _stdcall CWiaDrvItem::CallDrvUninitializeForAppItems( ACTIVE_DEVICE *pActiveDevice) { // // If this drv item has corresponding app items, run down the // list and call drvUnInitializeWia for each App. Item. // if (pActiveDevice) { PLIST_ENTRY pEntry = m_leAppItemListHead.Flink; while (pEntry != &m_leAppItemListHead) { PLIST_ENTRY pEntryNext = pEntry->Flink; PAPP_ITEM_LIST_EL pElem; pElem = CONTAINING_RECORD(pEntry, APP_ITEM_LIST_EL, ListEntry); CWiaItem *pCWiaItem = pElem->pCWiaItem; HRESULT hr = E_FAIL; LONG lDevErrVal = 0; if (pCWiaItem) { // // Only call drvUninitializeWia if it has not been called for this item // already... // if (!(pCWiaItem->m_lInternalFlags & ITEM_FLAG_DRV_UNINITIALIZE_THROWN)) { hr = g_pStiLockMgr->RequestLock(pActiveDevice, WIA_LOCK_WAIT_TIME, FALSE); if(SUCCEEDED(hr)) { hr = pActiveDevice->m_DrvWrapper.WIA_drvUnInitializeWia((BYTE*)pCWiaItem); if (FAILED(hr)) { DBG_WRN(("CWiaDrvItem::CallDrvUninitializeForAppItems, drvUnitializeWia failed")); } pCWiaItem->m_lInternalFlags |= ITEM_FLAG_DRV_UNINITIALIZE_THROWN; g_pStiLockMgr->RequestUnlock(pActiveDevice, FALSE); } } } pEntry = pEntryNext; } DBG_TRC(("Done calling drvUnInitializeWia for all items...")); } else { ASSERT(("CWiaDrvItem::CallDrvUninitializeForAppItems , called with NULL - this should never happen!", pActiveDevice)); } // // We don't care what happened - always return S_OK // return S_OK; } /**************************************************************************\ * GetDeviceSpecContext * * Get the device specific context from a driver item. * * Arguments: * * ppSpecContext - Pointer to a pointer to receive the device * specific context pointer. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::GetDeviceSpecContext(PBYTE *ppSpecContext) { DBG_FN(CWiaDrvItem::GetDeviceSpecContext); if (ppSpecContext == NULL) { DBG_ERR(("GetDeviceSpecContext, NULL ppSpecContext pointer")); return E_POINTER; } *ppSpecContext = m_pbDrvItemContext; if (!m_pbDrvItemContext) { DBG_ERR(("GetDeviceSpecContext, NULL device specific context")); return E_INVALIDARG; } return S_OK; } /**************************************************************************\ * AllocDeviceSpecContext * * Allocate the device specific context from a driver item. * * Arguments: * * cbDevSpecContext - Number of bytes to allocate for device * specific context. * ppDevSpecContext - Pointer to returned device specific context. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::AllocDeviceSpecContext( LONG cbSize, PBYTE *ppSpecContext) { DBG_FN(CWiaDrvItem::AllocDeviceSpecContext); // // validate size, may want to set max // if ((cbSize < 0) || (cbSize > WIA_MAX_CTX_SIZE)) { DBG_ERR(("CWiaDrvItem::AllocDeviceSpecContext, request > WIA_MAX_CTX_SIZE")); return E_INVALIDARG; } // // if a spec context already exists then fail // if (m_pbDrvItemContext != NULL) { DBG_ERR(("CWiaDrvItem::AllocDeviceSpecContext, Context already exists!")); return E_INVALIDARG; } // // attempt to alloc // m_pbDrvItemContext = (PBYTE)LocalAlloc(LPTR, cbSize); if (m_pbDrvItemContext == NULL) { DBG_ERR(("CWiaDrvItem::AllocDeviceSpecContext, unable to allocate %d bytes", cbSize)); return E_OUTOFMEMORY; } // // return ctx if pointer supplied // if (ppSpecContext != NULL) { *ppSpecContext = m_pbDrvItemContext; } return S_OK; } /**************************************************************************\ * FreeDeviceSpecContext * * Free device specific context * * Arguments: * * None * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::FreeDeviceSpecContext(void) { DBG_FN(CWiaDrvItem::FreeDeviceSpecContext); if (m_pbDrvItemContext != NULL) { LocalFree(m_pbDrvItemContext); m_pbDrvItemContext = NULL; } return S_OK; } /**************************************************************************\ * GetItemFlags * * Return the driver item flags. * * Arguments: * * plFlags - Pointer to a value to receive the driver item flags. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::GetItemFlags(LONG *plFlags) { DBG_FN(CWiaDrvItem::GetItemFlags); return m_pCWiaTree->GetItemFlags(plFlags); } /**************************************************************************\ * LinkToDrvItem * * Adds the passed in CWiaItem to the driver items list of corresponding * application items. * * Arguments: * * pCWiaItem - Pointer to application item. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::LinkToDrvItem(CWiaItem *pCWiaItem) { DBG_FN(CWiaDrvItem::LinkToDrvItem); CWiaCritSect CritSect(&g_semDeviceMan); PAPP_ITEM_LIST_EL pElem; pElem = (PAPP_ITEM_LIST_EL) LocalAlloc(0, sizeof(APP_ITEM_LIST_EL)); if (pElem) { pElem->pCWiaItem = pCWiaItem; InsertHeadList(&m_leAppItemListHead, &pElem->ListEntry); return S_OK; } else { DBG_ERR(("CWiaDrvItem::LinkToDrvItem alloc of APP_ITEM_LIST_EL failed")); return E_OUTOFMEMORY; } } /**************************************************************************\ * UnlinkFromDrvItem * * Removes the passed in CWiaItem from the driver items list of * corresponding application items. * * Arguments: * * pCWiaItem - Pointer to application item. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::UnlinkFromDrvItem(CWiaItem *pCWiaItem) { DBG_FN(CWiaDrvItem::UnlinkFromDrvItem); CWiaCritSect CritSect(&g_semDeviceMan); PLIST_ENTRY pEntry = m_leAppItemListHead.Flink; while (pEntry != &m_leAppItemListHead) { PAPP_ITEM_LIST_EL pElem; pElem = CONTAINING_RECORD(pEntry, APP_ITEM_LIST_EL, ListEntry); if (pElem->pCWiaItem == pCWiaItem) { RemoveEntryList(pEntry); LocalFree(pElem); return S_OK; } pEntry = pEntry->Flink; } DBG_ERR(("CWiaDrvItem::UnlinkFromDrvItem, app item not found: 0x%08X", pCWiaItem)); return S_FALSE; } /**************************************************************************\ * CWiaDrvItem::GetFullItemName * * Allocates and fills in a BSTR with this items full name. The full item * name includes item path information. * * Arguments: * * pbstrFullItemName - Pointer to returned full item name. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::GetFullItemName(BSTR *pbstrFullItemName) { DBG_FN(CWiaDrvItem::GetFullItemName); return m_pCWiaTree->GetFullItemName(pbstrFullItemName); } /**************************************************************************\ * CWiaDrvItem::GetItemName * * Allocates and fills in a BSTR with this items name. The item name * does not include item path information. * * Arguments: * * pbstrItemName - Pointer to returned item name. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::GetItemName(BSTR *pbstrItemName) { DBG_FN(CWiaDrvItem::GetItemName); return m_pCWiaTree->GetItemName(pbstrItemName); } /**************************************************************************\ * CWiaDrvItem::DumpItemData * * Allocate buffer and dump formatted private CWiaDrvItem data into it. * This method is debug only. Free component returns E_NOTIMPL. * * Arguments: * * bstrDrvItemData - Pointer to allocated buffer. Caller must free. * * Return Value: * * Status * * History: * * 1/19/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::DumpItemData(BSTR *bstrDrvItemData) { DBG_FN(CWiaDrvItem::DumpItemData); #ifdef ITEMDEBUG #define TREE_BUF_SIZE 1024 #define BUF_SIZE 512 + TREE_BUF_SIZE #define LINE_SIZE 128 WCHAR szTemp[BUF_SIZE], szTreeTmp[TREE_BUF_SIZE]; LPOLESTR psz = szTemp; wcscpy(szTemp, L""); psz+= wsprintfW(psz, L"Drv item, CWiaDrvItem: %08X\r\n\r\n", this); psz+= wsprintfW(psz, L"Address Member Value\r\n"); psz+= wsprintfW(psz, L"%08X m_ulSig: %08X\r\n", &m_ulSig, m_ulSig); psz+= wsprintfW(psz, L"%08X m_cRef: %08X\r\n", &m_cRef, m_cRef); psz+= wsprintfW(psz, L"%08X m_pIWiaMiniDrv: %08X\r\n", &m_pIWiaMiniDrv, m_pIWiaMiniDrv); psz+= wsprintfW(psz, L"%08X m_pbDrvItemContext: %08X\r\n", &m_pbDrvItemContext, m_pbDrvItemContext); psz+= wsprintfW(psz, L"%08X m_leAppItemListHead:%08X\r\n", &m_leAppItemListHead,m_leAppItemListHead); psz+= wsprintfW(psz, L"\r\n"); BSTR bstrTree; HRESULT hr = m_pCWiaTree->DumpTreeData(&bstrTree); if (SUCCEEDED(hr)) { psz+= wsprintfW(psz, L"%ls", bstrTree); SysFreeString(bstrTree); } psz+= wsprintfW(psz, L"\r\n"); if (psz > (szTemp + (BUF_SIZE - LINE_SIZE))) { DBG_ERR(("CWiaDrvItem::DumpDrvItemData buffer too small")); } if (bstrDrvItemData) { *bstrDrvItemData = SysAllocString(szTemp); if (*bstrDrvItemData) { return S_OK; } } return E_OUTOFMEMORY; #else return E_NOTIMPL; #endif } /**************************************************************************\ * CWiaDrvItem::UnlinkItemTree * * This method unlinks the tree. Must be called on the root * driver item. * * Arguments: * * lReason - Reason for unlinking the tree. * * Return Value: * * Status * * History: * * 1/21/1999 Original Version * \**************************************************************************/ HRESULT _stdcall CWiaDrvItem::UnlinkItemTree(LONG lReason) { DBG_FN(CWiaDrvItem::UnlinkItemTree); // // AddRef this item, since ReleaseDrvItemCallback will call release // and we don't want to destroy this object. // AddRef(); return m_pCWiaTree->UnlinkItemTree(lReason, (PFN_UNLINK_CALLBACK)ReleaseDrvItemCallback); } /**************************************************************************\ * CWiaDrvItem::FindItemByName * * Locate a driver item by it's full item name. * * Arguments: * * lFlags - Operation flags. * bstrFullItemName - Requested item name. * ppItem - Pointer to returned item, if found. * * Return Value: * * Status * * History: * * 1/27/1999 Original Version * \**************************************************************************/ HRESULT CWiaDrvItem::FindItemByName( LONG lFlags, BSTR bstrFullItemName, IWiaDrvItem **ppItem) { DBG_FN(CWiaDrvItem::FindItemByName); if (ppItem) { *ppItem = NULL; } else { DBG_ERR(("CWiaDrvItem::FindItemByName NULL ppItem")); return E_INVALIDARG; } CWiaTree *pCWiaTree; HRESULT hr = m_pCWiaTree->FindItemByName(lFlags, bstrFullItemName, &pCWiaTree); if (hr == S_OK) { pCWiaTree->GetItemData((void**)ppItem); if (*ppItem) { (*ppItem)->AddRef(); } } return hr; } /**************************************************************************\ * CWiaDrvItem::FindChildItemByName * * Locate a child item by it's item name. * * Arguments: * * bstrItemName - Requested item name. * ppIChildItem - Pointer to returned item, if found. * * Return Value: * * Status * * History: * * 1/27/1999 Original Version * \**************************************************************************/ HRESULT CWiaDrvItem::FindChildItemByName( BSTR bstrItemName, IWiaDrvItem **ppIChildItem) { DBG_FN(CWiaDrvItem::FindChildItemName); CWiaTree *pCWiaTree; HRESULT hr = m_pCWiaTree->FindChildItemByName(bstrItemName, &pCWiaTree); if (hr == S_OK) { hr = pCWiaTree->GetItemData((void**)ppIChildItem); if ((hr == S_OK) && (*ppIChildItem)) { (*ppIChildItem)->AddRef(); } } return hr; } /**************************************************************************\ * CWiaDrvItem::GetParent * * Get parent of this item. * * Arguments: * * ppIParentItem - Pointer to returned parent, if found. * * Return Value: * * Status * * History: * * 1/27/1999 Original Version * \**************************************************************************/ HRESULT CWiaDrvItem::GetParentItem(IWiaDrvItem **ppIParentItem) { DBG_FN(CWiaDrvItem::GetParentItem); CWiaTree *pCWiaTree; HRESULT hr = m_pCWiaTree->GetParentItem(&pCWiaTree); if (hr == S_OK) { pCWiaTree->GetItemData((void**)ppIParentItem); } else { *ppIParentItem = NULL; } return hr; } /**************************************************************************\ * CWiaDrvItem::GetFirstChild * * Return the first child item of this folder. * * Arguments: * * ppIChildItem - Pointer to returned child item, if found. * * Return Value: * * Status * * History: * * 1/27/1999 Original Version * \**************************************************************************/ HRESULT CWiaDrvItem::GetFirstChildItem(IWiaDrvItem **ppIChildItem) { DBG_FN(CWiaDrvItem::GetFirstChildItem); CWiaTree *pCWiaTree; HRESULT hr = m_pCWiaTree->GetFirstChildItem(&pCWiaTree); if (hr == S_OK) { pCWiaTree->GetItemData((void**)ppIChildItem); } else { *ppIChildItem = NULL; } return hr; } /**************************************************************************\ * CWiaDrvItem::GetNextSiblingItem * * Find the next sibling of this item. * * Arguments: * * ppSiblingItem - Pointer to the returned sibling item, if found. * * Return Value: * * Status * * History: * * 1/27/1999 Original Version * \**************************************************************************/ HRESULT CWiaDrvItem::GetNextSiblingItem( IWiaDrvItem **ppSiblingItem) { DBG_FN(CWiaDrvItem::GetNextSiblingItem); CWiaTree *pCWiaTree; HRESULT hr = m_pCWiaTree->GetNextSiblingItem(&pCWiaTree); if (hr == S_OK) { pCWiaTree->GetItemData((void**)ppSiblingItem); } else { *ppSiblingItem = NULL; } return hr; } /**************************************************************************\ * FreeDrvItemContextCallback * * Callback function to free the driver item context. Called by * CWiaTree::UnlinkItemTree(...) for each node in the tree. * * Arguments: * * pData - payload data for the tree node. We know that this will be * a driver item, since only a driver item specifies this * callback (see CWiaDrvItem::UnlinkItemTree(...)) * * Return Value: * * Status * * History: * * 10/20/1998 Original Version * \**************************************************************************/ VOID WINAPI FreeDrvItemContextCallback( VOID *pData) { DBG_FN(::FreeDrvItemContextCallback); CWiaDrvItem *pDrvItem = (CWiaDrvItem*) pData; HRESULT hr = S_OK; if (pDrvItem) { // // Free device specific context, if it exists. // LONG lFlags = 0; LONG lDevErrVal; if (pDrvItem->m_pbDrvItemContext != NULL) { __try { if (pDrvItem->m_pIWiaMiniDrv) { hr = pDrvItem->m_pIWiaMiniDrv->drvFreeDrvItemContext(lFlags, pDrvItem->m_pbDrvItemContext, &lDevErrVal); } if (FAILED(hr)) { DBG_ERR(("FreeDrvItemContextCallback, drvFreeDrvItemContext failed 0x%X", hr)); } } __except(EXCEPTION_EXECUTE_HANDLER) { DBG_WRN(("FreeDrvItemContextCallback, exception calling drvFreeDrvItemContext (this is expected)")); } LocalFree(pDrvItem->m_pbDrvItemContext); pDrvItem->m_pbDrvItemContext = NULL; } else { DBG_TRC(("FreeDrvItemContextCallback, Context is NULL! Nothing to free...")); } } } VOID WINAPI ReleaseDrvItemCallback( VOID *pData) { DBG_FN(::ReleaseDrvItemCallback); CWiaDrvItem *pDrvItem = (CWiaDrvItem*) pData; HRESULT hr = S_OK; if (pDrvItem) { // // First, free the driver item context // FreeDrvItemContextCallback(pData); // // Call release on the driver item // pDrvItem->Release(); } }