|
|
/*****************************************************************************
* * (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 <precomp.h>
#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
<Notes>
*****************************************************************************/
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
<Notes>
*****************************************************************************/
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
<Notes>
*****************************************************************************/
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
<Notes>
*****************************************************************************/
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
<Notes>
*****************************************************************************/
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
<Notes>
*****************************************************************************/
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"<NA>"); 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; }
|