|
|
/*****************************************************************************
* * (C) COPYRIGHT MICROSOFT CORPORATION, 1998 - 2000 * * TITLE: minidrv.cpp * * VERSION: 1.0 * * AUTHOR: RickTu * * DATE: 9/9/99 * * DESCRIPTION: This module implements IWiaMiniDrv for this device. * *****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#include "wiamindr_i.c"
#include <sddl.h>
#include <shlobj.h>
///////////////////////////////
// Constants
//
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 TAKE_PICTURE_TIMEOUT = 1000 * 15; // 15 seconds
//const UINT DEFAULT_LOCK_TIMEOUT = 1000 * 2; // 2 seconds
// This is the Security Descriptor Language
// - Each ACE (access control entry) is represented in by parentheses.
// - A = Allow ACE (as opposed to a Deny ACE)
// - OICI = Allow Object Inheritance and Container Inheritence
// - GA = Generic All Access (Full Control)
// - SY = System account (SID)
// - BA = Builtin Administrators Group
// - CO = Creator/Owner
// - GR = Generic Read
// - GW = Generic Write
// - GX = Generic Execute.
// - IU = Interactive Users (User's logged on at the computer)
//
// More info, go to http://msdn.microsoft.com/library/psdk/winbase/accctrl_2n1v.htm
//
//
//
const TCHAR *OBJECT_DACLS= TEXT("D:(A;OICI;GA;;;SY)") // SYSTEM
TEXT("(A;OICI;GA;;;BA)") // Admin
TEXT("(A;OICI;GRGWGXDTSDCCLC;;;WD)") // Everyone
TEXT("(A;OICI;GRGWGXDTSDCCLC;;;PU)") // Power Users
TEXT("(A;OICI;GRGWGXDTSDCCLC;;;BU)"); // Users
/*****************************************************************************
DirectoryExists
Checks to see whether the given fully qualified directory exists.
*****************************************************************************/
BOOL DirectoryExists(LPCTSTR pszDirectoryName) { BOOL bExists = FALSE;
//
// Try to determine if this directory exists
//
if (pszDirectoryName) { DWORD dwFileAttributes = GetFileAttributes(pszDirectoryName); if (dwFileAttributes == 0xFFFFFFFF || !(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { bExists = FALSE; } else { bExists = TRUE; } } else { bExists = FALSE; }
return bExists; }
/*****************************************************************************
RecursiveCreateDirectory
Take a fully qualified path and create the directory in pieces as needed.
*****************************************************************************/
BOOL RecursiveCreateDirectory(CSimpleString *pstrDirectoryName) { ASSERT(pstrDirectoryName != NULL);
//
// If this directory already exists, return true.
//
if (DirectoryExists(*pstrDirectoryName)) { return TRUE; }
//
// Otherwise try to create it.
//
CreateDirectory(*pstrDirectoryName, NULL );
//
// If it now exists, return true
//
if (DirectoryExists(*pstrDirectoryName)) { return TRUE; } else { //
// Remove the last subdir and try again
//
int nFind = pstrDirectoryName->ReverseFind(TEXT('\\')); if (nFind >= 0) { RecursiveCreateDirectory(&(pstrDirectoryName->Left(nFind)));
//
// Now try to create it.
//
CreateDirectory(*pstrDirectoryName, NULL); } }
//
//Does it exist now?
//
return DirectoryExists(*pstrDirectoryName); }
///////////////////////////////
// SetDirectorySecurity
//
HRESULT SetDirectorySecurity(CSimpleString *pstrDirectoryName) { HRESULT hr = S_OK; BOOL bSuccess = TRUE; SECURITY_ATTRIBUTES SA;
SA.nLength = sizeof(SECURITY_ATTRIBUTES); SA.bInheritHandle = TRUE;
if (ConvertStringSecurityDescriptorToSecurityDescriptor( OBJECT_DACLS, SDDL_REVISION_1, &(SA.lpSecurityDescriptor), NULL)) { bSuccess = SetFileSecurity(*pstrDirectoryName, DACL_SECURITY_INFORMATION, SA.lpSecurityDescriptor);
if (!bSuccess) { hr = HRESULT_FROM_WIN32(GetLastError()); }
if (SA.lpSecurityDescriptor) { LocalFree(SA.lpSecurityDescriptor); } } else { hr = HRESULT_FROM_WIN32(GetLastError()); }
return hr; }
/*****************************************************************************
CVideoStiUsd::drvInitializeWia [IWiaMiniDrv]
WIA calls this method to ask us to do the following:
* Initialize our mini driver. * Setup our optional private interface(s). * Build our device item tree.
During initializiation we:
* Cache the STI device pointer for locking. * Cache the device ID and root item full item name. * Initialize and hook up the DirectShow stream.
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvInitializeWia( BYTE *pWiasContext, LONG lFlags, BSTR bstrDeviceID, BSTR bstrRootFullItemName, IUnknown *pStiDevice, IUnknown *pIUnknownOuter, IWiaDrvItem **ppIDrvItemRoot, IUnknown **ppIUnknownInner, LONG *plDevErrVal ) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvInitializeWia");
//
// Initialize return values
//
if (ppIDrvItemRoot) { *ppIDrvItemRoot = NULL; }
if (ppIUnknownInner) { *ppIUnknownInner = NULL; }
if (plDevErrVal) { *plDevErrVal = 0; }
//
// Enter the critical section.
//
EnterCriticalSection(&m_csItemTree);
m_dwConnectedApps++;
DBG_TRC(("CVideoStiUsd::drvInitializeWia - Initializing Video Driver, " "Num Connected Apps = '%lu', device id = '%ws', Root Item Name = '%ws'", m_dwConnectedApps, bstrDeviceID, bstrRootFullItemName));
if (m_dwConnectedApps == 1) { //
// Cache what we need to
//
if (pStiDevice) { pStiDevice->QueryInterface( IID_IStiDevice, (void **)&m_pStiDevice ); } m_strDeviceId.Assign(CSimpleStringWide(bstrDeviceID)); m_strRootFullItemName.Assign(CSimpleStringWide(bstrRootFullItemName)); //
// Set the images directory. The first param is NULL, which indicates
// that a default directory should be set.
//
if (hr == S_OK) { hr = SetImagesDirectory(NULL, pWiasContext, &m_pRootItem, plDevErrVal); }
//
// Enable the take picture event so that an app can send this driver
// the take picture command, and this driver can signal the appliation
// that owns wiavideo to take the picture.
//
if (hr == S_OK) { EnableTakePicture(pWiasContext); } } else { RefreshTree(m_pRootItem, plDevErrVal); }
if (ppIDrvItemRoot) { *ppIDrvItemRoot = m_pRootItem; }
//
// Leave the critical section
//
LeaveCriticalSection(&m_csItemTree);
CHECK_S_OK(hr); return hr; }
/**************************************************************************\
CVideoStiUsd::drvUnInitializeWia [IWiaMiniDrv]
Gets called when a client connection is going away. WIA calls this method to ask us to do the following:
* Cleanup any resources that are releated to this client connection (identified by pWiasContext)
*************************************************************************/
STDMETHODIMP CVideoStiUsd::drvUnInitializeWia(BYTE *pWiasContext) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvUnInitializeWia");
EnterCriticalSection(&m_csItemTree);
if (m_dwConnectedApps > 0) { m_dwConnectedApps--; }
DBG_TRC(("CVideoStiUsd::drvUnInitializeWia, Num Connected Apps = '%lu'", m_dwConnectedApps));
if ((m_dwConnectedApps == 0) && (m_pRootItem)) { DisableTakePicture(pWiasContext, TRUE);
DBG_TRC(("CVideoStiUsd::drvUnInitializeWia, no more connected apps, deleting tree"));
hr = m_pRootItem->UnlinkItemTree(WiaItemTypeDisconnected); CHECK_S_OK2(hr,("m_pRootItem->UnlinkItemTree()"));
// Clear the root item
m_pRootItem = NULL;
// Clear the pointer to the STI device we received
m_pStiDevice = NULL;
// reset the num pictures taken to 0.
m_lPicsTaken = 0; }
LeaveCriticalSection(&m_csItemTree);
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvGetDeviceErrorStr [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvGetDeviceErrorStr(LONG lFlags, LONG lDevErrVal, LPOLESTR * ppszDevErrStr, LONG * plDevErr) { HRESULT hr = E_NOTIMPL;
DBG_FN("CVideoStiUsd::drvGetDeviceErrorStr");
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvDeviceCommand [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvDeviceCommand(BYTE * pWiasContext, LONG lFlags, const GUID * pGUIDCommand, IWiaDrvItem ** ppMiniDrvItem, LONG * plDevErrVal) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvDeviceCommand");
if (plDevErrVal) { *plDevErrVal = 0; }
//
// We support "Take snapshot"
//
if (*pGUIDCommand == WIA_CMD_TAKE_PICTURE) { DBG_TRC(("CVideoStiUsd::drvDeviceCommand received command " "WIA_CMD_TAKE_PICTURE"));
//
// Take a picture
//
hr = TakePicture(pWiasContext, ppMiniDrvItem); } else if (*pGUIDCommand == WIA_CMD_ENABLE_TAKE_PICTURE) { //
// This command doesn't do anything. However WiaVideo still expects
// it to succeed, so if you remove this, remove the call from WiaVideo too.
//
DBG_TRC(("CVideoStiUsd::drvDeviceCommand received command " "WIA_CMD_ENABLE_TAKE_PICTURE"));
hr = S_OK; } else if (*pGUIDCommand == WIA_CMD_DISABLE_TAKE_PICTURE) { //
// This command doesn't do anything. However WiaVideo still expects
// it to succeed, so if you remove this, remove the call from WiaVideo too.
//
DBG_TRC(("CVideoStiUsd::drvDeviceCommand received command " "WIA_CMD_DISABLE_TAKE_PICTURE"));
hr = S_OK; }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::ValidateDataTransferContext
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::ValidateDataTransferContext( PMINIDRV_TRANSFER_CONTEXT pDataTransferContext) { DBG_FN("CVideoStiUsd::ValidateDataTransferContext");
if (pDataTransferContext->lSize != sizeof(MINIDRV_TRANSFER_CONTEXT)) { DBG_ERR(("invalid data transfer context -- wrong lSize")); return E_INVALIDARG;; }
//
// for tymed file or hglobal, only WiaImgFmt_BMP || WiaImgFmt_JPEG
// is allowed
//
if ((pDataTransferContext->tymed == TYMED_FILE) || (pDataTransferContext->tymed == TYMED_HGLOBAL) ) { if ((pDataTransferContext->guidFormatID != WiaImgFmt_BMP) && (pDataTransferContext->guidFormatID != WiaImgFmt_JPEG)) { DBG_ERR(("invalid format -- asked for TYMED_FILE or TYMED_HGLOBAL " "but guidFormatID != (WiaImgFmt_BMP | WiaImgFmt_JPEG)"));
return E_INVALIDARG;; } }
//
// for tymed CALLBACK, only WiaImgFmt_MEMORYBMP, WiaImgFmt_BMP and
// WiaImgFmt_JPEG are allowed
//
if (pDataTransferContext->tymed == TYMED_CALLBACK) { if ((pDataTransferContext->guidFormatID != WiaImgFmt_BMP) && (pDataTransferContext->guidFormatID != WiaImgFmt_MEMORYBMP) && (pDataTransferContext->guidFormatID != WiaImgFmt_JPEG)) { DBG_ERR(("invalid format -- asked for TYMED_CALLBACK but " "guidFormatID != (WiaImgFmt_BMP | WiaImgFmt_MEMORYBMP " "| WiaImgFmt_JPEG)"));
return E_INVALIDARG;; } }
//
// callback is always double buffered, non-callback never is
//
if (pDataTransferContext->pTransferBuffer == NULL) { DBG_ERR(("invalid transfer context -- pTransferBuffer is NULL!")); return E_INVALIDARG; }
return S_OK; }
/*****************************************************************************
CVideoStiUsd::SendBitmapHeader
Sends bitmap header during banded transfer
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::SendBitmapHeader(IWiaDrvItem * pDrvItem, PMINIDRV_TRANSFER_CONTEXT pTranCtx) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::SendBitmapHeader");
//
// driver is sending TOPDOWN data, must swap biHeight
//
// this routine assumes pTranCtx->pHeader points to a
// BITMAPINFO header (TYMED_FILE doesn't use this path
// and DIB is the only format supported now)
//
PBITMAPINFO pbmi = (PBITMAPINFO)pTranCtx->pTransferBuffer;
if (pTranCtx->guidFormatID == WiaImgFmt_MEMORYBMP) { pbmi->bmiHeader.biHeight = -pbmi->bmiHeader.biHeight; }
hr = pTranCtx->pIWiaMiniDrvCallBack->MiniDrvCallback( IT_MSG_DATA, IT_STATUS_TRANSFER_TO_CLIENT, 0, 0, pTranCtx->lHeaderSize, pTranCtx, 0);
if (hr == S_OK) { //
// advance offset for destination copy
//
pTranCtx->cbOffset += pTranCtx->lHeaderSize;
}
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvAquireItemData [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvAcquireItemData(BYTE * pWiasContext, LONG lFlags, PMINIDRV_TRANSFER_CONTEXT pDataContext, LONG * plDevErrVal) { HRESULT hr = E_NOTIMPL;
DBG_FN("CVideoStiUsd::drvAcquireItemData");
*plDevErrVal = 0;
//
// Get a pointer to the associated driver item.
//
IWiaDrvItem* pDrvItem;
hr = wiasGetDrvItem(pWiasContext, &pDrvItem);
if (FAILED(hr)) { CHECK_S_OK2(hr, ("wiaGetDrvItem Failed")); return hr; }
//
// Validate the data transfer context.
//
hr = ValidateDataTransferContext( pDataContext );
if (FAILED(hr)) { CHECK_S_OK2(hr, ("ValidateTransferContext failed")); return hr; }
#ifdef DEBUG
//
// Dump the request
//
DBG_TRC(("Asking for TYMED of 0x%x", pDataContext->tymed));
if (pDataContext->guidFormatID == WiaImgFmt_BMP) { DBG_TRC(("Asking for WiaImgFmt_BMP")); } else if (pDataContext->guidFormatID == WiaImgFmt_MEMORYBMP) { DBG_TRC(("Asking for WiaImgFmt_MEMORYBMP")); } else if (pDataContext->guidFormatID == WiaImgFmt_JPEG) { DBG_TRC(("Asking for WiaImgFmt_JPEG")); } #endif
//
// get item specific driver data
//
STILLCAM_IMAGE_CONTEXT *pContext;
pDrvItem->GetDeviceSpecContext((BYTE **)&pContext);
if (!pContext) { hr = E_INVALIDARG; CHECK_S_OK2(hr, ("drvAcquireItemData, NULL item context")); return hr; }
//
// Use our internal routines to get format specific info...
//
if (pContext->pImage) { hr = pContext->pImage->SetItemSize( pWiasContext, pDataContext ); CHECK_S_OK2(hr, ("pContext->pImage->SetItemSize()")); } else { DBG_ERR(("Couldn't use our internal routines to compute image " "information, this is bad!"));
//
// As a last resort, use WIA services to fetch format specific info.
//
hr = wiasGetImageInformation(pWiasContext, 0, pDataContext);
CHECK_S_OK2(hr,("wiaGetImageInformation()")); }
if (FAILED(hr)) { CHECK_S_OK2(hr, ("wiasGetImageInformation failed")); return hr; }
//
// determine if this is a callback or buffered transfer
//
if (pDataContext->tymed == TYMED_CALLBACK) { DBG_TRC(("Caller wants callback"));
//
// For formats that have a data header, send it to the client
//
if (pDataContext->lHeaderSize > 0) { DBG_TRC(("Sending Bitmap Header...")); hr = SendBitmapHeader( pDrvItem, pDataContext );
CHECK_S_OK2(hr,("SendBitmapHeader( pDrvItem, pDataContext )")); }
if (hr == S_OK) { DBG_TRC(("Calling LoadImageCB...")); hr = LoadImageCB( pContext, pDataContext, plDevErrVal ); CHECK_S_OK2(hr, ("LoadImageCB( pContext, pDataContext, " "plDevErrVal")); } } else { DBG_TRC(("Caller doesn't want callback"));
//
// inc past header
//
pDataContext->cbOffset += pDataContext->lHeaderSize;
DBG_TRC(("Calling LoadImage...")); hr = LoadImage( pContext, pDataContext, plDevErrVal ); CHECK_S_OK2(hr, ("LoadImage( pContext, pDataContext, " "plDevErrVal )")); }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvInitItemProperties [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvInitItemProperties(BYTE * pWiasContext, LONG lFlags, LONG * plDevErrVal) { DBG_FN("CVideoStiUsd::drvInitItemProperties");
HRESULT hr = S_OK; LONG lItemType; PSTILLCAM_IMAGE_CONTEXT pContext; IWiaDrvItem * pDrvItem; // This is not a CComPtr because there
// is no addref for us to release
//
// This device doesn't touch hardware to initialize the
// device item properties.
//
*plDevErrVal = 0;
//
// Parameter validation.
//
if (!pWiasContext) { DBG_ERR(("drvInitItemProperties, invalid input pointers")); return E_INVALIDARG; }
//
// Get a pointer to the associated driver item.
//
if (hr == S_OK) { hr = wiasGetDrvItem(pWiasContext, &pDrvItem); CHECK_S_OK2(hr,("wiaGetDrvItem")); }
if (hr == S_OK) { //
// Root item has the all the device properties
//
hr = pDrvItem->GetItemFlags(&lItemType); CHECK_S_OK2(hr,("pDrvItem->GetItemFlags")); }
if (hr == S_OK) { if (lItemType & WiaItemTypeRoot) { //
// Root item property init finishes here
//
hr = InitDeviceProperties( pWiasContext, plDevErrVal ); CHECK_S_OK2(hr,("InitDeviceProperties for root item"));
} else if (lItemType & WiaItemTypeFile) { //
// If this is a file, init the properties
//
//
// Add the item property names.
//
if (hr == S_OK) { hr = wiasSetItemPropNames(pWiasContext, NUM_CAM_ITEM_PROPS, gItemPropIDs, gItemPropNames);
CHECK_S_OK2(hr,("wiaSetItemPropNames for item")); }
if (hr == S_OK) { //
// Use WIA services to set the default item properties.
//
hr = wiasWriteMultiple(pWiasContext, NUM_CAM_ITEM_PROPS, gPropSpecDefaults, (PROPVARIANT*)gPropVarDefaults);
CHECK_S_OK2(hr,("wiaWriteMultiple for item props")); } if (hr == S_OK) { hr = pDrvItem->GetDeviceSpecContext( (BYTE **)&pContext ); CHECK_S_OK2(hr,("GetDeviceSpecContext")); }
if (hr == S_OK) { hr = InitImageInformation(pWiasContext, pContext, plDevErrVal); CHECK_S_OK2(hr,("InitImageInformation")); } } }
return hr; }
/*****************************************************************************
CVideoStiUsd::ValidateItemProperties
<Notes>
*****************************************************************************/ HRESULT CVideoStiUsd::ValidateItemProperties(BYTE *pWiasContext, LONG lFlags, ULONG nPropSpec, const PROPSPEC *pPropSpec, LONG *plDevErrVal, IWiaDrvItem *pDrvItem) { DBG_FN("CVideoStiUsd::ValidateFileProperties");
HRESULT hr = S_OK;
if ((pWiasContext == NULL) || (pPropSpec == NULL)) { hr = E_INVALIDARG;
CHECK_S_OK2(hr, ("CVideoStiUsd::ValidateItemProperties received " "NULL params")); return hr; }
STILLCAM_IMAGE_CONTEXT *pContext = NULL;
hr = pDrvItem->GetDeviceSpecContext( (BYTE **)&pContext);
CHECK_S_OK2(hr,("CVideoStiUsd::ValidateItemProperties, " "GetDeviceSpecContext failed"));
if (SUCCEEDED(hr) && pContext) { CImage * pImage = pContext->pImage;
if (pImage) { //
// calc item size
//
hr = pImage->SetItemSize( pWiasContext, NULL ); CHECK_S_OK2(hr,("SetItemSize( pWiasContext )")); }
//
// Change MinBufferSize property. Need to get Tymed and
// ItemSize first, since MinBufferSize in dependant on these
// properties.
//
LONG lTymed; LONG lItemSize; LONG lMinBufSize = 0;
hr = wiasReadPropLong(pWiasContext, WIA_IPA_TYMED, &lTymed, NULL, TRUE);
CHECK_S_OK2(hr, ("wiasReadPropLong( WIA_IPA_TYPMED )"));
if (SUCCEEDED(hr)) { hr = wiasReadPropLong(pWiasContext, WIA_IPA_ITEM_SIZE, &lItemSize, NULL, TRUE);
CHECK_S_OK2(hr,("wiasReadPropLong( WIA_IPA_ITEM_SIZE )"));
if (SUCCEEDED(hr)) { //
// Update the MinBufferSize property.
//
switch (lTymed) { case TYMED_CALLBACK: lMinBufSize = 65535; break;
default: lMinBufSize = lItemSize; break; }
if (lMinBufSize) { hr = wiasWritePropLong(pWiasContext, WIA_IPA_MIN_BUFFER_SIZE, lMinBufSize);
CHECK_S_OK2(hr, ("wiasWritePropLong( " "WIA_IPA_MIN_BUFFER_SIZE )")); }
DBG_TRC(("WIA_IPA_MIN_BUFFER_SIZE set to %d bytes", lMinBufSize)); } } }
return hr; }
/*****************************************************************************
CVideoStiUsd::ValidateDeviceProperties
<Notes>
*****************************************************************************/ HRESULT CVideoStiUsd::ValidateDeviceProperties(BYTE *pWiasContext, LONG lFlags, ULONG nPropSpec, const PROPSPEC *pPropSpec, LONG *plDevErrVal, IWiaDrvItem *pDrvItem) { DBG_FN("CVideoStiUsd::ValidateRootProperties");
HRESULT hr = S_OK;
//
// Parameter validation.
//
if ((pWiasContext == NULL) || (pPropSpec == NULL)) { hr = E_INVALIDARG;
CHECK_S_OK2(hr, ("CVideoStiUsd::ValidateDeviceProperties received " "NULL params")); return hr; }
for (ULONG i = 0; i < nPropSpec; i++) { if ((pPropSpec[i].ulKind == PRSPEC_PROPID) && (pPropSpec[i].propid == WIA_DPV_LAST_PICTURE_TAKEN)) { DBG_TRC(("CVideoStiUsd::ValidateDeviceProperties, setting the " "WIA_DPV_LAST_PICTURE_TAKEN property."));
EnterCriticalSection(&m_csItemTree);
//
// process the last picture taken property change.
//
BSTR bstrLastPictureTaken = NULL; //
// Read in the value for last picture taken.
//
hr = wiasReadPropStr(pWiasContext, WIA_DPV_LAST_PICTURE_TAKEN, &bstrLastPictureTaken, NULL, TRUE); if (hr == S_OK) { m_strLastPictureTaken = bstrLastPictureTaken;
DBG_TRC(("CVideoStiUsd::ValidateDeviceProperties, last picture " "taken = '%ls'", m_strLastPictureTaken.String()));
//
// This will add the new item to the tree and queue an
// ITEM_CREATED event
//
hr = SignalNewImage(bstrLastPictureTaken); }
// reset the last picture taken value. This is needed because the
// service checks to see if the new value being set is the same as
// the current value, and if it is, it doesn't forward it on to us.
// This is bad in the event of the Scanner and Camera wizard, where
// it takes 1 picture, (so LAST_PICTURE_TAKEN has a value of "Picture 1"),
// then deletes it, then user backs up the wizard, and takes a picture
// again. This new picture will have a value of "Picture 1" but we won't
// add it to the tree because the value of the property hasn't changed
// as far as the wia service is concerned.
//
if (hr == S_OK) { //
// Write the Last Picture Taken
//
hr = wiasWritePropStr(pWiasContext, WIA_DPV_LAST_PICTURE_TAKEN, CSimpleBStr(TEXT("")));
} //
// Free the BSTR
//
if (bstrLastPictureTaken) { ::SysFreeString(bstrLastPictureTaken); bstrLastPictureTaken = NULL; }
LeaveCriticalSection(&m_csItemTree); } else if ((pPropSpec[i].ulKind == PRSPEC_PROPID) && (pPropSpec[i].propid == WIA_DPV_IMAGES_DIRECTORY)) { //
// DPV_IMAGES_DIRECTORY -
//
hr = E_FAIL; CHECK_S_OK2(hr, ("CVideoStiUsd::ValidateRootProperties, " "attempting to validate the Images Directory " "property, but this is a read-only " "property")); } else if ((pPropSpec[i].ulKind == PRSPEC_PROPID) && (pPropSpec[i].propid == WIA_DPV_DSHOW_DEVICE_PATH)) { //
// process the DShowDeviceID change.
//
hr = E_FAIL; CHECK_S_OK2(hr, ("CVideoStiUsd::ValidateRootProperties, " "attempting to validate the DShow Device " "ID property, but this is a read-only " "property")); } }
return hr; }
/*****************************************************************************
CVideoStiUsd::drvValidateItemProperties [IWiaMiniDrv]
<Notes>
*****************************************************************************/ STDMETHODIMP CVideoStiUsd::drvValidateItemProperties(BYTE *pWiasContext, LONG lFlags, ULONG nPropSpec, const PROPSPEC *pPropSpec, LONG *plDevErrVal) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvValidateItemProperties");
if (plDevErrVal) { *plDevErrVal = 0; }
//
// Parameter validation.
//
if ((pWiasContext == NULL) || (pPropSpec == NULL)) { hr = E_INVALIDARG;
CHECK_S_OK2(hr, ("CVideoStiUsd::drvValidateItemProperties received " "NULL params")); return hr; }
//
// Get item in question
//
//
// not a CComPtr because there isn't an extra ref
// on this guy from the caller
//
IWiaDrvItem* pDrvItem = NULL;
hr = wiasGetDrvItem(pWiasContext, &pDrvItem);
CHECK_S_OK2(hr,("wiasGetDrvItem( pWiasContext, &pDrvItem )"));
if (SUCCEEDED(hr)) { LONG lItemType = 0;
//
// What kind of item is this?
//
hr = pDrvItem->GetItemFlags(&lItemType); CHECK_S_OK2(hr,("pDrvItem->GetItemFlags( &lItemType )"));
if (SUCCEEDED(hr)) { if (lItemType & WiaItemTypeFile) { hr = ValidateItemProperties(pWiasContext, lFlags, nPropSpec, pPropSpec, plDevErrVal, pDrvItem); } else if (lItemType & WiaItemTypeRoot) { hr = ValidateDeviceProperties(pWiasContext, lFlags, nPropSpec, pPropSpec, plDevErrVal, pDrvItem); } } }
CHECK_S_OK(hr);
return hr; }
/*****************************************************************************
CVideoStiUsd::drvWriteItemProperties [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvWriteItemProperties(BYTE * pWiasContext, LONG lFLags, PMINIDRV_TRANSFER_CONTEXT pmdtc, LONG * plDevErrVal) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvWriteItemProperties");
if (plDevErrVal) { *plDevErrVal = 0; }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::ReadItemProperties
We only support reading thumbnails on demand for items
*****************************************************************************/
HRESULT CVideoStiUsd::ReadItemProperties(BYTE *pWiasContext, LONG lFlags, ULONG nPropSpec, const PROPSPEC *pPropSpec, LONG *plDevErrVal, IWiaDrvItem *pDrvItem) { HRESULT hr = S_OK; STILLCAM_IMAGE_CONTEXT *pContext = NULL;
if ((pPropSpec == NULL) || (pDrvItem == NULL)) { hr = E_INVALIDARG; CHECK_S_OK2(hr, ("CVideoStiUsd::ReadItemProperties received a " "NULL param")); return hr; }
//
// It's an item, now loop through the requested properties
// and see if they're looking for the Thumbnail
//
for (ULONG i = 0; i < nPropSpec; i++) { if (((pPropSpec[i].ulKind == PRSPEC_PROPID) && (pPropSpec[i].propid == WIA_IPC_THUMBNAIL)) || ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) && (wcscmp(pPropSpec[i].lpwstr, WIA_IPC_THUMBNAIL_STR) == 0))) { //
// They'd like the thumbnail
//
hr = pDrvItem->GetDeviceSpecContext((BYTE **)&pContext); CHECK_S_OK2(hr,("pDrvItem->GetDeviceSpecContext()"));
if (SUCCEEDED(hr) && pContext) { if (pContext->pImage) { //
// Use our internal routines to load the thumbnail...
//
hr = pContext->pImage->LoadThumbnail(pWiasContext); break; } else { DBG_ERR(("pContext->pImage was NULL!")); } } else { DBG_ERR(("Couldn't get pContext")); } } }
return hr; }
/*****************************************************************************
CVideoStiUsd::ReadDeviceProperties
We support all our custom properties
*****************************************************************************/
HRESULT CVideoStiUsd::ReadDeviceProperties(BYTE *pWiasContext, LONG lFlags, ULONG nPropSpec, const PROPSPEC *pPropSpec, LONG *plDevErrVal, IWiaDrvItem *pDrvItem) { HRESULT hr = S_OK;
if ((pPropSpec == NULL) || (pDrvItem == NULL)) { hr = E_INVALIDARG; CHECK_S_OK2(hr, ("CVideoStiUsd::ReadItemProperties received a " "NULL param")); return hr; }
for (ULONG i = 0; i < nPropSpec; i++) { if (((pPropSpec[i].ulKind == PRSPEC_PROPID) && (pPropSpec[i].propid == WIA_DPC_PICTURES_TAKEN)) || ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) && (!wcscmp(pPropSpec[i].lpwstr, WIA_DPC_PICTURES_TAKEN_STR)))) { //
// Requesting the number of pictures taken.
//
DBG_TRC(("CVideoStiUsd::ReadDeviceProperties, reading propID " "'%lu' (0x%08lx) WIA_DPC_PICTURES_TAKEN = '%lu'", pPropSpec[i].propid, pPropSpec[i].propid, m_lPicsTaken));
wiasWritePropLong(pWiasContext, WIA_DPC_PICTURES_TAKEN, m_lPicsTaken);
} else if (((pPropSpec[i].ulKind == PRSPEC_PROPID) && (pPropSpec[i].propid == WIA_DPV_DSHOW_DEVICE_PATH)) || ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) && (!wcscmp(pPropSpec[i].lpwstr, WIA_DPV_DSHOW_DEVICE_PATH_STR)))) { //
// Requesting the DShow Device ID.
//
DBG_TRC(("CVideoStiUsd::ReadDeviceProperties, reading propID " "'%lu' (0x%08lx) WIA_DPV_DSHOW_DEVICE_PATH = '%ls'", pPropSpec[i].propid, pPropSpec[i].propid, m_strDShowDeviceId.String())); wiasWritePropStr(pWiasContext, WIA_DPV_DSHOW_DEVICE_PATH, CSimpleBStr(m_strDShowDeviceId).BString());
} else if (((pPropSpec[i].ulKind == PRSPEC_PROPID) && (pPropSpec[i].propid == WIA_DPV_IMAGES_DIRECTORY)) || ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) && (!wcscmp(pPropSpec[i].lpwstr, WIA_DPV_IMAGES_DIRECTORY_STR)))) { //
// Requesting the Images Directory.
//
DBG_TRC(("CVideoStiUsd::ReadDeviceProperties, reading propID " "'%lu' (0x%08lx) WIA_DPV_IMAGES_DIRECTORY = '%ls'", pPropSpec[i].propid, pPropSpec[i].propid, m_strStillPath.String()));
wiasWritePropStr(pWiasContext, WIA_DPV_IMAGES_DIRECTORY, CSimpleBStr(m_strStillPath).BString()); } else if (((pPropSpec[i].ulKind == PRSPEC_PROPID) && (pPropSpec[i].propid == WIA_DPV_LAST_PICTURE_TAKEN)) || ((pPropSpec[i].ulKind == PRSPEC_LPWSTR) && (!wcscmp(pPropSpec[i].lpwstr, WIA_DPV_LAST_PICTURE_TAKEN_STR)))) { //
// Requesting the last picture taken
//
DBG_TRC(("CVideoStiUsd::ReadDeviceProperties, reading propID " "'%lu' (0x%08lx) WIA_DPV_LAST_PICTURE_TAKEN = '%ls'", pPropSpec[i].propid, pPropSpec[i].propid, m_strLastPictureTaken.String()));
wiasWritePropStr(pWiasContext, WIA_DPV_LAST_PICTURE_TAKEN, CSimpleBStr(m_strLastPictureTaken).BString()); } }
return hr; }
/*****************************************************************************
CVideoStiUsd::drvReadItemProperties [IWiaMiniDrv]
We only support reading thumbnails on demand.
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvReadItemProperties(BYTE *pWiasContext, LONG lFlags, ULONG nPropSpec, const PROPSPEC *pPropSpec, LONG *plDevErrVal) { HRESULT hr = S_OK; LONG lItemType = 0; IWiaDrvItem *pDrvItem = NULL;
DBG_FN("CVideoStiUsd::drvReadItemProperties");
//
// Check for bad args
//
if ((nPropSpec == 0) || (pPropSpec == NULL) || (pWiasContext == NULL)) { hr = E_INVALIDARG; CHECK_S_OK2(hr, ("CVideoStiUsd::drvReadItemProperties received " "NULL params"));
return hr; }
if (hr == S_OK) { //
// Make sure we're dealing with an item, not the root item.
//
//
// Get minidriver item
//
hr = wiasGetDrvItem(pWiasContext, &pDrvItem);
if ((hr == S_OK) && (pDrvItem == NULL)) { hr = E_FAIL; }
CHECK_S_OK2(hr,("CVideoStiUsd::drvReadItemProperties, wiasGetDrvItem " "failed")); }
if (hr == S_OK) { hr = pDrvItem->GetItemFlags(&lItemType); CHECK_S_OK2(hr,("pDrvItem->GetItemFlags()")); }
if (hr == S_OK) { if ((lItemType & WiaItemTypeFile) && (!(lItemType & WiaItemTypeRoot))) { //
// If property being requested is a file and it is NOT the root,
// then read in the item property.
//
hr = ReadItemProperties(pWiasContext, lFlags, nPropSpec, pPropSpec, plDevErrVal, pDrvItem); } else if ((lItemType & WiaItemTypeFolder) && (lItemType & WiaItemTypeRoot)) { //
// If the property being requested is the root, then read in
// the device properties.
//
hr = ReadDeviceProperties(pWiasContext, lFlags, nPropSpec, pPropSpec, plDevErrVal, pDrvItem); } }
if (plDevErrVal) { *plDevErrVal = 0; }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvLockWiaDevice [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvLockWiaDevice(BYTE *pWiasContext, LONG lFlags, LONG *plDevErrVal) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvLockWiaDevice");
if (plDevErrVal) { *plDevErrVal = 0; }
//
// We are purposely not locking the driver. This driver is thread
// safe and it looks like with large volumes of images (>1000)
// you get better performance if the driver manages synchronization.
//
// return m_pStiDevice->LockDevice(DEFAULT_LOCK_TIMEOUT);
return hr; }
/*****************************************************************************
CVideoStiUsd::drvUnLockWiaDevice [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvUnLockWiaDevice(BYTE *pWiasContext, LONG lFlags, LONG *plDevErrVal) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvUnLockWiaDevice");
if (plDevErrVal) { *plDevErrVal = 0; }
//
// We are purposely not locking the driver. This driver is thread
// safe and it looks like with large volumes of images (>1000)
// you get better performance if the driver manages synchronization.
//
// return m_pStiDevice->UnLockDevice();
return hr; }
/*****************************************************************************
CVideoStiUsd::drvAnalyzeItem [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvAnalyzeItem(BYTE *pWiasContext, LONG lFlags, LONG *plDevErrVal) { HRESULT hr = E_NOTIMPL;
DBG_FN("CVideoStiUsd::drvAnalyzeItem");
if (plDevErrVal) { *plDevErrVal = 0; }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvDeleteItem [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvDeleteItem(BYTE *pWiasContext, LONG lFlags, LONG *plDevErrVal) { HRESULT hr = E_FAIL;
DBG_FN("CVideoStiUsd::drvDeleteItem");
//
// check for bad params
//
if (pWiasContext == NULL) { DBG_ERR(("pWiasContext is NULL!")); return E_INVALIDARG; }
if (plDevErrVal) { *plDevErrVal = 0; }
EnterCriticalSection(&m_csItemTree);
//
// Get a pointer to the associated driver item.
//
IWiaDrvItem * pDrvItem = NULL;
hr = wiasGetDrvItem(pWiasContext, &pDrvItem); CHECK_S_OK2(hr,("wiasGetDrvItem"));
if (SUCCEEDED(hr) && pDrvItem) { //
// get item specific driver data
//
STILLCAM_IMAGE_CONTEXT *pContext = NULL;
pDrvItem->GetDeviceSpecContext((BYTE **)&pContext);
CHECK_S_OK2(hr,("pDrvItem->GetDeviceSpecContext"));
if (SUCCEEDED(hr) && pContext && pContext->pImage) {
//
// Delete the file in question
//
hr = pContext->pImage->DoDelete(); CHECK_S_OK2(hr,("pContext->pImage->DoDelete()"));
//
// Dec the number of pictures taken
//
InterlockedDecrement(&m_lPicsTaken);
//
// write out the new amount
//
wiasWritePropLong(pWiasContext, WIA_DPC_PICTURES_TAKEN, m_lPicsTaken);
if (SUCCEEDED(hr)) { HRESULT hr2;
BSTR bstrItemName = NULL;
//
// Get bstr of full item name
//
hr2 = pDrvItem->GetFullItemName(&bstrItemName); CHECK_S_OK2(hr2,("pDrvItem->GetFullItemName()"));
//
// Send event that item was deleted
//
hr2 = wiasQueueEvent(CSimpleBStr(m_strDeviceId), &WIA_EVENT_ITEM_DELETED, bstrItemName);
CHECK_S_OK2(hr2, ("wiasQueueEvent( WIA_EVENT_ITEM_DELETED )"));
//
// Cleanup
//
if (bstrItemName) { SysFreeString(bstrItemName); bstrItemName = NULL; } } } else { DBG_ERR(("pContext or pContext->pImage are NULL!")); hr = E_FAIL; } }
LeaveCriticalSection( &m_csItemTree );
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvFreeDrvItem [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvFreeDrvItemContext(LONG lFlags, BYTE *pDevContext, LONG *plDevErrVal) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvFreeDrvItemContext");
PSTILLCAM_IMAGE_CONTEXT pContext = (PSTILLCAM_IMAGE_CONTEXT)pDevContext;
if (pContext != NULL) { //
// delete is safe even if param is NULL.
//
delete pContext->pImage; pContext->pImage = NULL; }
if (plDevErrVal) { *plDevErrVal = 0; }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CMiniDev::drvGetCapabilities [IWiaMiniDrv]
Let WIA know what things this driver can do.
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvGetCapabilities(BYTE *pWiasContext, LONG lFlags, LONG *pCelt, WIA_DEV_CAP_DRV **ppCapabilities, LONG *plDevErrVal) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvGetCapabilities");
if (plDevErrVal) { *plDevErrVal = 0; }
//
// Return Commmand and/or Events depending on flags
//
switch (lFlags) { case WIA_DEVICE_COMMANDS:
//
// Only commands
//
*pCelt = NUM_CAP_ENTRIES - NUM_EVENTS; *ppCapabilities = &gCapabilities[NUM_EVENTS]; break;
case WIA_DEVICE_EVENTS:
//
// Only events
//
*pCelt = NUM_EVENTS; *ppCapabilities = gCapabilities; break;
case (WIA_DEVICE_COMMANDS | WIA_DEVICE_EVENTS):
//
// Both events and commands
//
*pCelt = NUM_CAP_ENTRIES; *ppCapabilities = gCapabilities; break;
default:
//
// Flags is invalid
//
DBG_ERR(("drvGetCapabilities, flags was invalid")); hr = E_INVALIDARG; break; }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvGetWiaFormatInfo [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvGetWiaFormatInfo(BYTE *pWiasContext, LONG lFlags, LONG *pCelt, WIA_FORMAT_INFO **ppwfi, LONG *plDevErrVal) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvGetWiaFormatInfo");
if (plDevErrVal) { *plDevErrVal = 0; }
//
// If it hasn't been done already, set up the g_wfiTable table
//
if (!m_wfi) { DBG_ERR(("drvGetWiaFormatInfo, m_wfi is NULL!")); return E_OUTOFMEMORY; }
if (pCelt) { *pCelt = NUM_WIA_FORMAT_INFO; }
if (ppwfi) { *ppwfi = m_wfi; }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::drvNotifyPnpEvent [IWiaMiniDrv]
<Notes>
*****************************************************************************/
STDMETHODIMP CVideoStiUsd::drvNotifyPnpEvent(const GUID *pEventGUID, BSTR bstrDeviceID, ULONG ulReserved) { HRESULT hr = S_OK;
DBG_FN("CVideoStiUsd::drvNotifyPnpEvent");
//
// CONNECTED event is of no interest, because a new USD is always created
//
if (*pEventGUID == WIA_EVENT_DEVICE_DISCONNECTED) { DBG_TRC(("got a WIA_EVENT_DISCONNECTED")); }
CHECK_S_OK(hr); return hr; }
/*****************************************************************************
CVideoStiUsd::VerifyCorrectImagePath
<Notes>
*****************************************************************************/
HRESULT CVideoStiUsd::VerifyCorrectImagePath(BSTR bstrNewImageFullPath) { DBG_FN("CVideoStiUsd::VerifyCorrectImagePath");
HRESULT hr = S_OK; INT iIndex = 0; CSimpleString strImageFullPath;
if (bstrNewImageFullPath == NULL) { hr = E_POINTER; CHECK_S_OK2(hr, ("CVideoStiUsd::VerifyCorrectImagePath received a NULL pointer")); return hr; }
if (hr == S_OK) { strImageFullPath = CSimpleStringConvert::NaturalString( CSimpleStringWide(bstrNewImageFullPath));
//
// Get the filename out of the full path. Find the last backslash.
//
iIndex = strImageFullPath.ReverseFind('\\'); strImageFullPath[iIndex] = 0;
if (strImageFullPath != m_strStillPath) { hr = E_ACCESSDENIED; CHECK_S_OK2(hr, ("CVideoStiUsd::VerifyCorrectImagePath, the file that is " "being added to the tree '%ls' is not in the allowed directory, " "denying request with an E_ACCESSDENIED", CSimpleStringWide(strImageFullPath).String())); } }
return hr; }
/*****************************************************************************
CVideoStiUsd::SignalNewImage
<Notes>
*****************************************************************************/
HRESULT CVideoStiUsd::SignalNewImage(BSTR bstrNewImageFullPath) { DBG_FN("CVideoStiUsd::SignalNewImage");
HRESULT hr = S_OK; CComPtr<IWiaDrvItem> pDrvItem = NULL; BSTR bstrFullItemName = NULL; CSimpleString strImageFullPath;
if (hr == S_OK) { hr = VerifyCorrectImagePath(bstrNewImageFullPath); }
if (hr == S_OK) { strImageFullPath = CSimpleStringConvert::NaturalString( CSimpleStringWide(bstrNewImageFullPath)); DBG_TRC(("CVideoStiUsd::SignalNewImage, adding image '%ls' to " "tree of device '%ls'", CSimpleStringWide(strImageFullPath).String(), m_strDeviceId.String())); // Add the new item to the tree if doesn't already exist
//
// Get the filename out of the full path. Find the last backslash and
// move 1 beyond it.
//
INT iIndex = strImageFullPath.ReverseFind('\\') + 1; if (!IsFileAlreadyInTree(m_pRootItem, &(strImageFullPath[iIndex]))) { hr = AddTreeItem(&strImageFullPath, &pDrvItem); CHECK_S_OK2(hr, ("CVideoStiUsd::SignalNewImage, failed to add " "image '%ls' to tree of device '%ls'", CSimpleStringWide(strImageFullPath).String(), m_strDeviceId.String())); if (hr == S_OK) { //
// Get the full item name for this item
//
m_pLastItemCreated = pDrvItem; hr = pDrvItem->GetFullItemName(&bstrFullItemName); CHECK_S_OK2(hr,("CVideoStiUsd::SignalNewImage, failed to get Item " "name for newly added item")); } if (hr == S_OK) { //
// Queue an event that a new item was created.
//
hr = wiasQueueEvent(CSimpleBStr(m_strDeviceId), &WIA_EVENT_ITEM_CREATED, bstrFullItemName); CHECK_S_OK2(hr,("CVideoStiUsd::SignalNewImage, failed to " "queue a new WIA_EVENT_ITEM_CREATED event")); } if (bstrFullItemName) { SysFreeString(bstrFullItemName); bstrFullItemName = NULL; } } else { DBG_TRC(("CVideoStiUsd::SignalNewImage, item '%ls' is already in the " "tree. Probably tree was recently refreshed", bstrNewImageFullPath)); } }
return hr; }
/*****************************************************************************
CVideoStiUsd::SetImagesDirectory
<Notes>
*****************************************************************************/
HRESULT CVideoStiUsd::SetImagesDirectory(BSTR bstrNewImagesDirectory, BYTE *pWiasContext, IWiaDrvItem **ppIDrvItemRoot, LONG *plDevErrVal) { DBG_FN("CVideoStiUsd::SetImagesDirectory");
HRESULT hr = S_OK; CSimpleString strOriginalDirectory;
//
// If we received a NULL Images directory, then build up our own
// generated one, then build the item tree.
//
strOriginalDirectory = m_strStillPath;
if (bstrNewImagesDirectory == NULL) { //
// If this path is not in the registry, we default to constructing
// a path of this type:
//
// %TEMP%\WIA\%DeviceID%
TCHAR szTempPath[MAX_PATH + 1] = {0};
hr = SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_DEFAULT, szTempPath);
//
// We allow for the case of S_FALSE which indicates that the folder doesn't
// exist. This is fine since we recursively create it below.
//
if ((hr == S_OK) || (hr == S_FALSE)) { if (szTempPath[_tcslen(szTempPath) - 1] != '\\') { _tcscat(szTempPath, TEXT("\\")); }
//
// Set path to "Documents and Settings\Application Data\Microsoft\Wia\{deviceid}"
//
m_strStillPath.Assign(szTempPath); m_strStillPath += TEXT("Microsoft\\WIA\\"); m_strStillPath += m_strDeviceId; } } else { // we received a valid BSTR, attempt to create the directory.
m_strStillPath = bstrNewImagesDirectory; }
if (!RecursiveCreateDirectory(&m_strStillPath)) { hr = E_FAIL;
CHECK_S_OK2(hr, ("RecursiveCreateDirectory( %ws ) failed w/GLE=%d", m_strStillPath.String(), ::GetLastError() )); }
//
// Set the security DACL on the directory so that users and power users
// will be able to write and delete from it too.
//
if (hr == S_OK) { //
// We only set this directory security if we are using our default directory
// path. This isn't an issue now since the user cannot update the directory,
// but in the future if we allow them to, this could expose a security whole.
//
if (bstrNewImagesDirectory == NULL) { hr = SetDirectorySecurity(&m_strStillPath); }
}
if (hr == S_OK) { if (m_strStillPath.Length()) { BOOL bSendUpdateEvent = FALSE;
//
// If the original directory is different from the new directory
// and we already have a tree, then we should destroy our
// existing tree, and recreate it for the new directory.
//
if ((strOriginalDirectory.CompareNoCase(m_strStillPath) != 0) && (m_pRootItem != NULL)) { EnterCriticalSection( &m_csItemTree );
hr = m_pRootItem->UnlinkItemTree(WiaItemTypeDisconnected); CHECK_S_OK2(hr,("m_pRootItem->UnlinkItemTree()"));
if (SUCCEEDED(hr)) { bSendUpdateEvent = TRUE; m_pRootItem = NULL; }
LeaveCriticalSection( &m_csItemTree ); }
//
// Build the item tree.
//
hr = BuildItemTree(ppIDrvItemRoot, plDevErrVal);
//
// write out the new amount of pictures taken
//
wiasWritePropLong(pWiasContext, WIA_DPC_PICTURES_TAKEN, m_lPicsTaken);
if (bSendUpdateEvent) { wiasQueueEvent(CSimpleBStr(m_strDeviceId), &WIA_EVENT_TREE_UPDATED, NULL); } } else { hr = E_FAIL; CHECK_S_OK2(hr, ("CVideoStiUsd::SetImagesDirectory, new directory " "path has a length of 0, Directory = '%ls'", m_strStillPath.String())); } }
return hr; }
/*****************************************************************************
CVideoStiUsd::TakePicture
<Notes>
*****************************************************************************/
HRESULT CVideoStiUsd::TakePicture(BYTE *pTakePictureOwner, IWiaDrvItem **ppNewDrvItem) { HRESULT hr = S_OK;
//
// Notice that we are allowing multiple applications to call the
// take picture command, even if they weren't the owns that enabled
// it.
//
DBG_TRC(("CVideoStiUsd::drvDeviceCommand received command " "WIA_CMD_TAKE_PICTURE"));
if ((m_hTakePictureEvent) && (m_hPictureReadyEvent)) { DWORD dwResult = 0;
m_pLastItemCreated = NULL;
//
// Tell the WiaVideo object that pertains to this device ID to
// take a picture.
//
SetEvent(m_hTakePictureEvent);
// The WiaVideo object has a thread waiting on the
// m_hTakePictureEvent. When it is signalled, the WiaVideo object
// takes the picture, then sets the driver's custom
// "LastPictureTaken" property. This causes the driver to update
// its tree and queue an ITEM_CREATED event. Once this is complete,
// the WiaVideo object sets the PictureReady Event, at which point
// we return from this function call.
// dwResult = WaitForSingleObject(m_hPictureReadyEvent,
// TAKE_PICTURE_TIMEOUT);
if (dwResult == WAIT_OBJECT_0) { // *ppNewDrvItem = m_pLastItemCreated;
} else { if (dwResult == WAIT_TIMEOUT) { hr = E_FAIL; CHECK_S_OK2(hr, ("CVideoStiUsd::TakePicture timed out " "after waiting for '%lu' seconds for the " "WiaVideo object to take a picture", TAKE_PICTURE_TIMEOUT)); } else if (dwResult == WAIT_ABANDONED) { hr = E_FAIL; CHECK_S_OK2(hr, ("CVideoStiUsd::TakePicture failed, received " "a WAIT_ABANDONED from the Wait function")); } else { hr = E_FAIL; CHECK_S_OK2(hr, ("CVideoStiUsd::TakePicture failed to take a " "picture.")); } } } else { DBG_TRC(("CVideoStiUsd::drvDeviceCommand, ignoring " "WIA_CMD_TAKE_PICTURE request, events created " "by WiaVideo are not open")); }
return hr; }
/*****************************************************************************
CVideoStiUsd::EnableTakePicture
<Notes>
*****************************************************************************/
HRESULT CVideoStiUsd::EnableTakePicture(BYTE *pTakePictureOwner) { DBG_FN("CVideoStiUsd::EnableTakePicture");
HRESULT hr = S_OK; CSimpleString strTakePictureEvent; CSimpleString strPictureReadyEvent; CSimpleString strDeviceID; SECURITY_ATTRIBUTES SA;
SA.nLength = sizeof(SECURITY_ATTRIBUTES); SA.bInheritHandle = TRUE;
//
// Convert to security descriptor
//
ConvertStringSecurityDescriptorToSecurityDescriptor(OBJECT_DACLS, SDDL_REVISION_1, &(SA.lpSecurityDescriptor), NULL);
strDeviceID = CSimpleStringConvert::NaturalString(m_strDeviceId);
m_pTakePictureOwner = pTakePictureOwner;
if (hr == S_OK) { INT iPosition = 0; CSimpleString strModifiedDeviceID;
// Change the device ID from {6B...}\xxxx, to {6B...}_xxxx
iPosition = strDeviceID.ReverseFind('\\'); strModifiedDeviceID = 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) { m_hTakePictureEvent = CreateEvent(&SA, FALSE, FALSE, strTakePictureEvent); //
// This is not really an error since the events will not have been created until
// the WiaVideo object comes up.
//
if (m_hTakePictureEvent == NULL) { hr = E_FAIL; DBG_TRC(("CVideoStiUsd::EnableTakePicture, failed to open the " "WIA event '%ls', this is not fatal (LastError = '%lu' " "(0x%08lx))", strTakePictureEvent.String(), ::GetLastError(), ::GetLastError())); } }
if (hr == S_OK) { m_hPictureReadyEvent = CreateEvent(&SA, FALSE, FALSE, strPictureReadyEvent);
//
// This is not really an error since the events will not have been created until
// the WiaVideo object comes up.
//
if (m_hPictureReadyEvent == NULL) { hr = E_FAIL;
DBG_TRC(("CVideoStiUsd::EnableTakePicture, failed to open the WIA " "event '%ls', this is not fatal (LastError = '%lu' " "(0x%08lx))", strPictureReadyEvent.String(), ::GetLastError(), ::GetLastError())); } }
if (SA.lpSecurityDescriptor) { LocalFree(SA.lpSecurityDescriptor); }
return hr; }
/*****************************************************************************
CVideoStiUsd::DisableTakePicture
<Notes>
*****************************************************************************/
HRESULT CVideoStiUsd::DisableTakePicture(BYTE *pTakePictureOwner, BOOL bShuttingDown) { HRESULT hr = S_OK;
if (m_hTakePictureEvent) { ::CloseHandle(m_hTakePictureEvent); m_hTakePictureEvent = NULL; }
if (m_hPictureReadyEvent) { ::CloseHandle(m_hPictureReadyEvent); m_hPictureReadyEvent = NULL; }
m_pTakePictureOwner = NULL;
return hr; }
|