#include "testmcro.h" #include "wiamicro.h" #include "resource.h" #include #include #include #include #ifdef DEBUG #include #endif // #define BUTTON_SUPPORT // (uncomment this to allow BUTTON SUPPORT) // button support is not functional in the test device #define MAX_BUTTONS 1 #define MAX_BUTTON_NAME 255 HINSTANCE g_hInst; // instance of this MicroDriver (used for loading from a resource) // note: MEMORYBMP, and BMP file will be added by wiafbdrv host driver. // do not include them in your extended list. // // #define _USE_EXTENDED_FORMAT_LIST (uncomment this to allow Extented file and memory formats) #define NUM_SUPPORTED_FILEFORMATS 1 GUID g_SupportedFileFormats[NUM_SUPPORTED_FILEFORMATS]; #define NUM_SUPPORTED_MEMORYFORMATS 2 GUID g_SupportedMemoryFormats[NUM_SUPPORTED_MEMORYFORMATS]; // // Button GUID array used in Capability negotiation. // Set your BUTTON guids here. These must match the GUIDS specified in // your INF. The Scan Button GUID is public to all scanners with a // scan button. // GUID g_Buttons[MAX_BUTTONS] ={{0xa6c5a715, 0x8c6e, 0x11d2,{ 0x97, 0x7a, 0x0, 0x0, 0xf8, 0x7a, 0x92, 0x6f}}}; BOOL g_bButtonNamesCreated = FALSE; WCHAR* g_ButtonNames[MAX_BUTTONS]; INT g_PalIndex = 0; // simple palette index counter (test driver specific) BOOL g_bDown = FALSE; // simple band direction bool (test drvier specific) BOOL InitializeScanner(PSCANINFO pScanInfo); VOID InitScannerDefaults(PSCANINFO pScanInfo); BOOL SetScannerSettings(PSCANINFO pScanInfo); VOID CheckButtonStatus(PVAL pValue); VOID GetButtonPress(LONG *pButtonValue); HRESULT GetInterruptEvent(PVAL pValue); LONG GetButtonCount(); HRESULT GetOLESTRResourceString(LONG lResourceID,LPOLESTR *ppsz,BOOL bLocal); VOID ReadRegistryInformation(PVAL pValue); BOOL APIENTRY DllMain( HANDLE hModule,DWORD dwreason, LPVOID lpReserved) { g_hInst = (HINSTANCE)hModule; switch(dwreason) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } /**************************************************************************\ * MicroEntry (MicroDriver Entry point) * * Called by the WIA driver to communicate with the MicroDriver. * * Arguments: * * lCommand - MicroDriver Command, sent from the WIA driver * pValue - VAL structure used for settings * * * Return Value: * * Status * * History: * * 1/20/2000 Original Version * \**************************************************************************/ WIAMICRO_API HRESULT MicroEntry(LONG lCommand, PVAL pValue) { HRESULT hr = E_NOTIMPL; DWORD dwBytesWritten = 0; INT index = 0; //#define _DEBUG_COMMANDS #ifdef _DEBUG_COMMANDS if(lCommand != CMD_STI_GETSTATUS) Trace(TEXT("Command Value (%d)"),lCommand); #endif if(pValue->pScanInfo == NULL) { return E_INVALIDARG; } switch(lCommand) { case CMD_INITIALIZE: hr = S_OK; // // create any DeviceIO handles needed, use index (1 - MAX_IO_HANDLES) to store these handles. // Index '0' is reserved by the WIA flatbed driver. The CreateFile Name is stored in the szVal // member of the VAL structure. // // pValue->pScanInfo->DeviceIOHandles[1] = CreateFileA( pValue->szVal, // GENERIC_READ | GENERIC_WRITE, // Access mask // 0, // Share mode // NULL, // SA // OPEN_EXISTING, // Create disposition // FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, // Attributes // NULL ); // // if your device supports buttons, create the BUTTON name information here.. // if(!g_bButtonNamesCreated) { for(index = 0; index < MAX_BUTTONS; index++){ g_ButtonNames[index] = (WCHAR*)CoTaskMemAlloc(MAX_BUTTON_NAME); } hr = GetOLESTRResourceString(IDS_SCAN_BUTTON_NAME,&g_ButtonNames[0],TRUE); if(SUCCEEDED(hr)){ g_bButtonNamesCreated = TRUE; } } // // Initialize the scanner's default settings // InitScannerDefaults(pValue->pScanInfo); break; case CMD_UNINITIALIZE: // // close any open handles created by the Micro driver // if(pValue->pScanInfo->DeviceIOHandles[1] != NULL){ CloseHandle(pValue->pScanInfo->DeviceIOHandles[1]); } // // if your device supports buttons, free/destroy the BUTTON name information here.. // if(g_bButtonNamesCreated) { for(index = 0; index < MAX_BUTTONS; index++){ CoTaskMemFree(g_ButtonNames[index]); } } // // close/unload libraries // hr = S_OK; break; case CMD_RESETSCANNER: // // reset scanner // hr = S_OK; break; case CMD_STI_DIAGNOSTIC: case CMD_STI_DEVICERESET: // // reset device // hr = S_OK; break; case CMD_STI_GETSTATUS: // // set status flag to ON-LINE // pValue->lVal = MCRO_STATUS_OK; pValue->pGuid = (GUID*) &GUID_NULL; // // button polling support // #ifdef BUTTON_SUPPORT CheckButtonStatus(pValue); #endif hr = S_OK; break; case CMD_SETXRESOLUTION: pValue->pScanInfo->Xresolution = pValue->lVal; hr = S_OK; break; case CMD_SETYRESOLUTION: pValue->pScanInfo->Yresolution = pValue->lVal; hr = S_OK; break; case CMD_SETCONTRAST: pValue->pScanInfo->Contrast = pValue->lVal; hr = S_OK; break; case CMD_SETINTENSITY: pValue->pScanInfo->Intensity = pValue->lVal; hr = S_OK; break; case CMD_SETDATATYPE: pValue->pScanInfo->DataType = pValue->lVal; hr = S_OK; break; case CMD_SETNEGATIVE: pValue->pScanInfo->Negative = pValue->lVal; hr = S_OK; break; case CMD_GETADFSTATUS: case CMD_GETADFHASPAPER: // pValue->lVal = MCRO_ERROR_PAPER_EMPTY; // hr = S_OK; break; case CMD_GET_INTERRUPT_EVENT: hr = GetInterruptEvent(pValue); break; case CMD_GETCAPABILITIES: pValue->lVal = 0; pValue->pGuid = NULL; pValue->ppButtonNames = NULL; hr = S_OK; break; case CMD_SETSCANMODE: hr = S_OK; switch(pValue->lVal){ case SCANMODE_FINALSCAN: Trace(TEXT("Final Scan")); break; case SCANMODE_PREVIEWSCAN: Trace(TEXT("Preview Scan")); break; default: Trace(TEXT("Unknown Scan Mode (%d)"),pValue->lVal); hr = E_FAIL; break; } break; case CMD_SETSTIDEVICEHKEY: ReadRegistryInformation(pValue); break; #ifdef _USE_EXTENDED_FORMAT_LIST // note: MEMORYBMP, and BMP file will be added by wiafbdrv host driver. // do not include them in your extended list. // case CMD_GETSUPPORTEDFILEFORMATS: g_SupportedFileFormats[0] = WiaImgFmt_JPEG; pValue->lVal = NUM_SUPPORTED_FILEFORMATS; pValue->pGuid = g_SupportedFileFormats; hr = S_OK; break; case CMD_GETSUPPORTEDMEMORYFORMATS: g_SupportedMemoryFormats[0] = WiaImgFmt_TIFF; g_SupportedMemoryFormats[1] = WiaImgFmt_MYNEWFORMAT; pValue->lVal = NUM_SUPPORTED_MEMORYFORMATS; pValue->pGuid = g_SupportedMemoryFormats; hr = S_OK; break; #endif default: Trace(TEXT("Unknown Command (%d)"),lCommand); break; } return hr; } /**************************************************************************\ * Scan (MicroDriver Entry point) * * Called by the WIA driver to acquire data from the MicroDriver. * * Arguments: * * pScanInfo - SCANINFO structure used for settings * lPhase - Current Scan phase, SCAN_FIRST, SCAN_NEXT, SCAN_FINISH... * pBuffer - data buffer to be filled with scanned data * lLength - Maximum length of pBuffer * plReceived - Number of actual bytes written to pBuffer. * * * Return Value: * * Status * * History: * * 1/20/2000 Original Version * \**************************************************************************/ WIAMICRO_API HRESULT Scan(PSCANINFO pScanInfo, LONG lPhase, PBYTE pBuffer, LONG lLength, LONG *plReceived) { if(pScanInfo == NULL) { return E_INVALIDARG; } INT i = 0; Trace(TEXT("------ Scan Requesting %d ------"),lLength); switch (lPhase) { case SCAN_FIRST: if (!SetScannerSettings(pScanInfo)) { return E_FAIL; } Trace(TEXT("SCAN_FIRST")); g_PalIndex = 0; g_bDown = FALSE; // // first phase // Trace(TEXT("Start Scan..")); case SCAN_NEXT: // SCAN_FIRST will fall through to SCAN_NEXT (because it is expecting data) // // next phase // if(lPhase == SCAN_NEXT) Trace(TEXT("SCAN_NEXT")); // // get data from the scanner and set plReceived value // // // read data // switch(pScanInfo->DataType) { case WIA_DATA_THRESHOLD: // // make buffer alternate black/White, for sample 1-bit data // memset(pBuffer,0,lLength); memset(pBuffer,255,lLength/2); break; case WIA_DATA_GRAYSCALE: // // make buffer grayscale data, for sample 8-bit data // if(!g_bDown){ g_PalIndex+=10; if(g_PalIndex > 255){ g_PalIndex = 255; g_bDown = TRUE; } } else { g_PalIndex-=10; if(g_PalIndex < 0){ g_PalIndex = 0; g_bDown = FALSE; } } memset(pBuffer,g_PalIndex,lLength); break; case WIA_DATA_COLOR: // // make buffer red, for sample color data // for (i = 0;i+2Window.xPos = x; pScanInfo->Window.yPos = y; pScanInfo->Window.xExtent = xExtent; pScanInfo->Window.yExtent = yExtent; return S_OK; } /**************************************************************************\ * ReadRegistryInformation (helper) * * Called by the MicroDriver to Read registry information from the device's * installed device section. The HKEY passed in will be closed by the host * driver after CMD_INITIALIZE is completed. * * Arguments: * * none * * Return Value: * * void * * History: * * 1/20/2000 Original Version * \**************************************************************************/ VOID ReadRegistryInformation(PVAL pValue) { HKEY hKey = NULL; if(NULL != pValue->pHandle){ hKey = (HKEY)*pValue->pHandle; // // Open DeviceData section to read driver specific information // 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) { DWORD dwWritten = sizeof(DWORD); DWORD dwType = REG_DWORD; LONG lSampleEntry = 0; RegQueryValueEx(hOpenKey, TEXT("Sample Entry"), NULL, &dwType, (LPBYTE)&lSampleEntry, &dwWritten); Trace(TEXT("lSampleEntry Value = %d"),lSampleEntry); } else { Trace(TEXT("Could not open DeviceData section")); } } } /**************************************************************************\ * InitScannerDefaults (helper) * * Called by the MicroDriver to Initialize the SCANINFO structure * * Arguments: * * none * * Return Value: * * void * * History: * * 1/20/2000 Original Version * \**************************************************************************/ VOID InitScannerDefaults(PSCANINFO pScanInfo) { pScanInfo->ADF = 0; // set to no ADF in Test device pScanInfo->RawDataFormat = WIA_PACKED_PIXEL; pScanInfo->RawPixelOrder = WIA_ORDER_BGR; pScanInfo->bNeedDataAlignment = TRUE; pScanInfo->SupportedCompressionType = 0; pScanInfo->SupportedDataTypes = SUPPORT_BW|SUPPORT_GRAYSCALE|SUPPORT_COLOR; pScanInfo->BedWidth = 8500; // 1000's of an inch (WIA compatible unit) pScanInfo->BedHeight = 11000; // 1000's of an inch (WIA compatible unit) pScanInfo->OpticalXResolution = 300; pScanInfo->OpticalYResolution = 300; pScanInfo->IntensityRange.lMin = -127; pScanInfo->IntensityRange.lMax = 127; pScanInfo->IntensityRange.lStep = 1; pScanInfo->ContrastRange.lMin = -127; pScanInfo->ContrastRange.lMax = 127; pScanInfo->ContrastRange.lStep = 1; // Scanner settings pScanInfo->Intensity = 0; pScanInfo->Contrast = 0; pScanInfo->Xresolution = 150; pScanInfo->Yresolution = 150; pScanInfo->Window.xPos = 0; pScanInfo->Window.yPos = 0; pScanInfo->Window.xExtent = (pScanInfo->Xresolution * pScanInfo->BedWidth)/1000; pScanInfo->Window.yExtent = (pScanInfo->Yresolution * pScanInfo->BedHeight)/1000; // Scanner options pScanInfo->DitherPattern = 0; pScanInfo->Negative = 0; pScanInfo->Mirror = 0; pScanInfo->AutoBack = 0; pScanInfo->ColorDitherPattern = 0; pScanInfo->ToneMap = 0; pScanInfo->Compression = 0; // Image Info pScanInfo->DataType = WIA_DATA_GRAYSCALE; pScanInfo->WidthPixels = (pScanInfo->Window.xExtent)-(pScanInfo->Window.xPos); switch(pScanInfo->DataType) { case WIA_DATA_THRESHOLD: pScanInfo->PixelBits = 1; break; case WIA_DATA_COLOR: pScanInfo->PixelBits = 24; break; case WIA_DATA_GRAYSCALE: default: pScanInfo->PixelBits = 8; break; } pScanInfo->WidthBytes = pScanInfo->Window.xExtent * (pScanInfo->PixelBits/8); pScanInfo->Lines = pScanInfo->Window.yExtent; } /**************************************************************************\ * SetScannerSettings (helper) * * Called by the MicroDriver to set the values stored in the SCANINFO structure * to the actual device. * * Arguments: * * none * * * Return Value: * * TRUE - Success, FALSE - Failure * * History: * * 1/20/2000 Original Version * \**************************************************************************/ BOOL SetScannerSettings(PSCANINFO pScanInfo) { if(pScanInfo->DataType == WIA_DATA_THRESHOLD) { pScanInfo->PixelBits = 1; pScanInfo->WidthBytes = (pScanInfo->Window.xExtent)-(pScanInfo->Window.xPos) * (pScanInfo->PixelBits/7); // // Set data type to device // // if the set fails.. // return FALSE; } else if(pScanInfo->DataType == WIA_DATA_GRAYSCALE) { pScanInfo->PixelBits = 8; pScanInfo->WidthBytes = (pScanInfo->Window.xExtent)-(pScanInfo->Window.xPos) * (pScanInfo->PixelBits/8); // // Set data type to device // // if the set fails.. // return FALSE; } else { pScanInfo->PixelBits = 24; pScanInfo->WidthBytes = (pScanInfo->Window.xExtent)-(pScanInfo->Window.xPos) * (pScanInfo->PixelBits/8); // // Set data type to device // // if the set fails.. // return FALSE; } #ifdef DEBUG Trace(TEXT("ScanInfo")); Trace(TEXT("x res = %d"),pScanInfo->Xresolution); Trace(TEXT("y res = %d"),pScanInfo->Yresolution); Trace(TEXT("bpp = %d"),pScanInfo->PixelBits); Trace(TEXT("xpos = %d"),pScanInfo->Window.xPos); Trace(TEXT("ypos = %d"),pScanInfo->Window.yPos); Trace(TEXT("xext = %d"),pScanInfo->Window.xExtent); Trace(TEXT("yext = %d"),pScanInfo->Window.yExtent); #endif // // send other values to device, use the values set in pScanInfo to set them to your // device. // return TRUE; } /**************************************************************************\ * InitializeScanner (helper) * * Called by the MicroDriver to Iniitialize any device specific operations * * Arguments: * * none * * Return Value: * * TRUE - Success, FALSE - Failure * * History: * * 1/20/2000 Original Version * \**************************************************************************/ BOOL InitializeScanner(PSCANINFO pScanInfo) { HRESULT hr = S_OK; // // Do any device initialization here... // The test device does not need any. // if (SUCCEEDED(hr)) { return TRUE; } return FALSE; } /**************************************************************************\ * CheckButtonStatus (helper) * * Called by the MicroDriver to Set the current Button pressed value. * * Arguments: * * pValue - VAL structure used for settings * * * Return Value: * * VOID * * History: * * 1/20/2000 Original Version * \**************************************************************************/ VOID CheckButtonStatus(PVAL pValue) { // // Button Polling is done here... // // // Check your device for button presses // LONG lButtonValue = 0; GetButtonPress(&lButtonValue); switch (lButtonValue) { case 1: pValue->pGuid = (GUID*) &guidScanButton; Trace(TEXT("Scan Button Pressed!")); break; default: pValue->pGuid = (GUID*) &GUID_NULL; break; } } /**************************************************************************\ * GetInterruptEvent (helper) * * Called by the MicroDriver to handle USB interrupt events. * * Arguments: * * pValue - VAL structure used for settings * * * Return Value: * * Status * * History: * * 1/20/2000 Original Version * \**************************************************************************/ HRESULT GetInterruptEvent(PVAL pValue) { // // Below is a simple example of how DeviceIOControl() can be used to // determine interrupts with a USB device. // // The test device does not support events, // So this should not be called. // BYTE InterruptData; DWORD dwIndex; DWORD dwError; OVERLAPPED Overlapped; ZeroMemory( &Overlapped, sizeof( Overlapped )); Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); HANDLE hEventArray[2] = {pValue->handle, Overlapped.hEvent}; BOOL fLooping = TRUE; BOOL bRet = TRUE; // // use the Handle created in CMD_INITIALIZE. // HANDLE InterruptHandle = pValue->pScanInfo->DeviceIOHandles[1]; while (fLooping) { // // Set the wait event, for the interrupt // bRet = DeviceIoControl( InterruptHandle, IOCTL_WAIT_ON_DEVICE_EVENT, NULL, 0, &InterruptData, sizeof(InterruptData), &dwError, &Overlapped ); if ( bRet || ( !bRet && ( ::GetLastError() == ERROR_IO_PENDING ))) { // // Wait for the event to happen // dwIndex = WaitForMultipleObjects( 2, hEventArray, FALSE, INFINITE ); // // Trap the result of the event // switch ( dwIndex ) { case WAIT_OBJECT_0+1: DWORD dwBytesRet; bRet = GetOverlappedResult( InterruptHandle, &Overlapped, &dwBytesRet, FALSE ); if ( dwBytesRet ) { // // assign the corresponding button GUID to the *pValue->pGuid // member., and Set the event. // // Change detected - signal if (*pValue->pHandle != INVALID_HANDLE_VALUE) { switch ( InterruptData ) { case 1: *pValue->pGuid = guidScanButton; Trace(TEXT("Scan Button Pressed!")); break; default: *pValue->pGuid = GUID_NULL; break; } Trace(TEXT("Setting This Event by Handle %d"),*pValue->pHandle); // // signal the event, after a button GUID was assigned. // SetEvent(*pValue->pHandle); } break; } // // reset the overlapped event // ResetEvent( Overlapped.hEvent ); break; case WAIT_OBJECT_0: // Fall through default: fLooping = FALSE; } } else { dwError = ::GetLastError(); break; } } return S_OK; } /**************************************************************************\ * GetButtonPress (helper) * * Called by the MicroDriver to set the actual button value pressed * * Arguments: * * pButtonValue - actual button pressed * * * Return Value: * * Status * * History: * * 1/20/2000 Original Version * \**************************************************************************/ VOID GetButtonPress(LONG *pButtonValue) { // // This where you can set your button value // pButtonValue = 0; } /**************************************************************************\ * GetButtonCount (helper) * * Called by the MicroDriver to get the number of buttons a device supports * * Arguments: * * none * * Return Value: * * LONG - number of supported buttons * * History: * * 1/20/2000 Original Version * \**************************************************************************/ LONG GetButtonCount() { LONG ButtonCount = 0; // // Since the test device does not have a button, // set this value to 0. For a real device with a button, // set (LONG ButtonCount = 1;) // // // determine the button count of your device // return ButtonCount; } /**************************************************************************\ * GetOLDSTRResourceString (helper) * * Called by the MicroDriver to Load a resource string in OLESTR format * * Arguments: * * lResourceID - String resource ID * ppsz - Pointer to a OLESTR to be filled with the loaded string * value * bLocal - Possible, other source for loading a resource string. * * * Return Value: * * Status * * History: * * 1/20/2000 Original Version * \**************************************************************************/ HRESULT GetOLESTRResourceString(LONG lResourceID,LPOLESTR *ppsz,BOOL bLocal) { HRESULT hr = S_OK; TCHAR szStringValue[255]; if(bLocal) { // // We are looking for a resource in our own private resource file // INT NumTCHARs = LoadString(g_hInst,lResourceID,szStringValue,sizeof(szStringValue)); DWORD dwError = GetLastError(); if (NumTCHARs <= 0) { #ifdef UNICODE Trace(TEXT("NumTCHARs = %d dwError = %d Resource ID = %d (UNICODE)szString = %ws"), NumTCHARs, dwError, lResourceID, szStringValue); #else Trace(TEXT("NumTCHARs = %d dwError = %d Resource ID = %d (ANSI)szString = %s"), NumTCHARs, dwError, lResourceID, szStringValue); #endif return E_FAIL; } // // NOTE: caller must free this allocated BSTR // #ifdef UNICODE *ppsz = NULL; *ppsz = (LPOLESTR)CoTaskMemAlloc(sizeof(szStringValue)); if(*ppsz != NULL) { wcscpy(*ppsz,szStringValue); } else { return E_OUTOFMEMORY; } #else WCHAR wszStringValue[255]; ZeroMemory(wszStringValue,sizeof(wszStringValue)); // // convert szStringValue from char* to unsigned short* (ANSI only) // MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szStringValue, lstrlenA(szStringValue)+1, wszStringValue, (sizeof(wszStringValue)/sizeof(WCHAR))); *ppsz = NULL; *ppsz = (LPOLESTR)CoTaskMemAlloc(sizeof(wszStringValue)); if(*ppsz != NULL) { wcscpy(*ppsz,wszStringValue); } else { return E_OUTOFMEMORY; } #endif } else { // // looking another place for resources?? // hr = E_NOTIMPL; } return hr; } /**************************************************************************\ * Trace * * Called by the MicroDriver to output strings to a debugger * * Arguments: * * format - formatted string to output * * * Return Value: * * VOID * * History: * * 1/20/2000 Original Version * \**************************************************************************/ VOID Trace(LPCTSTR format,...) { #ifdef DEBUG TCHAR Buffer[1024]; va_list arglist; va_start(arglist, format); wvsprintf(Buffer, format, arglist); va_end(arglist); OutputDebugString(Buffer); OutputDebugString(TEXT("\n")); #endif }