1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/uriloader/exthandler/win/nsMIMEInfoWin.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,884 @@ 1.4 +/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsArrayEnumerator.h" 1.11 +#include "nsCOMArray.h" 1.12 +#include "nsIFile.h" 1.13 +#include "nsIVariant.h" 1.14 +#include "nsMIMEInfoWin.h" 1.15 +#include "nsNetUtil.h" 1.16 +#include <windows.h> 1.17 +#include <shellapi.h> 1.18 +#include "nsAutoPtr.h" 1.19 +#include "nsIMutableArray.h" 1.20 +#include "nsTArray.h" 1.21 +#include "shlobj.h" 1.22 +#include "windows.h" 1.23 +#include "nsIWindowsRegKey.h" 1.24 +#include "nsIProcess.h" 1.25 +#include "nsOSHelperAppService.h" 1.26 +#include "nsUnicharUtils.h" 1.27 +#include "nsITextToSubURI.h" 1.28 + 1.29 +#define RUNDLL32_EXE L"\\rundll32.exe" 1.30 + 1.31 + 1.32 +NS_IMPL_ISUPPORTS_INHERITED(nsMIMEInfoWin, nsMIMEInfoBase, nsIPropertyBag) 1.33 + 1.34 +nsMIMEInfoWin::~nsMIMEInfoWin() 1.35 +{ 1.36 +} 1.37 + 1.38 +nsresult 1.39 +nsMIMEInfoWin::LaunchDefaultWithFile(nsIFile* aFile) 1.40 +{ 1.41 + // Launch the file, unless it is an executable. 1.42 + bool executable = true; 1.43 + aFile->IsExecutable(&executable); 1.44 + if (executable) 1.45 + return NS_ERROR_FAILURE; 1.46 + 1.47 + return aFile->Launch(); 1.48 +} 1.49 + 1.50 +NS_IMETHODIMP 1.51 +nsMIMEInfoWin::LaunchWithFile(nsIFile* aFile) 1.52 +{ 1.53 + nsresult rv; 1.54 + 1.55 + // it doesn't make any sense to call this on protocol handlers 1.56 + NS_ASSERTION(mClass == eMIMEInfo, 1.57 + "nsMIMEInfoBase should have mClass == eMIMEInfo"); 1.58 + 1.59 + if (mPreferredAction == useSystemDefault) { 1.60 + return LaunchDefaultWithFile(aFile); 1.61 + } 1.62 + 1.63 + if (mPreferredAction == useHelperApp) { 1.64 + if (!mPreferredApplication) 1.65 + return NS_ERROR_FILE_NOT_FOUND; 1.66 + 1.67 + // at the moment, we only know how to hand files off to local handlers 1.68 + nsCOMPtr<nsILocalHandlerApp> localHandler = 1.69 + do_QueryInterface(mPreferredApplication, &rv); 1.70 + NS_ENSURE_SUCCESS(rv, rv); 1.71 + 1.72 + nsCOMPtr<nsIFile> executable; 1.73 + rv = localHandler->GetExecutable(getter_AddRefs(executable)); 1.74 + NS_ENSURE_SUCCESS(rv, rv); 1.75 + 1.76 + nsAutoString path; 1.77 + aFile->GetPath(path); 1.78 + 1.79 + // Deal with local dll based handlers 1.80 + nsCString filename; 1.81 + executable->GetNativeLeafName(filename); 1.82 + if (filename.Length() > 4) { 1.83 + nsCString extension(Substring(filename, filename.Length() - 4, 4)); 1.84 + 1.85 + if (extension.LowerCaseEqualsLiteral(".dll")) { 1.86 + nsAutoString args; 1.87 + 1.88 + // executable is rundll32, everything else is a list of parameters, 1.89 + // including the dll handler. 1.90 + if (!GetDllLaunchInfo(executable, aFile, args, false)) 1.91 + return NS_ERROR_INVALID_ARG; 1.92 + 1.93 + WCHAR rundll32Path[MAX_PATH + sizeof(RUNDLL32_EXE) / sizeof(WCHAR) + 1] = {L'\0'}; 1.94 + if (!GetSystemDirectoryW(rundll32Path, MAX_PATH)) { 1.95 + return NS_ERROR_FILE_NOT_FOUND; 1.96 + } 1.97 + lstrcatW(rundll32Path, RUNDLL32_EXE); 1.98 + 1.99 + SHELLEXECUTEINFOW seinfo; 1.100 + memset(&seinfo, 0, sizeof(seinfo)); 1.101 + seinfo.cbSize = sizeof(SHELLEXECUTEINFOW); 1.102 + seinfo.fMask = 0; 1.103 + seinfo.hwnd = nullptr; 1.104 + seinfo.lpVerb = nullptr; 1.105 + seinfo.lpFile = rundll32Path; 1.106 + seinfo.lpParameters = args.get(); 1.107 + seinfo.lpDirectory = nullptr; 1.108 + seinfo.nShow = SW_SHOWNORMAL; 1.109 + if (ShellExecuteExW(&seinfo)) 1.110 + return NS_OK; 1.111 + 1.112 + switch ((LONG_PTR)seinfo.hInstApp) { 1.113 + case 0: 1.114 + case SE_ERR_OOM: 1.115 + return NS_ERROR_OUT_OF_MEMORY; 1.116 + case SE_ERR_ACCESSDENIED: 1.117 + return NS_ERROR_FILE_ACCESS_DENIED; 1.118 + case SE_ERR_ASSOCINCOMPLETE: 1.119 + case SE_ERR_NOASSOC: 1.120 + return NS_ERROR_UNEXPECTED; 1.121 + case SE_ERR_DDEBUSY: 1.122 + case SE_ERR_DDEFAIL: 1.123 + case SE_ERR_DDETIMEOUT: 1.124 + return NS_ERROR_NOT_AVAILABLE; 1.125 + case SE_ERR_DLLNOTFOUND: 1.126 + return NS_ERROR_FAILURE; 1.127 + case SE_ERR_SHARE: 1.128 + return NS_ERROR_FILE_IS_LOCKED; 1.129 + default: 1.130 + switch(GetLastError()) { 1.131 + case ERROR_FILE_NOT_FOUND: 1.132 + return NS_ERROR_FILE_NOT_FOUND; 1.133 + case ERROR_PATH_NOT_FOUND: 1.134 + return NS_ERROR_FILE_UNRECOGNIZED_PATH; 1.135 + case ERROR_BAD_FORMAT: 1.136 + return NS_ERROR_FILE_CORRUPTED; 1.137 + } 1.138 + 1.139 + } 1.140 + return NS_ERROR_FILE_EXECUTION_FAILED; 1.141 + } 1.142 + } 1.143 + return LaunchWithIProcess(executable, path); 1.144 + } 1.145 + 1.146 + return NS_ERROR_INVALID_ARG; 1.147 +} 1.148 + 1.149 +NS_IMETHODIMP 1.150 +nsMIMEInfoWin::GetHasDefaultHandler(bool * _retval) 1.151 +{ 1.152 + // We have a default application if we have a description 1.153 + // We can ShellExecute anything; however, callers are probably interested if 1.154 + // there is really an application associated with this type of file 1.155 + *_retval = !mDefaultAppDescription.IsEmpty(); 1.156 + return NS_OK; 1.157 +} 1.158 + 1.159 +NS_IMETHODIMP 1.160 +nsMIMEInfoWin::GetEnumerator(nsISimpleEnumerator* *_retval) 1.161 +{ 1.162 + nsCOMArray<nsIVariant> properties; 1.163 + 1.164 + nsCOMPtr<nsIVariant> variant; 1.165 + GetProperty(NS_LITERAL_STRING("defaultApplicationIconURL"), getter_AddRefs(variant)); 1.166 + if (variant) 1.167 + properties.AppendObject(variant); 1.168 + 1.169 + GetProperty(NS_LITERAL_STRING("customApplicationIconURL"), getter_AddRefs(variant)); 1.170 + if (variant) 1.171 + properties.AppendObject(variant); 1.172 + 1.173 + return NS_NewArrayEnumerator(_retval, properties); 1.174 +} 1.175 + 1.176 +static nsresult GetIconURLVariant(nsIFile* aApplication, nsIVariant* *_retval) 1.177 +{ 1.178 + nsresult rv = CallCreateInstance("@mozilla.org/variant;1", _retval); 1.179 + if (NS_FAILED(rv)) 1.180 + return rv; 1.181 + nsAutoCString fileURLSpec; 1.182 + NS_GetURLSpecFromFile(aApplication, fileURLSpec); 1.183 + nsAutoCString iconURLSpec; iconURLSpec.AssignLiteral("moz-icon://"); 1.184 + iconURLSpec += fileURLSpec; 1.185 + nsCOMPtr<nsIWritableVariant> writable(do_QueryInterface(*_retval)); 1.186 + writable->SetAsAUTF8String(iconURLSpec); 1.187 + return NS_OK; 1.188 +} 1.189 + 1.190 +NS_IMETHODIMP 1.191 +nsMIMEInfoWin::GetProperty(const nsAString& aName, nsIVariant* *_retval) 1.192 +{ 1.193 + nsresult rv; 1.194 + if (mDefaultApplication && aName.EqualsLiteral(PROPERTY_DEFAULT_APP_ICON_URL)) { 1.195 + rv = GetIconURLVariant(mDefaultApplication, _retval); 1.196 + NS_ENSURE_SUCCESS(rv, rv); 1.197 + } else if (mPreferredApplication && 1.198 + aName.EqualsLiteral(PROPERTY_CUSTOM_APP_ICON_URL)) { 1.199 + nsCOMPtr<nsILocalHandlerApp> localHandler = 1.200 + do_QueryInterface(mPreferredApplication, &rv); 1.201 + NS_ENSURE_SUCCESS(rv, rv); 1.202 + 1.203 + nsCOMPtr<nsIFile> executable; 1.204 + rv = localHandler->GetExecutable(getter_AddRefs(executable)); 1.205 + NS_ENSURE_SUCCESS(rv, rv); 1.206 + 1.207 + rv = GetIconURLVariant(executable, _retval); 1.208 + NS_ENSURE_SUCCESS(rv, rv); 1.209 + } 1.210 + 1.211 + return NS_OK; 1.212 +} 1.213 + 1.214 +// this implementation was pretty much copied verbatime from 1.215 +// Tony Robinson's code in nsExternalProtocolWin.cpp 1.216 +nsresult 1.217 +nsMIMEInfoWin::LoadUriInternal(nsIURI * aURL) 1.218 +{ 1.219 + nsresult rv = NS_OK; 1.220 + 1.221 + // 1. Find the default app for this protocol 1.222 + // 2. Set up the command line 1.223 + // 3. Launch the app. 1.224 + 1.225 + // For now, we'll just cheat essentially, check for the command line 1.226 + // then just call ShellExecute()! 1.227 + 1.228 + if (aURL) 1.229 + { 1.230 + // extract the url spec from the url 1.231 + nsAutoCString urlSpec; 1.232 + aURL->GetAsciiSpec(urlSpec); 1.233 + 1.234 + // Unescape non-ASCII characters in the URL 1.235 + nsAutoCString urlCharset; 1.236 + nsAutoString utf16Spec; 1.237 + rv = aURL->GetOriginCharset(urlCharset); 1.238 + NS_ENSURE_SUCCESS(rv, rv); 1.239 + 1.240 + nsCOMPtr<nsITextToSubURI> textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); 1.241 + NS_ENSURE_SUCCESS(rv, rv); 1.242 + 1.243 + rv = textToSubURI->UnEscapeNonAsciiURI(urlCharset, urlSpec, utf16Spec); 1.244 + NS_ENSURE_SUCCESS(rv, rv); 1.245 + 1.246 + static const wchar_t cmdVerb[] = L"open"; 1.247 + SHELLEXECUTEINFOW sinfo; 1.248 + memset(&sinfo, 0, sizeof(sinfo)); 1.249 + sinfo.cbSize = sizeof(sinfo); 1.250 + sinfo.fMask = SEE_MASK_FLAG_DDEWAIT | 1.251 + SEE_MASK_FLAG_NO_UI; 1.252 + sinfo.hwnd = nullptr; 1.253 + sinfo.lpVerb = (LPWSTR)&cmdVerb; 1.254 + sinfo.nShow = SW_SHOWNORMAL; 1.255 + 1.256 + LPITEMIDLIST pidl = nullptr; 1.257 + SFGAOF sfgao; 1.258 + 1.259 + // Bug 394974 1.260 + if (SUCCEEDED(SHParseDisplayName(utf16Spec.get(), nullptr, 1.261 + &pidl, 0, &sfgao))) { 1.262 + sinfo.lpIDList = pidl; 1.263 + sinfo.fMask |= SEE_MASK_INVOKEIDLIST; 1.264 + } else { 1.265 + // SHParseDisplayName failed. Bailing out as work around for 1.266 + // Microsoft Security Bulletin MS07-061 1.267 + rv = NS_ERROR_FAILURE; 1.268 + } 1.269 + if (NS_SUCCEEDED(rv)) { 1.270 + BOOL result = ShellExecuteExW(&sinfo); 1.271 + if (!result || ((LONG_PTR)sinfo.hInstApp) < 32) 1.272 + rv = NS_ERROR_FAILURE; 1.273 + } 1.274 + if (pidl) 1.275 + CoTaskMemFree(pidl); 1.276 + } 1.277 + 1.278 + return rv; 1.279 +} 1.280 + 1.281 +// Given a path to a local file, return its nsILocalHandlerApp instance. 1.282 +bool nsMIMEInfoWin::GetLocalHandlerApp(const nsAString& aCommandHandler, 1.283 + nsCOMPtr<nsILocalHandlerApp>& aApp) 1.284 +{ 1.285 + nsCOMPtr<nsIFile> locfile; 1.286 + nsresult rv = 1.287 + NS_NewLocalFile(aCommandHandler, true, getter_AddRefs(locfile)); 1.288 + if (NS_FAILED(rv)) 1.289 + return false; 1.290 + 1.291 + aApp = do_CreateInstance("@mozilla.org/uriloader/local-handler-app;1"); 1.292 + if (!aApp) 1.293 + return false; 1.294 + 1.295 + aApp->SetExecutable(locfile); 1.296 + return true; 1.297 +} 1.298 + 1.299 +// Return the cleaned up file path associated with a command verb 1.300 +// located in root/Applications. 1.301 +bool nsMIMEInfoWin::GetAppsVerbCommandHandler(const nsAString& appExeName, 1.302 + nsAString& applicationPath, 1.303 + bool edit) 1.304 +{ 1.305 + nsCOMPtr<nsIWindowsRegKey> appKey = 1.306 + do_CreateInstance("@mozilla.org/windows-registry-key;1"); 1.307 + if (!appKey) 1.308 + return false; 1.309 + 1.310 + // HKEY_CLASSES_ROOT\Applications\iexplore.exe 1.311 + nsAutoString applicationsPath; 1.312 + applicationsPath.AppendLiteral("Applications\\"); 1.313 + applicationsPath.Append(appExeName); 1.314 + 1.315 + nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.316 + applicationsPath, 1.317 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.318 + if (NS_FAILED(rv)) 1.319 + return false; 1.320 + 1.321 + // Check for the NoOpenWith flag, if it exists 1.322 + uint32_t value; 1.323 + if (NS_SUCCEEDED(appKey->ReadIntValue( 1.324 + NS_LITERAL_STRING("NoOpenWith"), &value)) && 1.325 + value == 1) 1.326 + return false; 1.327 + 1.328 + nsAutoString dummy; 1.329 + if (NS_SUCCEEDED(appKey->ReadStringValue( 1.330 + NS_LITERAL_STRING("NoOpenWith"), dummy))) 1.331 + return false; 1.332 + 1.333 + appKey->Close(); 1.334 + 1.335 + // HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command 1.336 + applicationsPath.AssignLiteral("Applications\\"); 1.337 + applicationsPath.Append(appExeName); 1.338 + if (!edit) 1.339 + applicationsPath.AppendLiteral("\\shell\\open\\command"); 1.340 + else 1.341 + applicationsPath.AppendLiteral("\\shell\\edit\\command"); 1.342 + 1.343 + 1.344 + rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.345 + applicationsPath, 1.346 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.347 + if (NS_FAILED(rv)) 1.348 + return false; 1.349 + 1.350 + nsAutoString appFilesystemCommand; 1.351 + if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(), 1.352 + appFilesystemCommand))) { 1.353 + 1.354 + // Expand environment vars, clean up any misc. 1.355 + if (!nsOSHelperAppService::CleanupCmdHandlerPath(appFilesystemCommand)) 1.356 + return false; 1.357 + 1.358 + applicationPath = appFilesystemCommand; 1.359 + return true; 1.360 + } 1.361 + return false; 1.362 +} 1.363 + 1.364 +// Return a fully populated command string based on 1.365 +// passing information. Used in launchWithFile to trace 1.366 +// back to the full handler path based on the dll. 1.367 +// (dll, targetfile, return args, open/edit) 1.368 +bool nsMIMEInfoWin::GetDllLaunchInfo(nsIFile * aDll, 1.369 + nsIFile * aFile, 1.370 + nsAString& args, 1.371 + bool edit) 1.372 +{ 1.373 + if (!aDll || !aFile) 1.374 + return false; 1.375 + 1.376 + nsString appExeName; 1.377 + aDll->GetLeafName(appExeName); 1.378 + 1.379 + nsCOMPtr<nsIWindowsRegKey> appKey = 1.380 + do_CreateInstance("@mozilla.org/windows-registry-key;1"); 1.381 + if (!appKey) 1.382 + return false; 1.383 + 1.384 + // HKEY_CLASSES_ROOT\Applications\iexplore.exe 1.385 + nsAutoString applicationsPath; 1.386 + applicationsPath.AppendLiteral("Applications\\"); 1.387 + applicationsPath.Append(appExeName); 1.388 + 1.389 + nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.390 + applicationsPath, 1.391 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.392 + if (NS_FAILED(rv)) 1.393 + return false; 1.394 + 1.395 + // Check for the NoOpenWith flag, if it exists 1.396 + uint32_t value; 1.397 + rv = appKey->ReadIntValue(NS_LITERAL_STRING("NoOpenWith"), &value); 1.398 + if (NS_SUCCEEDED(rv) && value == 1) 1.399 + return false; 1.400 + 1.401 + nsAutoString dummy; 1.402 + if (NS_SUCCEEDED(appKey->ReadStringValue(NS_LITERAL_STRING("NoOpenWith"), 1.403 + dummy))) 1.404 + return false; 1.405 + 1.406 + appKey->Close(); 1.407 + 1.408 + // HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command 1.409 + applicationsPath.AssignLiteral("Applications\\"); 1.410 + applicationsPath.Append(appExeName); 1.411 + if (!edit) 1.412 + applicationsPath.AppendLiteral("\\shell\\open\\command"); 1.413 + else 1.414 + applicationsPath.AppendLiteral("\\shell\\edit\\command"); 1.415 + 1.416 + rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.417 + applicationsPath, 1.418 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.419 + if (NS_FAILED(rv)) 1.420 + return false; 1.421 + 1.422 + nsAutoString appFilesystemCommand; 1.423 + if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(), 1.424 + appFilesystemCommand))) { 1.425 + // Replace embedded environment variables. 1.426 + uint32_t bufLength = 1.427 + ::ExpandEnvironmentStringsW(appFilesystemCommand.get(), 1.428 + L"", 0); 1.429 + if (bufLength == 0) // Error 1.430 + return false; 1.431 + 1.432 + nsAutoArrayPtr<wchar_t> destination(new wchar_t[bufLength]); 1.433 + if (!destination) 1.434 + return false; 1.435 + if (!::ExpandEnvironmentStringsW(appFilesystemCommand.get(), 1.436 + destination, 1.437 + bufLength)) 1.438 + return false; 1.439 + 1.440 + appFilesystemCommand = static_cast<const wchar_t*>(destination); 1.441 + 1.442 + // C:\Windows\System32\rundll32.exe "C:\Program Files\Windows 1.443 + // Photo Gallery\PhotoViewer.dll", ImageView_Fullscreen %1 1.444 + nsAutoString params; 1.445 + NS_NAMED_LITERAL_STRING(rundllSegment, "rundll32.exe "); 1.446 + int32_t index = appFilesystemCommand.Find(rundllSegment); 1.447 + if (index > kNotFound) { 1.448 + params.Append(Substring(appFilesystemCommand, 1.449 + index + rundllSegment.Length())); 1.450 + } else { 1.451 + params.Append(appFilesystemCommand); 1.452 + } 1.453 + 1.454 + // check to make sure we have a %1 and fill it 1.455 + NS_NAMED_LITERAL_STRING(percentOneParam, "%1"); 1.456 + index = params.Find(percentOneParam); 1.457 + if (index == kNotFound) // no parameter 1.458 + return false; 1.459 + 1.460 + nsString target; 1.461 + aFile->GetTarget(target); 1.462 + params.Replace(index, 2, target); 1.463 + 1.464 + args = params; 1.465 + 1.466 + return true; 1.467 + } 1.468 + return false; 1.469 +} 1.470 + 1.471 +// Return the cleaned up file path associated with a progid command 1.472 +// verb located in root. 1.473 +bool nsMIMEInfoWin::GetProgIDVerbCommandHandler(const nsAString& appProgIDName, 1.474 + nsAString& applicationPath, 1.475 + bool edit) 1.476 +{ 1.477 + nsCOMPtr<nsIWindowsRegKey> appKey = 1.478 + do_CreateInstance("@mozilla.org/windows-registry-key;1"); 1.479 + if (!appKey) 1.480 + return false; 1.481 + 1.482 + nsAutoString appProgId(appProgIDName); 1.483 + 1.484 + // HKEY_CLASSES_ROOT\Windows.XPSReachViewer\shell\open\command 1.485 + if (!edit) 1.486 + appProgId.AppendLiteral("\\shell\\open\\command"); 1.487 + else 1.488 + appProgId.AppendLiteral("\\shell\\edit\\command"); 1.489 + 1.490 + nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.491 + appProgId, 1.492 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.493 + if (NS_FAILED(rv)) 1.494 + return false; 1.495 + 1.496 + nsAutoString appFilesystemCommand; 1.497 + if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(), appFilesystemCommand))) { 1.498 + 1.499 + // Expand environment vars, clean up any misc. 1.500 + if (!nsOSHelperAppService::CleanupCmdHandlerPath(appFilesystemCommand)) 1.501 + return false; 1.502 + 1.503 + applicationPath = appFilesystemCommand; 1.504 + return true; 1.505 + } 1.506 + return false; 1.507 +} 1.508 + 1.509 +// Helper routine used in tracking app lists. Converts path 1.510 +// entries to lower case and stores them in the trackList array. 1.511 +void nsMIMEInfoWin::ProcessPath(nsCOMPtr<nsIMutableArray>& appList, 1.512 + nsTArray<nsString>& trackList, 1.513 + const nsAString& appFilesystemCommand) 1.514 +{ 1.515 + nsAutoString lower(appFilesystemCommand); 1.516 + ToLowerCase(lower); 1.517 + 1.518 + // Don't include firefox.exe in the list 1.519 + WCHAR exe[MAX_PATH+1]; 1.520 + uint32_t len = GetModuleFileNameW(nullptr, exe, MAX_PATH); 1.521 + if (len < MAX_PATH && len != 0) { 1.522 + uint32_t index = lower.Find(exe); 1.523 + if (index != -1) 1.524 + return; 1.525 + } 1.526 + 1.527 + nsCOMPtr<nsILocalHandlerApp> aApp; 1.528 + if (!GetLocalHandlerApp(appFilesystemCommand, aApp)) 1.529 + return; 1.530 + 1.531 + // Save in our main tracking arrays 1.532 + appList->AppendElement(aApp, false); 1.533 + trackList.AppendElement(lower); 1.534 +} 1.535 + 1.536 +// Helper routine that handles a compare between a path 1.537 +// and an array of paths. 1.538 +static bool IsPathInList(nsAString& appPath, 1.539 + nsTArray<nsString>& trackList) 1.540 +{ 1.541 + // trackList data is always lowercase, see ProcessPath 1.542 + // above. 1.543 + nsAutoString tmp(appPath); 1.544 + ToLowerCase(tmp); 1.545 + 1.546 + for (uint32_t i = 0; i < trackList.Length(); i++) { 1.547 + if (tmp.Equals(trackList[i])) 1.548 + return true; 1.549 + } 1.550 + return false; 1.551 +} 1.552 + 1.553 +/** 1.554 + * Returns a list of nsILocalHandlerApp objects containing local 1.555 + * handlers associated with this mimeinfo. Implemented per 1.556 + * platform using information in this object to generate the 1.557 + * best list. Typically used for an "open with" style user 1.558 + * option. 1.559 + * 1.560 + * @return nsIArray of nsILocalHandlerApp 1.561 + */ 1.562 +NS_IMETHODIMP 1.563 +nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray **_retval) 1.564 +{ 1.565 + nsresult rv; 1.566 + 1.567 + *_retval = nullptr; 1.568 + 1.569 + nsCOMPtr<nsIMutableArray> appList = 1.570 + do_CreateInstance("@mozilla.org/array;1"); 1.571 + 1.572 + if (!appList) 1.573 + return NS_ERROR_FAILURE; 1.574 + 1.575 + nsTArray<nsString> trackList; 1.576 + 1.577 + nsAutoCString fileExt; 1.578 + GetPrimaryExtension(fileExt); 1.579 + 1.580 + nsCOMPtr<nsIWindowsRegKey> regKey = 1.581 + do_CreateInstance("@mozilla.org/windows-registry-key;1"); 1.582 + if (!regKey) 1.583 + return NS_ERROR_FAILURE; 1.584 + nsCOMPtr<nsIWindowsRegKey> appKey = 1.585 + do_CreateInstance("@mozilla.org/windows-registry-key;1"); 1.586 + if (!appKey) 1.587 + return NS_ERROR_FAILURE; 1.588 + 1.589 + nsAutoString workingRegistryPath; 1.590 + 1.591 + bool extKnown = false; 1.592 + if (fileExt.IsEmpty()) { 1.593 + extKnown = true; 1.594 + // Mime type discovery is possible in some cases, through 1.595 + // HKEY_CLASSES_ROOT\MIME\Database\Content Type, however, a number 1.596 + // of file extensions related to mime type are simply not defined, 1.597 + // (application/rss+xml & application/atom+xml are good examples) 1.598 + // in which case we can only provide a generic list. 1.599 + nsAutoCString mimeType; 1.600 + GetMIMEType(mimeType); 1.601 + if (!mimeType.IsEmpty()) { 1.602 + workingRegistryPath.AppendLiteral("MIME\\Database\\Content Type\\"); 1.603 + workingRegistryPath.Append(NS_ConvertASCIItoUTF16(mimeType)); 1.604 + 1.605 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.606 + workingRegistryPath, 1.607 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.608 + if(NS_SUCCEEDED(rv)) { 1.609 + nsAutoString mimeFileExt; 1.610 + if (NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), mimeFileExt))) { 1.611 + CopyUTF16toUTF8(mimeFileExt, fileExt); 1.612 + extKnown = false; 1.613 + } 1.614 + } 1.615 + } 1.616 + } 1.617 + 1.618 + nsAutoString fileExtToUse; 1.619 + if (fileExt.First() != '.') 1.620 + fileExtToUse = char16_t('.'); 1.621 + fileExtToUse.Append(NS_ConvertUTF8toUTF16(fileExt)); 1.622 + 1.623 + // Note, the order in which these occur has an effect on the 1.624 + // validity of the resulting display list. 1.625 + 1.626 + if (!extKnown) { 1.627 + // 1) Get the default handler if it exists 1.628 + workingRegistryPath = fileExtToUse; 1.629 + 1.630 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.631 + workingRegistryPath, 1.632 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.633 + if (NS_SUCCEEDED(rv)) { 1.634 + nsAutoString appProgId; 1.635 + if (NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), appProgId))) { 1.636 + // Bug 358297 - ignore the embedded internet explorer handler 1.637 + if (appProgId != NS_LITERAL_STRING("XPSViewer.Document")) { 1.638 + nsAutoString appFilesystemCommand; 1.639 + if (GetProgIDVerbCommandHandler(appProgId, 1.640 + appFilesystemCommand, 1.641 + false) && 1.642 + !IsPathInList(appFilesystemCommand, trackList)) { 1.643 + ProcessPath(appList, trackList, appFilesystemCommand); 1.644 + } 1.645 + } 1.646 + } 1.647 + regKey->Close(); 1.648 + } 1.649 + 1.650 + 1.651 + // 2) list HKEY_CLASSES_ROOT\.ext\OpenWithList 1.652 + 1.653 + workingRegistryPath = fileExtToUse; 1.654 + workingRegistryPath.AppendLiteral("\\OpenWithList"); 1.655 + 1.656 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.657 + workingRegistryPath, 1.658 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.659 + if (NS_SUCCEEDED(rv)) { 1.660 + uint32_t count = 0; 1.661 + if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) { 1.662 + for (uint32_t index = 0; index < count; index++) { 1.663 + nsAutoString appName; 1.664 + if (NS_FAILED(regKey->GetValueName(index, appName))) 1.665 + continue; 1.666 + 1.667 + // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params" 1.668 + nsAutoString appFilesystemCommand; 1.669 + if (!GetAppsVerbCommandHandler(appName, 1.670 + appFilesystemCommand, 1.671 + false) || 1.672 + IsPathInList(appFilesystemCommand, trackList)) 1.673 + continue; 1.674 + ProcessPath(appList, trackList, appFilesystemCommand); 1.675 + } 1.676 + } 1.677 + regKey->Close(); 1.678 + } 1.679 + 1.680 + 1.681 + // 3) List HKEY_CLASSES_ROOT\.ext\OpenWithProgids, with the 1.682 + // different step of resolving the progids for the command handler. 1.683 + 1.684 + workingRegistryPath = fileExtToUse; 1.685 + workingRegistryPath.AppendLiteral("\\OpenWithProgids"); 1.686 + 1.687 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.688 + workingRegistryPath, 1.689 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.690 + if (NS_SUCCEEDED(rv)) { 1.691 + uint32_t count = 0; 1.692 + if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) { 1.693 + for (uint32_t index = 0; index < count; index++) { 1.694 + // HKEY_CLASSES_ROOT\.ext\OpenWithProgids\Windows.XPSReachViewer 1.695 + nsAutoString appProgId; 1.696 + if (NS_FAILED(regKey->GetValueName(index, appProgId))) 1.697 + continue; 1.698 + 1.699 + nsAutoString appFilesystemCommand; 1.700 + if (!GetProgIDVerbCommandHandler(appProgId, 1.701 + appFilesystemCommand, 1.702 + false) || 1.703 + IsPathInList(appFilesystemCommand, trackList)) 1.704 + continue; 1.705 + ProcessPath(appList, trackList, appFilesystemCommand); 1.706 + } 1.707 + } 1.708 + regKey->Close(); 1.709 + } 1.710 + 1.711 + 1.712 + // 4) Add any non configured applications located in the MRU list 1.713 + 1.714 + // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion 1.715 + // \Explorer\FileExts\.ext\OpenWithList 1.716 + workingRegistryPath = 1.717 + NS_LITERAL_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"); 1.718 + workingRegistryPath += fileExtToUse; 1.719 + workingRegistryPath.AppendLiteral("\\OpenWithList"); 1.720 + 1.721 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, 1.722 + workingRegistryPath, 1.723 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.724 + if (NS_SUCCEEDED(rv)) { 1.725 + uint32_t count = 0; 1.726 + if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) { 1.727 + for (uint32_t index = 0; index < count; index++) { 1.728 + nsAutoString appName, appValue; 1.729 + if (NS_FAILED(regKey->GetValueName(index, appName))) 1.730 + continue; 1.731 + if (appName.EqualsLiteral("MRUList")) 1.732 + continue; 1.733 + if (NS_FAILED(regKey->ReadStringValue(appName, appValue))) 1.734 + continue; 1.735 + 1.736 + // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params" 1.737 + nsAutoString appFilesystemCommand; 1.738 + if (!GetAppsVerbCommandHandler(appValue, 1.739 + appFilesystemCommand, 1.740 + false) || 1.741 + IsPathInList(appFilesystemCommand, trackList)) 1.742 + continue; 1.743 + ProcessPath(appList, trackList, appFilesystemCommand); 1.744 + } 1.745 + } 1.746 + } 1.747 + 1.748 + 1.749 + // 5) Add any non configured progids in the MRU list, with the 1.750 + // different step of resolving the progids for the command handler. 1.751 + 1.752 + // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion 1.753 + // \Explorer\FileExts\.ext\OpenWithProgids 1.754 + workingRegistryPath = 1.755 + NS_LITERAL_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"); 1.756 + workingRegistryPath += fileExtToUse; 1.757 + workingRegistryPath.AppendLiteral("\\OpenWithProgids"); 1.758 + 1.759 + regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, 1.760 + workingRegistryPath, 1.761 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.762 + if (NS_SUCCEEDED(rv)) { 1.763 + uint32_t count = 0; 1.764 + if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) { 1.765 + for (uint32_t index = 0; index < count; index++) { 1.766 + nsAutoString appIndex, appProgId; 1.767 + if (NS_FAILED(regKey->GetValueName(index, appProgId))) 1.768 + continue; 1.769 + 1.770 + nsAutoString appFilesystemCommand; 1.771 + if (!GetProgIDVerbCommandHandler(appProgId, 1.772 + appFilesystemCommand, 1.773 + false) || 1.774 + IsPathInList(appFilesystemCommand, trackList)) 1.775 + continue; 1.776 + ProcessPath(appList, trackList, appFilesystemCommand); 1.777 + } 1.778 + } 1.779 + regKey->Close(); 1.780 + } 1.781 + 1.782 + 1.783 + // 6) Check the perceived type value, and use this to lookup the perceivedtype 1.784 + // open with list. 1.785 + // http://msdn2.microsoft.com/en-us/library/aa969373.aspx 1.786 + 1.787 + workingRegistryPath = fileExtToUse; 1.788 + 1.789 + regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.790 + workingRegistryPath, 1.791 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.792 + if (NS_SUCCEEDED(rv)) { 1.793 + nsAutoString perceivedType; 1.794 + rv = regKey->ReadStringValue(NS_LITERAL_STRING("PerceivedType"), 1.795 + perceivedType); 1.796 + if (NS_SUCCEEDED(rv)) { 1.797 + nsAutoString openWithListPath(NS_LITERAL_STRING("SystemFileAssociations\\")); 1.798 + openWithListPath.Append(perceivedType); // no period 1.799 + openWithListPath.Append(NS_LITERAL_STRING("\\OpenWithList")); 1.800 + 1.801 + nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.802 + openWithListPath, 1.803 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.804 + if (NS_SUCCEEDED(rv)) { 1.805 + uint32_t count = 0; 1.806 + if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) { 1.807 + for (uint32_t index = 0; index < count; index++) { 1.808 + nsAutoString appName; 1.809 + if (NS_FAILED(regKey->GetValueName(index, appName))) 1.810 + continue; 1.811 + 1.812 + // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params" 1.813 + nsAutoString appFilesystemCommand; 1.814 + if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand, 1.815 + false) || 1.816 + IsPathInList(appFilesystemCommand, trackList)) 1.817 + continue; 1.818 + ProcessPath(appList, trackList, appFilesystemCommand); 1.819 + } 1.820 + } 1.821 + } 1.822 + } 1.823 + } 1.824 + } // extKnown == false 1.825 + 1.826 + 1.827 + // 7) list global HKEY_CLASSES_ROOT\*\OpenWithList 1.828 + // Listing general purpose handlers, not specific to a mime type or file extension 1.829 + 1.830 + workingRegistryPath = NS_LITERAL_STRING("*\\OpenWithList"); 1.831 + 1.832 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.833 + workingRegistryPath, 1.834 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.835 + if (NS_SUCCEEDED(rv)) { 1.836 + uint32_t count = 0; 1.837 + if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) { 1.838 + for (uint32_t index = 0; index < count; index++) { 1.839 + nsAutoString appName; 1.840 + if (NS_FAILED(regKey->GetValueName(index, appName))) 1.841 + continue; 1.842 + 1.843 + // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params" 1.844 + nsAutoString appFilesystemCommand; 1.845 + if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand, 1.846 + false) || 1.847 + IsPathInList(appFilesystemCommand, trackList)) 1.848 + continue; 1.849 + ProcessPath(appList, trackList, appFilesystemCommand); 1.850 + } 1.851 + } 1.852 + regKey->Close(); 1.853 + } 1.854 + 1.855 + 1.856 + // 8) General application's list - not file extension specific on windows 1.857 + workingRegistryPath = NS_LITERAL_STRING("Applications"); 1.858 + 1.859 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, 1.860 + workingRegistryPath, 1.861 + nsIWindowsRegKey::ACCESS_ENUMERATE_SUB_KEYS| 1.862 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.863 + if (NS_SUCCEEDED(rv)) { 1.864 + uint32_t count = 0; 1.865 + if (NS_SUCCEEDED(regKey->GetChildCount(&count)) && count > 0) { 1.866 + for (uint32_t index = 0; index < count; index++) { 1.867 + nsAutoString appName; 1.868 + if (NS_FAILED(regKey->GetChildName(index, appName))) 1.869 + continue; 1.870 + 1.871 + // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params" 1.872 + nsAutoString appFilesystemCommand; 1.873 + if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand, 1.874 + false) || 1.875 + IsPathInList(appFilesystemCommand, trackList)) 1.876 + continue; 1.877 + ProcessPath(appList, trackList, appFilesystemCommand); 1.878 + } 1.879 + } 1.880 + } 1.881 + 1.882 + // Return to the caller 1.883 + *_retval = appList; 1.884 + NS_ADDREF(*_retval); 1.885 + 1.886 + return NS_OK; 1.887 +}