/*++ Copyright (C) 1999- Microsoft Corporation Module Name: eventcb.cpp Abstract: This module implements CWiaPTPEventCallback class Author: William Hsieh (williamh) created Revision History: --*/ #include "pch.h" // // This method is the callback function for every PTP event // // Input: // pEvent -- PTP event block // HRESULT CWiaMiniDriver::EventCallbackDispatch( PPTP_EVENT pEvent ) { DBG_FN("CWiaMiniDriver::EventCallback"); HRESULT hr = S_OK; CPtpMutex cpm(m_hPtpMutex); if (!pEvent) { wiauDbgError("EventCallback", "invalid arg"); return E_INVALIDARG; } // // Events are not expected when there is no open session. Just ignore the event // if (!m_pPTPCamera || !m_pPTPCamera->IsCameraSessionOpen()) { wiauDbgError("EventCallback", "events not expected while there is no open session"); return E_FAIL; } // // Figure out what the event is and call the appropriate function // switch (pEvent->EventCode) { case PTP_EVENTCODE_CANCELTRANSACTION: hr = S_OK; break; case PTP_EVENTCODE_OBJECTADDED: hr = AddNewObject(pEvent->Params[0]); break; case PTP_EVENTCODE_OBJECTREMOVED: hr = RemoveObject(pEvent->Params[0]); break; case PTP_EVENTCODE_STOREADDED: hr = AddNewStorage(pEvent->Params[0]); break; case PTP_EVENTCODE_STOREREMOVED: hr = RemoveStorage(pEvent->Params[0]); break; case PTP_EVENTCODE_DEVICEPROPCHANGED: hr = DevicePropChanged((WORD) pEvent->Params[0]); break; case PTP_EVENTCODE_OBJECTINFOCHANGED: hr = ObjectInfoChanged(pEvent->Params[0]); break; case PTP_EVENTCODE_DEVICEINFOCHANGED: // WIAFIX-8/29/2000-davepar Need to handle this //hr = RebuildDrvItemTree(&DevErrVal); break; case PTP_EVENTCODE_REQUESTOBJECTTRANSFER: // // This event is ignored, because we don't know where to put the image. Maybe // it should cause a "button pushed" event. // break; case PTP_EVENTCODE_STOREFULL: hr = StorageFull(pEvent->Params[0]); break; case PTP_EVENTCODE_DEVICERESET: // WIAFIX-8/29/2000-davepar Need to handle this //hr = RebuildDrvItemTree(&DevErrVal); break; case PTP_EVENTCODE_STORAGEINFOCHANGED: hr = StorageInfoChanged(pEvent->Params[0]); break; case PTP_EVENTCODE_CAPTURECOMPLETE: hr = CaptureComplete(); break; case PTP_EVENTCODE_UNREPORTEDSTATUS: // WIAFIX-8/29/2000-davepar Need to handle this //hr = RebuildDrvItemTree(&DevErrVal); break; default: // // If it is a vendor's event, post it // if (pEvent->EventCode & PTP_DATACODE_VENDORMASK) { hr = PostVendorEvent(pEvent->EventCode); } break; } return hr; } // // This function adds a new object to the driver item tree. If a new driver // item is added, a WIA_EVENT_ITEM_CREATED event will be signaled. // // Input: // ObjectHandle -- the new object handle // HRESULT CWiaMiniDriver::AddNewObject(DWORD ObjectHandle) { DBG_FN("CWiaMiniDriver::AddNewObject"); HRESULT hr = S_OK; // // If there is a capture in progress, we need to wait until all new objects are reported, and // only then start querying imformation about them. See a sample sequence from the spec below: // // -> InitiateCapture Operation -> // <- InitiateCapture Response <- // <- ObjectAdded Event(1) <- // <- ObjectAdded Event(2) <- // <- ObjectAdded Event(n) <- // <- CaptureComplete Event <- // -> GetObjectInfo Operation(1) -> // <- ObjectInfo Dataset/Response(1) <- // -> GetObjectInfo Operation(2) -> // <- ObjectInfo Dataset/Response(2) <- // -> GetObjectInfo Operation(n) -> // <- ObjectInfo Dataset/Response(n) <- // // // Check if there is a capture in progress // DWORD dwWait = WaitForSingleObject(m_TakePictureDoneEvent, 0); // // If there is no capture in progress, process the new object immediately // if (dwWait == WAIT_OBJECT_0) { hr = AddObject(ObjectHandle, TRUE); if (FAILED(hr)) { wiauDbgError("AddNewObject", "AddObject failed"); goto Cleanup; } } // // If there is a capture in progress, add the new object's handle to the list, // all new objects will be processed once capture is finished // else if (dwWait == WAIT_TIMEOUT) { m_CapturedObjects.Add(ObjectHandle); } // // WAIT_FAILED or WAIT_ABANDONED - something's wrong // else { wiauDbgError("AddNewObject", "WaitForSingle object failed"); hr = E_FAIL; goto Cleanup; } Cleanup: return hr; } // // This function removes the given object handle from the driver item tree. // If the object handle has a driver item associated with it and the // driver item is removed, a WIA_EVENT_ITEM_REMOVED event will be signaled. // // Input: // ObjectHandle -- the object handle to be removed // HRESULT CWiaMiniDriver::RemoveObject(DWORD ObjectHandle) { DBG_FN("CWiaMiniDriver::RemoveObject"); HRESULT hr = S_OK; // // Find the driver item for the object handle. // IWiaDrvItem *pDrvItem = m_HandleItem.Lookup(ObjectHandle); if (!pDrvItem) { wiauDbgError("RemoveObject", "tried to remove object that doesn't exist"); return S_FALSE; } // // Try to remove the object from the ancillary assoc array, in case it's there too. Ancillary // association objects actually point to images in the handle/item map, so don't delete the // actual item // if (m_AncAssocParent.Remove(ObjectHandle)) { wiauDbgTrace("RemoveObject", "ancillary association object removed"); } else { BSTR bstrFullName; hr = pDrvItem->GetFullItemName(&bstrFullName); if (FAILED(hr)) { wiauDbgError("RemoveObject", "GetFullItemName failed"); return hr; } hr = pDrvItem->RemoveItemFromFolder(WiaItemTypeDisconnected); if (FAILED(hr)) { wiauDbgError("RemoveObject", "UnlinkItemTree failed"); return hr; } hr = wiasQueueEvent(m_bstrDeviceId, &WIA_EVENT_ITEM_DELETED, bstrFullName); if (FAILED(hr)) { wiauDbgError("RemoveObject", "wiasQueueEvent failed"); return hr; } SysFreeString(bstrFullName); } // // Remove the object from the handle/drvItem association // m_HandleItem.Remove(ObjectHandle); return hr; } // // This function adds a new storage to the driver item tree. // A WIA_EVENT_STORAGE_CREATED event will be singaled. // // Input: // StorageId -- the new storage id to be added // HRESULT CWiaMiniDriver::AddNewStorage(DWORD StorageId) { DBG_FN("CWiaMiniDriver::AddNewStorage"); HRESULT hr = S_OK; CArray32 StorageIdList; // // If several logical stores were added, the device may indicate // to re-enumerate the stores // if (StorageId == PTP_STORAGEID_UNDEFINED) { hr = m_pPTPCamera->GetStorageIDs(&StorageIdList); if (FAILED(hr)) { wiauDbgError("AddNewStorage", "GetStorageIDs failed"); return hr; } // // Loop through the list of new storage ids, removing the ones // that have already been enumerated // int index; for (int count = 0; count < StorageIdList.GetSize(); count++) { index = m_StorageIds.Find(StorageIdList[count]); if (index >= 0) { StorageIdList.RemoveAt(index); } } } // // Otherwise there is just one storage id to work on // else { StorageIdList.Add(StorageId); } // // Loop through all of the new storage ids // CPtpStorageInfo tempSI; for (int storageIndex = 0; storageIndex < StorageIdList.GetSize(); storageIndex++) { // // Get info for the new storage // hr = m_pPTPCamera->GetStorageInfo(StorageIdList[storageIndex], &tempSI); if (FAILED(hr)) { wiauDbgError("drvInitializeWia", "GetStorageInfo failed"); return hr; } // // Add the storage id to the main list // if (!m_StorageIds.Add(StorageIdList[storageIndex])) { wiauDbgError("AddNewStorage", "add storage id failed"); return E_OUTOFMEMORY; } // // Add storage info to array // if (!m_StorageInfos.Add(tempSI)) { wiauDbgError("drvInitializeWia", "add storage info failed"); return E_OUTOFMEMORY; } // // Add an empty entry to the DCIM handle array // ULONG dummy = 0; if (!m_DcimHandle.Add(dummy)) { wiauDbgError("AddNewStorage", "add dcim handle failed"); return E_OUTOFMEMORY; } // // Loop through all of the objects on the new storage, adding them one // at a time. // CArray32 ObjectHandleList; hr = m_pPTPCamera->GetObjectHandles(StorageIdList[storageIndex], PTP_FORMATCODE_ALL, PTP_OBJECTHANDLE_ALL, &ObjectHandleList); if (FAILED(hr)) { wiauDbgError("AddNewStorage", "GetObjectHandles failed"); return hr; } // // Iterate through the object handles, creating a WIA driver item for each // for (int objectindex = 0; objectindex < ObjectHandleList.GetSize(); objectindex++) { hr = AddObject(ObjectHandleList[objectindex], TRUE); if (FAILED(hr)) { wiauDbgError("AddNewStorage", "AddObject failed"); return hr; } } } return hr; } // // This function removes all of the objects on a storage from the // driver item tree, signalling WIA_EVENT_ITEM_DELETED as appropriate. // // Input: // StorageId -- storage to delete // HRESULT CWiaMiniDriver::RemoveStorage(DWORD StorageId) { DBG_FN("CWiaMiniDriver::RemoveStorage"); HRESULT hr = S_OK; // // If the lower 16 bits of the storage id is 0xffff, an entire physical store // was removed--match only the upper 16 bits of the storage id // DWORD StorageIdMask = PTP_STORAGEID_ALL; if ((StorageId & PTP_STORAGEID_LOGICAL) == PTP_STORAGEID_LOGICAL) { StorageIdMask = PTP_STORAGEID_PHYSICAL; StorageId &= StorageIdMask; } // // Traverse the driver item tree depth-first looking for objects that were on // the removed storage // CWiaArray ItemStack; IWiaDrvItem *pCurrent = NULL; IWiaDrvItem *pChild = NULL; IWiaDrvItem *pSibling = NULL; if (m_pDrvItemRoot) { hr = m_pDrvItemRoot->GetFirstChildItem(&pCurrent); if (FAILED(hr)) { wiauDbgError("RemoveStorage", "GetFirstChildItem failed"); return hr; } } else { wiauDbgWarning("RemoveStorage", "Tree is not built yet (m_pDrvItemRoot is NULL)"); pCurrent = NULL; } while (pCurrent) { hr = pCurrent->GetFirstChildItem(&pChild); // // GetFirstChildItem returns E_INVALIDARG if there are no child items // if (FAILED(hr) && hr != E_INVALIDARG) { wiauDbgError("RemoveStorage", "GetFirstChildItem failed"); return hr; } // // Children exist, so traverse down the tree // if (hr != E_INVALIDARG && pChild) { if (!ItemStack.Push(pCurrent)) { wiauDbgError("RemoveStorage", "memory allocation failed"); return E_OUTOFMEMORY; } pCurrent = pChild; pChild = NULL; } // // No children, so look for siblings and potentially delete the current driver item // else { // // Loop through all of the siblings // while (TRUE) { hr = pCurrent->GetNextSiblingItem(&pSibling); if (FAILED(hr)) { wiauDbgError("RemoveStorage", "GetNextSiblingItem failed"); return hr; } // // See if the item is on the storage which was removed // PDRVITEM_CONTEXT pDrvItemContext; hr = pCurrent->GetDeviceSpecContext((BYTE **) &pDrvItemContext); if (FAILED(hr)) { wiauDbgError("RemoveStorage", "GetDeviceSpecContext failed"); return hr; } if ((pDrvItemContext->pObjectInfo->m_StorageId & StorageIdMask) == StorageId) { // // Remove the item // hr = RemoveObject(pDrvItemContext->pObjectInfo->m_ObjectHandle); if (FAILED(hr)) { wiauDbgError("RemoveStorage", "RemoveObject failed"); return hr; } } // // Found a sibling, so go to the top and look for children // if (pSibling) { pCurrent = pSibling; pSibling = NULL; break; } // // No sibling, so pop up a level // else { if (ItemStack.GetSize() > 0) { if (!ItemStack.Pop(pCurrent)) { wiauDbgError("RemoveStorage", "Pop failed"); return E_FAIL; } } // // No more levels to pop, so the loop is done // else { pCurrent = NULL; break; } } } } } // // Remove the store from the appropriate arrays // for (int count = 0; count < m_StorageIds.GetSize(); count++) { if ((m_StorageIds[count] & StorageIdMask) == StorageId) { m_StorageIds.RemoveAt(count); m_StorageInfos.RemoveAt(count); m_DcimHandle.RemoveAt(count); count--; } } return hr; } // // This function updates the value for a property // // Input: // PropCode -- property code that was updated // HRESULT CWiaMiniDriver::DevicePropChanged(WORD PropCode) { DBG_FN("CWiaMiniDriver::DevicePropChanged"); HRESULT hr = S_OK; int idx = m_DeviceInfo.m_SupportedProps.Find(PropCode); if (idx < 0) { wiauDbgWarning("DevicePropChanged", "prop code not found %d", PropCode); return hr; } hr = m_pPTPCamera->GetDevicePropValue(PropCode, &m_PropDescs[idx]); if (FAILED(hr)) { wiauDbgError("DevicePropChanged", "GetDevicePropValue failed"); return hr; } return hr; } // // This function updates the object info for an object // // Input: // ObjectHandle -- the object whose ObjectInfo needs updating // HRESULT CWiaMiniDriver::ObjectInfoChanged(DWORD ObjectHandle) { DBG_FN("CWiaMiniDriver::ObjectInfoChanged"); HRESULT hr = S_OK; // // Find the driver item for the object handle. // IWiaDrvItem *pDrvItem = m_HandleItem.Lookup(ObjectHandle); if (!pDrvItem) { wiauDbgError("ObjectInfoChanged", "tried to update object that doesn't exist"); return S_FALSE; } PDRVITEM_CONTEXT pDrvItemContext; hr = pDrvItem->GetDeviceSpecContext((BYTE **) &pDrvItemContext); if (FAILED(hr)) { wiauDbgError("ObjectInfoChanged", "GetDeviceSpecContext failed"); return hr; } hr = m_pPTPCamera->GetObjectInfo(ObjectHandle, pDrvItemContext->pObjectInfo); if (FAILED(hr)) { wiauDbgError("ObjectInfoChanged", "GetObjectInfo failed"); return hr; } return hr; } // // This function marks a storage as full // // Input: // StorageId -- the storage to be marked // HRESULT CWiaMiniDriver::StorageFull(DWORD StorageId) { DBG_FN("CWiaMiniDriver::StorageFull"); HRESULT hr = S_OK; INT index = m_StorageIds.Find(StorageId); if (index < 0) { wiauDbgError("StorageFull", "storage id not found"); return S_FALSE; } CPtpStorageInfo *pStorageInfo = &m_StorageInfos[index]; pStorageInfo->m_FreeSpaceInBytes = 0; pStorageInfo->m_FreeSpaceInImages = 0; // // Signal that the TakePicture command is complete, if the driver was waiting for one // if (!SetEvent(m_TakePictureDoneEvent)) { hr = HRESULT_FROM_WIN32(::GetLastError()); wiauDbgErrorHr(hr, "EventCallbackDispatch", "SetEvent failed"); return hr; } return hr; } // // This function updates a StorageInfo // // Input: // StorageId -- the storage id to be updated // HRESULT CWiaMiniDriver::StorageInfoChanged(DWORD StorageId) { DBG_FN("CWiaMiniDriver::StorageInfoChanged"); HRESULT hr = S_OK; INT index = m_StorageIds.Find(StorageId); if (index < 0) { wiauDbgError("StorageInfoChanged", "storage id not found"); return S_FALSE; } CPtpStorageInfo *pStorageInfo = &m_StorageInfos[index]; hr = m_pPTPCamera->GetStorageInfo(StorageId, pStorageInfo); if (FAILED(hr)) { wiauDbgError("StorageInfoChanged", "GetStorageInfo failed"); return hr; } return hr; } // // This function processes the CaptureComplete event // // Input: // StorageId -- the storage id to be updated // HRESULT CWiaMiniDriver::CaptureComplete() { DBG_FN("CWiaMiniDriver::CaptureComplete"); HRESULT hr = S_OK; // // Signal that the TakePicture command is complete // if (!SetEvent(m_TakePictureDoneEvent)) { hr = HRESULT_FROM_WIN32(::GetLastError()); wiauDbgErrorHr(hr, "EventCallbackDispatch", "SetEvent failed"); return hr; } return hr; } // // This function posts a vendor defined event // // Input: // EventCode -- the event code // HRESULT CWiaMiniDriver::PostVendorEvent(WORD EventCode) { DBG_FN("CWiaMiniDriver::PostVendorEvent"); HRESULT hr = S_OK; CVendorEventInfo *pEventInfo = NULL; pEventInfo = m_VendorEventMap.Lookup(EventCode); if (pEventInfo) { hr = wiasQueueEvent(m_bstrDeviceId, pEventInfo->pGuid, NULL); if (FAILED(hr)) { wiauDbgError("PostVendorEvent", "wiasQueueEvent failed"); return hr; } } return hr; }