/***************************************************************************** * * (C) COPYRIGHT MICROSOFT CORPORATION, 1999-2000 * * TITLE: ItemTree.cpp * * VERSION: 1.0 * * AUTHOR: RickTu * * DATE: 9/10/99 RickTu * 2000/11/09 OrenR * * DESCRIPTION: This code was originally in 'camera.cpp' but was broken out. * This code builds and maintains the camera's IWiaDrvItem tree. * * *****************************************************************************/ #include #pragma hdrstop /***************************************************************************** CVideoStiUsd::BuildItemTree Constructs an item tree which represents the layout of this WIA camera... *****************************************************************************/ STDMETHODIMP CVideoStiUsd::BuildItemTree(IWiaDrvItem ** ppIDrvItemRoot, LONG * plDevErrVal) { HRESULT hr; DBG_FN("CVideoStiUsd::BuildItemTree"); EnterCriticalSection( &m_csItemTree ); // // Check for bad args // if (!ppIDrvItemRoot) { hr = E_POINTER; } // // Make sure that there is only one item tree // else if (m_pRootItem) { *ppIDrvItemRoot = m_pRootItem; // // refresh our tree. We prune out all files which no longer exist // but for some reason remain in our tree (this can happen if someone // manually deletes a file from the temp WIA directory where we store // these images before they are transfered) // RefreshTree(m_pRootItem, plDevErrVal); hr = S_OK; } // // Lastly, build the tree if we need to // else { // // First check to see if we have a corresponding DShow device id // in the registry -- if not, then bail. // if (!m_strDShowDeviceId.Length()) { hr = E_FAIL; CHECK_S_OK2(hr, ("CVideoStiUsd::BuildItemTree, the DShow Device ID" "is empty, this should never happen")); } else { // // Create the new root // CSimpleBStr bstrRoot(L"Root"); // // Call Wia service library to create new root item // hr = wiasCreateDrvItem(WiaItemTypeFolder | WiaItemTypeRoot | WiaItemTypeDevice, bstrRoot.BString(), CSimpleBStr(m_strRootFullItemName), (IWiaMiniDrv *)this, sizeof(STILLCAM_IMAGE_CONTEXT), NULL, ppIDrvItemRoot); CHECK_S_OK2( hr, ("wiaCreateDrvItem" )); if (SUCCEEDED(hr) && *ppIDrvItemRoot) { m_pRootItem = *ppIDrvItemRoot; // // Add the items for this device // hr = EnumSavedImages( m_pRootItem ); CHECK_S_OK2( hr, ("EnumSavedImages" )); } } } LeaveCriticalSection(&m_csItemTree); CHECK_S_OK(hr); return hr; } /***************************************************************************** CVideoStiUsd::AddTreeItem *****************************************************************************/ HRESULT CVideoStiUsd::AddTreeItem(CSimpleString *pstrFullImagePath, IWiaDrvItem **ppDrvItem) { HRESULT hr = S_OK; INT iPos = 0; LPCTSTR pszFileName = NULL; if (pstrFullImagePath == NULL) { hr = E_INVALIDARG; CHECK_S_OK2(hr, ("CVideoStiUsd::AddTreeItem, received NULL " "param")); return hr; } // // Extract the file name from the full path. We do this by searching // for the first '\' from the end of the string. // iPos = pstrFullImagePath->ReverseFind('\\'); if (iPos < (INT) pstrFullImagePath->Length()) { // // increment the position by 1 because we want to skip over the // backslash. // ++iPos; // // point to the filename within the full path. // pszFileName = &(*pstrFullImagePath)[iPos]; } if (pszFileName) { // // Create a new DrvItem for this image and add it to the // DrvItem tree. // IWiaDrvItem *pNewFolder = NULL; hr = CreateItemFromFileName(WiaItemTypeFile | WiaItemTypeImage, pstrFullImagePath->String(), pszFileName, &pNewFolder); CHECK_S_OK2( hr, ("CVideoStiUsd::AddTreeItem, " "CreateItemFromFileName failed")); if (hr == S_OK) { hr = pNewFolder->AddItemToFolder(m_pRootItem); CHECK_S_OK2( hr, ("CVideoStiUsd::AddTreeItem, " "pNewFolder->AddItemToFolder failed")); } if (ppDrvItem) { *ppDrvItem = pNewFolder; (*ppDrvItem)->AddRef(); } pNewFolder->Release(); } return hr; } /***************************************************************************** CVideoStiUsd::EnumSavedImages *****************************************************************************/ STDMETHODIMP CVideoStiUsd::EnumSavedImages(IWiaDrvItem * pRootItem) { DBG_FN("CVideoStiUsd::EnumSavedImages"); HRESULT hr = S_OK; WIN32_FIND_DATA FindData; if (!m_strStillPath.Length()) { DBG_ERR(("m_strStillPath is NULL, can't continue!")); return E_FAIL; } CSimpleString strTempName(m_strStillPath); strTempName.Concat( TEXT("\\*.jpg") ); // // look for files at this level // HANDLE hFile = FindFirstFile(strTempName.String(), &FindData); if (hFile != INVALID_HANDLE_VALUE) { BOOL bStatus = FALSE; do { // // generate file name // strTempName.Assign( m_strStillPath ); strTempName.Concat( TEXT("\\") ); strTempName.Concat( FindData.cFileName ); hr = AddTreeItem(&strTempName, NULL); if (FAILED(hr)) { continue; } // // look for more images // bStatus = FindNextFile(hFile,&FindData); } while (bStatus); FindClose(hFile); } return S_OK; } /***************************************************************************** CVideoStiUsd::DoesFileExist *****************************************************************************/ BOOL CVideoStiUsd::DoesFileExist(BSTR bstrFileName) { DBG_FN("CVideoStiUsd::DoesFileExist"); BOOL bExists = FALSE; DWORD dwAttrib = 0; if (bstrFileName == NULL) { return FALSE; } CSimpleString strTempName(m_strStillPath); strTempName.Concat(TEXT("\\")); strTempName.Concat(bstrFileName); strTempName.Concat(TEXT(".jpg")); dwAttrib = ::GetFileAttributes(strTempName); if (dwAttrib != 0xFFFFFFFF) { bExists = TRUE; } else { bExists = FALSE; } return bExists; } /***************************************************************************** CVideoStiUsd::PruneTree Removes nodes from the tree whose filenames no longer exist in the temp directory *****************************************************************************/ HRESULT CVideoStiUsd::PruneTree(IWiaDrvItem * pRootItem, BOOL * pbTreeChanged) { DBG_FN("CVideoStiUsd::PruneTree"); HRESULT hr = S_OK; BOOL bTreeChanged = FALSE; IWiaDrvItem *pCurrentItem = NULL; IWiaDrvItem *pNextItem = NULL; BSTR bstrItemName = NULL; if ((pRootItem == NULL) || (pbTreeChanged == NULL)) { return E_INVALIDARG; } else if (!m_strStillPath.Length()) { DBG_ERR(("m_strStillPath is NULL, can't continue!")); return E_FAIL; } // This function DOES NOT do an AddRef hr = pRootItem->GetFirstChildItem(&pCurrentItem); while ((hr == S_OK) && (pCurrentItem != NULL)) { pNextItem = NULL; pCurrentItem->AddRef(); hr = pCurrentItem->GetItemName(&bstrItemName); if (SUCCEEDED(hr) && (bstrItemName != NULL)) { // // if the filename for this item does not exist, // then remove it from our tree. // if (!DoesFileExist(bstrItemName)) { // // get the next item in the list so we don't lose our place // in the list after removing the current item. // hr = pCurrentItem->GetNextSiblingItem(&pNextItem); CHECK_S_OK2(hr, ("pCurrentItem->GetNextSiblingItem")); // // remove the item from the folder, we no longer need it. // hr = pCurrentItem->RemoveItemFromFolder(WiaItemTypeDeleted); CHECK_S_OK2(hr, ("pItemToRemove->RemoveItemFromFolder")); // // Report the error, but continue. If we failed to // remove the item from the tree, for whatever reason, // there really is nothing we can do but proceed and // prune the remainder of the tree. // if (hr != S_OK) { DBG_ERR(("Failed to remove item from folder, " "hr = 0x%08lx", hr)); hr = S_OK; } if (m_lPicsTaken > 0) { // // Decrement the # of pics taken only if the // current # of pics is greater than 0. // InterlockedCompareExchange( &m_lPicsTaken, m_lPicsTaken - 1, (m_lPicsTaken > 0) ? m_lPicsTaken : -1); } // // Indicate the tree was changed so we can send a notification // when we are done. // bTreeChanged = TRUE; } else { // file does exist, all is well in the world, move on to next // item in the tree. hr = pCurrentItem->GetNextSiblingItem(&pNextItem); } } // // release the current item since we AddRef'd it at the start of this // loop. // pCurrentItem->Release(); pCurrentItem = NULL; // // set our next item to be our current item. It is possible that // pNextItem is NULL. // pCurrentItem = pNextItem; // // Free the BSTR. // if (bstrItemName) { ::SysFreeString(bstrItemName); bstrItemName = NULL; } } hr = S_OK; if (pbTreeChanged) { *pbTreeChanged = bTreeChanged; } return hr; } /***************************************************************************** CVideoStiUsd::IsFileAlreadyInTree *****************************************************************************/ BOOL CVideoStiUsd::IsFileAlreadyInTree(IWiaDrvItem * pRootItem, LPCTSTR pszFileName) { DBG_FN("CVideoStiUsd::IsFileAlreadyInTree"); HRESULT hr = S_OK; BOOL bFound = FALSE; IWiaDrvItem *pCurrentItem = NULL; if ((pRootItem == NULL) || (pszFileName == NULL)) { bFound = FALSE; DBG_ERR(("CVideoStiUsd::IsFileAlreadyInTree received a NULL pointer, " "returning FALSE, item not found in tree.")); return bFound; } CSimpleString strFileName( m_strStillPath ); CSimpleString strBaseName( pszFileName ); strFileName.Concat( TEXT("\\") ); strFileName.Concat( strBaseName ); CImage Image(m_strStillPath, CSimpleBStr(m_strRootFullItemName), strFileName.String(), strBaseName.String(), WiaItemTypeFile | WiaItemTypeImage); hr = pRootItem->FindItemByName(0, Image.bstrFullItemName(), &pCurrentItem); if (hr == S_OK) { bFound = TRUE; // // Don't forget to release the driver item, since it was AddRef'd by // FindItemByName(..) // pCurrentItem->Release(); } else { bFound = FALSE; } return bFound; } /***************************************************************************** CVideoStiUsd::AddNewFilesToTree *****************************************************************************/ HRESULT CVideoStiUsd::AddNewFilesToTree(IWiaDrvItem * pRootItem, BOOL * pbTreeChanged) { DBG_FN("CVideoStiUsd::AddNewFilesToTree"); HRESULT hr = E_FAIL; BOOL bTreeChanged = FALSE; HANDLE hFile = NULL; BOOL bFileFound = FALSE; WIN32_FIND_DATA FindData; if ((pRootItem == NULL) || (pbTreeChanged == NULL)) { return E_INVALIDARG; } if (!m_strStillPath.Length()) { DBG_ERR(("m_strStillPath is NULL, can't continue!")); return E_FAIL; } CSimpleString strTempName(m_strStillPath); strTempName.Concat( TEXT("\\*.jpg") ); // // Find all JPG files in the m_strStillPath directory. // This directory is %windir%\temp\wia\{Device GUID}\XXXX // where X is numeric. // hFile = FindFirstFile(strTempName.String(), &FindData); if (hFile != INVALID_HANDLE_VALUE) { bFileFound = TRUE; } // // Iterate through all files in the directory and for each // one check to see if it is already in the tree. If it // isn't, then add it to the tree. If it is, do nothing // and move to the next file in the directory // while (bFileFound) { // // Check if the file in the directory is already in our // tree. // if (!IsFileAlreadyInTree(pRootItem, FindData.cFileName)) { // // add an image to this folder // // generate file name // strTempName.Assign( m_strStillPath ); strTempName.Concat( TEXT("\\") ); strTempName.Concat( FindData.cFileName ); hr = AddTreeItem(&strTempName, NULL); // // Set this flag to indicate that changes were made to the // tree, hence we will send an event indicating this when we // are done. // bTreeChanged = TRUE; } // // look for more images // bFileFound = FindNextFile(hFile,&FindData); } if (hFile) { FindClose(hFile); hFile = NULL; } if (pbTreeChanged) { *pbTreeChanged = bTreeChanged; } return S_OK; } /***************************************************************************** CVideoStiUsd::RefreshTree *****************************************************************************/ STDMETHODIMP CVideoStiUsd::RefreshTree(IWiaDrvItem * pRootItem, LONG * plDevErrVal) { DBG_FN("CVideoStiUsd::RefreshTree"); BOOL bItemsAdded = FALSE; BOOL bItemsRemoved = FALSE; HRESULT hr = S_OK; // // Remove any dead nodes from the tree. A dead node is a node in the tree // whose file has been deleted from the directory in m_strStillPath, // but we still have a tree item for it. // hr = PruneTree(pRootItem, &bItemsRemoved); CHECK_S_OK2(hr, ("PruneTree")); // // Add any news files that have been added to the folder but for some // reason we don't have a tree node for them. // hr = AddNewFilesToTree(pRootItem, &bItemsAdded); CHECK_S_OK2(hr, ("AddNewFilesToTree")); // // If we added new nodes, removed some nodes, or both, then notify the // guys upstairs (in the UI world) that the tree has been updated. // if ((bItemsAdded) || (bItemsRemoved)) { hr = wiasQueueEvent(CSimpleBStr(m_strDeviceId), &WIA_EVENT_TREE_UPDATED, NULL); } return hr; } /***************************************************************************** CVideoStiUsd::CreateItemFromFileName Helper function that creates a WIA item from a filename (which is a .jpg). *****************************************************************************/ STDMETHODIMP CVideoStiUsd::CreateItemFromFileName(LONG FolderType, LPCTSTR pszPath, LPCTSTR pszName, IWiaDrvItem ** ppNewFolder) { HRESULT hr = E_FAIL; IWiaDrvItem * pNewFolder = NULL; PSTILLCAM_IMAGE_CONTEXT pContext = NULL; DBG_FN("CVideoStiUsd::CreateItemFromFileName"); // // Check for bad args // if (!ppNewFolder) { DBG_ERR(("ppNewFolder is NULL, returning E_INVALIDARG")); return E_INVALIDARG; } // // Set up return value // *ppNewFolder = NULL; // // Create new image object // CImage * pImage = new CImage(m_strStillPath, CSimpleBStr(m_strRootFullItemName), pszPath, pszName, FolderType); if (!pImage) { DBG_ERR(("Couldn't create new CImage, returning E_OUTOFMEMORY")); return E_OUTOFMEMORY; } // // call Wia to create new DrvItem // hr = wiasCreateDrvItem(FolderType, pImage->bstrItemName(), pImage->bstrFullItemName(), (IWiaMiniDrv *)this, sizeof(STILLCAM_IMAGE_CONTEXT), (BYTE **)&pContext, &pNewFolder); CHECK_S_OK2( hr, ("wiasCreateDrvItem")); if (SUCCEEDED(hr) && pNewFolder) { // // init device specific context // pContext->pImage = pImage; // // Return the item // *ppNewFolder = pNewFolder; // // Inc the number of pictures taken // InterlockedIncrement(&m_lPicsTaken); } else { DBG_ERR(("CVideoStiUsd::CreateItemFromFileName - wiasCreateItem " "failed or returned NULL pNewFolder, hr = 0x%08lx, " "pNewFolder = 0x%08lx, pContext = 0x%08lx", hr, pNewFolder,pContext )); delete pImage; hr = E_OUTOFMEMORY; } return hr; } /***************************************************************************** CVideoStiUsd::InitDeviceProperties Initializes properties for the device on the device root item. *****************************************************************************/ STDMETHODIMP CVideoStiUsd::InitDeviceProperties(BYTE * pWiasContext, LONG * plDevErrVal) { HRESULT hr = S_OK; BSTR bstrFirmwreVer = NULL; int i = 0; SYSTEMTIME camTime; PROPVARIANT propVar; DBG_FN("CVideoStiUsd::InitDeviceProperties"); // // This device doesn't touch hardware to initialize the device properties. // if (plDevErrVal) { *plDevErrVal = 0; } // // Parameter validation. // if (pWiasContext == NULL) { hr = E_INVALIDARG; CHECK_S_OK2(hr, ("CVideoStiUsd::InitDeviceProperties received " "NULL param.")); return hr; } // // Write standard property names // hr = wiasSetItemPropNames(pWiasContext, sizeof(gDevicePropIDs)/sizeof(PROPID), gDevicePropIDs, gDevicePropNames); CHECK_S_OK2(hr, ("wiaSetItemPropNames")); if (hr == S_OK) { // // Write the properties supported by all WIA devices // bstrFirmwreVer = SysAllocString(L""); if (bstrFirmwreVer) { wiasWritePropStr(pWiasContext, WIA_DPA_FIRMWARE_VERSION, bstrFirmwreVer); SysFreeString(bstrFirmwreVer); } hr = wiasWritePropLong(pWiasContext, WIA_DPA_CONNECT_STATUS, 1); hr = wiasWritePropLong(pWiasContext, WIA_DPC_PICTURES_TAKEN, 0); // // Write the camera properties, just default values, it may // vary with items // hr = wiasWritePropLong(pWiasContext, WIA_DPC_THUMB_WIDTH, 80); hr = wiasWritePropLong(pWiasContext, WIA_DPC_THUMB_HEIGHT, 60); // // Write the Directshow Device ID // hr = wiasWritePropStr(pWiasContext, WIA_DPV_DSHOW_DEVICE_PATH, CSimpleBStr(m_strDShowDeviceId)); // // Write the Images Directory // hr = wiasWritePropStr(pWiasContext, WIA_DPV_IMAGES_DIRECTORY, CSimpleBStr(m_strStillPath)); // // Write the Last Picture Taken // hr = wiasWritePropStr(pWiasContext, WIA_DPV_LAST_PICTURE_TAKEN, CSimpleBStr(TEXT(""))); // // Use WIA services to set the property access and // valid value information from gDevPropInfoDefaults. // hr = wiasSetItemPropAttribs(pWiasContext, NUM_CAM_DEV_PROPS, gDevicePropSpecDefaults, gDevPropInfoDefaults); } return S_OK; } /***************************************************************************** CVideoStiUsd::InitImageInformation Used to initialize device items (images) from this device. *****************************************************************************/ STDMETHODIMP CVideoStiUsd::InitImageInformation( BYTE * pWiasContext, PSTILLCAM_IMAGE_CONTEXT pContext, LONG * plDevErrVal ) { HRESULT hr = S_OK; DBG_FN("CVideoStiUsd::InitImageInformation"); // // Check for bad args // if ((pWiasContext == NULL) || (pContext == NULL)) { hr = E_INVALIDARG; CHECK_S_OK2(hr, ("CVideoStiUsd::InitImageInformation, received " "NULL params")); return hr; } // // Get the image in question // CImage * pImage = pContext->pImage; if (pImage == NULL) { hr = E_INVALIDARG; } if (hr == S_OK) { // // Ask the image to initialize the information // hr = pImage->InitImageInformation(pWiasContext, plDevErrVal); } return hr; }