Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1601 lines
44 KiB

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORP., 1997
*
* TITLE: DevMgr.Cpp
*
* VERSION: 2.0
*
* AUTHOR: ReedB
*
* DATE: 26 Dec, 1997
*
* DESCRIPTION:
* Class implementation for WIA device manager.
* 07/12/2000 - Added support for shell's Hardware Event notification to
* receive volume arrival notification and start the WIA Wizard.
*
*******************************************************************************/
#include "precomp.h"
#include "stiexe.h"
#include "wiacfact.h"
#include "wiamindr.h"
#include "devmgr.h"
#include "devinfo.h"
#include "helpers.h"
#include "wiaevntp.h"
#include "wiapriv.h"
#include "device.h"
#include "lockmgr.h"
#include "fstidev.h"
#define INITGUID
#include "initguid.h"
//
// Acquisition Manager's class ID {D13E3F25-1688-45A0-9743-759EB35CDF9A}
// NOTE: We shouldn't really use this. Rather GetCLSIDFromProgID and use the
// version independant AppID name.
//
DEFINE_GUID(
CLSID_Manager,
0xD13E3F25, 0x1688, 0x45A0, 0x97, 0x43, 0x75, 0x9E, 0xB3, 0x5C, 0xDF, 0x9A);
/**************************************************************************\
* CWiaDevMgr::CreateInstance
*
* Create the CWiaDevMgr object.
*
* Arguments:
*
* iid - iid of dev manager
* ppv - return interface pointer
*
* Return Value:
*
* status
*
* History:
*
* 9/2/1998 Original Version
*
\**************************************************************************/
HRESULT CWiaDevMgr::CreateInstance(const IID& iid, void** ppv)
{
DBG_FN(CWiaDevMgr::CreateInstance);
HRESULT hr;
if ((iid == IID_IWiaDevMgr) || (iid == IID_IUnknown) || (iid == IID_IHWEventHandler)) {
// Create the WIA device manager component.
CWiaDevMgr* pDevMgr = new CWiaDevMgr();
if (!pDevMgr) {
DBG_ERR(("CWiaDevMgr::CreateInstance, Out of Memory"));
return E_OUTOFMEMORY;
}
// Initialize the WIA device manager component.
hr = pDevMgr->Initialize();
if (FAILED(hr)) {
delete pDevMgr;
DBG_ERR(("CWiaDevMgr::CreateInstance, Initialize failed"));
return hr;
}
// Get the requested interface from the device manager component.
hr = pDevMgr->QueryInterface(iid, ppv);
if (FAILED(hr)) {
delete pDevMgr;
DBG_ERR(("CWiaDevMgr::CreateInstance, QI failed"));
return hr;
}
DBG_TRC(("CWiaDevMgr::CreateInstance, Created WiaDevMgr"));
}
else {
hr = E_NOINTERFACE;
DBG_ERR(("CWiaDevMgr::CreateInstance, Unknown interface (0x%X)", hr));
}
return hr;
}
/**************************************************************************\
* QueryInterface
* AddRef
* Release
*
* CWiaDevMgr IUnknown Interface
*
* Arguments:
*
*
*
* Return Value:
*
*
*
* History:
*
* 9/2/1998 Original Version
*
\**************************************************************************/
HRESULT __stdcall CWiaDevMgr::QueryInterface(const IID& iid, void** ppv)
{
*ppv = NULL;
if ((iid == IID_IUnknown) || (iid == IID_IWiaDevMgr)) {
*ppv = (IWiaDevMgr*) this;
} else if (iid == IID_IWiaNotifyDevMgr) {
*ppv = (IWiaNotifyDevMgr*) this;
} else if (iid == IID_IHWEventHandler) {
*ppv = (IHWEventHandler*) this;
} else {
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG __stdcall CWiaDevMgr::AddRef()
{
InterlockedIncrement((long*) &m_cRef);
return m_cRef;
}
ULONG __stdcall CWiaDevMgr::Release()
{
ULONG ulRefCount = m_cRef - 1;
if (InterlockedDecrement((long*) &m_cRef) == 0) {
delete this;
return 0;
}
return ulRefCount;
}
/*******************************************************************************
*
* CWiaDevMgr
* ~CWiaDevMgr
*
* CWiaDevMgr Constructor/Initialize/Destructor Methods.
*
* History:
*
* 9/2/1998 Original Version
*
\**************************************************************************/
CWiaDevMgr::CWiaDevMgr():m_cRef(0)
{
m_cRef = 0;
m_pITypeInfo = NULL;
//
// We're creating a component that exposes interfaces to clients, so
// inform service to make sure service wont shutdown prematurely.
//
CWiaSvc::AddRef();
}
CWiaDevMgr::~CWiaDevMgr()
{
DBG_FN(CWiaDevMgr::~CWiaDevMgr);
if (m_pITypeInfo != NULL) {
m_pITypeInfo->Release();
}
//
// Component is destroyed, so no more interfaces are exposed from here.
// Inform server by decrementing it's reference count. This will allow
// it to shutdown if it's no longer needed.
//
CWiaSvc::Release();
}
/**************************************************************************\
* CWiaDevMgr::Initialize
*
* Create global sti instance
*
* Arguments:
*
* none
*
* Return Value:
*
* status
*
* History:
*
* 9/2/1998 Original Version
*
\**************************************************************************/
HRESULT CWiaDevMgr::Initialize()
{
DBG_FN(CWiaDevMgr::Initialize);
HRESULT hr = S_OK;
return hr;
}
/**************************************************************************\
* EnumWIADevInfo
*
* Create an WIA device information enumerator object.
*
* Arguments:
*
* lFlag - type of device to enumerate
* ppIEnum - return enumerator
*
* Return Value:
*
* status
*
* History:
*
* 9/2/1998 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaDevMgr::EnumDeviceInfo(
LONG lFlag,
IEnumWIA_DEV_INFO** ppIEnum)
{
DBG_FN(CWiaDevMgr::EnumDeviceInfo);
HRESULT hr = S_OK;
DWORD dwWait = 0;
//
// Make sure that refreshing of the device list has completed. If
// it hasn't, we'll wait up to DEVICE_LIST_WAIT_TIME, before proceeding
// anyway. This will ensure the device list is not empty because
// WIA device enumeration was called too soon after start-up (e.g.
// app's CoCreateInstance call started the service).
//
//
// Enumerate LPT if necessary.
//
EnumLpt();
dwWait = WaitForSingleObject(g_hDevListCompleteEvent, DEVICE_LIST_WAIT_TIME);
if (dwWait != WAIT_OBJECT_0) {
DBG_WRN(("CWiaDevMgr::EnumDeviceInfo, Device list was not complete before enumeration call..."));
}
*ppIEnum = NULL;
CEnumWIADevInfo* pEnum = new CEnumWIADevInfo;
if (!pEnum) {
DBG_ERR(("CWiaDevMgr::EnumDeviceInfo, Out of Memory"));
return E_OUTOFMEMORY;
}
hr = pEnum->Initialize(lFlag);
if (FAILED(hr)) {
DBG_ERR(("CWiaDevMgr::EnumDeviceInfo, Initialize failed"));
delete pEnum;
return hr;
}
hr = pEnum->QueryInterface(IID_IEnumWIA_DEV_INFO,
(void**) ppIEnum);
if (FAILED(hr)) {
DBG_ERR(("CWiaDevMgr::EnumDeviceInfo, QI for IWiaPropertyStorage failed"));
delete pEnum;
return E_UNEXPECTED;
}
return S_OK;
}
/**************************************************************************\
* FindMatchingDevice
*
* search enumeration info for named device
*
* Arguments:
*
* ppIPropStg
* pbstrDeviceID
*
* Return Value:
*
* Status
*
* History:
*
* 9/3/1998 Original Version
*
\**************************************************************************/
HRESULT CWiaDevMgr::FindMatchingDevice(
BSTR pbstrDeviceID,
IWiaPropertyStorage **ppIWiaPropStg)
{
DBG_FN(CWiaDevMgr::FindMatchingDevice);
// Enumerate the WIA devices, getting a IWIADevInfo
// pointer for each. Use this interface to query the registry
// based properties for each installed device.
HRESULT hr;
ULONG ul, ulFound = 0;
BSTR bstrDevId;
IEnumWIA_DEV_INFO *pIEnum;
//
// Notice that we specify DEV_MAN_ENUM_TYPE_ALL here.
//
hr = EnumDeviceInfo(DEV_MAN_ENUM_TYPE_ALL,&pIEnum);
if (SUCCEEDED(hr)) {
ul = 1;
while ((hr = pIEnum->Next(1, ppIWiaPropStg, &ul)) == S_OK) {
DBG_TRC(("# Found device candidate"));
hr = ReadPropStr(WIA_DIP_DEV_ID, *ppIWiaPropStg, &bstrDevId);
if (SUCCEEDED(hr)) {
DBG_TRC(("# \tDevice Name: %S", bstrDevId));
ulFound = !lstrcmpiW(bstrDevId, pbstrDeviceID);
SysFreeString(bstrDevId);
if (ulFound) {
break;
}
}
else {
DBG_ERR(("FindMatchingDevice, ReadPropStr of WIA_DIP_DEV_ID failed"));
}
(*ppIWiaPropStg)->Release();
*ppIWiaPropStg = NULL;
}
pIEnum->Release();
}
else {
DBG_ERR(("FindMatchingDevice:Failed to create enumerator"));
}
if (SUCCEEDED(hr)) {
if (!ulFound) {
hr = S_FALSE;
}
}
return hr;
}
#ifdef WINNT
/**************************************************************************\
* IsDeviceRemote
*
*
*
* Arguments:
*
*
*
* Return Value:
*
* TRUE if device is remote, caller must free server name.
*
* History:
*
* 1/5/1999 Original Version
*
\**************************************************************************/
BOOL IsDeviceRemote(
IWiaPropertyStorage *pIWiaPropStg,
BSTR *pbstrServer)
{
DBG_FN(::IsDeviceRemote);
HRESULT hr;
hr = ReadPropStr(WIA_DIP_SERVER_NAME, pIWiaPropStg, pbstrServer);
if ((SUCCEEDED(hr)) && (**pbstrServer)) {
if (lstrcmpiW(*pbstrServer, L"local") != 0) {
return TRUE;
}
}
else {
DBG_ERR(("IsDeviceRemote, ReadPropStr of WIA_DIP_SERVER_NAME failed"));
DBG_ERR(("Registry value DeviceData\\Server may not have been set during installation"));
}
if (*pbstrServer) {
SysFreeString(*pbstrServer);
}
return FALSE;
}
/**************************************************************************\
* CreateRemoteDevice
*
*
*
* Arguments:
*
*
*
* Return Value:
*
* Status
*
* History:
*
* 1/5/1999 Original Version
*
\**************************************************************************/
HRESULT CreateRemoteDevice(
BSTR bstrServer,
IWiaPropertyStorage *pIWiaPropStg,
IWiaItem **ppWiaDevice
)
{
DBG_FN(::CreateRemoteDevice);
*ppWiaDevice = NULL;
if (!bstrServer || !*bstrServer) {
DBG_ERR(("CreateRemoteDevice, bad remote server name"));
return E_INVALIDARG;
}
//
// must use client
//
HRESULT hr = CoImpersonateClient();
if (FAILED(hr)) {
DBG_ERR(("CreateRemoteDevice, CoImpersonateClient failed (0x%X)", hr));
return hr;
}
COSERVERINFO coServInfo;
MULTI_QI multiQI[1];
multiQI[0].pIID = &IID_IWiaDevMgr;
multiQI[0].pItf = NULL;
coServInfo.pwszName = bstrServer;
coServInfo.pAuthInfo = NULL;
coServInfo.dwReserved1 = 0;
coServInfo.dwReserved2 = 0;
//
// create connection to dev mgr
//
hr = CoCreateInstanceEx(
CLSID_WiaDevMgr,
NULL,
CLSCTX_REMOTE_SERVER,
&coServInfo,
1,
&multiQI[0]
);
if (hr == S_OK) {
BSTR bstrRemoteDevId;
BSTR bstrDevId;
IWiaDevMgr *pIWiaDevMgr = (IWiaDevMgr*)multiQI[0].pItf;
IWiaItem *pIWiaItem;
//
// use remote dev id to create
//
hr = ReadPropStr(WIA_DIP_DEV_ID, pIWiaPropStg, &bstrDevId);
if (hr == S_OK) {
hr = ReadPropStr(WIA_DIP_REMOTE_DEV_ID, pIWiaPropStg, &bstrRemoteDevId);
}
if (hr == S_OK) {
//
// create remote device
//
hr = pIWiaDevMgr->CreateDevice(bstrRemoteDevId, &pIWiaItem);
if (hr == S_OK) {
*ppWiaDevice = pIWiaItem;
//
// set devinfo props for remote access
//
IWiaPropertyStorage *pIPropDev;
hr = pIWiaItem->QueryInterface(IID_IWiaPropertyStorage,
(void **)&pIPropDev);
if (hr == S_OK) {
//
// set copy of devinfo to contain correct Remote DEVID, DEVID and server name
//
PROPSPEC PropSpec[3];
PROPVARIANT PropVar[3];
memset(PropVar,0,sizeof(PropVar));
// server name
PropSpec[0].ulKind = PRSPEC_PROPID;
PropSpec[0].propid = WIA_DIP_SERVER_NAME;
PropVar[0].vt = VT_BSTR;
PropVar[0].bstrVal = bstrServer;
// DEVID
PropSpec[1].ulKind = PRSPEC_PROPID;
PropSpec[1].propid = WIA_DIP_DEV_ID;
PropVar[1].vt = VT_BSTR;
PropVar[1].bstrVal = bstrDevId;
//Remote DEVID
PropSpec[2].ulKind = PRSPEC_PROPID;
PropSpec[2].propid = WIA_DIP_REMOTE_DEV_ID;
PropVar[2].vt = VT_BSTR;
PropVar[2].bstrVal = bstrRemoteDevId;
hr = pIPropDev->WriteMultiple(sizeof(PropVar)/sizeof(PROPVARIANT),
PropSpec,
PropVar,
WIA_DIP_FIRST);
if (FAILED(hr)) {
ReportReadWriteMultipleError(hr, "CreateRemoteDevice", NULL, FALSE, sizeof(PropVar)/sizeof(PROPVARIANT), PropSpec);
}
//
// !!! hack to fix device over-checking
//
hr = S_OK;
pIPropDev->Release();
}
else {
DBG_ERR(("CreateRemoteDevice, remote QI of IID_IWiaPropertyStorage failed (0x%X)", hr));
}
} else {
DBG_ERR(("CreateRemoteDevice, Remote CreateDevice call failed (0x%X)", hr));
}
} else {
DBG_ERR(("CreateRemoteDevice, Read propeties for BSTRDevID failed (0x%X)", hr));
}
pIWiaDevMgr->Release();
}
else {
DBG_ERR(("CreateRemoteDevice, remote CoCreateInstanceEx failed (0x%X)", hr));
}
CoRevertToSelf();
return hr;
}
#endif
/**************************************************************************\
* CreateLocalDevice
*
*
*
* Arguments:
*
*
*
* Return Value:
*
* Status
*
* History:
*
* 1/5/1999 Original Version
*
\**************************************************************************/
HRESULT CreateLocalDevice(
BSTR bstrDeviceID,
IWiaPropertyStorage *pIWiaPropStg,
IWiaItem **ppWiaItemRoot)
{
DBG_FN(::CreateLocalDevice);
USES_CONVERSION;
*ppWiaItemRoot = NULL;
//
// Build the root full item name.
//
WCHAR szTmp[32], *psz;
BSTR bstrRootFullItemName;
#ifdef WINNT
psz = wcsstr(bstrDeviceID, L"}\\");
#else
psz = wcsstr(bstrDeviceID, L"\\");
#endif
if (!psz) {
//This is no longer true
//DBG_ERR(("CreateLocalDevice, parse of device ID failed"));
//return E_INVALIDARG;
psz = bstrDeviceID;
} else {
#ifdef WINNT
psz += 2;
#else
psz += 1;
#endif
}
wcscpy(szTmp, psz);
wcscat(szTmp, L"\\Root");
bstrRootFullItemName = SysAllocString(szTmp);
if (!bstrRootFullItemName) {
DBG_ERR(("CreateLocalDevice, unable to allocate property stream device name"));
return E_OUTOFMEMORY;
}
//
// Get an interface pointer to the STI USD object.
//
HRESULT hr = E_FAIL;
ACTIVE_DEVICE *pActiveDevice = NULL;
PSTIDEVICE pFakeStiDevice = NULL;
CWiaItem *pWiaItemRoot = NULL;
pActiveDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, bstrDeviceID);
if (pActiveDevice) {
//
// Make sure driver is loaded
//
pActiveDevice->LoadDriver();
//
// Create the FakeStiDevice if we don't have one
//
if (!pActiveDevice->m_pFakeStiDevice) {
pActiveDevice->m_pFakeStiDevice = new FakeStiDevice();
}
if (pActiveDevice->m_pFakeStiDevice) {
pActiveDevice->m_pFakeStiDevice->Init(pActiveDevice);
hr = pActiveDevice->m_pFakeStiDevice->QueryInterface(IID_IStiDevice, (VOID**)&pFakeStiDevice);
if (SUCCEEDED(hr)) {
//
// Get a pointer to the WIA mini driver interface.
//
//
// Create the root item.
//
pWiaItemRoot = new CWiaItem;
if (pWiaItemRoot) {
//
// Query the root item for the IWiaItem interface.
//
hr = pWiaItemRoot->QueryInterface(IID_IWiaItem,
(void**)ppWiaItemRoot);
if (SUCCEEDED(hr)) {
//
// Initialize the USD.
//
IUnknown *pIUnknownInner = NULL;
IWiaDrvItem *pIDrvItemRoot = NULL;
LONG lFlags = 0;
//
// Call Sti Lock Manager to lock the device. Before
// drvInitializeWia is called, drivers wont have their
// IStiDevice pointer yet, so we can't call
// drvLockWiaDevice.
//
hr = g_pStiLockMgr->RequestLock(pActiveDevice, STIMON_AD_DEFAULT_WAIT_LOCK);
if (SUCCEEDED(hr)) {
_try {
pWiaItemRoot->m_bInitialized = TRUE;
DBG_WRN(("=> drvInitializeWia <="));
//DPRINTF(DM_TRACE, TEXT("=> drvInitializeWia <=\n"));
hr = pActiveDevice->m_DrvWrapper.WIA_drvInitializeWia(
(BYTE*)*ppWiaItemRoot,
lFlags,
bstrDeviceID,
bstrRootFullItemName,
(IUnknown *)pFakeStiDevice,
*ppWiaItemRoot,
&pIDrvItemRoot,
&pIUnknownInner,
&(pWiaItemRoot->m_lLastDevErrVal));
DBG_WRN(("=> Returned from drvInitializeWia <="));
} _except(EXCEPTION_EXECUTE_HANDLER){
DBG_ERR(("CreateLocalDevice, exception in drvInitializeWia: %X", GetExceptionCode()));
hr = E_FAIL;
}
pWiaItemRoot->m_bInitialized = FALSE;
g_pStiLockMgr->RequestUnlock(pActiveDevice);
}
if (SUCCEEDED(hr) && pIDrvItemRoot) {
if (pIUnknownInner) {
DBG_TRC(("CreateLocalDevice driver provided optional inner component"));
}
//
// Store the root to the driver item tree for later use.
//
pActiveDevice->SetDriverItem((CWiaDrvItem*) pIDrvItemRoot);
//
// Initialize the root item.
//
hr = pWiaItemRoot->Initialize(pWiaItemRoot,
pIWiaPropStg,
pActiveDevice,
(CWiaDrvItem *)pIDrvItemRoot,
pIUnknownInner);
if (SUCCEEDED(hr)) {
//
// AddRef the ActiveDevice since we're keeping it
//
pActiveDevice->AddRef();
} else {
DBG_ERR(("CreateLocalDevice Initialize of root item failed"));
pWiaItemRoot = NULL;
}
}
else {
DBG_ERR(("CreateLocalDevice drvInitializeWia failed. lDevErrVal: 0x%08X hr: 0x%X", pWiaItemRoot->m_lLastDevErrVal, hr));
}
}
else {
DBG_ERR(("CreateLocalDevice unable to QI item for its IWIaItem interface"));
}
}
else {
DBG_ERR(("CreateLocalDevice unable to allocate root item"));
hr = E_OUTOFMEMORY;
}
} else {
DBG_ERR(("CreateLocalDevice, QI for fake STI device failed"));
}
} else {
DBG_ERR(("CreateLocalDevice, unable to allocate fake device"));
hr = E_OUTOFMEMORY;
}
}
else {
DBG_ERR(("CreateLocalDevice, unable to find active STI USD device object"));
hr = WIA_S_NO_DEVICE_AVAILABLE;
}
//
// Failure cleanup
//
if (FAILED(hr)) {
*ppWiaItemRoot = NULL;
if (pWiaItemRoot) {
delete pWiaItemRoot;
pWiaItemRoot = NULL;
}
}
//
// Other cleanup
//
if (pActiveDevice) {
pActiveDevice->Release();
pActiveDevice = NULL;
}
SysFreeString(bstrRootFullItemName);
return hr;
}
/**************************************************************************\
* CWiaDevMgr::CreateDevice
*
* Create a WIA device from pbstrDeviceID
*
* Arguments:
*
* pbstrDeviceID - device ID
* ppWiaItemRoot - return interface
*
* Return Value:
*
* Status
*
* History:
*
* 9/3/1998 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaDevMgr::CreateDevice(
BSTR bstrDeviceID,
IWiaItem **ppWiaItemRoot)
{
DBG_FN(CWiaDevMgr::CreateDevice);
HRESULT hr;
// Validate parameters.
if (bstrDeviceID == NULL) {
DBG_ERR(("CWiaDevMgr::CreateDevice: invalid bstrDeviceID"));
return E_INVALIDARG;
}
if (ppWiaItemRoot == NULL) {
DBG_ERR(("CWiaDevMgr::CreateDevice: invalid ppWiaItemRoot"));
return E_INVALIDARG;
}
*ppWiaItemRoot = NULL;
// try to find a device matching pbstrDeviceID
IWiaPropertyStorage *pIWiaPropStg = NULL;
hr = FindMatchingDevice(bstrDeviceID, &pIWiaPropStg);
if (hr != S_OK) {
//
// Do a full refresh.
//
g_pDevMan->ReEnumerateDevices(DEV_MAN_FULL_REFRESH | DEV_MAN_GEN_EVENTS);
hr = FindMatchingDevice(bstrDeviceID, &pIWiaPropStg);
}
if (hr == S_OK) {
//
// find out if this is a remote device
//
#ifdef WINNT
BOOL bRemote = FALSE;
BSTR bstrServer;
bRemote = IsDeviceRemote(pIWiaPropStg, &bstrServer);
if (bRemote) {
hr = CreateRemoteDevice(bstrServer, pIWiaPropStg, ppWiaItemRoot);
SysFreeString(bstrServer);
} else {
hr = CreateLocalDevice(bstrDeviceID, pIWiaPropStg, ppWiaItemRoot);
}
#else
hr = CreateLocalDevice(bstrDeviceID, pIWiaPropStg, ppWiaItemRoot);
#endif
pIWiaPropStg->Release();
}
else {
DBG_ERR(("CWiaDevMgr::CreateDevice Failed to find device: %ls", bstrDeviceID));
hr = WIA_S_NO_DEVICE_AVAILABLE;
}
return hr;
}
/*******************************************************************************
*
* SelectDevice
*
* Never called. This method executes completely on the client side.
*
* History:
*
* 9/2/1998 Original Version
*
*******************************************************************************/
HRESULT _stdcall CWiaDevMgr::SelectDeviceDlg(
HWND hwndParent,
LONG lDeviceType,
LONG lFlags,
BSTR *pbstrDeviceID,
IWiaItem **ppWiaItemRoot)
{
DBG_FN(CWiaDevMgr::SelectDeviceDlg);
DBG_ERR(("CWiaDevMgr::SelectDeviceDlg, Illegal server call, bad proxy"));
return E_UNEXPECTED;
}
/*******************************************************************************
*
* SelectDevice
*
* Never called. This method executes completely on the client side.
*
* History:
*
* 9/2/1998 Original Version
*
*******************************************************************************/
HRESULT _stdcall CWiaDevMgr::SelectDeviceDlgID(
HWND hwndParent,
LONG lDeviceType,
LONG lFlags,
BSTR *pbstrDeviceID )
{
DBG_FN(CWiaDevMgr::SelectDeviceDlgID);
DBG_ERR(("CWiaDevMgr::SelectDeviceDlgID, Illegal server call, bad proxy"));
return E_UNEXPECTED;
}
/*******************************************************************************
*
* AddDeviceDlg
*
* Never called. This method executes completely on the client side.
*
* History:
*
* 9/2/1998 Original Version
*
*******************************************************************************/
HRESULT _stdcall CWiaDevMgr::AddDeviceDlg(
HWND hwndParent,
LONG lFlags)
{
DBG_FN(CWiaDevMgr::AddDeviceDlg);
HRESULT hres = E_NOTIMPL;
return hres;
}
/*******************************************************************************
*
* GetImage
*
* Never called. This method executes completely on the client side.
*
* History:
*
* 9/2/1998 Original Version
*
*******************************************************************************/
HRESULT _stdcall CWiaDevMgr::GetImageDlg(
HWND hwndParent,
LONG lDeviceType,
LONG lFlags,
LONG lIntent,
IWiaItem *pItemRoot,
BSTR bstrFilename,
GUID *pguidFormat)
{
DBG_FN(CWiaDevMgr::GetImageDlg);
DBG_ERR(("CWiaDevMgr::GetImageDlg, Illegal server call, bad proxy"));
return E_UNEXPECTED;
}
/*******************************************************************************
*
* CWiaDevMgr::RegisterEventCallbackProgram
*
* Register an WIA destination application
*
* Arguments:
*
* lFlags -
* bstrDeviceID -
* pEventGUID -
* bstrCommandline -
* bstrName -
* bstrDescription -
* bstrIcon -
*
* Return Value:
*
* status
*
* History:
*
* 10/14/1999 Original Version
*
*******************************************************************************/
HRESULT _stdcall CWiaDevMgr::RegisterEventCallbackProgram(
LONG lFlags,
BSTR bstrDeviceID,
const GUID *pEventGUID,
BSTR bstrCommandline,
BSTR bstrName,
BSTR bstrDescription,
BSTR bstrIcon)
{
DBG_FN(CWiaDevMgr::RegisterEventCallbackProgram);
HRESULT hr;
#ifndef UNICODE
CHAR szCommandline[MAX_PATH];
#endif
WCHAR *pPercentSign;
//
// Basic sanity check
//
if (! pEventGUID) {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackProgram, bad pEventGUID"));
return (E_INVALIDARG);
}
if (! bstrCommandline) {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackProgram, bad bstrCommandline"));
return (E_INVALIDARG);
}
//
// Check the commandline, there are either 2 % or 0
//
pPercentSign = wcschr(bstrCommandline, L'%');
if (pPercentSign) {
if ((*(pPercentSign + 1) < L'0') || (*(pPercentSign + 1) > L'9')) {
return (E_INVALIDARG);
}
pPercentSign = wcschr(pPercentSign + 1, L'%');
if (! pPercentSign) {
return (E_INVALIDARG);
}
if ((*(pPercentSign + 1) < L'0') || (*(pPercentSign + 1) > L'9')) {
return (E_INVALIDARG);
}
}
if ((lFlags != WIA_REGISTER_EVENT_CALLBACK) &&
(lFlags != WIA_SET_DEFAULT_HANDLER) &&
(lFlags != WIA_UNREGISTER_EVENT_CALLBACK)) {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackProgram, bad lFlags"));
return (E_INVALIDARG);
}
hr = CoImpersonateClient();
if (FAILED(hr)) {
DBG_ERR(("RegisterEventCallbackProgram, CoImpersonateClient failed (0x%X)", hr));
return hr;
}
#ifndef UNICODE
WideCharToMultiByte(CP_ACP,
0,
bstrCommandline,
-1,
szCommandline,
MAX_PATH,
NULL,
NULL);
hr = g_eventNotifier.RegisterEventCallback(
lFlags,
bstrDeviceID,
pEventGUID,
NULL, // No CLSID available
szCommandline,
bstrName,
bstrDescription,
bstrIcon);
#else
hr = g_eventNotifier.RegisterEventCallback(
lFlags,
bstrDeviceID,
pEventGUID,
NULL, // No CLSID available
bstrCommandline,
bstrName,
bstrDescription,
bstrIcon);
#endif
//
// Revert back to ourselves.
//
CoRevertToSelf();
return (hr);
}
/***************************************************************************
*
* RegisterEventCallbackInterface
*
* Registers an WIA Event Callback
*
* Arguments:
*
* lFlags -
* pWiaItemRoot -
* llEvents -
* pClsID - app can register using clsid or interface
* pIWIAEventCallback - app can register using clsid or interface
*
* Return Value:
*
* status
*
* History:
*
* 9/2/1998 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaDevMgr::RegisterEventCallbackInterface(
LONG lFlags,
BSTR bstrDeviceID,
const GUID *pEventGUID,
IWiaEventCallback *pIWIAEventCallback,
IUnknown **ppIEventObj)
{
DBG_FN(CWiaDevMgr::RegisterEventCallbackInterface);
HRESULT hr;
//
// Validate params
//
if (pEventGUID == NULL) {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackInterface, bad pEventGUID"));
return (E_INVALIDARG);
}
if (pIWIAEventCallback == NULL) {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackInterface, bad pIWIAEventCallback"));
return (E_INVALIDARG);
}
if (ppIEventObj == NULL) {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackInterface, bad ppIEventObj"));
return (E_INVALIDARG);
}
//
// lFlags is ignored, register the callback always
//
//
// Register event
//
hr = g_eventNotifier.RegisterEventCallback(
lFlags,
bstrDeviceID,
pEventGUID,
pIWIAEventCallback,
ppIEventObj);
return (hr);
}
/***************************************************************************
*
* RegisterEventCallbackCLSID
*
* Registers an WIA Event Callback
*
* Arguments:
*
* lFlags -
* bstrDeviceID -
* pEventGUID -
* pClsID - app can register using clsid or interface
* bstrDescription -
* bstrIcon -
*
* Return Value:
*
* status
*
* History:
*
* 9/2/1998 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaDevMgr::RegisterEventCallbackCLSID(
LONG lFlags,
BSTR bstrDeviceID,
const GUID *pEventGUID,
const GUID *pClsID,
BSTR bstrName,
BSTR bstrDescription,
BSTR bstrIcon)
{
DBG_FN(CWiaDevMgr::RegisterEventCallbackCLSID);
HRESULT hr;
//
// Validate params
//
if (pEventGUID == NULL) {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackCLSID, bad pEventGUID"));
return (E_INVALIDARG);
}
if (pClsID == NULL) {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackCLSID, bad pClsID"));
return (E_INVALIDARG);
}
if (lFlags == WIA_REGISTER_EVENT_CALLBACK) {
DBG_TRC(("CWiaDevMgr::RegisterEventCallback"));
} else {
if (lFlags == WIA_UNREGISTER_EVENT_CALLBACK) {
DBG_TRC(("CWiaDevMgr::UnregisterEventCallback"));
} else {
if (lFlags == WIA_SET_DEFAULT_HANDLER) {
DBG_TRC(("CWiaDevMgr::SetDefaultHandler"));
} else {
DBG_ERR(("CWiaDevMgr::RegisterEventCallbackCLSID, Invalid operation"));
return (HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION));
}
}
}
//
// register event
//
hr = CoImpersonateClient();
if (FAILED(hr)) {
DBG_ERR(("RegisterEventCallbackProgram, CoImpersonateClient failed (0x%X)", hr));
return hr;
}
hr = g_eventNotifier.RegisterEventCallback(
lFlags,
bstrDeviceID,
pEventGUID,
pClsID,
NULL, // No commandline necessary
bstrName,
bstrDescription,
bstrIcon);
//
// Revert back to ourselves.
//
CoRevertToSelf();
return (hr);
}
/***************************************************************************
*
* Initialize
*
* This is the first call received from the Shell's Hardware event
* notification.
*
* Arguments:
*
* pszParams - The parameter string we wrote in our registration.
* Currently, we don't specify a parameter string, so this
* will be empty.
*
* Return Value:
*
* status
*
* History:
*
* 07/12/2000 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaDevMgr::Initialize(
LPCWSTR pszParams)
{
HRESULT hr = E_FAIL;
//
// Initialize the device manager here. This is so that when HandleEvent gets
// processed, we can successfully enumerate the WIA devices.
//
hr = Initialize();
if (FAILED(hr)) {
DBG_ERR(("CWiaDevMgr::Initialize(string), Initialize() call failed"));
}
return hr;
}
/***************************************************************************
*
* HandleEventWithContent
*
* This is the second call received from the Shell's Hardware event
* notification. This tells us the driver letter of the volume that
* just arrived. Our action is to find the appropriate file system driver
* and launch the WIA Wizard.
*
* Arguments:
*
* pszDeviceID - The PnP device id. Ignored.
* pszAltDeviceID - Alternate device id. For volume arrivals,
* this is the drive letter.
* pszEventType - String signifying the event type. Ignored.
* pszContentTypeHandler - Content that triggered this event
* pdataobject - IDataObject to get an HDROP to enumerate
* the files found
*
* Return Value:
*
* status
*
* History:
*
* 08/04/2000 Original Version
*
\**************************************************************************/
HRESULT _stdcall CWiaDevMgr::HandleEventWithContent(
LPCWSTR pszDeviceID,
LPCWSTR pszAltDeviceID,
LPCWSTR pszEventType,
LPCWSTR /*pszContentTypeHandler*/,
IDataObject* pdataobject)
{
HRESULT hres = E_INVALIDARG;
BSTR bstrDeviceId = NULL;
// No need for this object
// NOTE: Appears to be a shell bug here - if I release it then it
// faults - looks like a double release.
//pdataobject->Release();
//pdataobject = NULL;
if (pszAltDeviceID)
{
hres = FindFileSystemDriver(pszAltDeviceID, &bstrDeviceId);
if (hres != S_OK) {
if (bstrDeviceId) {
SysFreeString(bstrDeviceId);
bstrDeviceId = NULL;
}
//
// Get the DeviceId of the file system driver
//
WCHAR wszDevId[STI_MAX_INTERNAL_NAME_LENGTH];
memset(wszDevId, 0, sizeof(wszDevId));
//
// Construct Device ID. Device ID looks like:
// {MountPoint}
// e.g. {e:\}
//
lstrcpyW(wszDevId, L"{");
//
// We don't want to overrun our internal name length constarint, so we first check
// to see whether the string length of pszAltDeviceID is short enough to allow concatenation
// of {, }, pszAltDeviceID and NULL terminator, and still fit all this into a string of
// length STI_MAX_INTERNAL_NAME_LENGTH.
// Note the space after the brackets in sizeof(L"{} ").
//
if (lstrlenW(pszAltDeviceID) > (STI_MAX_INTERNAL_NAME_LENGTH - (sizeof(L"{} ") / sizeof(WCHAR)))) {
//
// The name is too long, so we just insert our own name instead
//
lstrcatW(wszDevId, L"NameTooLong");
} else {
lstrcatW(wszDevId, pszAltDeviceID);
}
lstrcatW(wszDevId, L"}");
bstrDeviceId = SysAllocString(wszDevId);
}
//
// Run the Acquisition Manager on the file system driver.
//
hres = RunAcquisitionManager(bstrDeviceId);
if (bstrDeviceId) {
SysFreeString(bstrDeviceId);
bstrDeviceId = NULL;
}
}
return hres;
}
/***************************************************************************
*
* HandleEvent
*
* This should never be called. WIA does not register for it.
*
* Arguments:
*
* pszDeviceID - The PnP device id. Ignored.
* pszAltDeviceID - Alternate device id. For volume arrivals, this is
* the drive letter.
* pszEventType - String signifying the event type. Ignored.
*
* Return Value:
*
* status
*
* History:
*
* 07/12/2000 Original Version
* 08/04/2000 Replaced by HandleEventWithContent
*
\**************************************************************************/
HRESULT _stdcall CWiaDevMgr::HandleEvent(
LPCWSTR pszDeviceID,
LPCWSTR pszAltDeviceID,
LPCWSTR pszEventType)
{
return E_NOTIMPL;
}
HRESULT CWiaDevMgr::FindFileSystemDriver(
LPCWSTR pszAltDeviceID,
BSTR *pbstrDeviceId)
{
HRESULT hr = S_OK;
WCHAR *wszDevId = NULL;
ACTIVE_DEVICE *pActiveDevice = NULL;
DEVICE_INFO *pDeviceInfo = NULL;
*pbstrDeviceId = NULL;
//
// Do a full refresh.
//
hr = g_pDevMan->ReEnumerateDevices(DEV_MAN_FULL_REFRESH | DEV_MAN_GEN_EVENTS);
pActiveDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_ALT_ID, pszAltDeviceID);
//
// Let's check whether we found the device - a full refresh would have been done
// by this point if it was not found initially.
//
if (pActiveDevice) {
//
// Update the device information
//
pDeviceInfo = pActiveDevice->m_DrvWrapper.getDevInfo();
if (pDeviceInfo) {
RefreshDevInfoFromMountPoint(pDeviceInfo, (WCHAR*)pszAltDeviceID);
}
wszDevId = pActiveDevice->GetDeviceID();
pActiveDevice->Release();
} else {
DBG_WRN(("CWiaDevMgr::FindFileSystemDriver, File system driver not available for this mount point"));
hr = E_FAIL;
}
if (wszDevId) {
*pbstrDeviceId = SysAllocString(wszDevId);
if (!*pbstrDeviceId) {
DBG_WRN(("CWiaDevMgr::FindFileSystemDriver, Out of memory!"));
hr = E_OUTOFMEMORY;
}
}
return hr;
}
HRESULT CWiaDevMgr::RunAcquisitionManager(BSTR bstrDeviceId)
{
HRESULT hr = E_FAIL;
IWiaEventCallback *pCallback = NULL;
//
// CoCreate the Wia Acquisition Manager
//
hr = _CoCreateInstanceInConsoleSession (CLSID_Manager,
NULL,
CLSCTX_LOCAL_SERVER,
IID_IWiaEventCallback,
(void**)(&pCallback));
if (SUCCEEDED(hr)) {
//
// Send a Device_Connected event for the file system driver, indicating
// StiDeviceTypeDigitalCamera, so Acquisition Manager will show it's
// camera UI.
//
ULONG ulEventType = 0;
hr = pCallback->ImageEventCallback(&WIA_EVENT_DEVICE_CONNECTED,
NULL,
bstrDeviceId,
NULL,
StiDeviceTypeDigitalCamera,
NULL,
&ulEventType,
0);
if FAILED(hr) {
DBG_ERR(("CWiaDevMgr::RunAcquisitionManager, ImageEventCallback failed"));
}
pCallback->Release();
}
return hr;
}