//------------------------------------------------------------------------------ // Copyright (c) 1999-2000 Microsoft Corporation. // // device.cpp // // Implement IrTran-P device methods. // // Author: // // EdwardR 12-Aug-1999 Modeled from code by ReedB. // //------------------------------------------------------------------------------ #include #include #include #include "ircamera.h" #include "resource.h" #include "tcamprop.h" // #include "/nt/private/windows/imagein/ui/uicommon/simstr.h" // #include "/nt/private/windows/imagein/ui/inc/shellext.h" extern HINSTANCE g_hInst; extern DWORD EnableDisableIrCOMM( IN BOOL fDisable ); // irtranp\irtranp.cpp DWORD WINAPI EventMonitorThread( IN void *pvIrUsdDevice ); // Forward Ref. #define SZ_REG_KEY_INFRARED TEXT("Control Panel\\Infrared") #define SZ_REG_KEY_IRTRANP TEXT("Control Panel\\Infrared\\IrTranP") #define SZ_REG_DISABLE_IRCOMM TEXT("DisableIrCOMM") HKEY g_hRegistryKey = 0; //-------------------------------------------------------------------------- // SignalWIA() // // Helper function used by the IrTran-P code to signal WIA that a new // picture has arrived. // // Arguments: // // pvIrUsdDevice -- Device object. IrTran-P only knows this as a void*. // //-------------------------------------------------------------------------- DWORD SignalWIA( IN char *pszPathPlusFileName, IN void *pvIrUsdDevice ) { HRESULT hr; DWORD dwStatus = 0; IrUsdDevice *pIrUsdDevice = (IrUsdDevice*)pvIrUsdDevice; // // First, add the new picture to the tree representing the images: // if (pIrUsdDevice && pIrUsdDevice->IsInitialized()) { TCHAR *ptszPath; TCHAR *ptszFileName; #ifdef UNICODE int iStatus; WCHAR wszTemp[MAX_PATH]; iStatus = MultiByteToWideChar( CP_ACP, 0, pszPathPlusFileName, -1, // Auto-calculate length... wszTemp, MAX_PATH); ptszPath = wszTemp; ptszFileName = wcsrchr(wszTemp,L'\\'); ptszFileName++; #else ptszPath = pszPathPlusFileName; ptszFileName = strrchr(pszPathPlusFileName,'\\'); ptszFileName++; #endif IrUsdDevice *pIrUsdDevice = (IrUsdDevice*)pvIrUsdDevice; IWiaDrvItem *pNewImage; hr = pIrUsdDevice->CreateItemFromFileName( WiaItemTypeFile | WiaItemTypeImage, ptszPath, ptszFileName, &pNewImage); if (!FAILED(hr)) { IWiaDrvItem *pDrvItemRoot = pIrUsdDevice->GetDrvItemRoot(); hr = pNewImage->AddItemToFolder(pDrvItemRoot); pNewImage->Release(); } else { WIAS_ERROR((g_hInst,"SignalWIA(): CreateItemFromFileName() Failed: %x",hr)); } } // // Now, signal WIA: // if (pIrUsdDevice) { DWORD dwNewTime = GetTickCount(); DWORD dwDelta = dwNewTime - pIrUsdDevice->m_dwLastConnectTime; if (dwDelta > RECONNECT_TIMEOUT) { pIrUsdDevice->m_guidLastEvent = WIA_EVENT_DEVICE_CONNECTED; if (!SetEvent(pIrUsdDevice->m_hSignalEvent)) { dwStatus = GetLastError(); WIAS_ERROR((g_hInst,"SignalWIA(): SetEvent() Failed: %d",dwStatus)); } } else { pIrUsdDevice->m_guidLastEvent = WIA_EVENT_ITEM_CREATED; if (!SetEvent(pIrUsdDevice->m_hSignalEvent)) { dwStatus = GetLastError(); WIAS_ERROR((g_hInst,"SignalWIA(): SetEvent() Failed: %d",dwStatus)); } } pIrUsdDevice->m_dwLastConnectTime = dwNewTime; } else { WIAS_ERROR((g_hInst,"SignalWIA(): null pvIrUsdDevice object")); return dwStatus; } // // Display IrCamera browser if it's not already up: // #if FALSE HINSTANCE hInst = LoadLibrary(TEXT("WIASHEXT.DLL")); if (hInst) { WIAMAKEFULLPIDLFORDEVICE pfn = (WIAMAKEFULLPIDLFORDEVICE)GetProcAddress(hInst, "MakeFullPidlForDevice"); if (pfn) { LPITEMIDLIST pidl = NULL; pfn( pIrUsdDevice->m_bstrDeviceID, &pidl ); if (pidl) { SHELLEXECUTEINFO sei; memset( &sei, 0, sizeof(sei) ); sei.cbSize = sizeof(sei); // sei.hwnd = hDlg; sei.fMask = SEE_MASK_IDLIST; sei.nShow = SW_SHOW; sei.lpIDList = pidl; ShellExecuteEx( &sei ); LPMALLOC pMalloc = NULL; if (SUCCEEDED(SHGetMalloc(&pMalloc)) && pMalloc) { pMalloc->Free(pidl); pMalloc->Release(); } } } FreeLibrary( hInst ); } #endif return dwStatus; } //-------------------------------------------------------------------------- // IrUsdDevice::IrUsdDevice() // // Device class constructor // // Arguments: // // punkOuter // // Return Value: // // None // //-------------------------------------------------------------------------- IrUsdDevice::IrUsdDevice( LPUNKNOWN punkOuter ): m_cRef(1), m_punkOuter(NULL), m_dwLastConnectTime(0), m_fValid(FALSE), m_pIStiDevControl(NULL), m_hShutdownEvent(INVALID_HANDLE_VALUE), m_hRegistryEvent(INVALID_HANDLE_VALUE), m_hSignalEvent(INVALID_HANDLE_VALUE), m_hIrTranPThread(NULL), m_hEventMonitorThread(NULL), m_guidLastEvent(GUID_NULL), m_pIWiaEventCallback(NULL), m_pStiDevice(NULL), m_bstrDeviceID(NULL), m_bstrRootFullItemName(NULL), m_pIDrvItemRoot(NULL) { WIAS_TRACE((g_hInst,"IrUsdDevice::IrUsdDevice")); // // 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 (static_cast (this)); } } HRESULT IrUsdDevice::PrivateInitialize() { HRESULT hr = S_OK; __try { if(!InitializeCriticalSectionAndSpinCount(&m_csShutdown, MINLONG)) { hr = HRESULT_FROM_WIN32(::GetLastError()); WIAS_ERROR((g_hInst,"IrUsdDevice::PrivateInitialize, create shutdown CritSect failed")); } } __except(EXCEPTION_EXECUTE_HANDLER) { hr = E_OUTOFMEMORY; } if(hr == S_OK) { // // Create event for syncronization of notifications shutdown. // m_hShutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hShutdownEvent && (INVALID_HANDLE_VALUE != m_hShutdownEvent)) { m_fValid = TRUE; } else { hr = HRESULT_FROM_WIN32(::GetLastError()); WIAS_ERROR((g_hInst,"IrUsdDevice::PrivateInitialize, create shutdown event failed")); } } return hr; } //------------------------------------------------------------------------ // IrUsdDevice::~IrUsdDevice // // Device class destructor // // Arguments: // // None // // Return Value: // // None // //------------------------------------------------------------------------ IrUsdDevice::~IrUsdDevice(void) { WIAS_TRACE((g_hInst,"IrUsdDevice::~IrUsdDevice")); // // Kill notification thread if it exists. // SetNotificationHandle(NULL); // // Close event for syncronization of notifications shutdown. // if (m_hShutdownEvent && (m_hShutdownEvent != INVALID_HANDLE_VALUE)) { CloseHandle(m_hShutdownEvent); } if (m_hRegistryEvent && (m_hRegistryEvent != INVALID_HANDLE_VALUE)) { CloseHandle(m_hRegistryEvent); } // // Release the device control interface. // if (m_pIStiDevControl) { m_pIStiDevControl->Release(); m_pIStiDevControl = NULL; } // // WIA member destruction // // Cleanup the WIA event sink. // if (m_pIWiaEventCallback) { m_pIWiaEventCallback->Release(); } // // Free the storage for the device ID. // if (m_bstrDeviceID) { SysFreeString(m_bstrDeviceID); } // // Release the objects supporting device property storage. // if (m_bstrRootFullItemName) { SysFreeString(m_bstrRootFullItemName); } // // Free the critical section. // DeleteCriticalSection(&m_csShutdown); } /**************************************************************************\ * IrUsdDevice::GetCapabilities * * Get the device STI capabilities. * * Arguments: * * pUsdCaps - Pointer to USD capabilities data. * * Return Value: * * Status. * * History: * * 9/11/1998 Original Version * \**************************************************************************/ STDMETHODIMP IrUsdDevice::GetCapabilities(PSTI_USD_CAPS pUsdCaps) { ZeroMemory(pUsdCaps, sizeof(*pUsdCaps)); pUsdCaps->dwVersion = STI_VERSION; // // We do support device notifications, but do not requiring polling. // pUsdCaps->dwGenericCaps = STI_USD_GENCAP_NATIVE_PUSHSUPPORT; return STI_OK; } //-------------------------------------------------------------------------- // IrUsdDevice::GetStatus() // // Query device online and/or event status. // // Arguments: // // pDevStatus - Pointer to device status data. // // Return Value: // // HRESULT - STI_OK // E_INVALIDARG // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::GetStatus( IN OUT PSTI_DEVICE_STATUS pDevStatus ) { WIAS_TRACE((g_hInst,"IrUsdDevice::GetStatus()")); // // Validate parameters. // if (!pDevStatus) { WIAS_ERROR((g_hInst,"IrUsdDevice::GetStatus, NULL device status")); return E_INVALIDARG; } // // If we are asked, verify whether device is online. // pDevStatus->dwOnlineState = 0L; if (pDevStatus->StatusMask & STI_DEVSTATUS_ONLINE_STATE) { // // The IrTran-P device is always on-line: // pDevStatus->dwOnlineState |= STI_ONLINESTATE_OPERATIONAL; } // // If we are asked, verify state of event. // pDevStatus->dwEventHandlingState &= ~STI_EVENTHANDLING_PENDING; if (pDevStatus->StatusMask & STI_DEVSTATUS_EVENTS_STATE) { // // Generate an event the first time we load. // if (m_bUsdLoadEvent) { pDevStatus->dwEventHandlingState = STI_EVENTHANDLING_PENDING; m_guidLastEvent = guidEventFirstLoaded; m_bUsdLoadEvent = FALSE; } // // event pending ??? // } return STI_OK; } //-------------------------------------------------------------------------- // IrUsdDevice::DeviceReset() // // Reset data file pointer to start of file. For IrTran-P, we don't need // to do anything. // // Arguments: // // None // // Return Value: // // HRESULT - STI_OK // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::DeviceReset(void) { WIAS_TRACE((g_hInst,"IrUsdDevice::DeviceReset()")); return STI_OK; } //-------------------------------------------------------------------------- // IrUsdDevice::Diagnostic() // // Run the camera through a test diagnostic. The IrTran-P device will // always pass the diagnostic. // // Arguments: // // pBuffer - Pointer o diagnostic results data. // // Return Value: // // HRESULT - STI_OK // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::Diagnostic( IN OUT LPSTI_DIAG pBuffer ) { WIAS_TRACE((g_hInst,"IrUsdDevice::Diagnostic()")); // // Initialize response buffer // pBuffer->dwStatusMask = 0; memset( &pBuffer->sErrorInfo, 0, sizeof(pBuffer->sErrorInfo) ); pBuffer->sErrorInfo.dwGenericError = NOERROR; pBuffer->sErrorInfo.dwVendorError = 0; return STI_OK; } //-------------------------------------------------------------------------- // IrUsdDevice::StartIrTranPThread() // //-------------------------------------------------------------------------- DWORD IrUsdDevice::StartIrTranPThread() { DWORD dwStatus = S_OK; DWORD dwThread; if (!m_hIrTranPThread) { m_hIrTranPThread = CreateThread( NULL, // Default security 0, // Default stack size IrTranP, // IrTran-P protocol eng. (LPVOID)this, 0, // Creation flags &dwThread); // New thread ID. if (!m_hIrTranPThread) { dwStatus = ::GetLastError(); WIAS_ERROR((g_hInst,"IrUsdDevice::SetNotificationHandle(): unable to create IrTran-P thread: %d",dwStatus)); } } return dwStatus; } //-------------------------------------------------------------------------- // IrUsdDevice::StopIrTranPThread() // //-------------------------------------------------------------------------- DWORD IrUsdDevice::StopIrTranPThread() { DWORD dwStatus; // // Shutdown the listen on IrCOMM, this will cause the IrTran-P thread // to exit. // dwStatus = EnableDisableIrCOMM(TRUE); // TRUE == Disable. m_hIrTranPThread = NULL; return dwStatus; } //-------------------------------------------------------------------------- // IrUsdDevice::StartEventMonitorThread() // //-------------------------------------------------------------------------- DWORD IrUsdDevice::StartEventMonitorThread() { DWORD dwStatus = S_OK; DWORD dwThread; // // Event to signal for registry changes: // if ((!m_hRegistryEvent)||(m_hRegistryEvent == INVALID_HANDLE_VALUE)) { m_hRegistryEvent = CreateEvent( NULL, // Security FALSE, // Auto-reset FALSE, // Initially not set NULL ); // No name } if (!m_hRegistryEvent) { dwStatus = ::GetLastError(); WIAS_ERROR((g_hInst,"IrUsdDevice::StartEventMonitorThread(): unable to create Registry Monitor Event: %d",dwStatus)); return dwStatus; } // // Start monitoring the registry to look for enable/disable changes // for access to the IrCOMM port. // if (!m_hEventMonitorThread) { m_hEventMonitorThread = CreateThread( NULL, // Default security 0, // Default stack size EventMonitorThread, (LPVOID)this,// Function data 0, // Creation flags &dwThread ); // New thread ID if (!m_hEventMonitorThread) { dwStatus = ::GetLastError(); WIAS_ERROR((g_hInst,"IrUsdDevice::StartEventMonitorThread(): unable to create Registry Monitor Thread: %d",dwStatus)); } } return dwStatus; } //-------------------------------------------------------------------------- // IrUsdDevice::SetNotificationHandle() // // Starts and stops the event notification thread. // // Arguments: // // hEvent - Event to use in signaling WIA of events (like CONNECT etc.) // If valid start the notification thread otherwise kill the // notification thread. // // Return Value: // // HRESULT - STI_OK // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::SetNotificationHandle( IN HANDLE hEvent ) { DWORD dwStatus; HRESULT hr = STI_OK; WIAS_TRACE((g_hInst,"IrUsdDevice::SetNotificationHandle")); EnterCriticalSection(&m_csShutdown); // // Are we starting or stopping the notification thread? // if (hEvent && (hEvent != INVALID_HANDLE_VALUE)) { m_hSignalEvent = hEvent; // // Initialize to no event. // m_guidLastEvent = GUID_NULL; #if FALSE // // Create the notification thread. // if (!m_hIrTranPThread) { DWORD dwThread; m_hIrTranPThread = CreateThread( NULL, // Default security 0, // Default stack size IrTranP, // IrTran-P protocol eng. (LPVOID)this, 0, // Creation flags &dwThread); // New thread ID. if (m_hIrTranPThread) { WIAS_TRACE((g_hInst,"IrUsdDevice::SetNotificationHandle(): Enabling IrTran-P")); } else { dwStatus = ::GetLastError(); WIAS_ERROR((g_hInst,"IrUsdDevice::SetNotificationHandle(): unable to create IrTran-P thread: %d",dwStatus)); hr = HRESULT_FROM_WIN32(dwStatus); } } else { WIAS_ERROR((g_hInst,"IrUsdDevice::SetNotificationHandle(): spurious IrTran-P thread")); hr = STI_OK; // STIERR_UNSUPPORTED; } #endif dwStatus = StartEventMonitorThread(); if (dwStatus) { hr = HRESULT_FROM_WIN32(dwStatus); } } else { // // Disable event notifications. // SetEvent(m_hShutdownEvent); if (m_hIrTranPThread) { WIAS_TRACE((g_hInst,"IrUsdDevice::SetNotificationHandle(): stopping IrTran-P thread")); UninitializeIrTranP(m_hIrTranPThread); } } LeaveCriticalSection(&m_csShutdown); return hr; } //-------------------------------------------------------------------------- // IrUsdDevice::GetNotificationData() // // WIA calls this function to get data on the event. Currently for IrTran-P, // we get one of two events either WIA_EVENT_DEVICE_CONNECTED or // WIA_EVENT_ITEM_CREATED. // // Arguments: // // pStiNotify - Pointer to event data. // // Return Value: // // HRESULT - STI_OK // STIERR_NOEVENT (not currently returned). // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::GetNotificationData( IN OUT LPSTINOTIFY pStiNotify ) { DWORD dwStatus; WIAS_TRACE((g_hInst,"IrUsdDevice::GetNotificationData()")); memset(pStiNotify,0,sizeof(STINOTIFY)); pStiNotify->dwSize = sizeof(STINOTIFY); pStiNotify->guidNotificationCode = m_guidLastEvent; // // If we are to return a device connected then follow it by an item // created event. // if (IsEqualGUID(m_guidLastEvent,WIA_EVENT_DEVICE_CONNECTED)) { m_guidLastEvent = WIA_EVENT_ITEM_CREATED; if (!SetEvent(m_hSignalEvent)) { dwStatus = ::GetLastError(); WIAS_ERROR((g_hInst,"SignalWIA(): SetEvent() Failed: %d",dwStatus)); } } return STI_OK; } //-------------------------------------------------------------------------- // IrUsdDevice::Escape() // // Used to issue a command to the device. IrTran-P doesn't support this. // // 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: // // HRESULT - STI_OK // STIERR_UNSUPPORTED // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::Escape( STI_RAW_CONTROL_CODE EscapeFunction, LPVOID pInData, DWORD cbInDataSize, LPVOID pOutData, DWORD cbOutDataSize, LPDWORD pcbActualData ) { WIAS_TRACE((g_hInst,"IrUsdDevice::Escape(): unsupported")); // // Write command to device if needed. // return STIERR_UNSUPPORTED; } //-------------------------------------------------------------------------- // IrUsdDevice::GetLastError() // // Get the last error from the device. // // Arguments: // // pdwLastDeviceError - Pointer to last error data. // // Return Value: // // HRESULT - STI_OK // STIERR_INVALID_PARAM // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::GetLastError( OUT LPDWORD pdwLastDeviceError ) { WIAS_TRACE((g_hInst,"IrUsdDevice::GetLastError()")); if (IsBadWritePtr(pdwLastDeviceError, sizeof(DWORD))) { return STIERR_INVALID_PARAM; } *pdwLastDeviceError = m_dwLastOperationError; return STI_OK; } /**************************************************************************\ * IrUsdDevice::GetLastErrorInfo * * Get extended error information from the device. * * Arguments: * * pLastErrorInfo - Pointer to extended device error data. * * Return Value: * * Status. * * History: * * 9/11/1998 Original Version * \**************************************************************************/ STDMETHODIMP IrUsdDevice::GetLastErrorInfo(STI_ERROR_INFO *pLastErrorInfo) { WIAS_TRACE((g_hInst,"IrUsdDevice::GetLastErrorInfo")); if (IsBadWritePtr(pLastErrorInfo, sizeof(STI_ERROR_INFO))) { return STIERR_INVALID_PARAM; } pLastErrorInfo->dwGenericError = m_dwLastOperationError; pLastErrorInfo->szExtendedErrorText[0] = '\0'; return STI_OK; } /**************************************************************************\ * IrUsdDevice::LockDevice * * Lock access to the device. * * Arguments: * * None * * Return Value: * * Status. * * History: * * 9/11/1998 Original Version * \**************************************************************************/ STDMETHODIMP IrUsdDevice::LockDevice(void) { return STI_OK; } /**************************************************************************\ * IrUsdDevice::UnLockDevice * * Unlock access to the device. * * Arguments: * * None * * Return Value: * * Status. * * History: * * 9/11/1998 Original Version * \**************************************************************************/ STDMETHODIMP IrUsdDevice::UnLockDevice(void) { return STI_OK; } /**************************************************************************\ * IrUsdDevice::RawReadData * * Read raw data from the device. * * Arguments: * * lpBuffer - * lpdwNumberOfBytes - * lpOverlapped - * * Return Value: * * Status. * * History: * * 9/11/1998 Original Version * \**************************************************************************/ STDMETHODIMP IrUsdDevice::RawReadData( LPVOID lpBuffer, LPDWORD lpdwNumberOfBytes, LPOVERLAPPED lpOverlapped) { WIAS_TRACE((g_hInst,"IrUsdDevice::RawReadData")); return STI_OK; } /**************************************************************************\ * IrUsdDevice::RawWriteData * * Write raw data to the device. * * Arguments: * * lpBuffer - * dwNumberOfBytes - * lpOverlapped - * * Return Value: * * Status. * * History: * * 9/11/1998 Original Version * \**************************************************************************/ STDMETHODIMP IrUsdDevice::RawWriteData( LPVOID lpBuffer, DWORD dwNumberOfBytes, LPOVERLAPPED lpOverlapped) { WIAS_TRACE((g_hInst,"IrUsdDevice::RawWriteData")); return STI_OK; } //-------------------------------------------------------------------------- // IrUsdDevice::RawReadCommand() // // Raw read of bytes directly from the camera. Not supported by IrTran-P // device. // // Arguments: // // lpBuffer - // lpdwNumberOfBytes - // lpOverlapped - // // Return Value: // // HRESULT - STIERR_UNSUPPORTED // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::RawReadCommand( IN LPVOID lpBuffer, IN LPDWORD lpdwNumberOfBytes, IN LPOVERLAPPED lpOverlapped) { WIAS_TRACE((g_hInst,"IrUsdDevice::RawReadCommand() not supported")); return STIERR_UNSUPPORTED; } //-------------------------------------------------------------------------- // IrUsdDevice::RawWriteCommand() // // Raw write of byte directly to a camera. Not supported by IrTran-P device. // // Arguments: // // lpBuffer - // nNumberOfBytes - // lpOverlapped - // // Return Value: // // HRESULT - STIERR_UNSUPPORTED // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::RawWriteCommand( IN LPVOID lpBuffer, IN DWORD nNumberOfBytes, IN LPOVERLAPPED lpOverlapped ) { WIAS_TRACE((g_hInst,"IrUsdDevice::RawWriteCommand(): not supported")); return STIERR_UNSUPPORTED; } //-------------------------------------------------------------------------- // IrUsdDevice::Initialize() // // Initialize the device object. // // Arguments: // // pIStiDevControlNone - // dwStiVersion - // hParametersKey - // // Return Value: // // HRESULT STI_OK // STIERR_INVALID_PARAM // //-------------------------------------------------------------------------- STDMETHODIMP IrUsdDevice::Initialize( PSTIDEVICECONTROL pIStiDevControl, DWORD dwStiVersion, HKEY hParametersKey ) { HRESULT hr = STI_OK; UINT uiNameLen = 0; CAMERA_STATUS camStatus; WIAS_TRACE((g_hInst,"IrUsdDevice::Initialize")); if (!pIStiDevControl) { WIAS_ERROR((g_hInst,"IrUsdDevice::Initialize(): invalid device control interface")); return STIERR_INVALID_PARAM; } // // Cache the device control interface: // m_pIStiDevControl = pIStiDevControl; m_pIStiDevControl->AddRef(); // // Try to open the camera only once here during Initialize: // hr = CamOpenCamera(&camStatus); return hr; } //-------------------------------------------------------------------------- // IrUsdDevice::RunNotifications() // // Monitor changes to the source data file parent directory. // // Arguments: // // None // // Return Value: // // None // //-------------------------------------------------------------------------- VOID IrUsdDevice::RunNotifications(void) { // // Start up camera event dlg // WIAS_TRACE((g_hInst,"IrUsdDevice::RunNotifications: start up event dlg")); HWND hWnd = GetDesktopWindow(); int iret = DialogBoxParam( g_hInst, MAKEINTRESOURCE(IDD_EVENT_DLG), hWnd, CameraEventDlgProc, (LPARAM)this ); WIAS_TRACE((g_hInst,"IrUsdDevice::RunNotifications, iret = 0x%lx",iret)); if (iret == -1) { DWORD dwStatus = ::GetLastError(); WIAS_TRACE((g_hInst,"IrUsdDevice::RunNotifications, dlg error = 0x%lx",dwStatus)); } } //-------------------------------------------------------------------------- // NotificationsThread() // // Calls RunNotifications() to put up a dialog to start events. // // Arguments: // // lpParameter - Pointer to device object. // // Return Value: // // None // //-------------------------------------------------------------------------- VOID NotificationsThread( LPVOID lpParameter ) { WIAS_TRACE((g_hInst,"NotificationsThread(): Start")); IrUsdDevice *pThisDevice = (IrUsdDevice*)lpParameter; pThisDevice->RunNotifications(); } //-------------------------------------------------------------------------- // OpenIrTranPKey() // // Open and return a registry handle to the IrTranP key in the registry. // This key will be monitored for changes in value. //-------------------------------------------------------------------------- DWORD OpenIrTranPKey( HKEY *phRegistryKey ) { DWORD dwStatus = 0; DWORD dwDisposition = 0; HKEY hKey; *phRegistryKey = 0; // // If we've been called before, then we don't need to reopen the key. // if (g_hRegistryKey) { *phRegistryKey = g_hRegistryKey; return 0; } if (RegCreateKeyEx(HKEY_CURRENT_USER, SZ_REG_KEY_INFRARED, 0, // reserved MBZ 0, // class name REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, // security attributes &hKey, &dwDisposition)) { // Create failed. dwStatus = GetLastError(); WIAS_TRACE((g_hInst,"OpenIrTranPKey(): RegCreateKeyEx(): '%' failed %d", SZ_REG_KEY_INFRARED, dwStatus)); } if (RegCloseKey(hKey)) { // Close failed. } if (RegCreateKeyEx(HKEY_CURRENT_USER, SZ_REG_KEY_IRTRANP, 0, // reserved, MBZ 0, // class name REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, // security attributes &dwDisposition)) { // Create failed dwStatus = GetLastError(); WIAS_TRACE((g_hInst,"OpenIrTranPKey(): RegCreateKeyEx(): '%' failed %d", SZ_REG_KEY_IRTRANP, dwStatus)); } *phRegistryKey = g_hRegistryKey = hKey; return dwStatus; } //-------------------------------------------------------------------------- // CheckForIrCOMMEnabled() // // Check the registry to see if IrCOMM for IrTran-P is enabled, if it is // then return TRUE, else return FALSE. // // Note: Don't close the key, it is maintained globally and will be closed // at shutdown. //-------------------------------------------------------------------------- BOOL CheckForIrCOMMEnabled( IN IrUsdDevice *pIrUsdDevice ) { DWORD dwStatus; DWORD dwType; DWORD dwDisabled; DWORD dwValueSize = sizeof(dwDisabled); HKEY hKey; dwStatus = OpenIrTranPKey(&hKey); if (dwStatus) { // If the key doesn't exist, or can't be opened, then assume that // we are enabled... return TRUE; } // // Check the value of the "DisableIrCOMM" value. Zero or missing value // means fEnabled == TRUE, non-zero value means fEnabled == FALSE. // if (RegQueryValueEx( hKey, // IrTranP registry key SZ_REG_DISABLE_IRCOMM, NULL, // reserved, MB NULL &dwType, // out, value type (expect: REG_DWORD) (BYTE*)&dwDisabled, // out, value &dwValueSize)) // in/out, size of value { // Query disabled flag registry value failed, assume enabled. return TRUE; } if ((dwType == REG_DWORD) && (dwDisabled)) { // Disabled flag is set. return FALSE; } return TRUE; } //-------------------------------------------------------------------------- // EventMonitorThread() // //-------------------------------------------------------------------------- DWORD WINAPI EventMonitorThread( IN void *pvIrUsdDevice ) { DWORD dwStatus = 0; BOOL fEnabled; HANDLE hHandles[2]; HKEY hRegistryKey; IrUsdDevice *pIrUsdDevice = (IrUsdDevice*)pvIrUsdDevice; // // Get the IrTranP registry key. We will monitor this key for // changes... // dwStatus = OpenIrTranPKey(&hRegistryKey); if (dwStatus) { return dwStatus; } // // We will Monitor two events. One for shutdown of the USD, the // other for registry state changes (to enable/disable listen on // IrCOMM). // hHandles[0] = pIrUsdDevice->m_hShutdownEvent; hHandles[1] = pIrUsdDevice->m_hRegistryEvent; while (TRUE) { fEnabled = CheckForIrCOMMEnabled(pIrUsdDevice); if ((fEnabled) && (!pIrUsdDevice->m_hIrTranPThread)) { // Start IrTran-P listen/protocol thread. dwStatus = pIrUsdDevice->StartIrTranPThread(); } else if (pIrUsdDevice->m_hIrTranPThread) { // Stop IrTran-P listen/protocol thread. dwStatus = pIrUsdDevice->StopIrTranPThread(); } dwStatus = RegNotifyChangeKeyValue( hRegistryKey, // IrTranP key FALSE, // don't watch subtree REG_NOTIFY_CHANGE_LAST_SET, pIrUsdDevice->m_hRegistryEvent, TRUE ); // Asynchronous dwStatus = WaitForMultipleObjects( 2, hHandles, FALSE, INFINITE); if (dwStatus == WAIT_FAILED) { dwStatus = GetLastError(); break; } if (dwStatus == WAIT_OBJECT_0) { // Received a shutdown event. If the IrTranP thread is running // then shut it down. Break out of this while loop to stop this // monitor thread. break; } if (dwStatus == WAIT_OBJECT_0+1) { // Received a registry change event. We'll continue around the // while loop and check to see if IrTranP over IrCOMM has been // disabled... continue; } else if (dwStatus == WAIT_ABANDONED_0) { // Wait abandonded on the shutdown event } else if (dwStatus == WAIT_ABANDONED_0+1) { // Wait abandonded on the registry change event } } return dwStatus; }