#include #include #include #undef ASSERT #include "dtct.h" #include "hwdev.h" #include "dtctreg.h" #include "users.h" #include "cmmn.h" #include "sfstr.h" #include "reg.h" #include "misc.h" #include "dbg.h" #include "tfids.h" #include #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0])) // {C1FB73D0-EC3A-4ba2-B512-8CDB9187B6D1} const CLSID IID_IHWEventHandler = {0xC1FB73D0, 0xEC3A, 0x4ba2, {0xB5, 0x12, 0x8C, 0xDB, 0x91, 0x87, 0xB6, 0xD1}}; /////////////////////////////////////////////////////////////////////////////// // HRESULT _CreateAndInitEventHandler(LPCWSTR pszHandler, CLSID* pclsid, IHWEventHandler** ppihweh) { IHWEventHandler* pihweh; HRESULT hres = _CoCreateInstanceInConsoleSession(*pclsid, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IHWEventHandler, &pihweh)); *ppihweh = NULL; if (SUCCEEDED(hres)) { LPWSTR pszInitCmdLine; hres = _GetInitCmdLine(pszHandler, &pszInitCmdLine); if (SUCCEEDED(hres)) { if (S_FALSE == hres) { ASSERT(!pszInitCmdLine); hres = pihweh->Initialize(TEXT("")); } else { hres = pihweh->Initialize(pszInitCmdLine); } if (SUCCEEDED(hres)) { *ppihweh = pihweh; } if (pszInitCmdLine) { LocalFree((HLOCAL)pszInitCmdLine); } } if (FAILED(hres)) { pihweh->Release(); *ppihweh = NULL; } } return hres; } struct EXECUTEHANDLERDATA { CLSID clsidHandler; LPWSTR pszDeviceIDForAutoplay; LPWSTR pszEventType; union { LPWSTR pszHandler; LPWSTR pszInitCmdLine; }; }; HRESULT _CreateExecuteHandlerData(EXECUTEHANDLERDATA** ppehd) { HRESULT hres; *ppehd = (EXECUTEHANDLERDATA*)LocalAlloc(LPTR, sizeof(EXECUTEHANDLERDATA)); if (*ppehd) { hres = S_OK; } else { hres = E_OUTOFMEMORY; } return hres; } HRESULT _FreeEHDStrings(EXECUTEHANDLERDATA* pehd) { if (pehd->pszHandler) { LocalFree((HLOCAL)pehd->pszHandler); pehd->pszHandler = NULL; } if (pehd->pszDeviceIDForAutoplay) { LocalFree((HLOCAL)pehd->pszDeviceIDForAutoplay); pehd->pszDeviceIDForAutoplay = NULL; } if (pehd->pszEventType) { LocalFree((HLOCAL)pehd->pszEventType); pehd->pszEventType = NULL; } return S_OK; } HRESULT _FreeExecuteHandlerData(EXECUTEHANDLERDATA* pehd) { _FreeEHDStrings(pehd); LocalFree((HLOCAL)pehd); return S_OK; } HRESULT _SetExecuteHandlerData(EXECUTEHANDLERDATA* pehd, LPCWSTR pszDeviceIDForAutoplay, LPCWSTR pszEventType, LPCWSTR pszHandlerOrInitCmdLine, const CLSID* pclsidHandler) { HRESULT hres = DupString(pszHandlerOrInitCmdLine, &(pehd->pszHandler)); if (SUCCEEDED(hres)) { hres = DupString(pszDeviceIDForAutoplay, &(pehd->pszDeviceIDForAutoplay)); if (SUCCEEDED(hres)) { hres = DupString(pszEventType, &(pehd->pszEventType)); if (SUCCEEDED(hres)) { pehd->clsidHandler = *pclsidHandler; } } } if (FAILED(hres)) { // Free everything _FreeEHDStrings(pehd); } return hres; } DWORD WINAPI _ExecuteHandlerThreadProc(void* pv) { EXECUTEHANDLERDATA* pehd = (EXECUTEHANDLERDATA*)pv; IHWEventHandler* pihweh; DIAGNOSTIC((TEXT("[0100]Attempting to execute handler for: %s %s %s"), pehd->pszDeviceIDForAutoplay, pehd->pszEventType, pehd->pszHandler)); TRACE(TF_SHHWDTCTDTCT, TEXT("_ExecuteHandlerThreadProc for: %s %s %s"), pehd->pszDeviceIDForAutoplay, pehd->pszEventType, pehd->pszHandler); HRESULT hres = _CreateAndInitEventHandler(pehd->pszHandler, &(pehd->clsidHandler), &pihweh); if (SUCCEEDED(hres) && (S_FALSE != hres)) { WCHAR szDeviceIDAlt[MAX_PATH]; DIAGNOSTIC((TEXT("[0101]Got Handler Interface"))); TRACE(TF_SHHWDTCTDTCT, TEXT("Got Handler Interface")); hres = _GetAltDeviceID(pehd->pszDeviceIDForAutoplay, szDeviceIDAlt, ARRAYSIZE(szDeviceIDAlt)); if (S_FALSE == hres) { szDeviceIDAlt[0] = 0; } if (SUCCEEDED(hres)) { hres = pihweh->HandleEvent(pehd->pszDeviceIDForAutoplay, szDeviceIDAlt, pehd->pszEventType); DIAGNOSTIC((TEXT("[0103]IHWEventHandler::HandleEvent returned: hr = 0x%08X"), hres)); TRACE(TF_SHHWDTCTDTCT, TEXT("pIEventHandler->HandleEvent result: 0x%08X"), hres); } pihweh->Release(); } else { DIAGNOSTIC((TEXT("[0102]Did not get Handler Interface: hr = 0x%08X"), hres)); TRACE(TF_SHHWDTCTDTCT, TEXT("Did not get Handler Interface: 0x%08X"), hres); } _FreeExecuteHandlerData(pehd); TRACE(TF_SHHWDTCTDTCT, TEXT("Exiting _ExecuteHandlerThreadProc")); return (DWORD)hres; } HRESULT _DelegateToExecuteHandlerThread(EXECUTEHANDLERDATA* pehd, LPTHREAD_START_ROUTINE pThreadProc, HANDLE* phThread) { HRESULT hres; // set thread stack size? *phThread = CreateThread(NULL, 0, pThreadProc, pehd, 0, NULL); if (*phThread) { hres = S_OK; } else { hres = E_FAIL; } return hres; } HRESULT _ExecuteHandlerHelper(LPCWSTR pszDeviceIDForAutoplay, LPCWSTR pszEventType, LPCWSTR pszHandlerOrInitCmdLine, LPTHREAD_START_ROUTINE pThreadProc, const CLSID* pclsidHandler, HANDLE* phThread) { // Let's prepare to delegate to other thread EXECUTEHANDLERDATA* pehd; HRESULT hres = _CreateExecuteHandlerData(&pehd); *phThread = NULL; if (SUCCEEDED(hres)) { hres = _SetExecuteHandlerData(pehd, pszDeviceIDForAutoplay, pszEventType, pszHandlerOrInitCmdLine, pclsidHandler); if (SUCCEEDED(hres)) { hres = _DelegateToExecuteHandlerThread(pehd, pThreadProc, phThread); } if (FAILED(hres)) { _FreeExecuteHandlerData(pehd); } } return hres; } HRESULT _ExecuteHandler(LPCWSTR pszDeviceIDForAutoplay, LPCWSTR pszEventType, LPCWSTR pszHandler) { CLSID clsidHandler; HRESULT hres = _GetHandlerCLSID(pszHandler, &clsidHandler); if (SUCCEEDED(hres) && (S_FALSE != hres)) { HANDLE hThread; hres = _ExecuteHandlerHelper(pszDeviceIDForAutoplay, pszEventType, pszHandler, _ExecuteHandlerThreadProc, &clsidHandler, &hThread); if (SUCCEEDED(hres)) { CloseHandle(hThread); } } return hres; } /////////////////////////////////////////////////////////////////////////////// // DWORD WINAPI _PromptUserThreadProc(void* pv) { IHWEventHandler* pihweh; EXECUTEHANDLERDATA* pehd = (EXECUTEHANDLERDATA*)pv; DIAGNOSTIC((TEXT("[0110]Will prompt user for preferences"))); TRACE(TF_SHHWDTCTDTCT, TEXT("Entered _PromptUserThreadProc")); HRESULT hr = _CoCreateInstanceInConsoleSession(pehd->clsidHandler, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IHWEventHandler, &pihweh)); if (SUCCEEDED(hr)) { hr = pihweh->Initialize(pehd->pszInitCmdLine); if (SUCCEEDED(hr)) { WCHAR szDeviceIDAlt[MAX_PATH]; TRACE(TF_SHHWDTCTDTCT, TEXT("Got Handler Interface")); hr = _GetAltDeviceID(pehd->pszDeviceIDForAutoplay, szDeviceIDAlt, ARRAYSIZE(szDeviceIDAlt)); if (S_FALSE == hr) { szDeviceIDAlt[0] = 0; } if (SUCCEEDED(hr)) { hr = pihweh->HandleEvent(pehd->pszDeviceIDForAutoplay, szDeviceIDAlt, pehd->pszEventType); } } pihweh->Release(); } _FreeExecuteHandlerData(pehd); TRACE(TF_SHHWDTCTDTCT, TEXT("Exiting _PromptUserThreadProc")); return (DWORD)hr; } HRESULT _PromptUser(LPCWSTR pszDeviceIDForAutoplay, LPCWSTR pszEventType, LPCWSTR pszInitCmdLine) { HANDLE hThread; HRESULT hr = _ExecuteHandlerHelper(pszDeviceIDForAutoplay, pszEventType, pszInitCmdLine, _PromptUserThreadProc, &CLSID_ShellAutoplay, &hThread); if (SUCCEEDED(hr)) { CloseHandle(hThread); } return hr; } /////////////////////////////////////////////////////////////////////////////// // struct QUERYRUNNINGOBJECTSTRUCT { IHWEventHandler* phweh; WCHAR szDeviceIntfID[MAX_DEVICEID]; WCHAR szEventType[MAX_EVENTTYPE]; }; DWORD WINAPI _QueryRunningObjectThreadProc(void* pv) { QUERYRUNNINGOBJECTSTRUCT* pqro = (QUERYRUNNINGOBJECTSTRUCT*)pv; HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); if (SUCCEEDED(hr)) { hr = pqro->phweh->HandleEvent(pqro->szDeviceIntfID, TEXT(""), pqro->szEventType); CoUninitialize(); } pqro->phweh->Release(); LocalFree((HLOCAL)pqro); return (DWORD)hr; } HRESULT _QueryRunningObject(IHWEventHandler* phweh, LPCWSTR pszDeviceIntfID, LPCWSTR pszEventType, LPCWSTR pszHandler, BOOL* pfHandlesEvent) { HRESULT hr; QUERYRUNNINGOBJECTSTRUCT* pqro = (QUERYRUNNINGOBJECTSTRUCT*)LocalAlloc(LPTR, sizeof(QUERYRUNNINGOBJECTSTRUCT)); *pfHandlesEvent = FALSE; if (pqro) { phweh->AddRef(); pqro->phweh = phweh; hr = SafeStrCpyN(pqro->szDeviceIntfID, pszDeviceIntfID, ARRAYSIZE(pqro->szDeviceIntfID)); if (SUCCEEDED(hr)) { hr = SafeStrCpyN(pqro->szEventType, pszEventType, ARRAYSIZE(pqro->szEventType)); } if (SUCCEEDED(hr)) { HANDLE hThread = CreateThread(NULL, 0, _QueryRunningObjectThreadProc, pqro, 0, NULL); if (hThread) { // Wait 3 sec to see if wants to process it. If not, it's // fair play for us. DWORD dwWait = WaitForSingleObject(hThread, 3000); if (WAIT_OBJECT_0 == dwWait) { // Return within time and did not failed DWORD dwExitCode; if (GetExitCodeThread(hThread, &dwExitCode)) { HRESULT hrHandlesEvent = (HRESULT)dwExitCode; // WIA will return S_FALSE if they do NOT want to process // the event if (SUCCEEDED(hrHandlesEvent) && (S_FALSE != hrHandlesEvent)) { DIAGNOSTIC((TEXT("[0124]Already running handler will handle event (%s)"), pszHandler)); TRACE(TF_WIA, TEXT("Already running handler will handle event")); *pfHandlesEvent = TRUE; } else { DIAGNOSTIC((TEXT("[0125]Already running handler will *NOT* handle event(%s)"), pszHandler)); TRACE(TF_WIA, TEXT("WIA.HandleEventOverride will NOT Handle Event")); } hr = S_OK; } else { hr = S_FALSE; } } else { if (WAIT_TIMEOUT == dwWait) { DIAGNOSTIC((TEXT("[0126]Timed out on already running handler ( > 3 sec)"))); TRACE(TF_WIA, TEXT("Timed out waiting on already running object (%s)"), pszHandler); } hr = S_FALSE; } CloseHandle(hThread); } else { hr = E_OUTOFMEMORY; } } if (FAILED(hr)) { pqro->phweh->Release(); LocalFree((HLOCAL)pqro); } } else { hr = E_OUTOFMEMORY; } return hr; } HRESULT _FindAlreadyRunningHandler(LPCWSTR pszDeviceIntfID, LPCWSTR pszEventType, LPCWSTR pszEventHandler, BOOL* pfHandlesEvent) { CImpersonateConsoleSessionUser icsu; HRESULT hr = icsu.Impersonate(); if (SUCCEEDED(hr) && (S_FALSE != hr)) { IBindCtx* pbindctx; hr = CreateBindCtx(0, &pbindctx); *pfHandlesEvent = FALSE; if (SUCCEEDED(hr)) { IRunningObjectTable* prot; hr = pbindctx->GetRunningObjectTable(&prot); if (SUCCEEDED(hr)) { WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlers\\")); hr = SafeStrCatN(szKeyName, pszEventHandler, ARRAYSIZE(szKeyName)); if (SUCCEEDED(hr)) { HKEY hkey; hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKeyName, &hkey); if (SUCCEEDED(hr) && (S_FALSE != hr)) { WCHAR szHandler[MAX_HANDLER]; DWORD dwIndex = 0; while (!*pfHandlesEvent && SUCCEEDED(hr) && SUCCEEDED(hr = _RegEnumStringValue(hkey, dwIndex, szHandler, ARRAYSIZE(szHandler))) && (S_FALSE != hr)) { CLSID clsid; hr = _GetHandlerCancelCLSID(szHandler, &clsid); if (SUCCEEDED(hr) && (S_FALSE != hr)) { IMoniker* pmoniker; hr = _BuildMoniker(pszEventHandler, clsid, (USER_SHARED_DATA->ActiveConsoleId), &pmoniker); if (SUCCEEDED(hr)) { IUnknown* punk; hr = prot->GetObject(pmoniker, &punk); if (SUCCEEDED(hr) && (S_FALSE != hr)) { IHWEventHandler* phweh; hr = punk->QueryInterface( IID_IHWEventHandler, (void**)&phweh); if (SUCCEEDED(hr)) { hr = _QueryRunningObject(phweh, pszDeviceIntfID, pszEventType, szHandler, pfHandlesEvent); phweh->Release(); } punk->Release(); } else { // if it can't find it, it return s failure hr = S_FALSE; } pmoniker->Release(); } } ++dwIndex; } _RegCloseKey(hkey); } } prot->Release(); } pbindctx->Release(); } icsu.RevertToSelf(); } return hr; } HRESULT _FinalDispatch(LPCWSTR pszDeviceIntfID, LPCWSTR pszEventType, LPCWSTR pszEventHandler) { DIAGNOSTIC((TEXT("[0111]Looking for already running handler for: %s, %s, %s"), pszDeviceIntfID, pszEventType, pszEventHandler)); BOOL fHandlesEvent; HRESULT hres = _FindAlreadyRunningHandler(pszDeviceIntfID, pszEventType, pszEventHandler, &fHandlesEvent); if (SUCCEEDED(hres) && !fHandlesEvent) { WCHAR szHandler[MAX_HANDLER]; hres = _GetUserDefaultHandler(pszDeviceIntfID, pszEventHandler, szHandler, ARRAYSIZE(szHandler), GUH_USEWINSTA0USER); if (SUCCEEDED(hres) && (S_FALSE != hres)) { // We have a handler TRACE(TF_SHHWDTCTDTCT, TEXT("Found Handler: %s"), szHandler); BOOL fPrompt = FALSE; BOOL fCheckAlwaysDoThis = FALSE; BOOL fExecuteHandler = FALSE; if (HANDLERDEFAULT_GETFLAGS(hres) & HANDLERDEFAULT_USERCHOSENDEFAULT) { // We have a user chosen default... if (HANDLERDEFAULT_GETFLAGS(hres) & HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED) { // ... but we have more recent apps that were installed fPrompt = TRUE; } else { if (lstrcmp(szHandler, TEXT("MSTakeNoAction"))) { // The handler is *not* "Take no action" if (!lstrcmp(szHandler, TEXT("MSPromptEachTime"))) { // The handler is "Prompt each time" fPrompt = TRUE; } else { fExecuteHandler = TRUE; } } } } else { // If we do not have a user chosen handler, then we always // prompt fPrompt = TRUE; } if (fPrompt) { if (HANDLERDEFAULT_GETFLAGS(hres) & HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED) { // There are more recent handlers if (HANDLERDEFAULT_GETFLAGS(hres) & HANDLERDEFAULT_USERCHOSENDEFAULT) { // The user chose a default handler if (!(HANDLERDEFAULT_GETFLAGS(hres) & HANDLERDEFAULT_DEFAULTSAREDIFFERENT)) { // The handlers are the same, check the checkbox fCheckAlwaysDoThis = TRUE; } } } _GiveAllowForegroundToConsoleShell(); if (fCheckAlwaysDoThis) { // Notice the '*' at the end of the string hres = _PromptUser(pszDeviceIntfID, pszEventType, TEXT("PromptEachTimeNoContent*")); } else { hres = _PromptUser(pszDeviceIntfID, pszEventType, TEXT("PromptEachTimeNoContent")); } } else { if (fExecuteHandler) { hres = _ExecuteHandler(pszDeviceIntfID, pszEventType, szHandler); } } } } return hres; } /////////////////////////////////////////////////////////////////////////////// // HRESULT _IsWIAHandlingEvent(LPCWSTR pszDeviceIDForAutoplay, LPCWSTR pszEventType, BOOL* pfWIAHandlingEvent) { CLSID clsid = {0}; HRESULT hr = CLSIDFromProgID(TEXT("WIA.HandleEventOverride"), &clsid); *pfWIAHandlingEvent = FALSE; if (SUCCEEDED(hr)) { HANDLE hThread; hr = _ExecuteHandlerHelper(pszDeviceIDForAutoplay, pszEventType, TEXT(""), _ExecuteHandlerThreadProc, &clsid, &hThread); if (SUCCEEDED(hr)) { // Wait 3 sec to see if WIA wants to process it. If not, it's // fair play for us. DWORD dwWait = WaitForSingleObject(hThread, 3000); if (WAIT_OBJECT_0 == dwWait) { // Return within time and did not failed DWORD dwExitCode; if (GetExitCodeThread(hThread, &dwExitCode)) { HRESULT hrWIA = (HRESULT)dwExitCode; // WIA will return S_FALSE if they do NOT want to process // the event if (SUCCEEDED(hrWIA) && (S_FALSE != hrWIA)) { DIAGNOSTIC((TEXT("[0114]WIA will handle event"))); TRACE(TF_WIA, TEXT("WIA.HandleEventOverride will Handle Event")); *pfWIAHandlingEvent = TRUE; } else { TRACE(TF_WIA, TEXT("WIA.HandleEventOverride will NOT Handle Event")); } } } else { if (WAIT_TIMEOUT == dwWait) { TRACE(TF_WIA, TEXT("Timed out waiting on WIA.HandleEventOverride")); } } CloseHandle(hThread); } else { TRACE(TF_WIA, TEXT("_ExecuteHandlerHelper failed for WIA.HandleEventOverride")); } } else { TRACE(TF_WIA, TEXT("Could not get CLSID for WIA.HandleEventOverride")); } return hr; } HRESULT _DispatchToHandler(LPCWSTR pszDeviceIntfID, CHWDeviceInst* phwdevinst, LPCWSTR pszEventType, BOOL* pfHasHandler) { WCHAR szDeviceHandler[MAX_DEVICEHANDLER]; HRESULT hres = _GetDeviceHandler(phwdevinst, szDeviceHandler, ARRAYSIZE(szDeviceHandler)); *pfHasHandler = FALSE; if (SUCCEEDED(hres) && (S_FALSE != hres)) { WCHAR szEventHandler[MAX_EVENTHANDLER]; DIAGNOSTIC((TEXT("[0115]Found DeviceHandler: %s"), szDeviceHandler)); TRACE(TF_SHHWDTCTDTCT, TEXT("Found Device Handler: %s"), szDeviceHandler); if (SUCCEEDED(hres)) { DIAGNOSTIC((TEXT("[0117]Device does NOT Support Content"))); TRACE(TF_SHHWDTCTDTCT, TEXT("Device does NOT Support Content")); BOOL fWIAHandlingEvent = FALSE; GUID guidInterface; HRESULT hres2 = phwdevinst->GetInterfaceGUID(&guidInterface); if (SUCCEEDED(hres2)) { if ((guidInterface == guidImagingDeviceClass) || (guidInterface == guidVideoCameraClass)) { _IsWIAHandlingEvent(pszDeviceIntfID, pszEventType, &fWIAHandlingEvent); } } if (!fWIAHandlingEvent) { hres = _GetEventHandlerFromDeviceHandler(szDeviceHandler, pszEventType, szEventHandler, ARRAYSIZE(szEventHandler)); if (SUCCEEDED(hres)) { if (S_FALSE != hres) { *pfHasHandler = TRUE; hres = _FinalDispatch(pszDeviceIntfID, pszEventType, szEventHandler); TRACE(TF_SHHWDTCTDTCTDETAILED, TEXT(" _GetEventHandlerFromDeviceHandler returned: %s"), szEventHandler); } } } else { DIAGNOSTIC((TEXT("[0123]WIA will handle event"))); TRACE(TF_SHHWDTCTDTCTDETAILED, TEXT(" WIA will handle event")); } } } else { DIAGNOSTIC((TEXT("[0112]Did NOT find DeviceHandler: 0x%08X"), hres)); TRACE(TF_SHHWDTCTDTCT, TEXT("Did not find Device Handler: 0x%08X"), hres); } return hres; }