You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1713 lines
56 KiB
1713 lines
56 KiB
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORP., 2000
|
|
*
|
|
* TITLE: IStiUSD.cpp
|
|
*
|
|
* VERSION: 1.0
|
|
*
|
|
* DATE: 18 July, 2000
|
|
*
|
|
* DESCRIPTION:
|
|
* Implementation of the WIA sample scanner IStiUSD methods.
|
|
*
|
|
*******************************************************************************/
|
|
#include "pch.h"
|
|
#ifndef INITGUID
|
|
#include <initguid.h>
|
|
#endif
|
|
extern HINSTANCE g_hInst; // used for WIAS_LOGPROC macro
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::CWIADevice
|
|
*
|
|
* Device class constructor
|
|
*
|
|
* Arguments:
|
|
*
|
|
* None
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
CWIADevice::CWIADevice(LPUNKNOWN punkOuter):
|
|
m_cRef(1),
|
|
m_punkOuter(NULL),
|
|
m_dwLastOperationError(0),
|
|
m_dwLockTimeout(DEFAULT_LOCK_TIMEOUT),
|
|
m_bDeviceLocked(FALSE),
|
|
|
|
m_hDeviceDataHandle(NULL),
|
|
m_bPolledEvent(FALSE),
|
|
m_hFakeEventKey(NULL),
|
|
m_guidLastEvent(GUID_NULL),
|
|
|
|
m_pIDrvItemRoot(NULL),
|
|
m_pStiDevice(NULL),
|
|
m_pIWiaLog(NULL),
|
|
|
|
m_bADFEnabled(FALSE),
|
|
m_bADFAttached(TRUE),
|
|
m_lClientsConnected(0),
|
|
m_pScanAPI(NULL),
|
|
|
|
m_NumSupportedFormats(0),
|
|
m_pSupportedFormats(NULL),
|
|
m_NumSupportedCommands(0),
|
|
m_NumSupportedEvents(0),
|
|
m_pCapabilities(NULL),
|
|
m_NumInitialFormats(0),
|
|
m_pInitialFormats(NULL)
|
|
{
|
|
|
|
//
|
|
// initialize internal structures
|
|
//
|
|
|
|
memset(&m_EventOverlapped,0,sizeof(m_EventOverlapped));
|
|
memset(m_EventData,0,sizeof(m_EventData));
|
|
memset(&m_SupportedTYMED,0,sizeof(m_SupportedTYMED));
|
|
memset(&m_SupportedDataTypes,0,sizeof(m_SupportedDataTypes));
|
|
memset(&m_SupportedIntents,0,sizeof(m_SupportedIntents));
|
|
memset(&m_SupportedCompressionTypes,0,sizeof(m_SupportedCompressionTypes));
|
|
memset(&m_SupportedResolutions,0,sizeof(m_SupportedResolutions));
|
|
memset(&m_SupportedPreviewModes,0,sizeof(m_SupportedPreviewModes));
|
|
memset(&m_RootItemInitInfo,0,sizeof(m_RootItemInitInfo));
|
|
memset(&m_ChildItemInitInfo,0,sizeof(m_ChildItemInitInfo));
|
|
|
|
// See if we are aggregated. If we are (almost always the case) save
|
|
// pointer to the controlling Unknown , so subsequent calls will be
|
|
// delegated. If not, set the same pointer to "this".
|
|
if (punkOuter) {
|
|
m_punkOuter = punkOuter;
|
|
} else {
|
|
// Cast below is needed in order to point to right virtual table
|
|
m_punkOuter = reinterpret_cast<IUnknown*>(static_cast<INonDelegatingUnknown*>(this));
|
|
}
|
|
|
|
#ifdef UNKNOWN_LENGTH_FEEDER_ONLY_SCANNER
|
|
|
|
//
|
|
// since this driver supports a scanner that has only a feeder, the
|
|
// ADF Enabled flag needs to be set to TRUE by default. This will
|
|
// control the behavior of DrvAcquireItemData() method.
|
|
//
|
|
|
|
m_bADFEnabled = TRUE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::~CWIADevice
|
|
*
|
|
* Device class destructor
|
|
*
|
|
* Arguments:
|
|
*
|
|
* None
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
CWIADevice::~CWIADevice(void)
|
|
{
|
|
SetNotificationHandle(NULL);
|
|
|
|
//
|
|
// WIA member destruction
|
|
//
|
|
|
|
// Tear down the driver item tree.
|
|
if (m_pIDrvItemRoot) {
|
|
WIAS_LWARNING(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("~CWIADevice, Deleting Device Item Tree (this is OK)"));
|
|
DeleteItemTree();
|
|
m_pIDrvItemRoot = NULL;
|
|
}
|
|
|
|
// free any IO handles opened
|
|
if (m_hDeviceDataHandle) {
|
|
WIAS_LWARNING(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("~CWIADevice, Closing DefaultDeviceDataHandle"));
|
|
CloseHandle(m_hDeviceDataHandle);
|
|
m_hDeviceDataHandle = NULL;
|
|
}
|
|
|
|
// Delete allocated arrays
|
|
DeleteCapabilitiesArrayContents();
|
|
DeleteSupportedIntentsArrayContents();
|
|
|
|
if (m_pIWiaLog)
|
|
m_pIWiaLog->Release();
|
|
|
|
if (m_pScanAPI) {
|
|
// disable fake scanner device
|
|
m_pScanAPI->FakeScanner_DisableDevice();
|
|
delete m_pScanAPI;
|
|
m_pScanAPI = NULL;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::PrivateInitialize()
|
|
*
|
|
* PrivateInitialize is called from the CreateInstance() method of the
|
|
* WIA driver's class factory. It is needed to initialize the WIA
|
|
* driver object (CWIADevice). If this initialization fails the
|
|
* object will not be returned to the caller. This prevents the creation
|
|
* of a nonfunctional WIA device.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* None
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the operation succeeded
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
\**************************************************************************/
|
|
HRESULT CWIADevice::PrivateInitialize()
|
|
{
|
|
|
|
//
|
|
// attempt to create the IWiaLog interface to log status and errors to
|
|
// wiaservc.log file
|
|
//
|
|
|
|
HRESULT hr = CoCreateInstance(CLSID_WiaLog, NULL, CLSCTX_INPROC_SERVER,IID_IWiaLog,(void**)&m_pIWiaLog);
|
|
if (S_OK == hr) {
|
|
m_pIWiaLog->InitializeLog((LONG)(LONG_PTR)g_hInst);
|
|
WIAS_LTRACE(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,WIALOG_LEVEL1,("Logging COM object created successfully for wiascanr.dll"));
|
|
} else {
|
|
WIAS_LTRACE(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,WIALOG_LEVEL1,("Logging COM object not be created successfully for wiascanr.dll (STI only?)"));
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::Initialize
|
|
*
|
|
* Initialize is called by the WIA service when the driver is first loaded.
|
|
* Initialize is also called when a client uses the legacy STI APIs and
|
|
* calls IStillImage::CreateDevice() method.
|
|
*
|
|
* This method should initialize the WIA driver and the device for use.
|
|
* WIA drivers can store the pIStiDevControl interface if it needs it at a
|
|
* later time. IStiDevControl::AddRef() must be called before storing this
|
|
* interface. If you do not need to store the interface, then ignore it.
|
|
* DO NOT RELEASE the IStiDevControl interface if you have not called
|
|
* IStiDevControl::AddRef() first. This may cause unpredictable results.
|
|
*
|
|
* The IStiDeviceControl interface is needed to get information about your
|
|
* device's ports. The port name used in a CreateFile call can be obtained
|
|
* by calling the IStiDeviceControl::GetMyDevicePortName() method.
|
|
*
|
|
* For devices on shared ports, such as serial port devices, opening the port
|
|
* in Initialize() is not recommended. The port should only be opened in calls
|
|
* to IStiUsd::LockDevice(). The closing of the ports should be internally
|
|
* controlled to provide fast access. (opening and closing in
|
|
* LockDevice/UnLockDevice is very inefficent. CreateFile() could cause a delay
|
|
* making the user's experience appear slow, and nonresponsive)
|
|
*
|
|
* If this WIA driver can not support multiple CreateFile() calls on the same
|
|
* device port, then the IStiDevControl::GetMyDeviceOpenMode() should be called.
|
|
*
|
|
* The WIA driver should check the returned MODE value for the flag
|
|
* STI_DEVICE_CREATE_DATA and open the port accordingly.
|
|
*
|
|
* The following flags could be set:
|
|
*
|
|
* STI_DEVICE_CREATE_STATUS - open port for status
|
|
* STI_DEVICE_CREATE_DATA - open port for data
|
|
* STI_DEVICE_CREATE_BOTH - open port for status and data
|
|
*
|
|
* If the device port needs to be opened, a call to CreateFile() should be
|
|
* used. When opening a port the flag FILE_FLAG_OVERLAPPED should be used.
|
|
* This will allow OVERLAPPED i/o to be used when access the device. Using
|
|
* OVERLAPPED i/o will help control responsive access to the hardware. When
|
|
* a problem is detected the WIA driver can call CancelIo() to stop all
|
|
* current hardware access.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pIStiDevControl - device interface used for obtaining port information
|
|
* dwStiVersion - STI version
|
|
* hParametersKey - HKEY for registry reading/writing
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the operation was successful
|
|
* E_xxx - if the operation failed
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::Initialize(
|
|
PSTIDEVICECONTROL pIStiDevControl,
|
|
DWORD dwStiVersion,
|
|
HKEY hParametersKey)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::Initialize");
|
|
|
|
if (!pIStiDevControl) {
|
|
WIAS_LERROR(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("CWIADevice::Initialize, invalid device control interface"));
|
|
return STIERR_INVALID_PARAM;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Get the mode of the device to check why we were created. status, data, or both...
|
|
//
|
|
|
|
DWORD dwMode = 0;
|
|
hr = pIStiDevControl->GetMyDeviceOpenMode(&dwMode);
|
|
if(FAILED(hr)){
|
|
WIAS_LERROR(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("CWIADevice::Initialize, couldn't get device open mode"));
|
|
return hr;
|
|
}
|
|
|
|
if(dwMode & STI_DEVICE_CREATE_DATA)
|
|
{
|
|
//
|
|
// device is being opened for data
|
|
//
|
|
}
|
|
|
|
if(dwMode & STI_DEVICE_CREATE_STATUS)
|
|
{
|
|
//
|
|
// device is being opened for status
|
|
//
|
|
}
|
|
|
|
if(dwMode & STI_DEVICE_CREATE_BOTH)
|
|
{
|
|
//
|
|
// device is being opened for both data and status
|
|
//
|
|
}
|
|
|
|
//
|
|
// Get the name of the device port to be used in a call to CreateFile().
|
|
//
|
|
|
|
WCHAR szDevicePortNameW[MAX_PATH];
|
|
memset(szDevicePortNameW,0,sizeof(szDevicePortNameW));
|
|
|
|
hr = pIStiDevControl->GetMyDevicePortName(szDevicePortNameW,sizeof(szDevicePortNameW)/sizeof(WCHAR));
|
|
if(FAILED(hr)) {
|
|
WIAS_LERROR(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("CWIADevice::Initialize, couldn't get device port"));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// uncomment the code block below to have the driver create the kernel mode file
|
|
// handles and open a communication channel to the device.
|
|
//
|
|
|
|
/*
|
|
|
|
//
|
|
// Open kernel mode device driver. Use the FILE_FLAG_OVERLAPPED flag for proper cancellation
|
|
// of kernel mode operations and asynchronous file IO. The CancelIo() call will function
|
|
// properly if this flag is used. It is recommended to use this flag.
|
|
//
|
|
|
|
m_hDeviceDataHandle = CreateFileW(szDevicePortNameW,
|
|
GENERIC_READ | GENERIC_WRITE, // Access mask
|
|
0, // Share mode
|
|
NULL, // SA
|
|
OPEN_EXISTING, // Create disposition
|
|
FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED, // Attributes
|
|
NULL );
|
|
|
|
m_dwLastOperationError = ::GetLastError();
|
|
|
|
hr = (m_hDeviceDataHandle != INVALID_HANDLE_VALUE) ?
|
|
S_OK : MAKE_HRESULT(SEVERITY_ERROR,FACILITY_WIN32,m_dwLastOperationError);
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
*/
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
//
|
|
// creation of fake scanner device is here.
|
|
//
|
|
|
|
|
|
#ifdef UNKNOWN_LENGTH_FEEDER_ONLY_SCANNER
|
|
hr = CreateFakeScanner(&m_pScanAPI,UNKNOWN_FEEDER_ONLY_SCANNER_MODE);
|
|
#else
|
|
hr = CreateFakeScanner(&m_pScanAPI,FLATBED_SCANNER_MODE);
|
|
#endif
|
|
|
|
if (m_pScanAPI) {
|
|
|
|
//
|
|
// initialize fake scanner device
|
|
//
|
|
|
|
hr = m_pScanAPI->FakeScanner_Initialize();
|
|
} else {
|
|
WIAS_LERROR(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("Initialize, Could not create FakeScanner API object"));
|
|
hr = E_OUTOFMEMORY;
|
|
WIAS_LHRESULT(m_pIWiaLog, hr);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Open DeviceData section to read driver specific information
|
|
//
|
|
|
|
HKEY hKey = hParametersKey;
|
|
HKEY hOpenKey = NULL;
|
|
if (RegOpenKeyEx(hKey, // handle to open key
|
|
TEXT("DeviceData"), // address of name of subkey to open
|
|
0, // options (must be NULL)
|
|
KEY_QUERY_VALUE|KEY_READ, // just want to QUERY a value
|
|
&hOpenKey // address of handle to open key
|
|
) == ERROR_SUCCESS) {
|
|
|
|
|
|
|
|
//
|
|
// This is where you read registry entries for your device.
|
|
// The DeviceData section is the proper place to put this information. Information about
|
|
// your device should have been written using the WIA device's .INF installation file.
|
|
// You can access this information from this location in the Registry.
|
|
// The hParameters HKEY is owned by the WIA service. DO NOT CLOSE THIS KEY. Always close
|
|
// any HKEYS opened by this WIA driver after you are finished.
|
|
//
|
|
|
|
//
|
|
// close registry key when finished, reading DeviceData information.
|
|
//
|
|
|
|
RegCloseKey(hOpenKey);
|
|
} else {
|
|
WIAS_LERROR(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("CWIADevice::Initialize, couldn't open DeviceData KEY"));
|
|
return E_FAIL;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::GetCapabilities
|
|
*
|
|
* GetCapabilities is called by the WIA service to obtain the USD's
|
|
* capabilities. The WIA driver should fill out the following fields in the
|
|
* STI_USD_CAPS structure:
|
|
*
|
|
* 1. dwVersion field with STI_VERSION letting the WIA service know what
|
|
* version of STI this driver supports.
|
|
* 2. dwGenericCaps field with supported capabilities of the WIA device.
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pUsdCaps - Pointer to a STI_USD_CAPS USD capabilities structure.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the data can be written correctly
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
*
|
|
* Remarks:
|
|
*
|
|
* This WIA driver sets the following capability flags:
|
|
*
|
|
* 1. STI_GENCAP_WIA - This driver supports WIA
|
|
* 2. STI_USD_GENCAP_NATIVE_PUSHSUPPORT - This driver supports push buttons
|
|
* 3. STI_GENCAP_NOTIFICATIONS - This driver requires the use of interrupt
|
|
* events.
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::GetCapabilities(PSTI_USD_CAPS pUsdCaps)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::GetCapabilities");
|
|
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if (!pUsdCaps) {
|
|
WIAS_LERROR(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("CWIADevice::GetCapabilities, NULL parameter"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
memset(pUsdCaps, 0, sizeof(STI_USD_CAPS));
|
|
pUsdCaps->dwVersion = STI_VERSION; // STI verison
|
|
pUsdCaps->dwGenericCaps = STI_GENCAP_WIA| // WIA support
|
|
STI_USD_GENCAP_NATIVE_PUSHSUPPORT| // button support
|
|
STI_GENCAP_NOTIFICATIONS; // interrupt event support
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::GetStatus
|
|
*
|
|
* GetStatus is called by the WIA service for two major operations:
|
|
*
|
|
* 1. Checking device ON-LINE status.
|
|
* 2. Polling for device events. (like a push button event)
|
|
*
|
|
* Determining the operation request can be done by checking the StatusMask
|
|
* field of the STI_DEVICE_STATUS structure. The StatusMask field can be
|
|
* any of the following requests. (STI_DEVSTATUS_ONLINE_STATE or
|
|
* STI_DEVSTATUS_EVENTS_STATE)
|
|
*
|
|
* STI_DEVSTATUS_ONLINE_STATE = check if the device is ON-LINE.
|
|
*
|
|
* This operation request should be fill by setting the dwOnlinesState
|
|
* field of the STI_DEVICE_STATUS structure.
|
|
* Value that should be used are:
|
|
*
|
|
* STI_ONLINESTATE_OPERATIONAL - Device is ON-LINE and operational
|
|
* STI_ONLINESTATE_OFFLINE - Device is OFF-LINE and NOT operational
|
|
* STI_ONLINESTATE_PENDING - Device has I/O operations pending
|
|
* STI_ONLINESTATE_ERROR - Device is currently in an error state
|
|
* STI_ONLINESTATE_PAUSED - Device is paused
|
|
* STI_ONLINESTATE_PAPER_JAM - Device has a paper jam
|
|
* STI_ONLINESTATE_PAPER_PROBLEM - Device has a paper problem
|
|
* STI_ONLINESTATE_IO_ACTIVE - Device is active, but not accepting
|
|
* commands at this time
|
|
* STI_ONLINESTATE_BUSY - Device is busy
|
|
* STI_ONLINESTATE_TRANSFERRING - Device is currently transferring data
|
|
* STI_ONLINESTATE_INITIALIZING - Device is being initialized
|
|
* STI_ONLINESTATE_WARMING_UP - Device is warming up
|
|
* STI_ONLINESTATE_USER_INTERVENTION - Device requires user intervention
|
|
* to resolve a problem
|
|
* STI_ONLINESTATE_POWER_SAVE - Device is in power save mode
|
|
*
|
|
*
|
|
* STI_DEVSTATUS_EVENTS_STATE = check for device events.
|
|
*
|
|
* This operation request should be filled by setting the dwEventHandlingState
|
|
* field of the STI_DEVICE_STATUS structure.
|
|
* Values that should be used are:
|
|
*
|
|
* STI_EVENTHANDLING_PENDING - Device has an event pending and is wanting
|
|
* to report it to the WIA service.
|
|
*
|
|
* It is always a good idea to clear the STI_EVENTHANDLING_PENDING flag from
|
|
* the dwEventHandlingState member to make sure that it is properly set when
|
|
* a device event occurs.
|
|
*
|
|
* When the STI_EVENTHANDLING_PENDING is set the WIA service is signaled that
|
|
* an event has occured in the WIA driver. The WIA service calls the
|
|
* GetNotificationData() entry point to get more information about the event.
|
|
* GetNotificationData() is called for polled events and interrupt events.
|
|
* This is where you should fill out the proper event information to return to
|
|
* the WIA service.
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pDevStatus - Pointer to a STI_DEVICE_STATUS device status structure.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the data can be written correctly
|
|
* E_INVALIDARG - if an invalid parameter was passed in to the GetStatus
|
|
* method.
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
*
|
|
* Remarks:
|
|
*
|
|
* This WIA driver should set the m_guidLastEvent to the proper event GUID when
|
|
* an event is detected. It should also set the m_bPolledEvent flag to TRUE
|
|
* indicating that the event was received from a "polled source" (the GetStatus()
|
|
* call). The m_guidLastEvent is checked at a later time when the WIA service
|
|
* calls GetNotificationData().
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::GetStatus(PSTI_DEVICE_STATUS pDevStatus)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::GetStatus");
|
|
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if(!pDevStatus)
|
|
{
|
|
WIAS_LERROR(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("CWIADevice::GetStatus, NULL parameter"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// If we are asked, verify the device is online.
|
|
//
|
|
|
|
if (pDevStatus->StatusMask & STI_DEVSTATUS_ONLINE_STATE) {
|
|
|
|
WIAS_LTRACE(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,WIALOG_LEVEL2,("GetStatus, WIA is asking the device if we are ONLINE"));
|
|
|
|
//
|
|
// assume the device is OFF-LINE before continuing. This will validate
|
|
// that the on-line check was successful.
|
|
//
|
|
|
|
pDevStatus->dwOnlineState = STI_ONLINESTATE_OFFLINE;
|
|
|
|
hr = m_pScanAPI->FakeScanner_DeviceOnline();
|
|
if (SUCCEEDED(hr)) {
|
|
WIAS_LTRACE(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,WIALOG_LEVEL2,("GetStatus, Device is ONLINE"));
|
|
|
|
//
|
|
// device is ON-LINE and operational
|
|
//
|
|
|
|
pDevStatus->dwOnlineState |= STI_ONLINESTATE_OPERATIONAL;
|
|
} else {
|
|
|
|
//
|
|
// device is OFF-LINE and NOT operational
|
|
//
|
|
|
|
WIAS_LERROR(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("GetStatus, Device is OFFLINE"));
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are asked, verify state of an event handler (front panel buttons, user controlled attachments, etc..).
|
|
//
|
|
//
|
|
// If your device requires polling, then this is where you would specify the event
|
|
// result.
|
|
//
|
|
// *** It is not recommended to have polled events. Interrupt events are better
|
|
// for performance, and reliability. See the SetNotificationsHandle() method for how to
|
|
// implement interrupt events.
|
|
//
|
|
|
|
//
|
|
// clear the dwEventHandlingState field first to make sure we are really setting
|
|
// a pending event.
|
|
//
|
|
|
|
pDevStatus->dwEventHandlingState &= ~STI_EVENTHANDLING_PENDING;
|
|
if (pDevStatus->StatusMask & STI_DEVSTATUS_EVENTS_STATE) {
|
|
|
|
//
|
|
// set the polled event source flag to true, because this will control the
|
|
// behavior of the GetNotificationData() method.
|
|
//
|
|
|
|
m_bPolledEvent = TRUE;
|
|
|
|
//
|
|
// set the polled event result here, for the GetNotificationData() method to
|
|
// read and report.
|
|
//
|
|
|
|
m_guidLastEvent = GUID_NULL; // WIA_EVENT_SCAN_IMAGE is an example of an event GUID
|
|
|
|
if (m_guidLastEvent != GUID_NULL) {
|
|
|
|
//
|
|
// if the event GUID is NOT GUID_NULL, set the STI_EVENTHANDLING_PENDING flag
|
|
// letting the WIA service know that we have an event ready. This will tell
|
|
// the WIA service to call GetNotificationData() for the event specific information.
|
|
//
|
|
|
|
pDevStatus->dwEventHandlingState |= STI_EVENTHANDLING_PENDING;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::DeviceReset
|
|
*
|
|
* DeviceReset is called to reset the device to a power-on state.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* None
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if device reset was successful
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::DeviceReset(void)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::DeviceReset");
|
|
if(!m_pScanAPI){
|
|
return E_UNEXPECTED;
|
|
}
|
|
return m_pScanAPI->FakeScanner_ResetDevice();
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::Diagnostic
|
|
*
|
|
* Diagnostic is called when the device needs to be tested. The device
|
|
* default property page "Test Device" button calls this method.
|
|
*
|
|
* The WIA driver should set the following fields of the STI_DIAG structure:
|
|
* sErrorInfo - error information contained in a STI_ERROR_INFO structure,
|
|
* detailing the test results of the the diagnostic method.
|
|
* The WIA device should set the following members:
|
|
* dwGenericError - set to NOERROR if the device passed
|
|
* the diagnostic test, or to an error
|
|
* code if the device failed the test.
|
|
* dwVendorError - set this to give more information
|
|
* about the failure. Remember that
|
|
* this code is specific to this device
|
|
* only. The caller of Diagnostic will
|
|
* not know the meaning of this vendor-
|
|
* specific code.
|
|
* szExtendedErrorText - Extended error text. This member
|
|
* is limited to 255 characters.
|
|
* dwBasicDiagCode - this code indicates the type of test to be performed.
|
|
* Currently this must be set to STI_DIAGCODE_HWPRESENCE.
|
|
* dwVendorDiagCode - OPTIONAL - vendor supplied diagnostic test code.
|
|
* dwStatusMask - RESERVED FOR FUTURE USE
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pBuffer - Pointer to a STI_DIAG diagnostic result structure.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the data can be written correctly
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::Diagnostic(LPSTI_DIAG pBuffer)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::Diagnostic");
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if(!pBuffer){
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if(!m_pScanAPI){
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// initialize response buffer
|
|
//
|
|
|
|
memset(&pBuffer->sErrorInfo,0,sizeof(pBuffer->sErrorInfo));
|
|
|
|
//
|
|
// This sample device does nothing during this diagnostic method call.
|
|
// It is recommended to perform a quick test of the hardware to verify
|
|
// that it is functional within operational parameters.
|
|
//
|
|
|
|
pBuffer->sErrorInfo.dwGenericError = NOERROR;
|
|
pBuffer->sErrorInfo.dwVendorError = 0;
|
|
|
|
return m_pScanAPI->FakeScanner_Diagnostic();
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::Escape
|
|
*
|
|
* Escape is called to pass information directly to the hardware. This
|
|
* method can be called directly using the original STI (legacy) APIs or
|
|
* the IWiaItemExtras::Escape() method.
|
|
* Any WIA application can obtain access to the IWiaItemExtras interface.
|
|
* It is recommended that you validate all incoming and outgoing calls to
|
|
* this method.
|
|
*
|
|
* Recommended validation order:
|
|
* 1. validate the Function code first. If it is not one your codes, fail
|
|
* immediately. This will help to prevent incorrect codes from being
|
|
* processed in your driver.
|
|
* 2. validate the incoming buffer second. If it is not valid, fail
|
|
* immediately. Bad incoming buffers coulsd crash the WIA driver.
|
|
* 3. validate the outgoing buffer third. If it is not valid, fail
|
|
* immediately. If you can not complete the request by writing the
|
|
* necessary data why process it?
|
|
* 4. validate the outgoing size buffer last. This is important. If you can
|
|
* not write the amount of data you just wrote to the outgoing buffer
|
|
* then that data can not be properly processed by the caller.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* EscapeFunction - Command to be issued.
|
|
* pInData - Input data to be passed with command.
|
|
* cbInDataSize - Size of input data.
|
|
* pOutData - Output data to be passed back from command.
|
|
* cbOutDataSize - Size of output data buffer.
|
|
* pcbActualData - Size of output data actually written.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the operation was successful
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::Escape(
|
|
STI_RAW_CONTROL_CODE EscapeFunction,
|
|
LPVOID pInData,
|
|
DWORD cbInDataSize,
|
|
LPVOID pOutData,
|
|
DWORD cbOutDataSize,
|
|
LPDWORD pcbActualData)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::Escape");
|
|
|
|
//
|
|
// only process EscapeFunction codes that are known to your driver.
|
|
// Any application can send escape calls to your driver using the
|
|
// IWiaItemExtras interface Escape() method call. The driver must
|
|
// be prepared to validate all incoming calls to Escape().
|
|
//
|
|
|
|
//
|
|
// since this driver does not support any escape functions it will reject all
|
|
// incoming EscapeFunction codes.
|
|
//
|
|
// If your driver supports an EscapeFunction, then add your function code to the
|
|
// switch statement, and set hr = S_OK. This will allow the function to continue
|
|
// to the incoming/outgoing buffer validation.
|
|
//
|
|
|
|
HRESULT hr = E_NOTIMPL;
|
|
switch(EscapeFunction){
|
|
case 0:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// if an EscapeFunction code is supported, then first validate the incoming and
|
|
// outgoing buffers.
|
|
//
|
|
|
|
if(S_OK == hr){
|
|
|
|
//
|
|
// validate the incoming data buffer
|
|
//
|
|
|
|
if(IsBadReadPtr(pInData,cbInDataSize)){
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// if the incoming buffer is valid, proceed to validate the
|
|
// outgoing buffer
|
|
//
|
|
|
|
if(S_OK == hr){
|
|
if(IsBadWritePtr(pOutData,cbOutDataSize)){
|
|
hr = E_UNEXPECTED;
|
|
} else {
|
|
|
|
//
|
|
// validate the outgoing size pointer
|
|
//
|
|
|
|
if(IsBadWritePtr(pcbActualData,sizeof(DWORD))){
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// now that buffer validation is complete, proceed to process the proper
|
|
// EscapeFunction code.
|
|
//
|
|
|
|
if (S_OK == hr) {
|
|
|
|
//
|
|
// only process a validated EscapeFunction code, and buffers
|
|
//
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// if your driver will not support this entry point then it needs to return
|
|
// E_NOTIMPL. (error, not implemented)
|
|
//
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::GetLastError
|
|
*
|
|
* GetLastError is called to obtain the last operation error code reported
|
|
* by the WIA device. This is an error code that is specific to the WIA
|
|
* driver. If the caller wants more information about this error code then
|
|
* they will call GetLastErrorInfo(). The GetLastErrorInfo() method is
|
|
* responsible for adding more details about the requested error. (strings,
|
|
* extended codes...etc)
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pdwLastDeviceError - Pointer to a DWORD indicating the last error code.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the data can be written correctly
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::GetLastError(LPDWORD pdwLastDeviceError)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::GetLastError");
|
|
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if (!pdwLastDeviceError) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pdwLastDeviceError = m_dwLastOperationError;
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::LockDevice
|
|
*
|
|
* LockDevice is called to lock a WIA device for exclusive access. This
|
|
* method can be called directly by an application using the legacy STI
|
|
* APIs, or by the WIA service.
|
|
*
|
|
* A device should return STIERR_DEVICE_LOCKED if it has already been
|
|
* locked by another client. The WIA service will call LockDevice to
|
|
* control the exclusive access to the WIA device.
|
|
*
|
|
* Do not get this confused with drvLockWiaDevice(). IStiUsd::LockDevice
|
|
* can get called directly by an appliation using the legacy STI APIs.
|
|
* drvLockWiaDevice() is only called by the WIA service. No appliation can
|
|
* call drvLockWiaDevice().
|
|
*
|
|
* Arguments:
|
|
*
|
|
* None
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the device was successfully locked
|
|
* STIERR_DEVICE_LOCKED - Error code if the device is already locked
|
|
*
|
|
* Remarks:
|
|
*
|
|
* The WIA shell extension, which controls the visibility of a WIA device
|
|
* in the "My Computer" and "Control Panel", calls LockDevice() directly.
|
|
* This is used to lock the the device so the IStiUsd::Diagnostic() method
|
|
* can get called when the user presses the "TEST Device" button.
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::LockDevice(void)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::LockDevice");
|
|
//
|
|
// be very careful about how long locks are held. An application can
|
|
// come in using the STI APIs only, and lock your device. This lock,
|
|
// if held indefinitly could prevent access to your device from other
|
|
// applications installed on the system.
|
|
|
|
//
|
|
// It might be useful to implement some sort of reasonable locking timeout
|
|
// mechanism. If a lock is held too long, then it should be auto-unlocked.
|
|
// to allow others to access the device.
|
|
// *** This should only be done, if you know it is safe to unlock your hardware.
|
|
// Cases that may take a long time (like HUGE scans) can hold a lock for the entire
|
|
// length. A good question to ask in a long-locking case, is, "what is my driver
|
|
// doing, that requires such a long locking time?"
|
|
//
|
|
|
|
HRESULT hr = S_OK;
|
|
if (m_bDeviceLocked) {
|
|
hr = STIERR_DEVICE_LOCKED;
|
|
} else {
|
|
m_bDeviceLocked = TRUE;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::UnLockDevice
|
|
*
|
|
* UnLockDevice is called to unlock a WIA device from exclusive access. This
|
|
* method can be called directly by an application using the legacy STI
|
|
* APIs, or by the WIA service.
|
|
*
|
|
* A device should return STIERR_NEEDS_LOCK if it has not already been
|
|
* locked by another client. The WIA service will call UnLockDevice to
|
|
* release exclusive access to the WIA device.
|
|
*
|
|
* Do not get this confused with drvUnLockWiaDevice(). IStiUsd::UnLockDevice
|
|
* can get called directly by an appliation using the legacy STI APIs.
|
|
* drvUnLockWiaDevice() is only called by the WIA service. No appliation can
|
|
* call drvUnLockWiaDevice().
|
|
*
|
|
* Arguments:
|
|
*
|
|
* None
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the device was successfully locked
|
|
* STIERR_NEEDS_LOCK - Error code if the device isn't already locked
|
|
*
|
|
* Remarks:
|
|
*
|
|
* The WIA shell extension, which controls the visibility of a WIA device
|
|
* in the "My Computer" and "Control Panel", calls UnLockDevice() directly.
|
|
* (see IStiUsd::LockDevice() for details)
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::UnLockDevice(void)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::UnLockDevice");
|
|
HRESULT hr = S_OK;
|
|
if (!m_bDeviceLocked)
|
|
hr = STIERR_NEEDS_LOCK;
|
|
else {
|
|
m_bDeviceLocked = FALSE;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::RawReadData
|
|
*
|
|
* RawReadData is called to access the hardware directly. Any application
|
|
* that uses the legacy STI APIs can call RawReadData(). This method is
|
|
* used when an application (useally a vendor-supplied application or library)
|
|
* wants to read data from an open device port (controlled by this WIA driver).
|
|
*
|
|
* Arguments:
|
|
*
|
|
* lpBuffer - buffer for returned data
|
|
* lpdwNumberOfBytes - number of bytes to read/returned
|
|
* lpOverlapped - overlap
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the read was successful
|
|
* E_xxx - if the operation failed
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::RawReadData(
|
|
LPVOID lpBuffer,
|
|
LPDWORD lpdwNumberOfBytes,
|
|
LPOVERLAPPED lpOverlapped)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::RawReadData");
|
|
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if(!lpdwNumberOfBytes){
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DWORD dwNumberOfBytes = *lpdwNumberOfBytes;
|
|
|
|
if(!lpBuffer){
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// lpOverlapped is used by a call to ReadFile, or DeviceIOControl call. This
|
|
// parameter can be NULL according to those APIs.
|
|
//
|
|
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
//
|
|
// if your driver will not support this entry point then it needs to return
|
|
// E_NOTIMPL. (error, not implemented)
|
|
//
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::RawWriteData
|
|
*
|
|
* RawWriteData is called to access the hardware directly. Any application
|
|
* that uses the legacy STI APIs can call RawWriteData(). This method is
|
|
* used when an application (useally a vendor-supplied application or library)
|
|
* wants to write data to an open device port (controlled by this WIA driver).
|
|
*
|
|
* Arguments:
|
|
*
|
|
* lpBuffer - buffer for returned data
|
|
* dwNumberOfBytes - number of bytes to write
|
|
* lpOverlapped - overlap
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the write was successful
|
|
* E_xxx - if the operation failed
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::RawWriteData(
|
|
LPVOID lpBuffer,
|
|
DWORD dwNumberOfBytes,
|
|
LPOVERLAPPED lpOverlapped)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::RawWriteData");
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if(!lpBuffer){
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// lpOverlapped is used by a call to ReadFile, or DeviceIOControl call. This
|
|
// parameter can be NULL according to those APIs.
|
|
//
|
|
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
//
|
|
// if your driver will not support this entry point then it needs to return
|
|
// E_NOTIMPL. (error, not implemented)
|
|
//
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::RawReadCommand
|
|
*
|
|
* RawReadCommand is called to access the hardware directly. Any application
|
|
* that uses the legacy STI APIs can call RawReadCommand(). This method is
|
|
* used when an application (useally a vendor-supplied application or library)
|
|
* wants to read data from an open device port (controlled by this WIA driver).
|
|
*
|
|
* Arguments:
|
|
*
|
|
* lpBuffer - buffer for returned data
|
|
* lpdwNumberOfBytes - number of bytes to read/returned
|
|
* lpOverlapped - overlap
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the read was successful
|
|
* E_xxx - if the operation failed
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::RawReadCommand(
|
|
LPVOID lpBuffer,
|
|
LPDWORD lpdwNumberOfBytes,
|
|
LPOVERLAPPED lpOverlapped)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::RawReadCommand");
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if(!lpdwNumberOfBytes){
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DWORD dwNumberOfBytes = *lpdwNumberOfBytes;
|
|
|
|
if(!lpBuffer){
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// lpOverlapped is used by a call to ReadFile, or DeviceIOControl call. This
|
|
// parameter can be NULL according to those APIs.
|
|
//
|
|
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
//
|
|
// if your driver will not support this entry point then it needs to return
|
|
// E_NOTIMPL. (error, not implemented)
|
|
//
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::RawWriteCommand
|
|
*
|
|
* RawWriteCommand is called to access the hardware directly. Any application
|
|
* that uses the legacy STI APIs can call RawWriteCommand(). This method is
|
|
* used when an application (useally a vendor-supplied application or library)
|
|
* wants to write data to an open device port (controlled by this WIA driver).
|
|
*
|
|
* Arguments:
|
|
*
|
|
* lpBuffer - buffer for returned data
|
|
* nNumberOfBytes - number of bytes to write
|
|
* lpOverlapped - overlap
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the write was successful
|
|
* E_xxx - if the operation failed
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::RawWriteCommand(
|
|
LPVOID lpBuffer,
|
|
DWORD dwNumberOfBytes,
|
|
LPOVERLAPPED lpOverlapped)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::RawWriteCommand");
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if(!lpBuffer){
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// lpOverlapped is used by a call to ReadFile, or DeviceIOControl call. This
|
|
// parameter can be NULL according to those APIs.
|
|
//
|
|
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
//
|
|
// if your driver will not support this entry point then it needs to return
|
|
// E_NOTIMPL. (error, not implemented)
|
|
//
|
|
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::SetNotificationHandle
|
|
*
|
|
* SetNotificationHandle is called by the WIA service or internally by this
|
|
* driver to start or stop event notifications. The WIA service will pass
|
|
* in a valid handle (created using CreateEvent() ), indicating that it
|
|
* wants the WIA driver to signal this handle when an event occurs in the
|
|
* hardware.
|
|
*
|
|
* NULL can be passed to this SetNotificationHandle() method. NULL
|
|
* indicates that the WIA driver is to STOP all device activity, and exit
|
|
* any event wait operations.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* hEvent - HANDLE to an event created by the WIA service using CreateEvent()
|
|
* This parameter can be NULL, indicating that all previous event
|
|
* waiting should be stopped.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the operation was successful
|
|
* E_xxx - Error Code if the operation fails
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::SetNotificationHandle(HANDLE hEvent)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::SetNotificationHandle");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (hEvent && (hEvent != INVALID_HANDLE_VALUE)) {
|
|
|
|
//
|
|
// A valid handle indicates that we are asked to start our "wait"
|
|
// for device interrupt events
|
|
//
|
|
|
|
WIAS_LWARNING(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("SetNotificationHandle, hEvent = %d",hEvent));
|
|
|
|
//
|
|
// reset last event GUID to GUID_NULL
|
|
//
|
|
|
|
m_guidLastEvent = GUID_NULL;
|
|
|
|
//
|
|
// clear EventOverlapped structure
|
|
//
|
|
|
|
memset(&m_EventOverlapped,0,sizeof(m_EventOverlapped));
|
|
|
|
//
|
|
// fill overlapped hEvent member with the event passed in by the WIA service.
|
|
// This handle will be automatically signaled when an event is triggered at
|
|
// the hardware level.
|
|
//
|
|
|
|
m_EventOverlapped.hEvent = hEvent;
|
|
|
|
//
|
|
// clear event data buffer. This is the buffer that will be used to determine
|
|
// what event was signaled from the device.
|
|
//
|
|
|
|
memset(m_EventData,0,sizeof(m_EventData));
|
|
|
|
//
|
|
// the code block below starts an interrupt event session using DeviceIoControl()
|
|
//
|
|
|
|
#ifdef USE_REAL_EVENTS
|
|
|
|
//
|
|
// use the following call for interrupt events on your device
|
|
//
|
|
|
|
DWORD dwError = 0;
|
|
BOOL bResult = DeviceIoControl( m_hDeviceDataHandle,
|
|
IOCTL_WAIT_ON_DEVICE_EVENT,
|
|
NULL,
|
|
0,
|
|
&m_EventData,
|
|
sizeof(m_EventData),
|
|
&dwError,
|
|
&m_EventOverlapped );
|
|
|
|
if (bResult) {
|
|
hr = S_OK;
|
|
} else {
|
|
hr = HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
#else // USE_REAL_EVENTS
|
|
|
|
//
|
|
// THIS IS FOR TESTING ONLY, DO NOT USE THIS METHOD FOR PROCESSING DEVICE EVENTS!!!
|
|
//
|
|
|
|
if (m_hFakeEventKey) {
|
|
RegCloseKey(m_hFakeEventKey);
|
|
m_hFakeEventKey = NULL;
|
|
}
|
|
|
|
DWORD dwDisposition = 0;
|
|
if (RegCreateKeyEx(HKEY_CURRENT_USER,
|
|
HKEY_WIASCANR_FAKE_EVENTS,
|
|
0,
|
|
NULL,
|
|
0,
|
|
KEY_READ,
|
|
NULL,
|
|
&m_hFakeEventKey,
|
|
&dwDisposition) == ERROR_SUCCESS) {
|
|
|
|
if (RegNotifyChangeKeyValue(
|
|
m_hFakeEventKey, // handle to key to watch
|
|
FALSE, // subkey notification option
|
|
REG_NOTIFY_CHANGE_LAST_SET, // changes to be reported
|
|
m_EventOverlapped.hEvent, // handle to event to be signaled
|
|
TRUE // asynchronous reporting option
|
|
) == ERROR_SUCCESS ) {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
#endif // USE_REAL_EVENTS
|
|
|
|
} else {
|
|
|
|
//
|
|
// stop any hardware waiting events here, the WIA service has notified us to kill
|
|
// all hardware event waiting
|
|
//
|
|
|
|
WIAS_LWARNING(m_pIWiaLog,WIALOG_NO_RESOURCE_ID,("SetNotificationHandle, Disabling event Notifications"));
|
|
|
|
#ifdef USE_REAL_EVENTS
|
|
|
|
//
|
|
// Stop hardware interrupt events. This will actually stop all activity on the device.
|
|
// Since DeviceIOControl was used with OVERLAPPED i/o functionality the CancelIo()
|
|
// can be used to stop all kernel mode activity.
|
|
//
|
|
|
|
//
|
|
// NOTE: It is important to use overlapped i/o calls with all activity involving the
|
|
// kernel mode drivers. This will allow for proper time-outs and cancellation
|
|
// of device requests.
|
|
//
|
|
|
|
if(m_hDeviceDataHandle){
|
|
if(!CancelIo(m_hDeviceDataHandle)){
|
|
|
|
//
|
|
// cancelling of the IO failed, call GetLastError() here to determine the cause.
|
|
//
|
|
|
|
LONG lError = ::GetLastError();
|
|
|
|
}
|
|
}
|
|
|
|
#else // USE_REAL_EVENTS
|
|
|
|
if (m_hFakeEventKey) {
|
|
RegCloseKey(m_hFakeEventKey);
|
|
m_hFakeEventKey = NULL;
|
|
}
|
|
|
|
#endif // USE_REAL_EVENTS
|
|
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::GetNotificationData
|
|
*
|
|
* GetNotificationData is called by the WIA service to get information about
|
|
* an event that has just been signaled. GetNotificationsData can be called
|
|
* as a result of one of two event operations.
|
|
*
|
|
* 1. GetStatus() reported that there was an event pending, by setting the
|
|
* STI_EVENTHANDLING_PENDING flag in the STI_DEVICE_STATUS structure.
|
|
*
|
|
* 2. The hEvent handle passed in by SetNotificationHandle() was signaled
|
|
* by the hardware, or by calling SetEvent() directly.
|
|
*
|
|
* The WIA driver is responsible for filling out the STINOTIFY structure
|
|
* members:
|
|
* dwSize - size of the STINOTIFY structure.
|
|
* guidNotificationCode - GUID that represents the event that is to be
|
|
* responded to. This should be set to GUID_NULL
|
|
* if no event is to be sent. This will tell the
|
|
* WIA service that no event really happened.
|
|
* abNotificationData - OPTIONAL - vendor specific information. This data
|
|
* is limited to 64 bytes of data ONLY.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pBuffer - Pointer to a STINOTIFY structure.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the data can be written successfully
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
* Remarks:
|
|
*
|
|
* This WIA driver checks the m_bPolledEvent flag to determine where to get
|
|
* the event information from. If this flag is TRUE, it uses the event GUID
|
|
* already set by the GetStatus() call. (see GetStatus comments for details)
|
|
* If this flag is FALSE, then the WIA driver needs to look at the OVERLAPPED
|
|
* result for more information. The m_EventData BYTE array should contain
|
|
* information about the event. This is also where you can ask the device
|
|
* more information about what event just occured.
|
|
*
|
|
* Sample Notes:
|
|
*
|
|
* This WIA sample driver uses the Windows Registry to simulate the interrupt
|
|
* event signaling. It is not recommended to use this method in a production
|
|
* driver. The #define USE_REAL_EVENTS should be defined to build a WIA driver
|
|
* that uses real device events.
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::GetNotificationData( LPSTINOTIFY pBuffer )
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::GetNotificationData");
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if(!pBuffer){
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DWORD dwBytesRet = 0;
|
|
|
|
//
|
|
// check the event source flag, m_bPolledEvent.
|
|
// * If it is TRUE, just pass the event set in GetStatus() call to
|
|
// the STINOTIFY buffer and continue.
|
|
//
|
|
// * If it is FALSE, then you need to read the m_EventData buffer
|
|
// to determine what event was fired.
|
|
//
|
|
|
|
if (m_bPolledEvent == FALSE) {
|
|
|
|
#ifdef USE_REAL_EVENTS
|
|
|
|
BOOL bResult = GetOverlappedResult(m_hDeviceDataHandle, &m_EventOverlapped, &dwBytesRet, FALSE );
|
|
if (bResult) {
|
|
//
|
|
// read the m_EventData buffer to determine the proper event.
|
|
// set the m_guidLastEvent member to the proper event GUID
|
|
// set the m_guidLastEvent to GUID_NULL when an event has
|
|
// not happened that you are concerned with
|
|
//
|
|
}
|
|
|
|
#else // USE_REAL_EVENTS
|
|
|
|
if(m_hFakeEventKey){
|
|
LONG lEventCode = 0;
|
|
DWORD dwEventCodeSize = sizeof(lEventCode);
|
|
DWORD dwType = REG_DWORD;
|
|
if(RegQueryValueEx(m_hFakeEventKey,
|
|
WIASCANR_DWORD_FAKE_EVENT_CODE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE*)&lEventCode,
|
|
&dwEventCodeSize) == ERROR_SUCCESS){
|
|
|
|
//
|
|
// process event code
|
|
//
|
|
|
|
switch(lEventCode){
|
|
case ID_FAKE_SCANBUTTON:
|
|
m_guidLastEvent = WIA_EVENT_SCAN_IMAGE;
|
|
break;
|
|
case ID_FAKE_COPYBUTTON:
|
|
m_guidLastEvent = WIA_EVENT_SCAN_PRINT_IMAGE;
|
|
break;
|
|
case ID_FAKE_FAXBUTTON:
|
|
m_guidLastEvent = WIA_EVENT_SCAN_FAX_IMAGE;
|
|
break;
|
|
case ID_FAKE_NOEVENT:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // USE_REAL_EVENTS
|
|
|
|
}
|
|
|
|
//
|
|
// If the event was triggered, then fill in the STINOTIFY structure with
|
|
// the proper event information
|
|
//
|
|
|
|
if (m_guidLastEvent != GUID_NULL) {
|
|
memset(pBuffer,0,sizeof(STINOTIFY));
|
|
pBuffer->dwSize = sizeof(STINOTIFY);
|
|
pBuffer->guidNotificationCode = m_guidLastEvent;
|
|
|
|
//
|
|
// reset the Last event GUID to GUID_NULL to clear the cached event
|
|
//
|
|
|
|
m_guidLastEvent = GUID_NULL;
|
|
} else {
|
|
return STIERR_NOEVENTS;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* CWIADevice::GetLastErrorInfo
|
|
*
|
|
* GetLastErrorInfo is called to get more information about a WIA device
|
|
* specific error code. This code could come from the IStiUsd::GetLastError()
|
|
* method call, or a vendor specific application may want more information
|
|
* about a known error code.
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pLastErrorInfo - Pointer to extended device error data.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* S_OK - if the data can be written correctly
|
|
* E_xxx - Error code if the operation fails
|
|
*
|
|
* History:
|
|
*
|
|
* 03/05/2002 Original Version
|
|
*
|
|
\**************************************************************************/
|
|
|
|
STDMETHODIMP CWIADevice::GetLastErrorInfo(STI_ERROR_INFO *pLastErrorInfo)
|
|
{
|
|
CWiaLogProc WIAS_LOGPROC(m_pIWiaLog,
|
|
WIALOG_NO_RESOURCE_ID,
|
|
WIALOG_LEVEL3,
|
|
"CWIADevice::GetLastErrorInfo");
|
|
|
|
//
|
|
// If the caller did not pass in the correct parameters, then fail the
|
|
// call with E_INVALIDARG.
|
|
//
|
|
|
|
if (!pLastErrorInfo) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
pLastErrorInfo->dwGenericError = m_dwLastOperationError;
|
|
pLastErrorInfo->szExtendedErrorText[0] = '\0';
|
|
|
|
return S_OK;
|
|
}
|