/***************************************************************************** * * Device.c * * Copyright (C) Microsoft Corporation, 1996 - 2000 All Rights Reserved. * * Abstract: * * The standard implementation of IStiDevice. * * Contents: * * CStiDevice_New * *****************************************************************************/ /* #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stipriv.h" #include "stiapi.h" #include "stirc.h" #include "debug.h" */ #define INITGUID #include "initguid.h" #include "sti.h" #include "stiusd.h" #include "sticomm.h" #include "enum.h" //#define COBJMACROS // // Using CreateInstance // // #define USE_REAL_OLE32 1 // // Private define // #define DbgFl DbgFlDevice /***************************************************************************** * * Declare the interfaces we will be providing. * *****************************************************************************/ Primary_Interface(CStiDevice, IStiDevice); Interface_Template_Begin(CStiDevice) Primary_Interface_Template(CStiDevice, IStiDevice) Interface_Template_End(CStiDevice) /***************************************************************************** * * @doc INTERNAL * * @struct CStiDevice | * * The device object * * * @field IStiDevice | stidev | * * Device interface * * @comm * * *****************************************************************************/ typedef struct CStiDevice { /* Supported interfaces */ IStiDevice stidev; DWORD dwVersion; RD(LONG cCrit;) D(DWORD thidCrit;) BOOL fCritInited; CRITICAL_SECTION crst; BOOL fLocked; HANDLE hNotify; PSTIDEVICECONTROL pDevCtl; IStiUSD *pUsd; LPUNKNOWN punkUsd; HKEY hkeyDeviceParameters; STI_USD_CAPS sUsdCaps; LPWSTR pszDeviceInternalName; HANDLE hDeviceStiHandle; HINSTANCE hUsdInstance; BOOL fCreateForMonitor; } CStiDevice, *PCStiDevice; #define ThisClass CStiDevice #define ThisInterface IStiDevice STDMETHODIMP LockDeviceHelper( PCStiDevice pThisDevice, DWORD dwTimeOut); STDMETHODIMP UnLockDeviceHelper( PCStiDevice pThisDevice); /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | QueryInterface | * * Gives a client access to other interfaces on an object. * * @cwrap LPStiDevice | lpStiDevice * * @parm IN REFIID | riid | * * The requested interface's IID. * * @parm OUT LPVOID * | ppvObj | * * Receives a pointer to the obtained interface. * * @returns * * Returns a COM error code. * * @xref OLE documentation for . * ***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | AddRef | * * Increments the reference count for the interface. * * @cwrap LPStiDevice | lpStiDevice * * @returns * * Returns the object reference count. * * @xref OLE documentation for . * ***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | Release | * * Decrements the reference count for the interface. * If the reference count on the object falls to zero, * the object is freed from memory. * * @cwrap LPStiDevice | lpStiDevice * * @returns * * Returns the object reference count. * * @xref OLE documentation for . * ***************************************************************************** * * @doc INTERNAL * * @method HRESULT | IStiDevice | QIHelper | * * We don't have any dynamic interfaces and simply forward * to . * * @parm IN REFIID | riid | * * The requested interface's IID. * * @parm OUT LPVOID * | ppvObj | * * Receives a pointer to the obtained interface. * ***************************************************************************** */ #ifdef DEBUG //Default_QueryInterface(CStiDevice) Default_AddRef(CStiDevice) Default_Release(CStiDevice) #else //#define CStiDevice_QueryInterface Common_QueryInterface #define CStiDevice_AddRef Common_AddRef #define CStiDevice_Release Common_Release #endif #define CStiDevice_QIHelper Common_QIHelper #pragma BEGIN_CONST_DATA #pragma END_CONST_DATA /***************************************************************************** * * @doc INTERNAL * * @method void | IStiDevice | EnterCrit | * * Enter the object critical section. * * @cwrap LPStiDevice | lpStiDevice * *****************************************************************************/ void EXTERNAL CStiDevice_EnterCrit(PCStiDevice this) { EnterCriticalSection(&this->crst); D(this->thidCrit = GetCurrentThreadId()); RD(InterlockedIncrement(&this->cCrit)); } /***************************************************************************** * * @doc INTERNAL * * @method void | IStiDevice | LeaveCrit | * * Leave the object critical section. * * @cwrap LPStiDevice | lpStiDevice * *****************************************************************************/ void EXTERNAL CStiDevice_LeaveCrit(PCStiDevice this) { #ifdef MAXDEBUG AssertF(this->cCrit); AssertF(this->thidCrit == GetCurrentThreadId()); if (InterlockedDecrement(&this->cCrit) == 0) { D(this->thidCrit = 0); } #endif LeaveCriticalSection(&this->crst); } /***************************************************************************** * * Verify device is locked * ***************************************************************************** */ BOOL CStiDevice_IsLocked(PCStiDevice this) { BOOL fRet ; CStiDevice_EnterCrit(this); fRet = this->fLocked; CStiDevice_LeaveCrit(this); return fRet; } void CStiDevice_MarkLocked(PCStiDevice this,BOOL fNewState) { CStiDevice_EnterCrit(this); this->fLocked = fNewState; CStiDevice_LeaveCrit(this); } /***************************************************************************** * * @doc INTERNAL * * @method void | IStiDevice | NotifyEvent | * * Set the event associated with the device, if any. * * @cwrap LPStiDevice | lpStiDevice * *****************************************************************************/ void EXTERNAL CStiDevice_NotifyEvent(PCStiDevice this) { if (this->hNotify) { SetEvent(this->hNotify); } } /***************************************************************************** * * @doc INTERNAL * * @method void | CStiDevice | LoadInitUSD | * * * @cwrap LPStiDevice | lpStiDevice * *****************************************************************************/ STDMETHODIMP LoadInitUSD( CStiDevice *this, HKEY hkeyDeviceParameters ) { HRESULT hres = STI_OK; IStiUSD *pNewUsd = NULL; BOOL fExternalUSD = FALSE; LPWSTR pwszCLSID = NULL; LPUNKNOWN this_punk; // // Load and initialize command translator (USD) // // We always create USD object as aggregated, so first we get Unknown // pointer and then query it for needed interfaces // this->punkUsd = NULL; IStiDevice_QueryInterface(&this->stidev,&IID_IUnknown,&this_punk); StiLogTrace(STI_TRACE_INFORMATION,MSG_LOADING_USD); // // First read CLSID for USD from the device registry key // pwszCLSID = NULL; hres = ReadRegistryString(hkeyDeviceParameters, REGSTR_VAL_USD_CLASS_W, L"",FALSE,&pwszCLSID); if (SUCCEEDED(hres) && *pwszCLSID) { if (DllInitializeCOM()) { #ifdef USE_REAL_OLE32 CLSID clsidUSD; hres = CLSIDFromString(pwszCLSID,&clsidUSD); if (SUCCEEDED(hres)) { hres = CoCreateInstance(&clsidUSD,this_punk,CLSCTX_INPROC,&IID_IUnknown,&this->punkUsd); } #else CHAR *pszAnsi; if (SUCCEEDED(OSUtil_GetAnsiString(&pszAnsi,pwszCLSID)) ) { hres = MyCoCreateInstanceA(pszAnsi,this_punk,&IID_IUnknown,&this->punkUsd,&this->hUsdInstance); FreePpv(&pszAnsi); } #endif } } else { // No class ID in registry - resort to pass through provider StiLogTrace(STI_TRACE_WARNING,MSG_LOADING_PASSTHROUGH_USD,hres); hres = CStiEmptyUSD_New(this_punk, &IID_IUnknown,&this->punkUsd); } // Free Class name FreePpv(&pwszCLSID); // // If USD object had been created - initialize it // if (SUCCEEDED(hres)) { hres = OLE_QueryInterface(this->punkUsd,&IID_IStiUSD,&pNewUsd ); if (SUCCEEDED(hres) && pNewUsd) { StiLogTrace(STI_TRACE_INFORMATION,MSG_INITIALIZING_USD); // // Initialize newly created USD object // __try { hres = IStiUSD_Initialize(pNewUsd, this->pDevCtl, STI_VERSION_REAL, hkeyDeviceParameters); } __except(EXCEPTION_EXECUTE_HANDLER ) { hres = GetExceptionCode(); } // if (SUCCEEDED(hres)) { HRESULT hResCaps; // // Now get capabilities of the USD and verify version // ZeroX(this->sUsdCaps); __try { hResCaps = IStiUSD_GetCapabilities(pNewUsd,&this->sUsdCaps); } __except (EXCEPTION_EXECUTE_HANDLER) { hResCaps = GetExceptionCode(); } if (SUCCEEDED(hResCaps) && STI_VERSION_MIN_ALLOWED <= this->sUsdCaps.dwVersion) { // // Hurray we loaded USD. // this->pUsd = pNewUsd; StiLogTrace(STI_TRACE_INFORMATION,MSG_SUCCESS_USD); } else { StiLogTrace(STI_TRACE_ERROR,MSG_OLD_USD); hres = STIERR_OLD_VERSION; } } else { StiLogTrace(STI_TRACE_ERROR,MSG_FAILED_INIT_USD,hres); } // Free original pointer to USD object //OLE_Release(this->punkUsd); // // Rules of aggregation require us to release outer object ( because it was // AddRef'd by inner object inside delegating QueryInterface // Only do it if SUCCEEDED, since the outer component wont be addref'd on // failure. // // Attention: first version of USD did not properly support aggregation, but claimed // they did, so check our internal ref counter to see if it is too low already. // if (SUCCEEDED(hres)) { { ULONG ulRC = OLE_AddRef(this_punk); OLE_Release(this_punk); if (ulRC > 1) { OLE_Release(this_punk); } } } } } else { ReportStiLogMessage(g_hStiFileLog, STI_TRACE_WARNING, TEXT("Failed to create instance of USD object ") ); } // // Free unknown interface we got to aggreagte USD object // OLE_Release(this_punk); return hres; } /***************************************************************************** * * @doc INTERNAL * * @method void | CStiDevice | QueryInterface | * * @cwrap LPStiDevice | lpStiDevice * *****************************************************************************/ STDMETHODIMP CStiDevice_QueryInterface( PSTIDEVICE pDev, RIID riid, PPV ppvObj ) { HRESULT hres; EnterProcR(IStiDevice::QueryInterface,(_ "p", pDev )); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); // // If we are asked for STI Device interface - return it. All other requests are // blindly passed to USD object // if (IsEqualIID(riid, &IID_IStiDevice) || IsEqualIID(riid, &IID_IUnknown)) { hres = Common_QueryInterface(pDev, riid, ppvObj); } /*else (IsEqualIID(riid, &IID_IStiUSD)) { // // We are asked for native USD interface - return it // if (this->pUsd) { *ppvObj= this->pUsd; OLE_AddRef(*ppvObj); hres = STI_OK; } else { hres = STIERR_NOT_INITIALIZED; } } */ else { if (this->punkUsd) { hres = IStiUSD_QueryInterface(this->punkUsd,riid,ppvObj); } else { hres = STIERR_NOINTERFACE; } } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | GetCapabilities | * * @parm PSTI_DEV_CAPS | pDevCaps | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_GetCapabilities( PSTIDEVICE pDev, PSTI_DEV_CAPS pDevCaps ) { HRESULT hres; EnterProcR(IStiDevice::GetCapabilities,(_ "pp", pDev, pDevCaps)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); STI_USD_CAPS sUsdCaps; __try { hres = IStiUSD_GetCapabilities(this->pUsd,&sUsdCaps); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } if (SUCCEEDED(hres)) { pDevCaps->dwGeneric = sUsdCaps.dwGenericCaps; } } return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | GetStatus | * * @parm PSTI_DEVICE_STATUS | PSTI_DEVICE_STATUS pDevStatus) | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_GetStatus( PSTIDEVICE pDev, PSTI_DEVICE_STATUS pDevStatus ) { HRESULT hres; EnterProcR(IStiDevice::GetStatus,(_ "pp", pDev, pDevStatus)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); ReportStiLogMessage(g_hStiFileLog, STI_TRACE_INFORMATION, TEXT("Called GetStatus on a device") ); if (CStiDevice_IsLocked(this)) { __try { hres = IStiUSD_GetStatus(this->pUsd,pDevStatus); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } else { hres = STIERR_NEEDS_LOCK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | DeviceReset | * * @parm * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_InternalReset( PCStiDevice this ) { HRESULT hres = S_OK; // // Free original pointer to USD object // CStiDevice_EnterCrit(this); // // Disconnect from monitor if connected // if ( INVALID_HANDLE_VALUE!= this->hDeviceStiHandle) { RpcStiApiCloseDevice(NULL,this->hDeviceStiHandle); this->hDeviceStiHandle = INVALID_HANDLE_VALUE; } if (this->pUsd) { CStiDevice_AddRef(this); IStiUSD_Release(this->pUsd ); this->pUsd = NULL; } if (this->punkUsd) { IStiUSD_Release(this->punkUsd ); this->punkUsd = NULL; } if (this->pDevCtl) { IStiDeviceControl_Release(this->pDevCtl); this->pDevCtl = NULL; } if (this->hNotify) { CloseHandle(this->hNotify); } if (!(this->fCreateForMonitor)) { // Unlock device if it was locked UnLockDeviceHelper(this); } // Free device name if(this->pszDeviceInternalName) { FreePpv(&this->pszDeviceInternalName); this->pszDeviceInternalName = NULL; } if(this->hUsdInstance) { // // Should do it only after last interface ptr deleted // #ifdef NOT_IMPL // FreeLibrary(this->hUsdInstance); #endif this->hUsdInstance = NULL; } CStiDevice_LeaveCrit(this); return hres; } STDMETHODIMP CStiDevice_DeviceReset( PSTIDEVICE pDev ) { HRESULT hres; EnterProcR(IStiDevice::DeviceReset,(_ "p", pDev)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (CStiDevice_IsLocked(this)) { __try { hres = IStiUSD_DeviceReset(this->pUsd); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } else { hres = STIERR_NEEDS_LOCK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | Diagnostic | * * @parm LPDIAG | pBuffer | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_Diagnostic( PSTIDEVICE pDev, LPSTI_DIAG pBuffer ) { HRESULT hres; EnterProcR(IStiDevice::Diagnostic,(_ "p", pDev, pBuffer )); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (CStiDevice_IsLocked(this)) { __try { hres = IStiUSD_Diagnostic(this->pUsd,pBuffer); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } else { hres = STIERR_NEEDS_LOCK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | LockDevice | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP LockDeviceHelper( PCStiDevice pThisDevice, DWORD dwTimeOut ) { HRESULT hres; PCStiDevice this = _thisPv(pThisDevice); hres = (HRESULT) RpcStiApiLockDevice(this->pszDeviceInternalName, dwTimeOut, this->fCreateForMonitor); if (!pThisDevice->fCreateForMonitor) { if (SUCCEEDED(hres)) { // // Call USD to lock (i.e. open any ports etc.) // __try { hres = IStiUSD_LockDevice(this->pUsd); if (SUCCEEDED(hres)) { CStiDevice_MarkLocked(this, TRUE); } else { // // The device is locked for mutally exclusive access but failed // to open port. Make sure we release the mutally exclusive lock. // UnLockDeviceHelper(this); } } __except (EXCEPTION_EXECUTE_HANDLER) { hres = HRESULT_FROM_WIN32(GetExceptionCode()); } } } return hres; } STDMETHODIMP CStiDevice_LockDevice( PSTIDEVICE pDev, DWORD dwTimeOut ) { HRESULT hres; EnterProcR(IStiDevice::LockDevice,(_ "p", pDev)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); hres = LockDeviceHelper(this, dwTimeOut); } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | UnLockDevice | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP UnLockDeviceHelper( PCStiDevice pThisDevice ) { HRESULT hres; PCStiDevice this = _thisPv(pThisDevice); hres = (HRESULT) RpcStiApiUnlockDevice(this->pszDeviceInternalName, this->fCreateForMonitor); if (!pThisDevice->fCreateForMonitor) { if (this->pUsd) { // // Call USD to unlock (i.e. close any open ports etc.) // __try { hres = IStiUSD_UnLockDevice(this->pUsd); if (SUCCEEDED(hres)) { CStiDevice_MarkLocked(this, FALSE); } } __except (EXCEPTION_EXECUTE_HANDLER) { hres = HRESULT_FROM_WIN32(GetExceptionCode()); } } } return hres; } STDMETHODIMP CStiDevice_UnLockDevice( PSTIDEVICE pDev ) { HRESULT hres; EnterProcR(IStiDevice::UnLockDevice,(_ "p", pDev)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); hres = UnLockDeviceHelper(this); } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | SetNotificationEvent | * Specify the event that should be set when the device * state changes, or turns off such notifications. * * "It is an error" to call on the event * while it has been selected into an * object. You must call * with the *

