// // // assocapi.cpp // // Association APIs // // // #include "priv.h" #include "apithk.h" #include #ifdef _X86_ #include #endif #include #include "assoc.h" #include BOOL _PathAppend(LPCTSTR pszBase, LPCTSTR pszAppend, LPTSTR pszOut, DWORD cchOut); void _MakeAppPathKey(LPCTSTR pszApp, LPTSTR pszKey, DWORD cchKey) { if (_PathAppend(REGSTR_PATH_APPPATHS, pszApp, pszKey, cchKey)) { // Currently we will only look up .EXE if an extension is not // specified if (*PathFindExtension(pszApp) == 0) { StrCatBuff(pszKey, TEXT(".exe"), cchKey); } } } void _MakeApplicationsKey(LPCWSTR pszApp, LPWSTR pszKey, DWORD cchKey) { if (_PathAppend(TEXT("Applications"), pszApp, pszKey, cchKey)) { // Currently we will only look up .EXE if an extension is not // specified if (*PathFindExtension(pszApp) == 0) { StrCatBuff(pszKey, TEXT(".exe"), cchKey); } } } HRESULT _AssocOpenRegKey(HKEY hk, LPCTSTR pszSub, HKEY *phkOut, BOOL fCreate) { ASSERT(phkOut); *phkOut = NULL; if (!hk) return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); DWORD err; if (!fCreate) err = RegOpenKeyEx(hk, pszSub, 0, MAXIMUM_ALLOWED, phkOut); else err = RegCreateKeyEx(hk, pszSub, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkOut, NULL); if (ERROR_SUCCESS != err) { ASSERT(!*phkOut); return HRESULT_FROM_WIN32(err); } return S_OK; } LWSTDAPI AssocCreate(CLSID clsid, REFIID riid, LPVOID *ppvOut) { HRESULT hr = E_INVALIDARG; if (ppvOut) { if (IsEqualGUID(clsid, CLSID_QueryAssociations) || IsEqualGUID(clsid, IID_IQueryAssociations)) { if (IsOS(OS_WHISTLERORGREATER)) hr = SHCoCreateInstance(NULL, &CLSID_QueryAssociations, NULL, riid, ppvOut); else { hr = AssocCreateW2k(riid, ppvOut); } } else hr = AssocCreateElement(clsid, riid, ppvOut); } return hr; } #define ASSOCF_INIT_ALL (ASSOCF_INIT_BYEXENAME | ASSOCF_INIT_DEFAULTTOFOLDER | ASSOCF_INIT_DEFAULTTOSTAR | ASSOCF_INIT_NOREMAPCLSID) LWSTDAPI AssocQueryStringW(ASSOCF flags, ASSOCSTR str, LPCWSTR pszAssoc, LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut) { IQueryAssociations *passoc; HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID *)&passoc); if (SUCCEEDED(hr)) { hr = passoc->Init(flags & ASSOCF_INIT_ALL, pszAssoc, NULL, NULL); if (SUCCEEDED(hr)) hr = passoc->GetString(flags, str, pszExtra, pszOut, pcchOut); passoc->Release(); } return hr; } LWSTDAPI AssocQueryStringA(ASSOCF flags, ASSOCSTR str, LPCSTR pszAssoc, LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut) { if (!pcchOut) return E_INVALIDARG; HRESULT hr = E_OUTOFMEMORY; SHSTRW strAssoc, strExtra; if (SUCCEEDED(strAssoc.SetStr(pszAssoc)) && SUCCEEDED(strExtra.SetStr(pszExtra))) { SHSTRW strOut; DWORD cchIn = IS_INTRESOURCE(pcchOut) ? PtrToUlong(pcchOut) : *pcchOut; DWORD cch; LPTSTR pszTemp = NULL; if (pszOut) { strOut.SetSize(cchIn); cch = strOut.GetSize(); pszTemp = strOut.GetInplaceStr(); } hr = AssocQueryStringW(flags, str, strAssoc, strExtra, pszTemp, &cch); if (SUCCEEDED(hr)) { cch = SHUnicodeToAnsi(strOut, pszOut, cchIn); if (!IS_INTRESOURCE(pcchOut)) *pcchOut = cch; } } return hr; } LWSTDAPI AssocQueryStringByKeyW(ASSOCF flags, ASSOCSTR str, HKEY hkAssoc, LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut) { IQueryAssociations *passoc; HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID *)&passoc); if (SUCCEEDED(hr)) { hr = passoc->Init(flags & ASSOCF_INIT_ALL, NULL, hkAssoc, NULL); if (SUCCEEDED(hr)) hr = passoc->GetString(flags, str, pszExtra, pszOut, pcchOut); passoc->Release(); } return hr; } LWSTDAPI AssocQueryStringByKeyA(ASSOCF flags, ASSOCSTR str, HKEY hkAssoc, LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut) { if (!pcchOut) return E_INVALIDARG; HRESULT hr = E_OUTOFMEMORY; SHSTRW strExtra; if (SUCCEEDED(strExtra.SetStr(pszExtra))) { SHSTRW strOut; DWORD cchIn = IS_INTRESOURCE(pcchOut) ? PtrToUlong(pcchOut) : *pcchOut; DWORD cch; LPWSTR pszTemp = NULL; if (pszOut) { strOut.SetSize(cchIn); cch = strOut.GetSize(); pszTemp = strOut.GetInplaceStr(); } hr = AssocQueryStringByKeyW(flags, str, hkAssoc, strExtra, pszTemp, &cch); if (SUCCEEDED(hr)) { cch = SHUnicodeToAnsi(strOut, pszOut, cchIn); if (!IS_INTRESOURCE(pcchOut)) *pcchOut = cch; } } return hr; } LWSTDAPI AssocQueryKeyW(ASSOCF flags, ASSOCKEY key, LPCWSTR pszAssoc, LPCWSTR pszExtra, HKEY *phkey) { IQueryAssociations *passoc; HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID *)&passoc); if (SUCCEEDED(hr)) { hr = passoc->Init(flags & ASSOCF_INIT_ALL, pszAssoc, NULL, NULL); if (SUCCEEDED(hr)) hr = passoc->GetKey(flags, key, pszExtra, phkey); passoc->Release(); } return hr; } LWSTDAPI AssocQueryKeyA(ASSOCF flags, ASSOCKEY key, LPCSTR pszAssoc, LPCSTR pszExtra, HKEY *phkey) { HRESULT hr = E_OUTOFMEMORY; SHSTRW strAssoc, strExtra; if (SUCCEEDED(strAssoc.SetStr(pszAssoc)) && SUCCEEDED(strExtra.SetStr(pszExtra))) { hr = AssocQueryKeyW(flags, key, strAssoc, strExtra, phkey); } return hr; } #define ISQUOTED(s) (TEXT('"') == *(s) && TEXT('"') == *((s) + lstrlen(s) - 1)) BOOL _TrySubst(SHSTR& str, LPCTSTR psz) { BOOL fRet = FALSE; TCHAR szVar[MAX_PATH]; DWORD cch = GetEnvironmentVariable(psz, szVar, SIZECHARS(szVar)); if (cch && cch <= SIZECHARS(szVar)) { if (0 == StrCmpNI(str, szVar, cch)) { // we got a match. // size the buffer for the env var... +3 = (% + % + \0) SHSTR strT; if (S_OK == strT.SetStr(str.GetStr() + cch) && S_OK == str.SetSize(str.GetLen() - cch + lstrlen(psz) + 3) ) { wnsprintf(str.GetInplaceStr(), str.GetSize(), TEXT("%%%s%%%s"), psz, strT.GetStr()); fRet = TRUE; } } } return fRet; } BOOL _TryEnvSubst(SHSTR& str) { static LPCTSTR rgszEnv[] = { TEXT("USERPROFILE"), TEXT("ProgramFiles"), TEXT("SystemRoot"), TEXT("SystemDrive"), TEXT("windir"), NULL }; LPCTSTR *ppsz = rgszEnv; BOOL fRet = FALSE; while (*ppsz && !fRet) { fRet = _TrySubst(str, *ppsz++); } return fRet; } HRESULT _MakeCommandString(ASSOCF *pflags, LPCTSTR pszExe, LPCTSTR pszArgs, SHSTR& str) { SHSTR strArgs; HRESULT hr; if (!pszArgs || !*pszArgs) { // default to just passing the // file name right in. // NOTE 16bit apps might have a problem with // this, but i request that the caller // specify that this is the case.... pszArgs = TEXT("\"%1\""); } // else NO _ParseCommand() hr = str.SetStr(pszExe); if (S_OK == hr) { // check for quotes before doing env subst BOOL fNeedQuotes = (!ISQUOTED(str.GetStr()) && PathIsLFNFileSpec(str)); // this will put environment vars into the string... if ((*pflags & ASSOCMAKEF_SUBSTENV) && _TryEnvSubst(str)) { *pflags |= ASSOCMAKEF_USEEXPAND; } str.Trim(); if (fNeedQuotes) { // 3 = " + " + \0 if (S_OK == str.SetSize(str.GetLen() + 3)) PathQuoteSpaces(str.GetInplaceStr()); } hr = str.Append(TEXT(' ')); if (S_OK == hr) { hr = str.Append(pszArgs); } } return hr; } HRESULT _AssocMakeCommand(ASSOCMAKEF flags, HKEY hkVerb, LPCWSTR pszExe, LPCWSTR pszArgs) { ASSERT(hkVerb && pszExe); SHSTR str; HRESULT hr = _MakeCommandString(&flags, pszExe, pszArgs, str); if (S_OK == hr) { DWORD dw = (flags & ASSOCMAKEF_USEEXPAND) ? REG_EXPAND_SZ : REG_SZ; DWORD err = SHSetValue(hkVerb, TEXT("command"), NULL, dw, (LPVOID) str.GetStr(), CbFromCch(str.GetLen() +1)); hr = HRESULT_FROM_WIN32(err); } return hr; } LWSTDAPI AssocMakeShell(ASSOCMAKEF flags, HKEY hkProgid, LPCWSTR pszApplication, ASSOCSHELL *pShell) { HRESULT hr = E_INVALIDARG; if (hkProgid && pszApplication && pShell) { for (DWORD c = 0; c < pShell->cVerbs; c++) { ASSOCVERB *pverb = &pShell->rgVerbs[c]; if (pverb->pszVerb) { TCHAR szVerbKey[MAX_PATH]; HKEY hkVerb; _PathAppend(TEXT("shell"), pverb->pszVerb, szVerbKey, SIZECHARS(szVerbKey)); if (c == pShell->iDefaultVerb) SHSetValue(hkProgid, TEXT("shell"), NULL, REG_SZ, pverb->pszVerb, CbFromCch(lstrlen(pverb->pszVerb) +1)); // ASSOCMAKEF_FAILIFEXIST check if its ok to overwrite if (SUCCEEDED(_AssocOpenRegKey(hkProgid, szVerbKey, &hkVerb, FALSE))) { RegCloseKey(hkVerb); SHDeleteKey(hkProgid, szVerbKey); } if (SUCCEEDED(_AssocOpenRegKey(hkProgid, szVerbKey, &hkVerb, TRUE))) { if (pverb->pszTitle) SHSetValue(hkVerb, NULL, NULL, REG_SZ, pverb->pszTitle, CbFromCch(lstrlen(pverb->pszTitle) +1)); hr = _AssocMakeCommand(flags, hkVerb, pverb->pszApplication ? pverb->pszApplication : pszApplication , pverb->pszParams); // if (SUCCEEDED(hr) && pverb->pDDEExec) // hr = _AssocMakeDDEExec(flags, hkVerb, pverb->pDDEExec); RegCloseKey(hkVerb); } } } } return hr; } HRESULT _OpenClasses(HKEY *phkOut) { *phkOut = NULL; DWORD err = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\classes"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, phkOut, NULL); if (err) err = RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("Software\\classes"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, phkOut, NULL); return HRESULT_FROM_WIN32(err); } LWSTDAPI AssocMakeProgid(ASSOCMAKEF flags, LPCWSTR pszApplication, ASSOCPROGID *pProgid, HKEY *phkProgid) { HRESULT hr = E_INVALIDARG; if (pszApplication && pProgid && pProgid->cbSize >= sizeof(ASSOCPROGID) && pProgid->pszProgid && *pProgid->pszProgid) { HKEY hkRoot; if ((!(flags & ASSOCMAKEF_VERIFY) || PathFileExists(pszApplication)) && SUCCEEDED(_OpenClasses(&hkRoot))) { HKEY hkProgid; // need to add support for ASSOCMAKEF_VOLATILE... hr = _AssocOpenRegKey(hkRoot, pProgid->pszProgid, &hkProgid, TRUE); if (SUCCEEDED(hr)) { if (pProgid->pszFriendlyDocName) SHSetValue(hkProgid, NULL, NULL, REG_SZ, pProgid->pszFriendlyDocName, CbFromCch(lstrlen(pProgid->pszFriendlyDocName) +1)); if (pProgid->pszDefaultIcon) SHSetValue(hkProgid, TEXT("DefaultIcon"), NULL, REG_SZ, pProgid->pszDefaultIcon, CbFromCch(lstrlen(pProgid->pszDefaultIcon) +1)); if (pProgid->pShellKey) hr = AssocMakeShell(flags, hkProgid, pszApplication, pProgid->pShellKey); if (SUCCEEDED(hr) && pProgid->pszExtensions) { LPCTSTR psz = pProgid->pszExtensions; DWORD err = NOERROR; while (*psz && NOERROR == err) { err = SHSetValue(hkRoot, psz, NULL, REG_SZ, pProgid->pszProgid, CbFromCch(lstrlen(pProgid->pszProgid) + 1)); psz += lstrlen(psz) + 1; } if (NOERROR != err) HRESULT_FROM_WIN32(err); } if (SUCCEEDED(hr) && phkProgid) *phkProgid = hkProgid; else RegCloseKey(hkProgid); } RegCloseKey(hkRoot); } } return hr; } HRESULT _AssocCopyVerb(HKEY hkSrc, HKEY hkDst, LPCTSTR pszVerb) { HRESULT hr = S_OK; TCHAR szKey[MAX_PATH]; HKEY hkVerb; DWORD dwDisp; // only copy the verb component wnsprintf(szKey, SIZECHARS(szKey), TEXT("shell\\%s"), pszVerb); RegCreateKeyEx(hkDst, szKey, 0, NULL, 0, MAXIMUM_ALLOWED, NULL, &hkVerb, &dwDisp); // create a failure state here... if (hkVerb) { // we avoid overwriting old keys by checking the dwDisp if ((dwDisp == REG_CREATED_NEW_KEY) && SHCopyKey(hkSrc, pszVerb, hkVerb, 0L)) hr = E_UNEXPECTED; RegCloseKey(hkVerb); } return hr; } typedef BOOL (*PFNALLOWVERB)(LPCWSTR psz, LPARAM param); LWSTDAPI _AssocCopyVerbs(HKEY hkSrc, HKEY hkDst, PFNALLOWVERB pfnAllow, LPARAM lParam) { HRESULT hr = E_INVALIDARG; HKEY hkEnum; if (SUCCEEDED(_AssocOpenRegKey(hkSrc, TEXT("shell"), &hkEnum, FALSE))) { TCHAR szVerb[MAX_PATH]; DWORD cchVerb = SIZECHARS(szVerb); for (DWORD i = 0 ; (NOERROR == RegEnumKeyEx(hkEnum, i, szVerb, &cchVerb, NULL, NULL, NULL, NULL)) ; (cchVerb = SIZECHARS(szVerb)), i++) { if (!pfnAllow || pfnAllow(szVerb, lParam)) hr = _AssocCopyVerb(hkEnum, hkDst, szVerb); } // switch to cbVerb here cchVerb = sizeof(szVerb); if (NOERROR == SHGetValue(hkEnum, NULL, NULL, NULL, szVerb, &cchVerb)) { SHSetValue(hkDst, TEXT("shell"), NULL, REG_SZ, szVerb, cchVerb); } RegCloseKey(hkEnum); } return hr; } LWSTDAPI AssocCopyVerbs(HKEY hkSrc, HKEY hkDst) { return _AssocCopyVerbs(hkSrc, hkDst, NULL, NULL); } BOOL _IsMSIPerUserInstall(IQueryAssociations *pqa, ASSOCF flags, LPCWSTR pszVerb) { WCHAR sz[MAX_PATH]; DWORD cb = sizeof(sz); if (SUCCEEDED(pqa->GetData(flags, ASSOCDATA_MSIDESCRIPTOR, pszVerb, sz, &cb))) { WCHAR szOut[3]; // bit enough for "1" or "0" cb = SIZECHARS(szOut); if (NOERROR == MsiGetProductInfoW(sz, INSTALLPROPERTY_ASSIGNMENTTYPE, szOut, &cb)) { // The string "1" for the value represents machine installations, // while "0" represents user installations. if (0 == StrCmpW(szOut, L"0")) return TRUE; } } return FALSE; } typedef struct { IQueryAssociations *pqa; ASSOCF Qflags; LPCWSTR pszExe; BOOL fAllowPerUser; } QUERYEXECB; BOOL _AllowExeVerb(LPCWSTR pszVerb, QUERYEXECB *pqcb) { BOOL fRet = FALSE; WCHAR sz[MAX_PATH]; if (SUCCEEDED(pqcb->pqa->GetString(pqcb->Qflags, ASSOCSTR_EXECUTABLE, pszVerb, sz, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(sz))))) { if (0 == StrCmpIW(PathFindFileNameW(sz), pqcb->pszExe)) { // // EXEs match so we should copy this verb. // but we need to block per-user installs by darwin being added to the // applications key, since other users wont be able to use them // if (_IsMSIPerUserInstall(pqcb->pqa, pqcb->Qflags, pszVerb)) fRet = pqcb->fAllowPerUser; else fRet = TRUE; } } // todo mask off DARWIN per-user installs return fRet; } HRESULT _AssocCreateAppKey(LPCWSTR pszExe, BOOL fPerUser, HKEY *phk) { WCHAR szKey[MAX_PATH]; wnsprintf(szKey, SIZECHARS(szKey), L"software\\classes\\applications\\%s", pszExe); if (*PathFindExtension(pszExe) == 0) { StrCatBuff(szKey, TEXT(".exe"), SIZECHARS(szKey)); } return _AssocOpenRegKey((IsOS(OS_NT) && fPerUser) ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szKey, phk, TRUE); } LWSTDAPI AssocMakeApplicationByKeyW(ASSOCMAKEF flags, HKEY hkSrc, LPCWSTR pszVerb) { WCHAR szPath[MAX_PATH]; HRESULT hr = HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); ASSOCF Qflags = (flags & ASSOCMAKEF_VERIFY) ? ASSOCF_VERIFY : 0; IQueryAssociations *pqa; AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID *)&pqa); if (!pqa) return E_OUTOFMEMORY; if (SUCCEEDED(pqa->Init(0, NULL, hkSrc, NULL))) { if (SUCCEEDED(pqa->GetString(Qflags, ASSOCSTR_EXECUTABLE, pszVerb, szPath, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szPath)))) && (0 != StrCmpW(szPath, TEXT("%1")))) { LPCWSTR pszExe = PathFindFileNameW(szPath); BOOL fPerUser = _IsMSIPerUserInstall(pqa, Qflags, pszVerb); HKEY hkDst; ASSERT(pszExe && *pszExe); // we have an exe to use // check to see if this Application already has // this verb installed DWORD cch; hr = AssocQueryString(Qflags | ASSOCF_OPEN_BYEXENAME, ASSOCSTR_COMMAND, pszExe, pszVerb, NULL, &cch); if (FAILED(hr) && SUCCEEDED(_AssocCreateAppKey(pszExe, fPerUser, &hkDst))) { QUERYEXECB qcb = {pqa, Qflags, pszExe, fPerUser}; if (pszVerb) { if (_AllowExeVerb(pszVerb, &qcb)) { HKEY hkSrcVerbs; if (SUCCEEDED(_AssocOpenRegKey(hkSrc, TEXT("shell"), &hkSrcVerbs, FALSE))) { hr = _AssocCopyVerb(hkSrcVerbs, hkDst, pszVerb); RegCloseKey(hkSrcVerbs); } else { hr = E_UNEXPECTED; } } } else { hr = _AssocCopyVerbs(hkSrc, hkDst, (PFNALLOWVERB)_AllowExeVerb, (LPARAM)&qcb); } RegCloseKey(hkDst); } // init the friendly name for later if ((flags & ASSOCMAKEF_VERIFY) && SUCCEEDED(hr)) { AssocQueryString(ASSOCF_OPEN_BYEXENAME | Qflags, ASSOCSTR_FRIENDLYAPPNAME, pszExe, NULL, NULL, &cch); } } pqa->Release(); } return hr; } LWSTDAPI AssocMakeApplicationByKeyA(ASSOCMAKEF flags, HKEY hkAssoc, LPCSTR pszVerb) { // convert pszVerb to wide char but preserve difference // between NULL and "" for AssocMakeApplicationByKeyW if (! pszVerb) return AssocMakeApplicationByKeyW(flags, hkAssoc, NULL); SHSTRW strVerb; HRESULT hr = strVerb.SetStr(pszVerb); if (SUCCEEDED(hr)) hr = AssocMakeApplicationByKeyW(flags, hkAssoc, strVerb); return hr; } // This list needs to continue to be updated and we should try to keep parity with Office const LPCTSTR c_arszUnsafeExts[] = { TEXT(".ade"), TEXT(".adp"), TEXT(".asp"), TEXT(".bas"), TEXT(".bat"), TEXT(".chm"), TEXT(".cmd"), TEXT(".com"), TEXT(".cpl"), TEXT(".crt"), TEXT(".exe"), TEXT(".hlp"), TEXT(".hta"), TEXT(".inf"), TEXT(".ins"), TEXT(".isp"), TEXT(".its"), TEXT(".js"), TEXT(".jse"), TEXT(".lnk"), TEXT(".mdb"), TEXT(".mde"), TEXT(".mdt"), TEXT(".mdw"), TEXT(".msc"), TEXT(".msi"), TEXT(".msp"), TEXT(".mst"), TEXT(".pcd"), TEXT(".pif"), TEXT(".reg"), TEXT(".scr"), TEXT(".sct"), TEXT(".shb"), TEXT(".shs"), TEXT(".tmp"), TEXT(".url"), TEXT(".vb"), TEXT(".vbe"), TEXT(".vbs"), TEXT(".vsd"), TEXT(".vsmacros"), TEXT(".vss"), TEXT(".vst"), TEXT(".vsw"), TEXT(".ws"), TEXT(".wsc"), TEXT(".wsf"), TEXT(".wsh"), }; typedef BOOL (*PFNSAFERIISEXECUTABLEFILETYPE)(LPCWSTR szFullPathname, BOOLEAN bFromShellExecute); LWSTDAPI_(BOOL) AssocIsDangerous(PCWSTR pszType) { #ifdef DEBUG // make sure our sort is good. static BOOL fCheckedUnsafe = FALSE; if (!fCheckedUnsafe) { for (int i = 1; i < ARRAYSIZE(c_arszUnsafeExts); i++) { ASSERT(0 > StrCmpIW(c_arszUnsafeExts[i-1], c_arszUnsafeExts[i])); } fCheckedUnsafe = TRUE; } #endif // DEBUG BOOL fDangerous = IsTypeInList(pszType, c_arszUnsafeExts, ARRAYSIZE(c_arszUnsafeExts)); if (!fDangerous && pszType) { IQueryAssociations *passoc; HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &passoc)); if (SUCCEEDED(hr)) { hr = passoc->Init(NULL, pszType, NULL, NULL); if (SUCCEEDED(hr)) { DWORD dwEditFlags; ULONG cb = sizeof(dwEditFlags); hr = passoc->GetData(NULL, ASSOCDATA_EDITFLAGS, NULL, &dwEditFlags, &cb); if (SUCCEEDED(hr)) { fDangerous = dwEditFlags & FTA_AlwaysUnsafe; } } passoc->Release(); } if (!fDangerous && IsOS(OS_WHISTLERORGREATER) && *pszType) { HMODULE hmod = LoadLibrary(TEXT("advapi32.dll")); if (hmod) { PFNSAFERIISEXECUTABLEFILETYPE pfnSaferiIsExecutableFileType = (PFNSAFERIISEXECUTABLEFILETYPE)GetProcAddress(hmod, "SaferiIsExecutableFileType"); if (pfnSaferiIsExecutableFileType) fDangerous = pfnSaferiIsExecutableFileType(pszType, TRUE); FreeLibrary(hmod); } } } return fDangerous; }