#include "dtctreg.h" #include "hwdev.h" #include "pnp.h" #include "cmmn.h" #include "sfstr.h" #include "reg.h" #include "misc.h" #include "shobjidl.h" #include "shpriv.h" #include "users.h" #include "strsafe.h" #include "str.h" #include "dbg.h" #include "mischlpr.h" #define ARRAYSIZE(a) (sizeof((a))/sizeof((a)[0])) HRESULT _GetValueToUse(LPWSTR pszKeyName, LPWSTR psz, DWORD cch) { HKEY hkey; HRESULT hr = _RegOpenKey(HKEY_LOCAL_MACHINE, pszKeyName, &hkey); if (SUCCEEDED(hr) && (S_FALSE != hr)) { // For now we take the first one. hr = _RegEnumStringValue(hkey, 0, psz, cch); _RegCloseKey(hkey); } return hr; } // Return Values: // S_FALSE: Can't find it HRESULT _GetEventHandlerFromKey(LPCWSTR pszKeyName, LPCWSTR pszEventType, LPWSTR pszEventHandler, DWORD cchEventHandler) { WCHAR szEventHandler[MAX_KEY]; DWORD cchLeft; LPWSTR pszNext; HRESULT hr = SafeStrCpyNEx(szEventHandler, pszKeyName, ARRAYSIZE(szEventHandler), &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = SafeStrCpyNEx(pszNext, TEXT("\\EventHandlers\\"), cchLeft, &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = SafeStrCpyN(pszNext, pszEventType, cchLeft); if (SUCCEEDED(hr)) { hr = _GetValueToUse(szEventHandler, pszEventHandler, cchEventHandler); } } } return hr; } // Return Values: // S_FALSE: Can't find it HRESULT _GetEventHandlerFromDeviceHandler(LPCWSTR pszDeviceHandler, LPCWSTR pszEventType, LPWSTR pszEventHandler, DWORD cchEventHandler) { WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("DeviceHandlers\\")); HRESULT hr = SafeStrCatN(szKeyName, pszDeviceHandler, ARRAYSIZE(szKeyName)); if (SUCCEEDED(hr)) { hr = _GetEventHandlerFromKey(szKeyName, pszEventType, pszEventHandler, cchEventHandler); } return hr; } HRESULT _GetStuffFromHandlerHelper(LPCWSTR pszHandler, LPCWSTR pszValueName, LPWSTR psz, DWORD cch) { HKEY hkey; WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("Handlers\\")); HRESULT hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKeyName, &hkey); if (SUCCEEDED(hr) && (S_FALSE != hr)) { hr = _RegQueryString(hkey, pszHandler, pszValueName, psz, cch); _RegCloseKey(hkey); } return hr; } HRESULT _GetActionFromHandler(LPCWSTR pszHandler, LPWSTR pszAction, DWORD cchAction) { HRESULT hr = _GetStuffFromHandlerHelper(pszHandler, TEXT("Action"), pszAction, cchAction); if (SUCCEEDED(hr) && (S_FALSE == hr)) { hr = _GetStuffFromHandlerHelper(pszHandler, TEXT("FriendlyName"), pszAction, cchAction); } return hr; } HRESULT _GetProviderFromHandler(LPCWSTR pszHandler, LPWSTR pszProvider, DWORD cchProvider) { HRESULT hr = _GetStuffFromHandlerHelper(pszHandler, TEXT("Provider"), pszProvider, cchProvider); if (SUCCEEDED(hr) && (S_FALSE == hr)) { hr = SafeStrCpyN(pszProvider, TEXT(""), cchProvider); } return hr; } HRESULT _GetIconLocationFromHandler(LPCWSTR pszHandler, LPWSTR pszIconLocation, DWORD cchIconLocation) { return _GetStuffFromHandlerHelper(pszHandler, TEXT("DefaultIcon"), pszIconLocation, cchIconLocation); } HRESULT _GetInvokeProgIDFromHandler(LPCWSTR pszHandler, LPWSTR pszInvokeProgID, DWORD cchInvokeProgID) { return _GetStuffFromHandlerHelper(pszHandler, TEXT("InvokeProgID"), pszInvokeProgID, cchInvokeProgID); } HRESULT _GetInvokeVerbFromHandler(LPCWSTR pszHandler, LPWSTR pszInvokeVerb, DWORD cchInvokeVerb) { return _GetStuffFromHandlerHelper(pszHandler, TEXT("InvokeVerb"), pszInvokeVerb, cchInvokeVerb); } HRESULT _GetEventKeyName(LPCWSTR pszDeviceID, LPCWSTR pszEventType, LPWSTR pszEventKeyName, DWORD cchEventKeyName) { WCHAR szDeviceIDReal[MAX_DEVICEID]; HRESULT hr = _GetDeviceID(pszDeviceID, szDeviceIDReal, ARRAYSIZE(szDeviceIDReal)); if (SUCCEEDED(hr) && (S_FALSE != hr)) { CHWDeviceInst* phwdevinst; CNamedElem* pelemToRelease; hr = _GetHWDeviceInstFromDeviceOrVolumeIntfID(szDeviceIDReal, &phwdevinst, &pelemToRelease); if (SUCCEEDED(hr) && (S_FALSE != hr)) { WCHAR szDeviceHandler[MAX_DEVICEHANDLER]; hr = _GetDeviceHandler(phwdevinst, szDeviceHandler, ARRAYSIZE(szDeviceHandler)); if (SUCCEEDED(hr) && (S_FALSE != hr)) { LPWSTR pszNext; DWORD cchLeft; hr = SafeStrCpyNEx(pszEventKeyName, SHDEVICEEVENTROOT(TEXT("DeviceHandlers\\")), cchEventKeyName, &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = SafeStrCpyNEx(pszNext, szDeviceHandler, cchLeft, &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = SafeStrCpyNEx(pszNext, TEXT("\\EventHandlers\\"), cchLeft, &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = SafeStrCpyN(pszNext, pszEventType, cchLeft); } } } } pelemToRelease->RCRelease(); } } if (FAILED(hr) || (S_FALSE == hr)) { *pszEventKeyName = NULL; } return hr; } HRESULT _GetEventString(LPCWSTR pszDeviceID, LPCWSTR pszEventType, LPCWSTR pszValueName, LPWSTR psz, DWORD cch) { WCHAR szKeyName[MAX_KEY]; HRESULT hr = _GetEventKeyName(pszDeviceID, pszEventType, szKeyName, ARRAYSIZE(szKeyName)); if (SUCCEEDED(hr) && (S_FALSE != hr)) { HKEY hkey; hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKeyName, &hkey); if (SUCCEEDED(hr) && (S_FALSE != hr)) { hr = _RegQueryString(hkey, NULL, pszValueName, psz, cch); _RegCloseKey(hkey); } } return hr; } HRESULT _GetEventFriendlyName(LPCWSTR pszDeviceID, LPCWSTR pszEventType, LPWSTR pszFriendlyName, DWORD cchFriendlyName) { return _GetEventString(pszDeviceID, pszEventType, TEXT("FriendlyName"), pszFriendlyName, cchFriendlyName); } HRESULT _GetEventIconLocation(LPCWSTR pszDeviceID, LPCWSTR pszEventType, LPWSTR pszIconLocation, DWORD cchIconLocation) { return _GetEventString(pszDeviceID, pszEventType, TEXT("DefaultIcon"), pszIconLocation, cchIconLocation); } /////////////////////////////////////////////////////////////////////////////// // // Return values: // S_FALSE: Did not find it // S_OK: Found it // // If finds it, the subkey is appended to pszKey HRESULT _CheckForSubKeyExistence(LPWSTR pszKey, DWORD cchKey, LPCWSTR pszSubKey) { LPWSTR pszNext; DWORD cchLeft; HRESULT hr = SafeStrCatNEx(pszKey, TEXT("\\"), cchKey, &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = SafeStrCpyNEx(pszNext, pszSubKey, cchLeft, &pszNext, &cchLeft); if (SUCCEEDED(hr)) { // Check if it exist HKEY hkey; hr = _RegOpenKey(HKEY_LOCAL_MACHINE, pszKey, &hkey); if (SUCCEEDED(hr) && (S_FALSE != hr)) { _RegCloseKey(hkey); } } } return hr; } HRESULT _GetDevicePropertySize(CHWDeviceInst* phwdevinst, LPCWSTR pszPropName, BOOL fUseMergeMultiSz, DWORD* pcbSize) { // Instance DEVINST devinst; HRESULT hr = phwdevinst->GetDeviceInstance(&devinst); if (SUCCEEDED(hr) && (S_FALSE != hr)) { BYTE rgb[1]; ULONG ulData = sizeof(rgb); ULONG ulFlags = 0; if (fUseMergeMultiSz) { ulFlags = CM_CUSTOMDEVPROP_MERGE_MULTISZ; } CONFIGRET cr = CM_Get_DevNode_Custom_Property(devinst, pszPropName, NULL, rgb, &ulData, ulFlags); if (CR_SUCCESS != cr) { if (CR_BUFFER_SMALL == cr) { hr = S_OK; *pcbSize = ulData; } else { // If we do not have the data at the instance level, let's try it // at the DeviceGroup level. // DeviceGroup WCHAR szDeviceGroup[MAX_DEVICEGROUP]; ulData = sizeof(szDeviceGroup); cr = CM_Get_DevNode_Custom_Property(devinst, TEXT("DeviceGroup"), NULL, (PBYTE)szDeviceGroup, &ulData, 0); if (CR_SUCCESS == cr) { WCHAR szKey[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("DeviceGroups\\")); hr = SafeStrCatN(szKey, szDeviceGroup, ARRAYSIZE(szKey)); if (SUCCEEDED(hr)) { hr = _GetPropertySizeHelper(szKey, pszPropName, pcbSize); } } else { hr = S_FALSE; } } } } if (S_FALSE == hr) { // If we do not have the data at the instance level, nor the device // group level, let's try it at the DeviceClass level. // DeviceClass GUID guidInterface; hr = phwdevinst->GetInterfaceGUID(&guidInterface); if (SUCCEEDED(hr) && (S_FALSE != hr)) { WCHAR szKey[MAX_KEY]; LPWSTR pszNext; DWORD cchLeft; hr = SafeStrCpyNEx(szKey, SHDEVICEEVENTROOT(TEXT("DeviceClasses\\")), ARRAYSIZE(szKey), &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = _StringFromGUID(&guidInterface, pszNext, cchLeft); if (SUCCEEDED(hr) && (S_FALSE != hr)) { hr = _GetPropertySizeHelper(szKey, pszPropName, pcbSize); } } } } return hr; } HRESULT _GetDevicePropertyGeneric(CHWDeviceInst* phwdevinst, LPCWSTR pszPropName, BOOL fUseMergeMultiSz, DWORD* pdwType, LPBYTE pbData, DWORD cbData) { // Instance DEVINST devinst; HRESULT hr = phwdevinst->GetDeviceInstance(&devinst); if (CHWEventDetectorHelper::_fDiagnosticAppPresent) { WCHAR szPnpID[MAX_PNPID]; WCHAR szGUID[MAX_GUIDSTRING]; GUID guid; HRESULT hrTmp = phwdevinst->GetPnpID(szPnpID, ARRAYSIZE(szPnpID)); if (SUCCEEDED(hrTmp) && (S_FALSE != hrTmp)) { DIAGNOSTIC((TEXT("[0269]Device PnP ID: %s"), szPnpID)); } hrTmp = phwdevinst->GetInterfaceGUID(&guid); if (SUCCEEDED(hrTmp) && (S_FALSE != hrTmp)) { hrTmp = _StringFromGUID(&guid, szGUID, ARRAYSIZE(szGUID)); if (SUCCEEDED(hrTmp)) { DIAGNOSTIC((TEXT("[0270]Device Class ID: %s"), szGUID)); } } } *pdwType = 0; if (SUCCEEDED(hr) && (S_FALSE != hr)) { ULONG ulData = cbData; ULONG ulType; ULONG ulFlags = 0; if (fUseMergeMultiSz) { ulFlags = CM_CUSTOMDEVPROP_MERGE_MULTISZ; } CONFIGRET cr = CM_Get_DevNode_Custom_Property(devinst, pszPropName, &ulType, pbData, &ulData, ulFlags); if (CR_SUCCESS != cr) { // If we do not have the data at the instance level, let's try it // at the DeviceGroup level. // DeviceGroup WCHAR szDeviceGroup[MAX_DEVICEGROUP]; DIAGNOSTIC((TEXT("[0252]Did NOT get Custom Property (%s) at device instance level"), pszPropName)); ulData = sizeof(szDeviceGroup); cr = CM_Get_DevNode_Custom_Property(devinst, TEXT("DeviceGroup"), NULL, (PBYTE)szDeviceGroup, &ulData, 0); if (CR_SUCCESS == cr) { WCHAR szKey[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("DeviceGroups\\")); hr = SafeStrCatN(szKey, szDeviceGroup, ARRAYSIZE(szKey)); if (SUCCEEDED(hr)) { hr = _GetPropertyHelper(szKey, pszPropName, pdwType, pbData, cbData); if (SUCCEEDED(hr)) { if (S_FALSE != hr) { DIAGNOSTIC((TEXT("[0253]Got Custom Property (%s) at DeviceGroup level (%s)"), pszPropName, szDeviceGroup)); } else { DIAGNOSTIC((TEXT("[0254]Did NOT get Custom Property (%s) at DeviceGroup level (%s)"), pszPropName, szDeviceGroup)); } } } } else { hr = S_FALSE; } } else { DIAGNOSTIC((TEXT("[0251]Got Custom Property (%s) at device instance level"), pszPropName)); *pdwType = (DWORD)ulType; } } if (S_FALSE == hr) { // If we do not have the data at the instance level, nor the device // group level, let's try it at the DeviceClass level. // DeviceClass GUID guidInterface; hr = phwdevinst->GetInterfaceGUID(&guidInterface); if (SUCCEEDED(hr) && (S_FALSE != hr)) { WCHAR szKey[MAX_KEY]; LPWSTR pszNext; DWORD cchLeft; hr = SafeStrCpyNEx(szKey, SHDEVICEEVENTROOT(TEXT("DeviceClasses\\")), ARRAYSIZE(szKey), &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = _StringFromGUID(&guidInterface, pszNext, cchLeft); if (SUCCEEDED(hr) && (S_FALSE != hr)) { hr = _GetPropertyHelper(szKey, pszPropName, pdwType, pbData, cbData); if (SUCCEEDED(hr)) { if (S_FALSE != hr) { DIAGNOSTIC((TEXT("[0255]Got Custom Property (%s) at DeviceClass level (%s)"), pszPropName, pszNext)); } else { DIAGNOSTIC((TEXT("[0256]Did NOT get Custom Property (%s) at DeviceClass level (%s)"), pszPropName, pszNext)); } } } } } } return hr; } HRESULT _GetDevicePropertyAsString(CHWDeviceInst* phwdevinst, LPCWSTR pszPropName, LPCWSTR psz, DWORD cch) { DWORD dwType; DWORD cbData = cch * sizeof(WCHAR); return _GetDevicePropertyGeneric(phwdevinst, pszPropName, FALSE, &dwType, (PBYTE)psz, cbData); } HRESULT _GetDevicePropertyGenericAsMultiSz(CHWDeviceInst* phwdevinst, LPCWSTR pszPropName, BOOL fUseMergeMultiSz, WORD_BLOB** ppblob) { DWORD cbSize = NULL; HRESULT hr = _GetDevicePropertySize(phwdevinst, pszPropName, FALSE, &cbSize); *ppblob = NULL; if (SUCCEEDED(hr) && (S_FALSE != hr)) { WORD_BLOB* pblob = (WORD_BLOB*)CoTaskMemAlloc( sizeof(WORD_BLOB) + cbSize + sizeof(WCHAR)); if (pblob) { DWORD dwType; DWORD cbSize2 = cbSize + sizeof(WCHAR); pblob->clSize = (cbSize + sizeof(WCHAR))/2; hr = _GetDevicePropertyGeneric(phwdevinst, pszPropName, fUseMergeMultiSz, &dwType, (PBYTE)(pblob->asData), cbSize2); if (SUCCEEDED(hr) && (S_FALSE != hr)) { if (REG_MULTI_SZ == dwType) { DIAGNOSTIC((TEXT("[0265]Found Property: '%s'"), pszPropName)); *ppblob = pblob; pblob = NULL; } else { DIAGNOSTIC((TEXT("[0266]Found Property: '%s', but NOT REG_MULTI_SZ type"), pszPropName)); hr = E_FAIL; } } if (pblob) { // It did not get assigned CoTaskMemFree(pblob); } } else { hr = E_OUTOFMEMORY; } } return hr; } HRESULT _GetDevicePropertyGenericAsBlob(CHWDeviceInst* phwdevinst, LPCWSTR pszPropName, BYTE_BLOB** ppblob) { DWORD cbSize = NULL; HRESULT hr = _GetDevicePropertySize(phwdevinst, pszPropName, FALSE, &cbSize); *ppblob = NULL; if (SUCCEEDED(hr) && (S_FALSE != hr)) { BYTE_BLOB* pblob = (BYTE_BLOB*)CoTaskMemAlloc( sizeof(BYTE_BLOB) + cbSize); if (pblob) { DWORD dwType; pblob->clSize = cbSize; hr = _GetDevicePropertyGeneric(phwdevinst, pszPropName, FALSE, &dwType, (PBYTE)pblob->abData, pblob->clSize); if (SUCCEEDED(hr) && (S_FALSE != hr)) { if (REG_BINARY == dwType) { DIAGNOSTIC((TEXT("[0267]Found Property: '%s'"), pszPropName)); *ppblob = pblob; pblob = NULL; } else { DIAGNOSTIC((TEXT("[0268]Found Property: '%s', but NOT REG_BINARY type"), pszPropName)); hr = E_FAIL; } } if (pblob) { // It did not get assigned CoTaskMemFree(pblob); } } else { hr = E_OUTOFMEMORY; } } return hr; } HRESULT _GetDevicePropertyStringNoBuf(CHWDeviceInst* phwdevinst, LPCWSTR pszPropName, BOOL fUseMergeMultiSz, DWORD* pdwType, LPWSTR* ppszProp) { DWORD cbSize = NULL; HRESULT hr = _GetDevicePropertySize(phwdevinst, pszPropName, FALSE, &cbSize); *ppszProp = NULL; if (SUCCEEDED(hr) && (S_FALSE != hr)) { LPWSTR psz; cbSize += sizeof(WCHAR); psz = (LPWSTR)CoTaskMemAlloc(cbSize); if (psz) { hr = _GetDevicePropertyGeneric(phwdevinst, pszPropName, fUseMergeMultiSz, pdwType, (PBYTE)psz, cbSize); if (FAILED(hr) || (S_FALSE == hr)) { CoTaskMemFree(psz); } else { *ppszProp = psz; } } else { hr = E_OUTOFMEMORY; } } return hr; } // Return Values: // S_FALSE: Can't find it HRESULT _GetDeviceHandler(CHWDeviceInst* phwdevinst, LPWSTR pszDeviceHandler, DWORD cchDeviceHandler) { return _GetDevicePropertyAsString(phwdevinst, TEXT("DeviceHandlers"), pszDeviceHandler, cchDeviceHandler); } /////////////////////////////////////////////////////////////////////////////// // HRESULT _OpenHandlerRegKey(LPCWSTR pszHandler, HKEY* phkey) { WCHAR szKey[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("Handlers\\")); HRESULT hr = SafeStrCatN(szKey, pszHandler, ARRAYSIZE(szKey)); if (SUCCEEDED(hr)) { hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKey, phkey); } return hr; } HRESULT _CloseHandlerRegKey(HKEY hkey) { return _RegCloseKey(hkey); } HRESULT _GetHandlerCancelCLSID(LPCWSTR pszHandler, CLSID* pclsid) { HKEY hkey; HRESULT hr = _OpenHandlerRegKey(pszHandler, &hkey); if (SUCCEEDED(hr)) { WCHAR szProgID[MAX_PROGID]; hr = _RegQueryString(hkey, NULL, TEXT("CLSIDForCancel"), szProgID, ARRAYSIZE(szProgID)); if (SUCCEEDED(hr)) { if (S_FALSE != hr) { hr = _GUIDFromString(szProgID, pclsid); DIAGNOSTIC((TEXT("[0162]Got Handler Cancel CLSID (from CLSIDForCancel): %s"), szProgID)); TRACE(TF_SHHWDTCTDTCTREG, TEXT("Got Handler Cancel CLSID")); } else { hr = _GetHandlerCLSID(pszHandler, pclsid); if (CHWEventDetectorHelper::_fDiagnosticAppPresent) { if (SUCCEEDED(hr)) { if (S_FALSE != hr) { hr = _StringFromGUID(pclsid, szProgID, ARRAYSIZE(szProgID)); if (SUCCEEDED(hr)) { DIAGNOSTIC((TEXT("[0164]Got Handler Cancel CLSID: %s"), szProgID)); } } } } } } _CloseHandlerRegKey(hkey); } return hr; } HRESULT _GetHandlerCLSID(LPCWSTR pszHandler, CLSID* pclsid) { HKEY hkey; HRESULT hr = _OpenHandlerRegKey(pszHandler, &hkey); if (SUCCEEDED(hr)) { WCHAR szProgID[MAX_PROGID]; hr = _RegQueryString(hkey, NULL, TEXT("ProgID"), szProgID, ARRAYSIZE(szProgID)); if (SUCCEEDED(hr)) { if (S_FALSE != hr) { hr = CLSIDFromProgID(szProgID, pclsid); DIAGNOSTIC((TEXT("[0160]Got Handler ProgID: %s"), szProgID)); TRACE(TF_SHHWDTCTDTCTREG, TEXT("Got Handler ProgID: %s"), szProgID); } else { // Not there, maybe we have CLSID value? // Reuse szProgID hr = _RegQueryString(hkey, NULL, TEXT("CLSID"), szProgID, ARRAYSIZE(szProgID)); if (SUCCEEDED(hr) && (S_FALSE != hr)) { hr = _GUIDFromString(szProgID, pclsid); DIAGNOSTIC((TEXT("[0161]Got Handler CLSID: %s"), szProgID)); TRACE(TF_SHHWDTCTDTCTREG, TEXT("Got Handler CLSID")); } else { DIAGNOSTIC((TEXT("[0163]Did NOT get Handler ProgID or CLSID"))); } } } _CloseHandlerRegKey(hkey); } return hr; } // Return values: // S_FALSE: Cannot find an InitCmdLine // HRESULT _GetInitCmdLine(LPCWSTR pszHandler, LPWSTR* ppsz) { HKEY hkey; HRESULT hr = _OpenHandlerRegKey(pszHandler, &hkey); *ppsz = NULL; if (SUCCEEDED(hr)) { DWORD cb = NULL; hr = _RegQueryValueSize(hkey, NULL, TEXT("InitCmdLine"), &cb); if (SUCCEEDED(hr) && (S_FALSE != hr)) { LPWSTR psz = (LPWSTR)LocalAlloc(LPTR, cb); if (psz) { hr = _RegQueryString(hkey, NULL, TEXT("InitCmdLine"), psz, cb / sizeof(WCHAR)); if (SUCCEEDED(hr) && (S_FALSE != hr)) { DIAGNOSTIC((TEXT("[0158]Got InitCmdLine for Handler (%s): '%s'"), pszHandler, psz)); *ppsz = psz; } else { LocalFree((HLOCAL)psz); } } else { hr = E_OUTOFMEMORY; } } else { DIAGNOSTIC((TEXT("[0159]NO InitCmdLine for Handler (%s)"), pszHandler)); } _CloseHandlerRegKey(hkey); } return hr; } HRESULT _MakeUserDefaultValueString(LPCWSTR pszDeviceID, LPCWSTR pszEventHandler, LPWSTR pszUserDefault, DWORD cchUserDefault) { DWORD cchLeft; LPWSTR pszNext; HRESULT hr = SafeStrCpyNEx(pszUserDefault, pszDeviceID, cchUserDefault, &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = SafeStrCpyNEx(pszNext, TEXT("+"), cchLeft, &pszNext, &cchLeft); if (SUCCEEDED(hr)) { hr = SafeStrCpyN(pszNext, pszEventHandler, cchLeft); } } return hr; } // from setenum.cpp HRESULT _GetKeyLastWriteTime(LPCWSTR pszHandler, FILETIME* pft); HRESULT _HaveNewHandlersBeenInstalledSinceUserSelection(LPCWSTR pszEventHandler, FILETIME* pftUserSelection, BOOL* pfNewHandlersSinceUserSelection) { WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlers\\")); HRESULT hr = SafeStrCatN(szKeyName, pszEventHandler, ARRAYSIZE(szKeyName)); ULARGE_INTEGER ulUserSelection; ulUserSelection.LowPart = pftUserSelection->dwLowDateTime; ulUserSelection.HighPart = pftUserSelection->dwHighDateTime; *pfNewHandlersSinceUserSelection = FALSE; if (SUCCEEDED(hr)) { HKEY hkey; hr = _RegOpenKey(HKEY_LOCAL_MACHINE, szKeyName, &hkey); if (SUCCEEDED(hr) && (S_FALSE != hr)) { DWORD dw = 0; BOOL fGoOut = FALSE; do { WCHAR szHandler[MAX_HANDLER]; hr = _RegEnumStringValue(hkey, dw, szHandler, ARRAYSIZE(szHandler)); if (SUCCEEDED(hr) && (S_FALSE != hr)) { FILETIME ft; hr = _GetKeyLastWriteTime(szHandler, &ft); if (SUCCEEDED(hr) && (S_FALSE != hr)) { ULARGE_INTEGER ul; ul.LowPart = ft.dwLowDateTime; ul.HighPart = ft.dwHighDateTime; if (ul.QuadPart > ulUserSelection.QuadPart) { *pfNewHandlersSinceUserSelection = TRUE; hr = S_OK; fGoOut = TRUE; } } } else { fGoOut = TRUE; } ++dw; } while (!fGoOut); if (S_FALSE == hr) { hr = S_OK; } _RegCloseKey(hkey); } } return hr; } struct _USERSELECTIONHIDDENDATA { _USERSELECTIONHIDDENDATA() : dw(0) {} FILETIME ft; // Set this to zero so that RegSetValueEx will not NULL terminate out stuff DWORD dw; }; // See comment for _MakeFinalUserDefaultHandler HRESULT _GetHandlerAndFILETIME(HKEY hkeyUser, LPCWSTR pszKeyName, LPCWSTR pszUserDefault, LPWSTR pszHandler, DWORD cchHandler, FILETIME* pft) { DWORD cb; HRESULT hr = _RegQueryValueSize(hkeyUser, pszKeyName, pszUserDefault, &cb); if (SUCCEEDED(hr) && (S_FALSE != hr)) { BYTE* pb = (BYTE*)LocalAlloc(LPTR, cb); if (pb) { hr = _RegQueryGeneric(hkeyUser, pszKeyName, pszUserDefault, pb, cb); if (SUCCEEDED(hr) && (S_FALSE != hr)) { // We should have something like this: // MyHandler\0<_USERSELECTIONHIDDENDATA struct> hr = StringCchCopy(pszHandler, cchHandler, (LPWSTR)pb); if (SUCCEEDED(hr)) { DWORD cbString = (lstrlen(pszHandler) + 1) * sizeof(WCHAR); // Make sure we're dealing with the right thing if ((cb >= cbString + sizeof(_USERSELECTIONHIDDENDATA)) && (cb <= cbString + sizeof(_USERSELECTIONHIDDENDATA) + sizeof(void*))) { // Yep! So _USERSELECTIONHIDDENDATA should be at the end of the blob _USERSELECTIONHIDDENDATA* pushd = (_USERSELECTIONHIDDENDATA*) (pb + (cb - sizeof(_USERSELECTIONHIDDENDATA))); *pft = pushd->ft; } else { *pszHandler = 0; hr = S_FALSE; } } } LocalFree(pb); } else { hr = E_OUTOFMEMORY; } } return hr; } HRESULT _GetEventHandlerDefault(HKEY hkeyUser, LPCWSTR pszEventHandler, LPWSTR pszHandler, DWORD cchHandler) { WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlersDefaultSelection\\")); return _RegQueryString(hkeyUser, szKeyName, pszEventHandler, pszHandler, cchHandler); } HRESULT _GetUserDefaultHandler(LPCWSTR pszDeviceID, LPCWSTR pszEventHandler, LPWSTR pszHandler, DWORD cchHandler, BOOL fImpersonateCaller) { WCHAR szUserDefault[MAX_USERDEFAULT] = TEXT("H:"); HRESULT hr = _MakeUserDefaultValueString(pszDeviceID, pszEventHandler, &(szUserDefault[2]), ARRAYSIZE(szUserDefault) - 2); if (cchHandler) { *pszHandler = 0; } if (SUCCEEDED(hr)) { WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("UserChosenExecuteHandlers\\")); HKEY hkeyUser; HANDLE hThreadToken; if (GUH_IMPERSONATEUSER == fImpersonateCaller) { hr = _CoGetCallingUserHKCU(&hThreadToken, &hkeyUser); } else { hr = _GetCurrentUserHKCU(&hThreadToken, &hkeyUser); } if (SUCCEEDED(hr) && (S_FALSE != hr)) { FILETIME ft; DWORD dwHandlerDefaultFlag = 0; hr = _GetHandlerAndFILETIME(hkeyUser, szKeyName, szUserDefault, pszHandler, cchHandler, &ft); if (SUCCEEDED(hr)) { if (S_FALSE == hr) { // we do not have a UserChosenDefault hr = SafeStrCpyN(pszHandler, TEXT("MSPromptEachTime"), cchHandler); } else { // we have a user chosen default dwHandlerDefaultFlag |= HANDLERDEFAULT_USERCHOSENDEFAULT; } } if (SUCCEEDED(hr)) { if (HANDLERDEFAULT_USERCHOSENDEFAULT & dwHandlerDefaultFlag) { BOOL fNewHandlersSinceUserSelection; hr = _HaveNewHandlersBeenInstalledSinceUserSelection( pszEventHandler, &ft, &fNewHandlersSinceUserSelection); if (SUCCEEDED(hr)) { if (fNewHandlersSinceUserSelection) { dwHandlerDefaultFlag |= HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED; } } } } if (SUCCEEDED(hr)) { BOOL fUseEventHandlerDefault = FALSE; if (!(HANDLERDEFAULT_USERCHOSENDEFAULT & dwHandlerDefaultFlag)) { fUseEventHandlerDefault = TRUE; } else { if (HANDLERDEFAULT_MORERECENTHANDLERSINSTALLED & dwHandlerDefaultFlag) { fUseEventHandlerDefault = TRUE; } } if (fUseEventHandlerDefault) { WCHAR szHandlerLocal[MAX_HANDLER]; hr = _GetEventHandlerDefault(hkeyUser, pszEventHandler, szHandlerLocal, ARRAYSIZE(szHandlerLocal)); if (SUCCEEDED(hr)) { if (S_FALSE != hr) { dwHandlerDefaultFlag |= HANDLERDEFAULT_EVENTHANDLERDEFAULT; if (HANDLERDEFAULT_USERCHOSENDEFAULT & dwHandlerDefaultFlag) { if (lstrcmp(szHandlerLocal, pszHandler)) { dwHandlerDefaultFlag |= HANDLERDEFAULT_DEFAULTSAREDIFFERENT; } } else { dwHandlerDefaultFlag |= HANDLERDEFAULT_DEFAULTSAREDIFFERENT; } hr = StringCchCopy(pszHandler, cchHandler, szHandlerLocal); } } } } if (SUCCEEDED(hr)) { // Let's build the return value hr = HANDLERDEFAULT_MAKERETURNVALUE(dwHandlerDefaultFlag); } if (GUH_IMPERSONATEUSER == fImpersonateCaller) { _CoCloseCallingUserHKCU(hThreadToken, hkeyUser); } else { _CloseCurrentUserHKCU(hThreadToken, hkeyUser); } } } return hr; } HRESULT _GetHandlerForNoContent(LPCWSTR pszEventHandler, LPWSTR pszHandler, DWORD cchHandler) { WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlers\\")); HRESULT hr = SafeStrCatN(szKeyName, pszEventHandler, ARRAYSIZE(szKeyName)); if (SUCCEEDED(hr)) { hr = _GetValueToUse(szKeyName, pszHandler, cchHandler); } return hr; } // We want to store the time this default is set. We'll need it to check if // other handlers for this event were installed after the user made a choice. // If that's the case, we'll reprompt the user. // *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! // We store the time as a FILETIME *after* the '\0' string terminator. This is // so it will be hidden in RegEdit. // stephstm (2002-04-12) // *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! HRESULT _MakeFinalUserDefaultHandler(LPCWSTR pszHandler, BYTE** ppb, DWORD* pcb) { HRESULT hr; DWORD cch = lstrlen(pszHandler) + 1; DWORD cbOffset = cch * sizeof(WCHAR); // Round up to be aligned on all platforms cbOffset = (cbOffset + sizeof(void*)) / sizeof(void*) * sizeof(void*); DWORD cb = cbOffset + sizeof(_USERSELECTIONHIDDENDATA); BYTE* pb = (BYTE*)LocalAlloc(LPTR, cb); if (pb) { hr = StringCchCopy((LPWSTR)pb, cch, pszHandler); if (SUCCEEDED(hr)) { _USERSELECTIONHIDDENDATA ushd; GetSystemTimeAsFileTime(&(ushd.ft)); CopyMemory(pb + cb - sizeof(_USERSELECTIONHIDDENDATA), &ushd, sizeof(ushd)); } if (SUCCEEDED(hr)) { *ppb = pb; *pcb = cb; } else { LocalFree(pb); } } else { hr = E_OUTOFMEMORY; } return hr; } HRESULT _DeleteUserDefaultHandler(HKEY hkeyUser, LPCWSTR pszDeviceID, LPCWSTR pszEventHandler) { WCHAR szUserDefault[MAX_USERDEFAULT] = TEXT("H:"); HRESULT hr = _MakeUserDefaultValueString(pszDeviceID, pszEventHandler, &(szUserDefault[2]), ARRAYSIZE(szUserDefault) - 2); if (SUCCEEDED(hr)) { WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("UserChosenExecuteHandlers\\")); hr = _RegDeleteValue(hkeyUser, szKeyName, szUserDefault); } return hr; } HRESULT _SetSoftUserDefaultHandler(LPCWSTR pszDeviceID, LPCWSTR pszEventHandler, LPCWSTR pszHandler) { HKEY hkey; WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlersDefaultSelection\\")); HKEY hkeyUser; HANDLE hThreadToken; HRESULT hr = _CoGetCallingUserHKCU(&hThreadToken, &hkeyUser); if (SUCCEEDED(hr) && (S_FALSE != hr)) { DWORD dwDisp; hr = _RegCreateKey(hkeyUser, szKeyName, &hkey, &dwDisp); if (SUCCEEDED(hr) && (S_FALSE != hr)) { hr = _RegSetString(hkey, pszEventHandler, pszHandler); _DeleteUserDefaultHandler(hkeyUser, pszDeviceID, pszEventHandler); _RegCloseKey(hkey); } _CoCloseCallingUserHKCU(hThreadToken, hkeyUser); } return hr; } HRESULT _DeleteSoftUserDefaultHandler(HKEY hkeyUser, LPCWSTR pszEventHandler) { WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("EventHandlersDefaultSelection\\")); return _RegDeleteValue(hkeyUser, szKeyName, pszEventHandler); } HRESULT _SetUserDefaultHandler(LPCWSTR pszDeviceID, LPCWSTR pszEventHandler, LPCWSTR pszHandler) { WCHAR szUserDefault[MAX_USERDEFAULT] = TEXT("H:"); HRESULT hr = _MakeUserDefaultValueString(pszDeviceID, pszEventHandler, &(szUserDefault[2]), ARRAYSIZE(szUserDefault) - 2); if (SUCCEEDED(hr)) { HKEY hkey; WCHAR szKeyName[MAX_KEY] = SHDEVICEEVENTROOT(TEXT("UserChosenExecuteHandlers\\")); HKEY hkeyUser; HANDLE hThreadToken; hr = _CoGetCallingUserHKCU(&hThreadToken, &hkeyUser); if (SUCCEEDED(hr) && (S_FALSE != hr)) { if (!lstrcmp(pszHandler, TEXT("MSPromptEachTime"))) { hr = _DeleteUserDefaultHandler(hkeyUser, pszDeviceID, pszEventHandler); } else { DWORD dwDisp; hr = _RegCreateKey(hkeyUser, szKeyName, &hkey, &dwDisp); if (SUCCEEDED(hr) && (S_FALSE != hr)) { BYTE* pb; DWORD cb; hr = _MakeFinalUserDefaultHandler(pszHandler, &pb, &cb); if (SUCCEEDED(hr)) { // See comment above _MakeFinalUserDefaultHandler // StephStm: 2002-04-09 if (ERROR_SUCCESS == RegSetValueEx(hkey, szUserDefault, 0, REG_SZ, pb, cb)) { _DeleteSoftUserDefaultHandler(hkeyUser, pszEventHandler); hr = S_OK; } else { hr = S_FALSE; } LocalFree(pb); } _RegCloseKey(hkey); } } _CoCloseCallingUserHKCU(hThreadToken, hkeyUser); } } return hr; } /////////////////////////////////////////////////////////////////////////////// //