Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605/* * Open With Context Menu extension * * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org> * Copyright 2009 Andrew Hill * Copyright 2012 Rafal Harabien * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include "precomp.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
//// [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system]// "NoInternetOpenWith"=dword:00000001//
EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath);
static SIZE_T PathGetAppFromCommandLine(LPCWSTR pszIn, LPWSTR pszOut, SIZE_T cchMax){ SIZE_T count = 0; WCHAR stop = ' '; if (pszIn[0] == '"') stop = *(pszIn++);
for (LPCWSTR pwszSrc = pszIn; *pwszSrc && *pwszSrc != stop; ++pwszSrc) { if (++count >= cchMax) return 0; *(pszOut++) = *pwszSrc; } *pszOut = UNICODE_NULL; return count;}
HRESULT SHELL32_GetDllFromRundll32CommandLine(LPCWSTR pszCmd, LPWSTR pszOut, SIZE_T cchMax){ WCHAR szDll[MAX_PATH + 100]; if (!PathGetAppFromCommandLine(pszCmd, szDll, _countof(szDll))) return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
PWSTR pszName = PathFindFileNameW(szDll); if (_wcsicmp(pszName, L"rundll32") && _wcsicmp(pszName, L"rundll32.exe")) return E_UNEXPECTED;
PCWSTR pszDllStart = pszCmd + (pszName - szDll) + lstrlenW(pszName);
if (*pszDllStart == '\"') ++pszDllStart; // Skip possible end quote of ..\rundll32.exe" foo.dll,func while (*pszDllStart <= ' ' && *pszDllStart) ++pszDllStart; if (PathGetAppFromCommandLine(pszDllStart, szDll, _countof(szDll))) { BOOL quoted = *pszDllStart == '\"'; PWSTR pszComma = szDll + lstrlenW(szDll); while (!quoted && pszComma > szDll && *pszComma != ',' && *pszComma != '\\' && *pszComma != '/') --pszComma; SIZE_T cch = pszComma - szDll; if (cch <= cchMax && (quoted || *pszComma == ',')) { *pszComma = UNICODE_NULL; lstrcpynW(pszOut, szDll, cchMax); return S_OK; } } return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);}
static HRESULT SH32_EvaluateValidExecApp(_Inout_ PWSTR pszCmd, _In_ SIZE_T cchMax){ // FIXME: SHEvaluateSystemCommandTemplate is not implemented yet, using a minimal version. if (!PathGetAppFromCommandLine(pszCmd, pszCmd, cchMax)) return E_FAIL;
UINT fPRF = PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS | PRF_DONTFINDLNK; WCHAR szCurrDir[MAX_PATH]; LPCWSTR pszDirsArr[2] = { szCurrDir, NULL }, *ppszDirs = NULL; if (GetCurrentDirectoryW(_countof(szCurrDir), szCurrDir)) ppszDirs = pszDirsArr; if (PathResolveW(pszCmd, ppszDirs, fPRF | (ppszDirs ? PRF_FIRSTDIRDEF : 0))) return S_OK; return E_FAIL;}
HRESULT SH32_InvokeOpenWith(_In_ PCWSTR pszPath, _In_ LPCMINVOKECOMMANDINFO pici, _Out_ HANDLE *phProcess){ if (!pszPath || !pici) return HResultFromWin32(ERROR_INVALID_PARAMETER);
HRESULT hr = HResultFromWin32(ERROR_NO_ASSOCIATION); SHELLEXECUTEINFOW sei = { sizeof(sei), CmicFlagsToSeeFlags(pici->fMask), pici->hwnd }; sei.fMask |= SEE_MASK_CLASSKEY | SEE_MASK_NOZONECHECKS; sei.lpFile = pszPath; sei.nShow = pici->nShow; if (phProcess) { sei.fMask |= SEE_MASK_NOCLOSEPROCESS; sei.hProcess = NULL; }
if (!RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Unknown", 0, KEY_READ, &sei.hkeyClass)) { // Use the internal dialog only if HKCR\Unknown\shell\openas\command exists but is invalid. WCHAR szCmd[MAX_PATH * 2]; DWORD cch = _countof(szCmd); hr = AssocQueryStringByKeyW(ASSOCF_NOTRUNCATE | ASSOCF_NOFIXUPS | ASSOCF_IGNOREBASECLASS | ASSOCF_INIT_IGNOREUNKNOWN, ASSOCSTR_COMMAND, sei.hkeyClass, NULL, szCmd, &cch); if (SUCCEEDED(hr) && FAILED(SH32_EvaluateValidExecApp(szCmd, _countof(szCmd)))) { OPENASINFO info = { pszPath, NULL, OAIF_EXEC | OAIF_REGISTER_EXT | OAIF_ALLOW_REGISTRATION }; hr = SHOpenWithDialog(sei.hwnd, &info); } else { hr = ShellExecuteExW(&sei) ? S_OK : HResultFromWin32(GetLastError()); } RegCloseKey(sei.hkeyClass); } else if (!(pici->fMask & CMIC_MASK_FLAG_NO_UI)) { SHELL_ErrorBox(sei.hwnd, hr); }
if (phProcess) *phProcess = sei.hProcess; return hr;}
class COpenWithList{ public: struct SApp { WCHAR wszFilename[MAX_PATH]; WCHAR wszCmd[MAX_PATH]; //WCHAR wszManufacturer[256]; WCHAR wszName[256]; BOOL bHidden; BOOL bRecommended; BOOL bMRUList; HICON hIcon; };
COpenWithList(); ~COpenWithList();
BOOL Load(); SApp *Add(LPCWSTR pwszPath); static BOOL SaveApp(SApp *pApp); SApp *Find(LPCWSTR pwszFilename); static LPCWSTR GetName(SApp *pApp); static HICON GetIcon(SApp *pApp); static BOOL Execute(SApp *pApp, LPCWSTR pwszFilePath); static BOOL IsHidden(SApp *pApp); inline BOOL IsNoOpen(VOID) { return m_bNoOpen; } BOOL LoadRecommended(LPCWSTR pwszFilePath); BOOL SetDefaultHandler(SApp *pApp, LPCWSTR pwszFilename);
inline SApp *GetList() { return m_pApp; } inline UINT GetCount() { return m_cApp; } inline UINT GetRecommendedCount() { return m_cRecommended; }
private: typedef struct _LANGANDCODEPAGE { WORD lang; WORD code; } LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
SApp *m_pApp; UINT m_cApp, m_cRecommended; BOOL m_bNoOpen;
SApp *AddInternal(LPCWSTR pwszFilename); static BOOL LoadInfo(SApp *pApp); static BOOL GetPathFromCmd(LPWSTR pwszAppPath, LPCWSTR pwszCmd); BOOL LoadProgIdList(HKEY hKey, LPCWSTR pwszExt); static HANDLE OpenMRUList(HKEY hKey); BOOL LoadMRUList(HKEY hKey); BOOL LoadAppList(HKEY hKey); VOID LoadFromProgIdKey(HKEY hKey, LPCWSTR pwszExt); VOID LoadRecommendedFromHKCR(LPCWSTR pwszExt); VOID LoadRecommendedFromHKCU(LPCWSTR pwszExt); static BOOL AddAppToMRUList(SApp *pApp, LPCWSTR pwszFilename);
inline VOID SetRecommended(SApp *pApp) { if (!pApp->bRecommended) ++m_cRecommended; pApp->bRecommended = TRUE; }};
COpenWithList::COpenWithList(): m_pApp(NULL), m_cApp(0), m_cRecommended(0), m_bNoOpen(FALSE) {}
COpenWithList::~COpenWithList(){ for (UINT i = 0; i < m_cApp; ++i) if (m_pApp[i].hIcon) DestroyIcon(m_pApp[i].hIcon);
HeapFree(GetProcessHeap(), 0, m_pApp);}
BOOL COpenWithList::Load(){ HKEY hKey, hKeyApp; WCHAR wszName[256], wszBuf[100]; DWORD i = 0, cchName, dwSize; SApp *pApp;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, L"Applications", 0, KEY_READ, &hKey) != ERROR_SUCCESS) { ERR("RegOpenKeyEx HKCR\\Applications failed!\n"); return FALSE; }
while (TRUE) { cchName = _countof(wszName); if (RegEnumKeyEx(hKey, i++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) break;
pApp = AddInternal(wszName);
if (pApp) { if (RegOpenKeyW(hKey, wszName, &hKeyApp) == ERROR_SUCCESS) { if ((RegQueryValueExW(hKeyApp, L"NoOpenWith", NULL, NULL, NULL, NULL) != ERROR_SUCCESS) && (RegQueryValueExW(hKeyApp, L"NoStartPage", NULL, NULL, NULL, NULL) != ERROR_SUCCESS)) { StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s\\shell\\open\\command", wszName); dwSize = sizeof(pApp->wszCmd); if (RegGetValueW(hKey, wszBuf, L"", RRF_RT_REG_SZ, NULL, pApp->wszCmd, &dwSize) != ERROR_SUCCESS) { ERR("Failed to add app %ls\n", wszName); pApp->bHidden = TRUE; } else { TRACE("App added %ls\n", pApp->wszCmd); } } else { pApp->bHidden = TRUE; } RegCloseKey(hKeyApp); } else { pApp->bHidden = TRUE; } } else { ERR("AddInternal failed\n"); } }
RegCloseKey(hKey); return TRUE;}
COpenWithList::SApp *COpenWithList::Add(LPCWSTR pwszPath){ SApp *pApp = AddInternal(PathFindFileNameW(pwszPath));
if (pApp) { StringCbPrintfW(pApp->wszCmd, sizeof(pApp->wszCmd), L"\"%s\" \"%%1\"", pwszPath); SaveApp(pApp); }
return pApp;}
BOOL COpenWithList::SaveApp(SApp *pApp){ WCHAR wszBuf[256]; HKEY hKey;
StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s\\shell\\open\\command", pApp->wszFilename); if (RegCreateKeyEx(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) { ERR("RegOpenKeyEx failed\n"); return FALSE; }
if (RegSetValueEx(hKey, L"", 0, REG_SZ, (PBYTE)pApp->wszCmd, (wcslen(pApp->wszCmd)+1)*sizeof(WCHAR)) != ERROR_SUCCESS) ERR("Cannot add app to registry\n");
RegCloseKey(hKey); return TRUE;}
COpenWithList::SApp *COpenWithList::Find(LPCWSTR pwszFilename){ for (UINT i = 0; i < m_cApp; ++i) if (_wcsicmp(m_pApp[i].wszFilename, pwszFilename) == 0) return &m_pApp[i]; return NULL;}
LPCWSTR COpenWithList::GetName(SApp *pApp){ if (!pApp->wszName[0]) { if (!LoadInfo(pApp)) { WARN("Failed to load %ls info\n", pApp->wszFilename); StringCbCopyW(pApp->wszName, sizeof(pApp->wszName), pApp->wszFilename);
WCHAR wszPath[MAX_PATH]; if (!GetPathFromCmd(wszPath, pApp->wszCmd)) { return NULL; } } }
TRACE("%ls name: %ls\n", pApp->wszFilename, pApp->wszName); return pApp->wszName;}
HICON COpenWithList::GetIcon(SApp *pApp){ if (!pApp->hIcon) { WCHAR wszPath[MAX_PATH];
GetPathFromCmd(wszPath, pApp->wszCmd); if (!ExtractIconExW(wszPath, 0, NULL, &pApp->hIcon, 1)) { SHFILEINFO fi; /* FIXME: Ideally we should include SHGFI_USEFILEATTRIBUTES because we already ** know the file has no icons but SHGetFileInfo is broken in that case (CORE-19122). ** Without SHGFI_USEFILEATTRIBUTES we needlessly hit the disk again but it will ** return the correct default .exe icon. */ SHGetFileInfoW(wszPath, 0, &fi, sizeof(fi), SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SHELLICONSIZE); pApp->hIcon = fi.hIcon; } }
TRACE("%ls icon: %p\n", pApp->wszFilename, pApp->hIcon);
return pApp->hIcon;}
BOOL COpenWithList::Execute(COpenWithList::SApp *pApp, LPCWSTR pwszFilePath){ WCHAR wszBuf[256]; HKEY hKey;
/* Add app to registry if it wasnt there before */ SaveApp(pApp); if (!pApp->bMRUList) AddAppToMRUList(pApp, pwszFilePath);
/* Get a handle to the reg key */ StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s", pApp->wszFilename); if (RegCreateKeyEx(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) { ERR("RegOpenKeyEx failed\n"); return FALSE; }
/* Let ShellExecuteExW do the work */ SHELLEXECUTEINFOW sei = {sizeof(SHELLEXECUTEINFOW), SEE_MASK_CLASSKEY}; sei.nShow = SW_SHOWNORMAL; sei.hkeyClass = hKey; sei.lpFile = pwszFilePath;
ShellExecuteExW(&sei);
return TRUE;}
BOOL COpenWithList::IsHidden(SApp *pApp){ WCHAR wszBuf[100]; DWORD dwSize = 0;
if (pApp->bHidden) return pApp->bHidden;
if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s", pApp->wszFilename))) { ERR("insufficient buffer\n"); return FALSE; }
if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, L"NoOpenWith", RRF_RT_REG_SZ, NULL, NULL, &dwSize) != ERROR_SUCCESS) return FALSE;
pApp->bHidden = TRUE; return TRUE;}
COpenWithList::SApp *COpenWithList::AddInternal(LPCWSTR pwszFilename){ /* Check for duplicate */ SApp *pApp = Find(pwszFilename); if (pApp) return pApp;
/* Create new item */ if (!m_pApp) m_pApp = static_cast<SApp *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(m_pApp[0]))); else m_pApp = static_cast<SApp *>(HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, m_pApp, (m_cApp + 1)*sizeof(m_pApp[0]))); if (!m_pApp) { ERR("Allocation failed\n"); return NULL; }
pApp = &m_pApp[m_cApp++]; wcscpy(pApp->wszFilename, pwszFilename); return pApp;}
BOOL COpenWithList::LoadInfo(COpenWithList::SApp *pApp){ UINT cbSize, cchLen; LPVOID pBuf; WORD wLang = 0, wCode = 0; LPLANGANDCODEPAGE lpLangCode; WCHAR wszBuf[100]; WCHAR *pResult; WCHAR wszPath[MAX_PATH]; BOOL success = FALSE;
GetPathFromCmd(wszPath, pApp->wszCmd); TRACE("LoadInfo %ls\n", wszPath);
/* query version info size */ cbSize = GetFileVersionInfoSizeW(wszPath, NULL); if (!cbSize) { ERR("GetFileVersionInfoSizeW %ls failed: %lu\n", wszPath, GetLastError()); return FALSE; }
/* allocate buffer */ pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbSize + 200); if (!pBuf) { ERR("HeapAlloc failed\n"); return FALSE; }
/* query version info */ if (!GetFileVersionInfoW(wszPath, 0, cbSize, pBuf)) { ERR("GetFileVersionInfoW %ls failed: %lu\n", wszPath, GetLastError()); HeapFree(GetProcessHeap(), 0, pBuf); return FALSE; }
/* query lang code */ if (VerQueryValueW(pBuf, L"VarFileInfo\\Translation", (LPVOID*)&lpLangCode, &cbSize)) { /* FIXME: find language from current locale / if not available, * default to english * for now default to first available language */ wLang = lpLangCode->lang; wCode = lpLangCode->code; }
/* Query name */ swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\FileDescription", wLang, wCode); success = VerQueryValueW(pBuf, wszBuf, (LPVOID *)&pResult, &cchLen) && (cchLen > 1); if (success) StringCchCopyNW(pApp->wszName, _countof(pApp->wszName), pResult, cchLen); else ERR("Cannot get app name\n");
/* Query manufacturer */ /*swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\CompanyName", wLang, wCode);
if (VerQueryValueW(pBuf, wszBuf, (LPVOID *)&pResult, &cchLen)) StringCchCopyNW(pApp->wszManufacturer, _countof(pApp->wszManufacturer), pResult, cchLen);*/ HeapFree(GetProcessHeap(), 0, pBuf); return success;}
BOOL COpenWithList::GetPathFromCmd(LPWSTR pwszAppPath, LPCWSTR pwszCmd){ WCHAR wszBuf[MAX_PATH];
/* Remove arguments */ if (!PathGetAppFromCommandLine(pwszCmd, wszBuf, _countof(wszBuf))) return FALSE;
/* Replace rundll32.exe with the dll path */ SHELL32_GetDllFromRundll32CommandLine(pwszCmd, wszBuf, _countof(wszBuf));
/* Expand env. vars and optionally search for path */ ExpandEnvironmentStrings(wszBuf, pwszAppPath, MAX_PATH); if (!PathFileExists(pwszAppPath)) { UINT cch = SearchPathW(NULL, pwszAppPath, NULL, MAX_PATH, pwszAppPath, NULL); if (!cch || cch >= MAX_PATH) return FALSE; } return TRUE;}
BOOL COpenWithList::LoadRecommended(LPCWSTR pwszFilePath){ LPCWSTR pwszExt;
pwszExt = PathFindExtensionW(pwszFilePath); if (!pwszExt[0]) return FALSE;
/* load programs directly associated from HKCU */ LoadRecommendedFromHKCU(pwszExt);
/* load programs associated from HKCR\Extension */ LoadRecommendedFromHKCR(pwszExt);
return TRUE;}
BOOL COpenWithList::LoadProgIdList(HKEY hKey, LPCWSTR pwszExt){ HKEY hSubkey, hSubkey2; WCHAR wszProgId[256]; DWORD i = 0, cchProgId;
if (RegOpenKeyExW(hKey, L"OpenWithProgIDs", 0, KEY_READ, &hSubkey) != ERROR_SUCCESS) return FALSE;
while (TRUE) { /* Enumerate values - value name is ProgId */ cchProgId = _countof(wszProgId); if (RegEnumValue(hSubkey, i++, wszProgId, &cchProgId, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) break;
/* If ProgId exists load it */ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszProgId, 0, KEY_READ, &hSubkey2) == ERROR_SUCCESS) { LoadFromProgIdKey(hSubkey2, pwszExt); RegCloseKey(hSubkey2); } }
RegCloseKey(hSubkey); return TRUE;}
HANDLE COpenWithList::OpenMRUList(HKEY hKey){ MRUINFOW Info;
/* Initialize mru list info */ Info.cbSize = sizeof(Info); Info.uMax = 32; Info.fFlags = MRU_STRING; Info.hKey = hKey; Info.lpszSubKey = L"OpenWithList"; Info.lpfnCompare = NULL;
return CreateMRUListW(&Info);}
BOOL COpenWithList::LoadMRUList(HKEY hKey){ HANDLE hList; int nItem, nCount, nResult; WCHAR wszAppFilename[MAX_PATH];
/* Open MRU list */ hList = OpenMRUList(hKey); if (!hList) { TRACE("OpenMRUList failed\n"); return FALSE; }
/* Get list count */ nCount = EnumMRUListW(hList, -1, NULL, 0);
for(nItem = 0; nItem < nCount; nItem++) { nResult = EnumMRUListW(hList, nItem, wszAppFilename, _countof(wszAppFilename)); if (nResult <= 0) continue;
/* Insert item */ SApp *pApp = Find(wszAppFilename);
TRACE("Recommended app %ls: %p\n", wszAppFilename, pApp); if (pApp) { pApp->bMRUList = TRUE; SetRecommended(pApp); } }
/* Free the MRU list */ FreeMRUList(hList); return TRUE;}
BOOL COpenWithList::LoadAppList(HKEY hKey){ WCHAR wszAppFilename[MAX_PATH]; HKEY hSubkey; DWORD i = 0, cchAppFilename;
if (RegOpenKeyExW(hKey, L"OpenWithList", 0, KEY_READ, &hSubkey) != ERROR_SUCCESS) return FALSE;
while (TRUE) { /* Enum registry keys - each of them is app name */ cchAppFilename = _countof(wszAppFilename); if (RegEnumKeyExW(hSubkey, i++, wszAppFilename, &cchAppFilename, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) break;
/* Set application as recommended */ SApp *pApp = Find(wszAppFilename);
TRACE("Recommended app %ls: %p\n", wszAppFilename, pApp); if (pApp) SetRecommended(pApp); }
RegCloseKey(hSubkey); return TRUE;}
VOID COpenWithList::LoadFromProgIdKey(HKEY hKey, LPCWSTR pwszExt){ WCHAR wszCmd[MAX_PATH], wszPath[MAX_PATH]; DWORD dwSize = 0;
/* Check if NoOpen value exists */ if (RegGetValueW(hKey, NULL, L"NoOpen", RRF_RT_REG_SZ, NULL, NULL, &dwSize) == ERROR_SUCCESS) { /* Display warning dialog */ m_bNoOpen = TRUE; }
/* Check if there is a directly available execute key */ dwSize = sizeof(wszCmd); if (RegGetValueW(hKey, L"shell\\open\\command", NULL, RRF_RT_REG_SZ, NULL, (PVOID)wszCmd, &dwSize) == ERROR_SUCCESS) { /* Erase extra arguments */ GetPathFromCmd(wszPath, wszCmd);
/* Add application */ SApp *pApp = AddInternal(PathFindFileNameW(wszPath)); TRACE("Add app %ls: %p\n", wszPath, pApp);
if (pApp) { StringCbCopyW(pApp->wszCmd, sizeof(pApp->wszCmd), wszCmd); SetRecommended(pApp); } }}
VOID COpenWithList::LoadRecommendedFromHKCR(LPCWSTR pwszExt){ HKEY hKey, hSubkey; WCHAR wszBuf[MAX_PATH], wszBuf2[MAX_PATH]; DWORD dwSize;
/* Check if extension exists */ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { /* Load items from SystemFileAssociations\Ext key */ StringCbPrintfW(wszBuf, sizeof(wszBuf), L"SystemFileAssociations\\%s", pwszExt); if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hKey) != ERROR_SUCCESS) return; }
/* Load programs referenced from HKCR\ProgId */ dwSize = sizeof(wszBuf); if (RegGetValueW(hKey, NULL, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS && RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hSubkey) == ERROR_SUCCESS) { LoadFromProgIdKey(hSubkey, pwszExt); RegCloseKey(hSubkey); } else LoadFromProgIdKey(hKey, pwszExt);
/* Load items from HKCR\Ext\OpenWithList */ LoadAppList(hKey);
/* Load items from HKCR\Ext\OpenWithProgIDs */ if (RegOpenKeyExW(hKey, L"OpenWithProgIDs", 0, KEY_READ, &hSubkey) == ERROR_SUCCESS) { LoadProgIdList(hSubkey, pwszExt); RegCloseKey(hSubkey); }
/* Load additional items from referenced PerceivedType */ dwSize = sizeof(wszBuf); if (RegGetValueW(hKey, NULL, L"PerceivedType", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS) { StringCbPrintfW(wszBuf2, sizeof(wszBuf2), L"SystemFileAssociations\\%s", wszBuf); if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf2, 0, KEY_READ | KEY_WRITE, &hSubkey) == ERROR_SUCCESS) { /* Load from OpenWithList key */ LoadAppList(hSubkey); RegCloseKey(hSubkey); } }
/* Close the key */ RegCloseKey(hKey);}
VOID COpenWithList::LoadRecommendedFromHKCU(LPCWSTR pwszExt){ WCHAR wszBuf[MAX_PATH]; HKEY hKey;
StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s", pwszExt); if (RegOpenKeyExW(HKEY_CURRENT_USER, wszBuf, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { /* Load MRU and ProgId lists */ LoadMRUList(hKey); LoadProgIdList(hKey, pwszExt);
/* Handle "Application" value */ DWORD cbBuf = sizeof(wszBuf); if (RegGetValueW(hKey, NULL, L"Application", RRF_RT_REG_SZ, NULL, wszBuf, &cbBuf) == ERROR_SUCCESS) { SApp *pApp = Find(wszBuf); if (pApp) SetRecommended(pApp); }
/* Close the key */ RegCloseKey(hKey); }}
BOOL COpenWithList::AddAppToMRUList(SApp *pApp, LPCWSTR pwszFilename){ WCHAR wszBuf[100]; LPCWSTR pwszExt; HKEY hKey; HANDLE hList;
/* Get file extension */ pwszExt = PathFindExtensionW(pwszFilename); if (!pwszExt[0]) return FALSE;
/* Build registry key */ if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s", pwszExt))) { ERR("insufficient buffer\n"); return FALSE; }
/* Open base key for this file extension */ if (RegCreateKeyExW(HKEY_CURRENT_USER, wszBuf, 0, NULL, 0, KEY_WRITE | KEY_READ, NULL, &hKey, NULL) != ERROR_SUCCESS) return FALSE;
/* Open MRU list */ hList = OpenMRUList(hKey); if (hList) { /* Insert the entry */ AddMRUStringW(hList, pApp->wszFilename);
/* Set MRU presence */ pApp->bMRUList = TRUE;
/* Close MRU list */ FreeMRUList(hList); }
RegCloseKey(hKey); return TRUE;}
BOOL COpenWithList::SetDefaultHandler(SApp *pApp, LPCWSTR pwszFilename){ HKEY hKey, hSrcKey, hDestKey; WCHAR wszBuf[256];
TRACE("SetDefaultHandler %ls %ls\n", pApp->wszFilename, pwszFilename);
/* Extract file extension */ LPCWSTR pwszExt = PathFindExtensionW(pwszFilename); if (!pwszExt[0] || !pwszExt[1]) return FALSE;
/* Create file extension key */ if (RegCreateKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) { ERR("Can't open ext key\n"); return FALSE; }
DWORD dwSize = sizeof(wszBuf); LONG lResult = RegGetValueW(hKey, NULL, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize);
if (lResult == ERROR_FILE_NOT_FOUND) { /* A new entry was created or the default key is not set: set the prog key id */ StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s_auto_file", pwszExt + 1); if (RegSetValueExW(hKey, L"", 0, REG_SZ, (const BYTE*)wszBuf, (wcslen(wszBuf) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) { RegCloseKey(hKey); ERR("RegSetValueExW failed\n"); return FALSE; } } else if (lResult != ERROR_SUCCESS) { RegCloseKey(hKey); ERR("RegGetValueExW failed: 0x%08x\n", lResult); return FALSE; }
/* Close file extension key */ RegCloseKey(hKey);
/* Create prog id key */ if (RegCreateKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) { ERR("RegCreateKeyExW failed\n"); return FALSE; }
/* Check if there already verbs existing for that app */ StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s\\shell", pApp->wszFilename); if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hSrcKey) != ERROR_SUCCESS) { ERR("RegOpenKeyExW %ls failed\n", wszBuf); RegCloseKey(hKey); return FALSE; }
/* Open destination key */ if (RegCreateKeyExW(hKey, L"shell", 0, NULL, 0, KEY_WRITE, NULL, &hDestKey, NULL) != ERROR_SUCCESS) { ERR("RegCreateKeyExW failed\n"); RegCloseKey(hSrcKey); RegCloseKey(hKey); return FALSE; }
/* Create "DefaultIcon" key */ HKEY hDefIconKey; if (RegCreateKeyExW(hKey, L"DefaultIcon", 0, NULL, 0, KEY_WRITE, NULL, &hDefIconKey, NULL) == ERROR_SUCCESS) { RegSetString(hDefIconKey, NULL, pApp->wszFilename, REG_EXPAND_SZ); RegCloseKey(hDefIconKey); SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSHNOWAIT, NULL, NULL); }
/* Copy static verbs from Classes\Applications key */ /* FIXME: SHCopyKey does not copy the security attributes of the keys */ /* FIXME: Windows does not actually copy the verb keys */ /* FIXME: Should probably delete any existing DelegateExecute/DropTarget/DDE verb information first */ LSTATUS Result = SHCopyKeyW(hSrcKey, NULL, hDestKey, 0);#ifdef __REACTOS__ // FIXME: When OpenWith is used to set a new default on Windows, the FileExts key // is changed to force this association. ROS does not support this. The best // we can do is to try to set the verb we (incorrectly) copied as the new default. HKEY hAppKey; StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s", pApp->wszFilename); if (Result == ERROR_SUCCESS && !RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hAppKey)) { if (HCR_GetDefaultVerbW(hAppKey, NULL, wszBuf, _countof(wszBuf)) && *wszBuf) RegSetString(hDestKey, NULL, wszBuf, REG_SZ); RegCloseKey(hAppKey); }#endif // __REACTOS__ RegCloseKey(hDestKey); RegCloseKey(hSrcKey); RegCloseKey(hKey);
if (Result != ERROR_SUCCESS) { ERR("SHCopyKeyW failed\n"); return FALSE; }
return TRUE;}
class COpenWithDialog{ public: COpenWithDialog(const OPENASINFO *pInfo, COpenWithList *pAppList); ~COpenWithDialog(); static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL IsNoOpen(HWND hwnd);
private: VOID Init(HWND hwnd); VOID AddApp(COpenWithList::SApp *pApp, BOOL bSelected); VOID Browse(); VOID Accept(); static INT_PTR CALLBACK NoOpenDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam); COpenWithList::SApp *GetCurrentApp();
const OPENASINFO *m_pInfo; COpenWithList *m_pAppList; UINT m_InFlags; BOOL m_bListAllocated; HWND m_hDialog, m_hTreeView; HTREEITEM m_hRecommend; HTREEITEM m_hOther; HIMAGELIST m_hImgList; BOOL m_bNoOpen;};
COpenWithDialog::COpenWithDialog(const OPENASINFO *pInfo, COpenWithList *pAppList = NULL): m_pInfo(pInfo), m_pAppList(pAppList), m_hImgList(NULL), m_bNoOpen(FALSE){ if (!m_pAppList) { m_pAppList = new COpenWithList; m_bListAllocated = TRUE; } else m_bListAllocated = FALSE;}
COpenWithDialog::~COpenWithDialog(){ if (m_bListAllocated && m_pAppList) delete m_pAppList; if (m_hImgList) ImageList_Destroy(m_hImgList);}
INT_PTR CALLBACK COpenWithDialog::NoOpenDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){ switch(Message) { case WM_INITDIALOG: { return TRUE; } case WM_CLOSE: EndDialog(hwnd, IDNO); break; case WM_COMMAND: switch(LOWORD(wParam)) { case IDYES: EndDialog(hwnd, IDYES); break; case IDNO: EndDialog(hwnd, IDNO); break; } break; default: return FALSE; } return TRUE;}
BOOL COpenWithDialog::IsNoOpen(HWND hwnd){ /* Only do the actual check if the file type has the 'NoOpen' flag. */ if (m_bNoOpen) { int dReturnValue = DialogBox(shell32_hInstance, MAKEINTRESOURCE(IDD_NOOPEN), hwnd, NoOpenDlgProc);
if (dReturnValue == IDNO) return TRUE; else if (dReturnValue == -1) { ERR("IsNoOpen failed to load dialog box\n"); return TRUE; } }
return FALSE;}
VOID COpenWithDialog::AddApp(COpenWithList::SApp *pApp, BOOL bSelected){ LPCWSTR pwszName = m_pAppList->GetName(pApp); if (!pwszName) return; HICON hIcon = m_pAppList->GetIcon(pApp);
TRACE("AddApp Cmd %ls Name %ls\n", pApp->wszCmd, pwszName);
/* Add item to the list */ TVINSERTSTRUCT tvins;
if (pApp->bRecommended) tvins.hParent = tvins.hInsertAfter = m_hRecommend; else tvins.hParent = tvins.hInsertAfter = m_hOther;
tvins.item.mask = TVIF_TEXT|TVIF_PARAM; tvins.item.pszText = const_cast<LPWSTR>(pwszName); tvins.item.lParam = (LPARAM)pApp;
if (hIcon) { tvins.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; tvins.item.iImage = tvins.item.iSelectedImage = ImageList_AddIcon(m_hImgList, hIcon); }
HTREEITEM hItem = TreeView_InsertItem(m_hTreeView, &tvins);
if (bSelected) TreeView_SelectItem(m_hTreeView, hItem);}
VOID COpenWithDialog::Browse(){ WCHAR wszTitle[64]; WCHAR wszFilter[256]; WCHAR wszPath[MAX_PATH]; OPENFILENAMEW ofn;
/* Initialize OPENFILENAMEW structure */ ZeroMemory(&ofn, sizeof(OPENFILENAMEW)); ofn.lStructSize = sizeof(OPENFILENAMEW); ofn.hInstance = shell32_hInstance; ofn.hwndOwner = m_hDialog; ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; ofn.nMaxFile = (sizeof(wszPath) / sizeof(WCHAR)); ofn.lpstrFile = wszPath; ofn.lpstrInitialDir = L"%programfiles%";
/* Init title */ if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH, wszTitle, sizeof(wszTitle) / sizeof(WCHAR))) { ofn.lpstrTitle = wszTitle; ofn.nMaxFileTitle = wcslen(wszTitle); }
/* Init the filter string */ if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH_FILTER, wszFilter, sizeof(wszFilter) / sizeof(WCHAR))) ofn.lpstrFilter = wszFilter; ZeroMemory(wszPath, sizeof(wszPath));
/* Create OpenFile dialog */ if (!GetOpenFileNameW(&ofn)) return;
/* Setup context for insert proc */ COpenWithList::SApp *pApp = m_pAppList->Add(wszPath); AddApp(pApp, TRUE);}
COpenWithList::SApp *COpenWithDialog::GetCurrentApp(){ TVITEM tvi; tvi.hItem = TreeView_GetSelection(m_hTreeView); if (!tvi.hItem) return NULL;
tvi.mask = TVIF_PARAM; if (!TreeView_GetItem(m_hTreeView, &tvi)) return NULL;
return (COpenWithList::SApp*)tvi.lParam;}
VOID COpenWithDialog::Init(HWND hwnd){ TRACE("COpenWithDialog::Init hwnd %p\n", hwnd);
m_hDialog = hwnd; SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)this);
UINT fDisallow = 0; PCWSTR pszExt = PathFindExtensionW(m_pInfo->pcszFile); // Don't allow registration for "" nor "." nor ".exe" etc. if (!pszExt || !pszExt[0] || !pszExt[1] || PathIsExeW(m_pInfo->pcszFile)) fDisallow |= OAIF_ALLOW_REGISTRATION | OAIF_FORCE_REGISTRATION; if (SHRestricted(REST_NOFILEASSOCIATE)) fDisallow |= OAIF_ALLOW_REGISTRATION | OAIF_FORCE_REGISTRATION | OAIF_REGISTER_EXT;
/* Handle register checkbox */ m_InFlags = m_pInfo->oaifInFlags & ~fDisallow; HWND hRegisterCheckbox = GetDlgItem(hwnd, 14003); if (!(m_InFlags & OAIF_ALLOW_REGISTRATION)) EnableWindow(hRegisterCheckbox, FALSE); if (m_InFlags & OAIF_FORCE_REGISTRATION) SendMessage(hRegisterCheckbox, BM_SETCHECK, BST_CHECKED, 0); if (m_InFlags & OAIF_HIDE_REGISTRATION) ShowWindow(hRegisterCheckbox, SW_HIDE);
if (m_pInfo->pcszFile) { WCHAR wszBuf[MAX_PATH]; UINT cchBuf;
/* Add filename to label */ cchBuf = GetDlgItemTextW(hwnd, 14001, wszBuf, _countof(wszBuf)); StringCchCopyW(wszBuf + cchBuf, _countof(wszBuf) - cchBuf, PathFindFileNameW(m_pInfo->pcszFile)); SetDlgItemTextW(hwnd, 14001, wszBuf);
/* Load applications from registry */ m_pAppList->Load(); m_pAppList->LoadRecommended(m_pInfo->pcszFile);
/* Determine if the type of file can be opened directly from the shell */ if (m_pAppList->IsNoOpen() != FALSE) m_bNoOpen = TRUE;
/* Init treeview */ m_hTreeView = GetDlgItem(hwnd, 14002); m_hImgList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, m_pAppList->GetCount() + 1, m_pAppList->GetCount() + 1); (void)TreeView_SetImageList(m_hTreeView, m_hImgList, TVSIL_NORMAL);
/* If there are some recommendations add parent nodes: Recommended and Others */ UINT cRecommended = m_pAppList->GetRecommendedCount(); if (cRecommended > 0) { TVINSERTSTRUCT tvins; HICON hFolderIcon;
tvins.hParent = tvins.hInsertAfter = TVI_ROOT; tvins.item.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; tvins.item.pszText = (LPWSTR)wszBuf; tvins.item.state = tvins.item.stateMask = TVIS_EXPANDED; hFolderIcon = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_PROGRAMS_FOLDER), IMAGE_ICON, 0, 0, 0); tvins.item.iImage = tvins.item.iSelectedImage = ImageList_AddIcon(m_hImgList, hFolderIcon);
LoadStringW(shell32_hInstance, IDS_OPEN_WITH_RECOMMENDED, wszBuf, _countof(wszBuf)); m_hRecommend = TreeView_InsertItem(m_hTreeView, &tvins);
LoadStringW(shell32_hInstance, IDS_OPEN_WITH_OTHER, wszBuf, _countof(wszBuf)); m_hOther = TreeView_InsertItem(m_hTreeView, &tvins); } else m_hRecommend = m_hOther = TVI_ROOT;
/* Add all applications */ BOOL bNoAppSelected = TRUE; COpenWithList::SApp *pAppList = m_pAppList->GetList(); for (UINT i = 0; i < m_pAppList->GetCount(); ++i) { if (!COpenWithList::IsHidden(&pAppList[i])) { if (bNoAppSelected && (pAppList[i].bRecommended || !cRecommended)) { AddApp(&pAppList[i], TRUE); bNoAppSelected = FALSE; } else AddApp(&pAppList[i], FALSE); } } }}
VOID COpenWithDialog::Accept(){ COpenWithList::SApp *pApp = GetCurrentApp(); if (pApp) { /* Set programm as default handler */ if (IsDlgButtonChecked(m_hDialog, 14003) == BST_CHECKED && (m_InFlags & OAIF_REGISTER_EXT)) m_pAppList->SetDefaultHandler(pApp, m_pInfo->pcszFile);
/* Execute program */ if (m_InFlags & OAIF_EXEC) m_pAppList->Execute(pApp, m_pInfo->pcszFile);
EndDialog(m_hDialog, 1); }}
INT_PTR CALLBACK COpenWithDialog::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam){ COpenWithDialog *pThis = reinterpret_cast<COpenWithDialog *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
switch(uMsg) { case WM_INITDIALOG: { COpenWithDialog *pThis = reinterpret_cast<COpenWithDialog *>(lParam);
pThis->Init(hwndDlg); return TRUE; } case WM_COMMAND: switch(LOWORD(wParam)) { case 14004: /* browse */ { pThis->Browse(); return TRUE; } case IDOK: /* ok */ { pThis->Accept(); return TRUE; } case IDCANCEL: /* cancel */ EndDialog(hwndDlg, 0); return TRUE; default: break; } break; case WM_NOTIFY: switch (((LPNMHDR)lParam)->code) { case TVN_SELCHANGED: EnableWindow(GetDlgItem(hwndDlg, IDOK), pThis->GetCurrentApp() ? TRUE : FALSE); break; case NM_DBLCLK: case NM_RETURN: pThis->Accept(); break; } break; case WM_CLOSE: EndDialog(hwndDlg, 0); return TRUE; default: break; } return FALSE;}
COpenWithMenu::COpenWithMenu(){ m_idCmdFirst = 0; m_idCmdLast = 0; m_pAppList = new COpenWithList;}
COpenWithMenu::~COpenWithMenu(){ TRACE("Destroying COpenWithMenu(%p)\n", this);
if (m_hSubMenu) { INT Count, Index; MENUITEMINFOW mii;
/* get item count */ Count = GetMenuItemCount(m_hSubMenu); if (Count == -1) return;
/* setup menuitem info */ ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_DATA | MIIM_FTYPE | MIIM_CHECKMARKS;
for(Index = 0; Index < Count; Index++) { if (GetMenuItemInfoW(m_hSubMenu, Index, TRUE, &mii)) { if (mii.hbmpChecked) DeleteObject(mii.hbmpChecked); } } }
if (m_pAppList) delete m_pAppList;}
HBITMAP COpenWithMenu::IconToBitmap(HICON hIcon){ HDC hdc, hdcScr; HBITMAP hbm, hbmOld; RECT rc;
hdcScr = GetDC(NULL); hdc = CreateCompatibleDC(hdcScr); SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK)); hbm = CreateCompatibleBitmap(hdcScr, rc.right, rc.bottom); ReleaseDC(NULL, hdcScr);
hbmOld = (HBITMAP)SelectObject(hdc, hbm); FillRect(hdc, &rc, (HBRUSH)(COLOR_MENU + 1)); if (!DrawIconEx(hdc, 0, 0, hIcon, rc.right, rc.bottom, 0, NULL, DI_NORMAL)) ERR("DrawIcon failed: %x\n", GetLastError()); SelectObject(hdc, hbmOld);
DeleteDC(hdc);
return hbm;}
VOID COpenWithMenu::AddChooseProgramItem(){ MENUITEMINFOW mii; WCHAR wszBuf[128];
ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE | MIIM_ID; mii.fType = MFT_SEPARATOR; mii.wID = -1; InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii);
if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH_CHOOSE, wszBuf, _countof(wszBuf))) { ERR("Failed to load string\n"); return; }
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.wID = m_idCmdLast; mii.dwTypeData = (LPWSTR)wszBuf; mii.cch = wcslen(wszBuf);
InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii);}
VOID COpenWithMenu::AddApp(PVOID pApp){ MENUITEMINFOW mii; LPCWSTR pwszName = m_pAppList->GetName((COpenWithList::SApp*)pApp); if (!pwszName) return;
ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; mii.wID = m_idCmdLast; mii.dwTypeData = const_cast<LPWSTR>(pwszName); mii.dwItemData = (ULONG_PTR)pApp;
HICON hIcon = m_pAppList->GetIcon((COpenWithList::SApp*)pApp); if (hIcon) { mii.fMask |= MIIM_CHECKMARKS; mii.hbmpChecked = mii.hbmpUnchecked = IconToBitmap(hIcon); }
if (InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii)) m_idCmdLast++;}
static const CMVERBMAP g_VerbMap[] ={ { "openas", 0 }, { NULL }};
HRESULT WINAPI COpenWithMenu::QueryContextMenu( HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags){ TRACE("hMenu %p indexMenu %u idFirst %u idLast %u uFlags %u\n", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
INT DefaultPos = GetMenuDefaultItem(hMenu, TRUE, 0);
WCHAR wszName[100]; UINT NameId = (DefaultPos == -1 ? IDS_OPEN : IDS_OPEN_WITH); if (!LoadStringW(shell32_hInstance, NameId, wszName, _countof(wszName))) { ERR("Failed to load string\n"); return E_FAIL; }
/* Init first cmd id and submenu */ m_idCmdFirst = m_idCmdLast = idCmdFirst; m_hSubMenu = NULL;
/* We can only be a submenu if we are not the default */ if (DefaultPos != -1) { /* Load applications list */ m_pAppList->Load(); m_pAppList->LoadRecommended(m_wszPath);
/* Create submenu only if there is more than one application and menu has a default item */ if (m_pAppList->GetRecommendedCount() > 1) { m_hSubMenu = CreatePopupMenu();
for(UINT i = 0; i < m_pAppList->GetCount(); ++i) { COpenWithList::SApp *pApp = m_pAppList->GetList() + i; if (pApp->bRecommended) AddApp(pApp); }
AddChooseProgramItem(); } }
/* Insert menu item */ MENUITEMINFOW mii; ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; if (m_hSubMenu) { mii.fMask |= MIIM_SUBMENU; mii.hSubMenu = m_hSubMenu; mii.wID = -1; } else mii.wID = m_idCmdLast;
mii.fType = MFT_STRING; mii.dwTypeData = (LPWSTR)wszName; mii.fState = MFS_ENABLED; if (DefaultPos == -1) { mii.fState |= MFS_DEFAULT; indexMenu = 0; }
if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii)) return E_FAIL;
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, m_idCmdLast - m_idCmdFirst + 1);}
HRESULT WINAPICOpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici){ const SIZE_T idChooseApp = m_idCmdLast; HRESULT hr = E_FAIL;
TRACE("This %p idFirst %u idLast %u idCmd %u\n", this, m_idCmdFirst, m_idCmdLast, m_idCmdFirst + LOWORD(lpici->lpVerb));
if (!IS_INTRESOURCE(lpici->lpVerb) && SHELL_MapContextMenuVerbToCmdId(lpici, g_VerbMap) == 0) goto DoChooseApp;
if (IS_INTRESOURCE(lpici->lpVerb) && m_idCmdFirst + LOWORD(lpici->lpVerb) <= m_idCmdLast) { if (m_idCmdFirst + LOWORD(lpici->lpVerb) == idChooseApp) {DoChooseApp: hr = SH32_InvokeOpenWith(m_wszPath, lpici, NULL); } else { /* retrieve menu item info */ MENUITEMINFOW mii; ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_DATA | MIIM_FTYPE;
if (GetMenuItemInfoW(m_hSubMenu, LOWORD(lpici->lpVerb), TRUE, &mii) && mii.dwItemData) { /* launch item with specified app */ COpenWithList::SApp *pApp = (COpenWithList::SApp*)mii.dwItemData; COpenWithList::Execute(pApp, m_wszPath); hr = S_OK; } } }
return hr;}
HRESULT WINAPICOpenWithMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax ){ TRACE("%p %lu %u %p %p %u\n", this, idCmd, uType, pwReserved, pszName, cchMax );
const SIZE_T idChooseApp = m_idCmdLast; if (m_idCmdFirst + idCmd == idChooseApp) return SHELL_GetCommandStringImpl(0, uType, pszName, cchMax, g_VerbMap);
return E_NOTIMPL;}
HRESULT WINAPI COpenWithMenu::HandleMenuMsg( UINT uMsg, WPARAM wParam, LPARAM lParam){ TRACE("This %p uMsg %x\n", this, uMsg);
return E_NOTIMPL;}
HRESULT WINAPICOpenWithMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID){ LPCITEMIDLIST pidlFolder2; LPCITEMIDLIST pidlChild;
TRACE("This %p\n", this);
if (pdtobj == NULL) return E_INVALIDARG;
CDataObjectHIDA pida(pdtobj); if (FAILED(pida.hr())) { ERR("pdtobj->GetData failed with 0x%x\n", pida.hr()); return pida.hr(); }
ASSERT(pida->cidl >= 1);
pidlFolder2 = HIDA_GetPIDLFolder(pida); pidlChild = HIDA_GetPIDLItem(pida, 0);
if (!_ILIsValue(pidlChild)) { TRACE("pidl is not a file\n"); return E_FAIL; }
CComHeapPtr<ITEMIDLIST> pidl(ILCombine(pidlFolder2, pidlChild)); if (!pidl) { ERR("no mem\n"); return E_OUTOFMEMORY; }
if (!SHGetPathFromIDListW(pidl, m_wszPath)) { ERR("SHGetPathFromIDListW failed\n"); return E_FAIL; }
TRACE("szPath %s\n", debugstr_w(m_wszPath));
LPCWSTR pwszExt = PathFindExtensionW(m_wszPath); if (PathIsExeW(pwszExt) || !_wcsicmp(pwszExt, L".lnk")) { TRACE("file is a executable or shortcut\n"); return E_FAIL; }
return S_OK;}
HRESULT WINAPISHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo){ INT_PTR ret;
TRACE("SHOpenWithDialog hwndParent %p poainfo %p\n", hwndParent, poainfo);
InitCommonControls();
if (poainfo->pcszClass == NULL && poainfo->pcszFile == NULL) return E_FAIL;
COpenWithDialog pDialog(poainfo);
if (pDialog.IsNoOpen(hwndParent)) return S_OK;
ret = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCE(IDD_OPEN_WITH), hwndParent, COpenWithDialog::DialogProc, (LPARAM)&pDialog);
if (ret == (INT_PTR)-1) { ERR("Failed to create dialog: %u\n", GetLastError()); return E_FAIL; }
return S_OK;}