2272 lines
57 KiB
C
2272 lines
57 KiB
C
/*****************************************************************************
|
|
*
|
|
* Device.c
|
|
*
|
|
* Copyright (C) Microsoft Corporation, 1996 - 2000 All Rights Reserved.
|
|
*
|
|
* Abstract:
|
|
*
|
|
* The standard implementation of IStiDevice.
|
|
*
|
|
* Contents:
|
|
*
|
|
* CStiDevice_New
|
|
*
|
|
*****************************************************************************/
|
|
/*
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <objbase.h>
|
|
#include <regstr.h>
|
|
#include <setupapi.h>
|
|
#include <cfgmgr32.h>
|
|
#include <devguid.h>
|
|
#include <stdio.h>
|
|
|
|
#include <stilog.h>
|
|
#include <stiregi.h>
|
|
|
|
#include <sti.h>
|
|
#include <stierr.h>
|
|
#include <stiusd.h>
|
|
#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 <i CStiDevice> 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 <mf IUnknown::QueryInterface>.
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* @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 <mf IUnknown::AddRef>.
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* @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 <mf IUnknown::Release>.
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @method HRESULT | IStiDevice | QIHelper |
|
|
*
|
|
* We don't have any dynamic interfaces and simply forward
|
|
* to <f Common_QIHelper>.
|
|
*
|
|
* @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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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 <f CloseHandle> on the event
|
|
* while it has been selected into an <i IStiDevice>
|
|
* object. You must call
|
|
* <mf IStiDevice::SetEventNotification> with the
|
|
* <p hEvent> 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 <f SetEvent> the handle when
|
|
* the state of the device changes.
|
|
*
|
|
* The application should create the handle via the
|
|
* <f CreateEvent> 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 <f ResetEvent> to reset it. We put will not
|
|
* call <f ResetEvent> for event notification handles.
|
|
*
|
|
* If the <p hEvent> is zero, then notification is disabled.
|
|
*
|
|
* @returns
|
|
*
|
|
* Returns a COM error code.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: The operation completed successfully.
|
|
* <c E_INVALIDARG>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: 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 <i IStillImage::CreateDevice> 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 <mf IStillImage::EnumDevices> 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.
|
|
*
|
|
* <c STI_OK> = <c S_OK>: The operation completed successfully.
|
|
*
|
|
* <c S_FALSE>: The device had already been initialized with
|
|
* the instance GUID passed in <p lpGUID>.
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
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::<constructor>, (_ "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)
|
|
|