parameter set to NULL before closing the * event handle. * * If the function is successful, then the application can * use the event handle in the same manner as any other * Win32 event handle. * * @cwrap LPSTIDEVICE | lpStiDevice * * @parm IN HANDLE | hEvent | * * Specifies the event handle which will be set when the * device state changes. It "must" be an event * handle. DirectInput will the handle when * the state of the device changes. * * The application should create the handle via the * function. If the event is created as * an automatic-reset event, then the operating system will * automatically reset the event once a wait has been * satisfied. If the event is created as a manual-reset * event, then it is the application's responsibility to * call to reset it. We put will not * call for event notification handles. * * If the

is zero, then notification is disabled. * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * : The thing isn't an event handle. * * *****************************************************************************/ STDMETHODIMP CStiDevice_SetNotificationEvent( PSTIDEVICE pDev, HANDLE hEvent ) { HRESULT hres; EnterProcR(IStiDevice::SetNotificationEvent,(_ "px", pDev, hEvent )); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); // Must protect with the critical section to prevent somebody from // acquiring or setting a new event handle while we're changing it. CStiDevice_EnterCrit(this); // // Don't operate on the original handle because // the app might decide to do something strange to it // on another thread. hres = DupEventHandle(hEvent, &hEvent); if (SUCCEEDED(hres)) { // // Resetting the event serves two purposes. // // 1. It performs parameter validation for us, and // 2. The event must be reset while the device is // not acquired. if (fLimpFF(hEvent, ResetEvent(hEvent))) { if (!this->hNotify || !hEvent) { if (SUCCEEDED(hres)) { } } else { hres = STIERR_HANDLEEXISTS; } } else { hres = E_HANDLE; } CloseHandle(hEvent); } CStiDevice_LeaveCrit(this); } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | Subscribe | * * @parm LPSUBSCRIBE | ppBuffer | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_Subscribe( PSTIDEVICE pDev, LPSTISUBSCRIBE pBuffer ) { HRESULT hres; DWORD dwError = NOERROR; EnterProcR(IStiDevice::Subscribe,(_ "pp", pDev, pBuffer)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); dwError = RpcStiApiSubscribe(this->hDeviceStiHandle,pBuffer); } hres = (dwError == NOERROR) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,dwError); ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | UnSubscribe | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_UnSubscribe( PSTIDEVICE pDev ) { HRESULT hres; DWORD dwError = NOERROR; EnterProcR(IStiDevice::UnSubscribe,(_ "p", pDev)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); dwError = RpcStiApiUnSubscribe(this->hDeviceStiHandle); } hres = (dwError == NOERROR) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,dwError); ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | GetNotificationData | * * @parm LPNOTIFY | ppBuffer | * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_GetNotificationData( PSTIDEVICE pDev, LPSTINOTIFY pBuffer ) { HRESULT hres; DWORD dwError = NOERROR; EnterProcR(IStiDevice::GetNotificationData,(_ "p", pDev, pBuffer)); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); dwError = RpcStiApiGetLastNotificationData(this->hDeviceStiHandle,pBuffer); } hres = (dwError == NOERROR) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,dwError); ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | Escape | * * @parm * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_Escape( PSTIDEVICE pDev, STI_RAW_CONTROL_CODE EscapeFunction, LPVOID lpInData, DWORD cbInDataSize, LPVOID lpOutData, DWORD cbOutDataSize, LPDWORD pcbActualData ) { HRESULT hres; EnterProcR(IStiDevice::Escape,(_ "pxpxp", pDev, EscapeFunction,lpInData,cbInDataSize,lpOutData )); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (CStiDevice_IsLocked(this)) { __try { hres = IStiUSD_Escape(this->pUsd, EscapeFunction, lpInData, cbInDataSize, lpOutData, cbOutDataSize, pcbActualData ); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } else { hres = STIERR_NEEDS_LOCK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | RawReadData | * * @parm * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_RawReadData( PSTIDEVICE pDev, LPVOID lpBuffer, LPDWORD lpdwNumberOfBytes, LPOVERLAPPED lpOverlapped ) { HRESULT hres; EnterProcR(IStiDevice::RawReadData,(_ "p", pDev )); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (CStiDevice_IsLocked(this)) { __try { hres = IStiUSD_RawReadData(this->pUsd,lpBuffer,lpdwNumberOfBytes,lpOverlapped); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } else { hres = STIERR_NEEDS_LOCK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | RawWriteData | * * @parm * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_RawWriteData( PSTIDEVICE pDev, LPVOID lpBuffer, DWORD dwNumberOfBytes, LPOVERLAPPED lpOverlapped ) { HRESULT hres; EnterProcR(IStiDevice::RawWriteData,(_ "p", pDev )); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (CStiDevice_IsLocked(this)) { __try { hres = IStiUSD_RawWriteData(this->pUsd,lpBuffer,dwNumberOfBytes,lpOverlapped); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } else { hres = STIERR_NEEDS_LOCK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | RawReadCommand | * * @parm * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_RawReadCommand( PSTIDEVICE pDev, LPVOID lpBuffer, LPDWORD lpdwNumberOfBytes, LPOVERLAPPED lpOverlapped ) { HRESULT hres; EnterProcR(IStiDevice::RawReadCommand,(_ "p", pDev )); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (CStiDevice_IsLocked(this)) { __try { hres = IStiUSD_RawReadCommand(this->pUsd,lpBuffer,lpdwNumberOfBytes,lpOverlapped); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } else { hres = STIERR_NEEDS_LOCK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | RawWriteCommand | * * @parm * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_RawWriteCommand( PSTIDEVICE pDev, LPVOID lpBuffer, DWORD dwNumberOfBytes, LPOVERLAPPED lpOverlapped ) { HRESULT hres; EnterProcR(IStiDevice::RawWriteCommand,(_ "p", pDev )); if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (CStiDevice_IsLocked(this)) { __try { hres = IStiUSD_RawWriteCommand(this->pUsd,lpBuffer,dwNumberOfBytes,lpOverlapped); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } else { hres = STIERR_NEEDS_LOCK; } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | GetLastError | * * @parm * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_GetLastError( PSTIDEVICE pDev, LPDWORD pdwLastDeviceError ) { HRESULT hres = STI_OK; EnterProcR(IStiDevice::GetLastError,(_ "p", pDev )); // Validate parameters if (!pdwLastDeviceError) { ExitOleProc(); return STIERR_INVALID_PARAM; } if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (this->pDevCtl ) { // // Call USD to obtain last error information on this device // __try { hres = IStiUSD_GetLastError(this->pUsd,pdwLastDeviceError); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @method HRESULT | IStiDevice | GetLastError | * * @parm * * @returns * * Returns a COM error code. * * = : The operation completed successfully. * *****************************************************************************/ STDMETHODIMP CStiDevice_GetLastErrorInfo( PSTIDEVICE pDev, STI_ERROR_INFO *pLastErrorInfo ) { HRESULT hres = STI_OK; EnterProcR(IStiDevice::GetLastErrorInfo,(_ "p", pDev )); // Validate parameters if (!pLastErrorInfo) { ExitOleProc(); return STIERR_INVALID_PARAM; } if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); // // Call USD to obtain last error information on this device // __try { hres = IStiUSD_GetLastErrorInfo(this->pUsd,pLastErrorInfo); } __except (EXCEPTION_EXECUTE_HANDLER) { hres = GetExceptionCode(); } } ExitOleProc(); return hres; } /***************************************************************************** * * @doc EXTERNAL * * @mfunc HRESULT | IStiDevice | Initialize | * * Initialize a StiDevice object. * * Note that if this method fails, the underlying object should * be considered to be an an indeterminate state and needs to * be reinitialized before it can be subsequently used. * The method automatically * initializes the device after creating it. Applications * normally do not need to call this function. * * @cwrap LPStiDEVICE | lpStiDevice * * @parm IN REFGUID | rguid | * * Identifies the instance of the device for which the interface * should be associated. * The method * can be used to determine which instance GUIDs are supported by * the system. * * @returns * Returns a COM error code. The following error codes are * intended to be illustrative and not necessarily comprehensive. * * = : The operation completed successfully. * * : The device had already been initialized with * the instance GUID passed in

. * * *****************************************************************************/ STDMETHODIMP CStiDevice_Initialize( PSTIDEVICE pDev, HINSTANCE hinst, LPCWSTR pwszDeviceName, DWORD dwVersion, DWORD dwMode ) { HRESULT hres = STI_OK; DWORD dwControlTypeType; DWORD dwBusType; LPWSTR pwszPortName = NULL; DWORD dwFlags = 0; DWORD dwError = 0; HKEY hkeyDeviceParameters = NULL; EnterProcR(IStiDevice::Initialize,(_ "pxpxx", pDev, hinst, pwszDeviceName,dwVersion, dwMode)); // // Validate parameters // if (!SUCCEEDED(hres = hresFullValidReadPvCb(pwszDeviceName,2,3)) ) { goto Cleanup; } if (SUCCEEDED(hres = hresPvI(pDev, ThisInterface))) { PCStiDevice this = _thisPv(pDev); if (SUCCEEDED(hres = hresValidInstanceVer(hinst, dwVersion)) ) { // // Open device key // hres = OpenDeviceRegistryKey(pwszDeviceName,NULL,&hkeyDeviceParameters); if (!SUCCEEDED(hres)) { DebugOutPtszV(DbgFl, TEXT("Cannot open device registry key")); StiLogTrace(STI_TRACE_ERROR,MSG_FAILED_OPEN_DEVICE_KEY); hres = STIERR_INVALID_PARAM; goto Cleanup; } pwszPortName = NULL; ReadRegistryString(hkeyDeviceParameters, REGSTR_VAL_DEVICEPORT_W, L"",FALSE,&pwszPortName); dwBusType = ReadRegistryDwordW(hkeyDeviceParameters, REGSTR_VAL_HARDWARE_W, 0L); if (!pwszPortName ) { DebugOutPtszV(DbgFl, TEXT("Cannot read device name from registry")); StiLogTrace(STI_TRACE_ERROR,MSG_FAILED_READ_DEVICE_NAME); hres = STIERR_INVALID_PARAM; goto Cleanup; } // // Convert STI bit flags for device mode into HEL_ bit mask // dwFlags = 0L; #if 0 if (dwMode & STI_DEVICE_CREATE_DATA) dwFlags |= STI_HEL_OPEN_DATA; if (dwMode & STI_DEVICE_CREATE_STATUS) dwFlags |= STI_HEL_OPEN_CONTROL; #endif // // Create device control object, establish connection to // hardware layer // if (dwBusType & (STI_HW_CONFIG_USB | STI_HW_CONFIG_SCSI)) { dwControlTypeType = HEL_DEVICE_TYPE_WDM; } else if (dwBusType & STI_HW_CONFIG_PARALLEL) { dwControlTypeType = HEL_DEVICE_TYPE_PARALLEL; } else if (dwBusType & STI_HW_CONFIG_SERIAL) { dwControlTypeType = HEL_DEVICE_TYPE_SERIAL; } else { DebugOutPtszV(DbgFl, TEXT("Cannot determine device control type, resort to WDM")); dwControlTypeType = HEL_DEVICE_TYPE_WDM; } hres = NewDeviceControl(dwControlTypeType,dwMode,pwszPortName,dwFlags,&this->pDevCtl); if (SUCCEEDED(hres)) { // // We created device control block, now load and initialize USD // hres = LoadInitUSD(this,hkeyDeviceParameters); if (!SUCCEEDED(hres)) { // // Failed to load USD - free device control object // IStiDeviceControl_Release(this->pDevCtl); this->pDevCtl = NULL; goto Cleanup; } } else { DebugOutPtszV(DbgFl, TEXT("Cannot create/allocate Device control object")); StiLogTrace(STI_TRACE_ERROR,MSG_FAILED_CREATE_DCB,hres ); goto Cleanup; } // Store device name for future use this->pszDeviceInternalName = NULL; hres = AllocCbPpv(sizeof(WCHAR)*(OSUtil_StrLenW(pwszDeviceName)+1), &this->pszDeviceInternalName); if (SUCCEEDED(hres)) { OSUtil_lstrcpyW( this->pszDeviceInternalName, pwszDeviceName ); } // // Connect to STI monitor if we are running in data mode or in status mode with device supporintg // notifications // if (SUCCEEDED(hres) ) { if (!(dwMode & STI_DEVICE_CREATE_FOR_MONITOR)) { if ((dwMode & STI_DEVICE_CREATE_DATA) || (this->sUsdCaps.dwGenericCaps & STI_USD_GENCAP_NATIVE_PUSHSUPPORT ) ) { DWORD dwProcessID = GetCurrentProcessId(); dwError = RpcStiApiOpenDevice(NULL, pwszDeviceName, dwMode, 0, dwProcessID, &(this->hDeviceStiHandle)); hres = (dwError == NOERROR) ? S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,dwError); if (NOERROR != dwError) { DebugOutPtszV(DbgFl, TEXT("Did not connect to monitor.Rpc status=%d"),dwError); ReportStiLogMessage(g_hStiFileLog, STI_TRACE_ERROR, TEXT("Requested but failed to connect to STI monitor. ")); } } } else { // // Indicate that we are in the server process. This is // used when locking/unlocking a device // this->fCreateForMonitor = TRUE; } // // BUGBUG - Problems connecting to RPC server on Millenium . Fix IT !!! // To allow STI TWAIN to continue working - ignore error now // hres = S_OK ; // END } } } Cleanup: // // Free allocated buffers // FreePpv(&pwszPortName); // // If opened key - close it // if (hkeyDeviceParameters) { RegCloseKey(hkeyDeviceParameters); hkeyDeviceParameters = NULL; } // Did we Fail ? if (!SUCCEEDED(hres)) { DebugOutPtszV(DbgFl, TEXT("Cannot create device object.")); } ExitOleProc(); return hres; } /***************************************************************************** * * @doc INTERNAL * * @mfunc void | IStiDevice | Init | * * Initialize the internal parts of the StiDevice object. * *****************************************************************************/ HRESULT INLINE CStiDevice_Init( PCStiDevice this ) { HRESULT hr = S_OK; this->pUsd = NULL; __try { // The critical section must be the very first thing we do, // because only Finalize checks for its existence. #ifdef UNICODE if(!InitializeCriticalSectionAndSpinCount(&this->crst, MINLONG)) { #else InitializeCriticalSection(&this->crst); if (TRUE) { #endif hr = HRESULT_FROM_WIN32(GetLastError()); } else { this->fLocked = FALSE; this->hDeviceStiHandle = INVALID_HANDLE_VALUE; this->fCritInited = TRUE; this->hUsdInstance = NULL; } } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_OUTOFMEMORY; } return hr; } /***************************************************************************** * * @doc INTERNAL * * @func void | CStiDev_Finalize | * * Releases the resources of a generic device. * * @parm PV | pvObj | * * Object being released. Note that it may not have been * completely initialized, so everything should be done * carefully. * *****************************************************************************/ void INTERNAL CStiDevice_Finalize(PV pvObj) { HRESULT hres; PCStiDevice this = pvObj; #ifdef MAXDEBUG if (this->cCrit) { DebugOutPtszV(DbgFl, TEXT("IStiDevice::Release: Another thread is using the object; crash soon!")); } #endif hres = CStiDevice_InternalReset(this); AssertF(SUCCEEDED(hres)); if (this->fCritInited) { DeleteCriticalSection(&this->crst); this->fCritInited = FALSE; } } /***************************************************************************** * * @doc INTERNAL * * @mfunc HRESULT | IStiDevice | New | * * Create a new StiDevice object, uninitialized. * * @parm IN PUNK | punkOuter | * * Controlling unknown for aggregation. * * @parm IN RIID | riid | * * Desired interface to new object. * * @parm OUT PPV | ppvObj | * * Output pointer for new object. * *****************************************************************************/ STDMETHODIMP CStiDevice_New(PUNK punkOuter, RIID riid, PPV ppvObj) { HRESULT hres; EnterProcR(IStiDevice::, (_ "Gp", riid, punkOuter)); hres = Common_NewRiid(CStiDevice, punkOuter, riid, ppvObj); if (SUCCEEDED(hres)) { PCStiDevice this = _thisPv(*ppvObj); hres = CStiDevice_Init(this); } ExitOleProcPpvR(ppvObj); return hres; } /***************************************************************************** * * Miscellaneous utility functions, specific for device processing * *****************************************************************************/ /***************************************************************************** * * @doc INTERNAL * * @mfunc OpenDeviceRegistryKey * * Opens registry key, associated with device instance to use for storing/retrieving * instance information. * * Key is obtained from setup api ,based on the STI device name. We should never * open device key by concatenating fixed name with device name, as it works on Memphis. * *****************************************************************************/ STDMETHODIMP OpenDeviceRegistryKey( LPCWSTR pwszDeviceName, LPCWSTR pwszSubKeyName, HKEY *phkeyDeviceParameters ) { DWORD dwErr; WCHAR wszDeviceKeyName[MAX_PATH]; HRESULT hRes; #ifdef WINNT GUID Guid = GUID_DEVCLASS_IMAGE; DWORD dwRequired; DWORD Idx; SP_DEVINFO_DATA spDevInfoData; HKEY hKeyDevice; WCHAR szDevDriver[STI_MAX_INTERNAL_NAME_LENGTH]; TCHAR sztDevClass[32]; ULONG cbData; DWORD dwError; BOOL fRet; BOOL fFoundDriverNameMatch; PWIA_DEVKEYLIST pWiaDevKeyList; dwRequired = 0; dwError = 0; hKeyDevice = INVALID_HANDLE_VALUE; *phkeyDeviceParameters = NULL; pWiaDevKeyList = NULL; // // We need to open device registry key, navigating through Setup API set // As we don't have reverse search to retrive device info handle , based on // driver name, we do exsaustive search. Number of imaging devices for given class ID // is never as large to make a problem. // // hRes = STIERR_INVALID_DEVICE_NAME; pWiaDevKeyList = WiaCreateDeviceRegistryList(TRUE); fFoundDriverNameMatch = FALSE; if (NULL != pWiaDevKeyList) { for (Idx = 0; Idx < pWiaDevKeyList->dwNumberOfDevices; Idx++) { // // Compare driver name // cbData = sizeof(szDevDriver); *szDevDriver = L'\0'; dwError = RegQueryValueExW(pWiaDevKeyList->Dev[Idx].hkDeviceRegistry, REGSTR_VAL_DEVICE_ID_W, // REGSTR_VAL_FRIENDLY_NAME_W, NULL, NULL, (LPBYTE)szDevDriver, &cbData); if( (ERROR_SUCCESS == dwError) && (!lstrcmpiW(szDevDriver,pwszDeviceName)) ) { fFoundDriverNameMatch = TRUE; hKeyDevice = pWiaDevKeyList->Dev[Idx].hkDeviceRegistry; // // Set INVALID_HANDLE_VALUE not to get closed on free. // pWiaDevKeyList->Dev[Idx].hkDeviceRegistry = INVALID_HANDLE_VALUE; break; } } // for (Idx = 0; Idx < pWiaDevKeyList->dwNumberOfDevices; Idx++) if(fFoundDriverNameMatch) { // // Open the software key and look for subclass. // if (hKeyDevice != INVALID_HANDLE_VALUE) { cbData = sizeof(sztDevClass); if ((RegQueryValueEx(hKeyDevice, REGSTR_VAL_SUBCLASS, NULL, NULL, (LPBYTE)sztDevClass, &cbData) != ERROR_SUCCESS) || (lstrcmpi(sztDevClass, STILLIMAGE) != 0)) { fFoundDriverNameMatch = FALSE; hRes = STIERR_INVALID_DEVICE_NAME; RegCloseKey(hKeyDevice); } else { // // Now open subkey if asked to. // if (pwszSubKeyName && *pwszSubKeyName) { dwErr = OSUtil_RegCreateKeyExW(hKeyDevice, (LPWSTR)pwszSubKeyName, 0L, NULL, 0L, KEY_READ | KEY_WRITE, NULL, phkeyDeviceParameters, NULL ); if ( ERROR_ACCESS_DENIED == dwErr ) { dwErr = OSUtil_RegCreateKeyExW(hKeyDevice, (LPWSTR)pwszSubKeyName, 0L, NULL, 0L, KEY_READ, NULL, phkeyDeviceParameters, NULL ); } RegCloseKey(hKeyDevice); } else { // // No subkey given - device key will be returned - don't close it. // *phkeyDeviceParameters = hKeyDevice; dwErr = NOERROR; } // endif Subkey name passed hRes = HRESULT_FROM_WIN32(dwErr); ; } // Is StillImage subclass } // endif Opened device registry key } // endif Found matching driver name } // if (NULL != pWiaDevKeyList) // // Free device registry list. // if(NULL != pWiaDevKeyList){ WiaDestroyDeviceRegistryList(pWiaDevKeyList); } return hRes; #else // // Based on device name and optional subkey name, open requested key // wcscat(wcscpy(wszDeviceKeyName, (g_NoUnicodePlatform) ? REGSTR_PATH_STIDEVICES_W : REGSTR_PATH_STIDEVICES_NT_W), L"\\"); wcscat(wszDeviceKeyName,pwszDeviceName); // // Validate this is correct device name ? // dwErr = OSUtil_RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszDeviceKeyName, 0L, KEY_READ , phkeyDeviceParameters ); if (NOERROR != dwErr ) { if ( (dwErr == ERROR_INVALID_NAME) || (dwErr == ERROR_FILE_NOT_FOUND)) { return STIERR_INVALID_DEVICE_NAME; } return HRESULT_FROM_WIN32(dwErr); } else { RegCloseKey(*phkeyDeviceParameters); *phkeyDeviceParameters = NULL; } // // Now open subkey // if (pwszSubKeyName && *pwszSubKeyName) { wcscat(wszDeviceKeyName,L"\\"); wcscat(wszDeviceKeyName,pwszSubKeyName); } dwErr = OSUtil_RegCreateKeyExW(HKEY_LOCAL_MACHINE, wszDeviceKeyName, 0L, NULL, 0L, KEY_READ | KEY_WRITE, NULL, phkeyDeviceParameters, NULL ); if ( ERROR_ACCESS_DENIED == dwErr ) { dwErr = OSUtil_RegCreateKeyExW(HKEY_LOCAL_MACHINE, wszDeviceKeyName, 0L, NULL, 0L, KEY_READ , NULL, phkeyDeviceParameters, NULL ); } return HRESULT_FROM_WIN32(dwErr); #endif } /***************************************************************************** * * The long-awaited vtbls and templates * *****************************************************************************/ #pragma BEGIN_CONST_DATA #define CStiDevice_Signature (DWORD)'DEV' Primary_Interface_Begin(CStiDevice, IStiDevice) CStiDevice_Initialize, CStiDevice_GetCapabilities, CStiDevice_GetStatus, CStiDevice_DeviceReset, CStiDevice_Diagnostic, CStiDevice_Escape, CStiDevice_GetLastError, CStiDevice_LockDevice, CStiDevice_UnLockDevice, CStiDevice_RawReadData, CStiDevice_RawWriteData, CStiDevice_RawReadCommand, CStiDevice_RawWriteCommand, CStiDevice_Subscribe, CStiDevice_GetNotificationData, CStiDevice_UnSubscribe, CStiDevice_GetLastErrorInfo, Primary_Interface_End(CStiDevice, IStiDevice)