uriloader/exthandler/win/nsMIMEInfoWin.cpp

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:62932b6d30e1
1 /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "nsArrayEnumerator.h"
8 #include "nsCOMArray.h"
9 #include "nsIFile.h"
10 #include "nsIVariant.h"
11 #include "nsMIMEInfoWin.h"
12 #include "nsNetUtil.h"
13 #include <windows.h>
14 #include <shellapi.h>
15 #include "nsAutoPtr.h"
16 #include "nsIMutableArray.h"
17 #include "nsTArray.h"
18 #include "shlobj.h"
19 #include "windows.h"
20 #include "nsIWindowsRegKey.h"
21 #include "nsIProcess.h"
22 #include "nsOSHelperAppService.h"
23 #include "nsUnicharUtils.h"
24 #include "nsITextToSubURI.h"
25
26 #define RUNDLL32_EXE L"\\rundll32.exe"
27
28
29 NS_IMPL_ISUPPORTS_INHERITED(nsMIMEInfoWin, nsMIMEInfoBase, nsIPropertyBag)
30
31 nsMIMEInfoWin::~nsMIMEInfoWin()
32 {
33 }
34
35 nsresult
36 nsMIMEInfoWin::LaunchDefaultWithFile(nsIFile* aFile)
37 {
38 // Launch the file, unless it is an executable.
39 bool executable = true;
40 aFile->IsExecutable(&executable);
41 if (executable)
42 return NS_ERROR_FAILURE;
43
44 return aFile->Launch();
45 }
46
47 NS_IMETHODIMP
48 nsMIMEInfoWin::LaunchWithFile(nsIFile* aFile)
49 {
50 nsresult rv;
51
52 // it doesn't make any sense to call this on protocol handlers
53 NS_ASSERTION(mClass == eMIMEInfo,
54 "nsMIMEInfoBase should have mClass == eMIMEInfo");
55
56 if (mPreferredAction == useSystemDefault) {
57 return LaunchDefaultWithFile(aFile);
58 }
59
60 if (mPreferredAction == useHelperApp) {
61 if (!mPreferredApplication)
62 return NS_ERROR_FILE_NOT_FOUND;
63
64 // at the moment, we only know how to hand files off to local handlers
65 nsCOMPtr<nsILocalHandlerApp> localHandler =
66 do_QueryInterface(mPreferredApplication, &rv);
67 NS_ENSURE_SUCCESS(rv, rv);
68
69 nsCOMPtr<nsIFile> executable;
70 rv = localHandler->GetExecutable(getter_AddRefs(executable));
71 NS_ENSURE_SUCCESS(rv, rv);
72
73 nsAutoString path;
74 aFile->GetPath(path);
75
76 // Deal with local dll based handlers
77 nsCString filename;
78 executable->GetNativeLeafName(filename);
79 if (filename.Length() > 4) {
80 nsCString extension(Substring(filename, filename.Length() - 4, 4));
81
82 if (extension.LowerCaseEqualsLiteral(".dll")) {
83 nsAutoString args;
84
85 // executable is rundll32, everything else is a list of parameters,
86 // including the dll handler.
87 if (!GetDllLaunchInfo(executable, aFile, args, false))
88 return NS_ERROR_INVALID_ARG;
89
90 WCHAR rundll32Path[MAX_PATH + sizeof(RUNDLL32_EXE) / sizeof(WCHAR) + 1] = {L'\0'};
91 if (!GetSystemDirectoryW(rundll32Path, MAX_PATH)) {
92 return NS_ERROR_FILE_NOT_FOUND;
93 }
94 lstrcatW(rundll32Path, RUNDLL32_EXE);
95
96 SHELLEXECUTEINFOW seinfo;
97 memset(&seinfo, 0, sizeof(seinfo));
98 seinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
99 seinfo.fMask = 0;
100 seinfo.hwnd = nullptr;
101 seinfo.lpVerb = nullptr;
102 seinfo.lpFile = rundll32Path;
103 seinfo.lpParameters = args.get();
104 seinfo.lpDirectory = nullptr;
105 seinfo.nShow = SW_SHOWNORMAL;
106 if (ShellExecuteExW(&seinfo))
107 return NS_OK;
108
109 switch ((LONG_PTR)seinfo.hInstApp) {
110 case 0:
111 case SE_ERR_OOM:
112 return NS_ERROR_OUT_OF_MEMORY;
113 case SE_ERR_ACCESSDENIED:
114 return NS_ERROR_FILE_ACCESS_DENIED;
115 case SE_ERR_ASSOCINCOMPLETE:
116 case SE_ERR_NOASSOC:
117 return NS_ERROR_UNEXPECTED;
118 case SE_ERR_DDEBUSY:
119 case SE_ERR_DDEFAIL:
120 case SE_ERR_DDETIMEOUT:
121 return NS_ERROR_NOT_AVAILABLE;
122 case SE_ERR_DLLNOTFOUND:
123 return NS_ERROR_FAILURE;
124 case SE_ERR_SHARE:
125 return NS_ERROR_FILE_IS_LOCKED;
126 default:
127 switch(GetLastError()) {
128 case ERROR_FILE_NOT_FOUND:
129 return NS_ERROR_FILE_NOT_FOUND;
130 case ERROR_PATH_NOT_FOUND:
131 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
132 case ERROR_BAD_FORMAT:
133 return NS_ERROR_FILE_CORRUPTED;
134 }
135
136 }
137 return NS_ERROR_FILE_EXECUTION_FAILED;
138 }
139 }
140 return LaunchWithIProcess(executable, path);
141 }
142
143 return NS_ERROR_INVALID_ARG;
144 }
145
146 NS_IMETHODIMP
147 nsMIMEInfoWin::GetHasDefaultHandler(bool * _retval)
148 {
149 // We have a default application if we have a description
150 // We can ShellExecute anything; however, callers are probably interested if
151 // there is really an application associated with this type of file
152 *_retval = !mDefaultAppDescription.IsEmpty();
153 return NS_OK;
154 }
155
156 NS_IMETHODIMP
157 nsMIMEInfoWin::GetEnumerator(nsISimpleEnumerator* *_retval)
158 {
159 nsCOMArray<nsIVariant> properties;
160
161 nsCOMPtr<nsIVariant> variant;
162 GetProperty(NS_LITERAL_STRING("defaultApplicationIconURL"), getter_AddRefs(variant));
163 if (variant)
164 properties.AppendObject(variant);
165
166 GetProperty(NS_LITERAL_STRING("customApplicationIconURL"), getter_AddRefs(variant));
167 if (variant)
168 properties.AppendObject(variant);
169
170 return NS_NewArrayEnumerator(_retval, properties);
171 }
172
173 static nsresult GetIconURLVariant(nsIFile* aApplication, nsIVariant* *_retval)
174 {
175 nsresult rv = CallCreateInstance("@mozilla.org/variant;1", _retval);
176 if (NS_FAILED(rv))
177 return rv;
178 nsAutoCString fileURLSpec;
179 NS_GetURLSpecFromFile(aApplication, fileURLSpec);
180 nsAutoCString iconURLSpec; iconURLSpec.AssignLiteral("moz-icon://");
181 iconURLSpec += fileURLSpec;
182 nsCOMPtr<nsIWritableVariant> writable(do_QueryInterface(*_retval));
183 writable->SetAsAUTF8String(iconURLSpec);
184 return NS_OK;
185 }
186
187 NS_IMETHODIMP
188 nsMIMEInfoWin::GetProperty(const nsAString& aName, nsIVariant* *_retval)
189 {
190 nsresult rv;
191 if (mDefaultApplication && aName.EqualsLiteral(PROPERTY_DEFAULT_APP_ICON_URL)) {
192 rv = GetIconURLVariant(mDefaultApplication, _retval);
193 NS_ENSURE_SUCCESS(rv, rv);
194 } else if (mPreferredApplication &&
195 aName.EqualsLiteral(PROPERTY_CUSTOM_APP_ICON_URL)) {
196 nsCOMPtr<nsILocalHandlerApp> localHandler =
197 do_QueryInterface(mPreferredApplication, &rv);
198 NS_ENSURE_SUCCESS(rv, rv);
199
200 nsCOMPtr<nsIFile> executable;
201 rv = localHandler->GetExecutable(getter_AddRefs(executable));
202 NS_ENSURE_SUCCESS(rv, rv);
203
204 rv = GetIconURLVariant(executable, _retval);
205 NS_ENSURE_SUCCESS(rv, rv);
206 }
207
208 return NS_OK;
209 }
210
211 // this implementation was pretty much copied verbatime from
212 // Tony Robinson's code in nsExternalProtocolWin.cpp
213 nsresult
214 nsMIMEInfoWin::LoadUriInternal(nsIURI * aURL)
215 {
216 nsresult rv = NS_OK;
217
218 // 1. Find the default app for this protocol
219 // 2. Set up the command line
220 // 3. Launch the app.
221
222 // For now, we'll just cheat essentially, check for the command line
223 // then just call ShellExecute()!
224
225 if (aURL)
226 {
227 // extract the url spec from the url
228 nsAutoCString urlSpec;
229 aURL->GetAsciiSpec(urlSpec);
230
231 // Unescape non-ASCII characters in the URL
232 nsAutoCString urlCharset;
233 nsAutoString utf16Spec;
234 rv = aURL->GetOriginCharset(urlCharset);
235 NS_ENSURE_SUCCESS(rv, rv);
236
237 nsCOMPtr<nsITextToSubURI> textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
238 NS_ENSURE_SUCCESS(rv, rv);
239
240 rv = textToSubURI->UnEscapeNonAsciiURI(urlCharset, urlSpec, utf16Spec);
241 NS_ENSURE_SUCCESS(rv, rv);
242
243 static const wchar_t cmdVerb[] = L"open";
244 SHELLEXECUTEINFOW sinfo;
245 memset(&sinfo, 0, sizeof(sinfo));
246 sinfo.cbSize = sizeof(sinfo);
247 sinfo.fMask = SEE_MASK_FLAG_DDEWAIT |
248 SEE_MASK_FLAG_NO_UI;
249 sinfo.hwnd = nullptr;
250 sinfo.lpVerb = (LPWSTR)&cmdVerb;
251 sinfo.nShow = SW_SHOWNORMAL;
252
253 LPITEMIDLIST pidl = nullptr;
254 SFGAOF sfgao;
255
256 // Bug 394974
257 if (SUCCEEDED(SHParseDisplayName(utf16Spec.get(), nullptr,
258 &pidl, 0, &sfgao))) {
259 sinfo.lpIDList = pidl;
260 sinfo.fMask |= SEE_MASK_INVOKEIDLIST;
261 } else {
262 // SHParseDisplayName failed. Bailing out as work around for
263 // Microsoft Security Bulletin MS07-061
264 rv = NS_ERROR_FAILURE;
265 }
266 if (NS_SUCCEEDED(rv)) {
267 BOOL result = ShellExecuteExW(&sinfo);
268 if (!result || ((LONG_PTR)sinfo.hInstApp) < 32)
269 rv = NS_ERROR_FAILURE;
270 }
271 if (pidl)
272 CoTaskMemFree(pidl);
273 }
274
275 return rv;
276 }
277
278 // Given a path to a local file, return its nsILocalHandlerApp instance.
279 bool nsMIMEInfoWin::GetLocalHandlerApp(const nsAString& aCommandHandler,
280 nsCOMPtr<nsILocalHandlerApp>& aApp)
281 {
282 nsCOMPtr<nsIFile> locfile;
283 nsresult rv =
284 NS_NewLocalFile(aCommandHandler, true, getter_AddRefs(locfile));
285 if (NS_FAILED(rv))
286 return false;
287
288 aApp = do_CreateInstance("@mozilla.org/uriloader/local-handler-app;1");
289 if (!aApp)
290 return false;
291
292 aApp->SetExecutable(locfile);
293 return true;
294 }
295
296 // Return the cleaned up file path associated with a command verb
297 // located in root/Applications.
298 bool nsMIMEInfoWin::GetAppsVerbCommandHandler(const nsAString& appExeName,
299 nsAString& applicationPath,
300 bool edit)
301 {
302 nsCOMPtr<nsIWindowsRegKey> appKey =
303 do_CreateInstance("@mozilla.org/windows-registry-key;1");
304 if (!appKey)
305 return false;
306
307 // HKEY_CLASSES_ROOT\Applications\iexplore.exe
308 nsAutoString applicationsPath;
309 applicationsPath.AppendLiteral("Applications\\");
310 applicationsPath.Append(appExeName);
311
312 nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
313 applicationsPath,
314 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
315 if (NS_FAILED(rv))
316 return false;
317
318 // Check for the NoOpenWith flag, if it exists
319 uint32_t value;
320 if (NS_SUCCEEDED(appKey->ReadIntValue(
321 NS_LITERAL_STRING("NoOpenWith"), &value)) &&
322 value == 1)
323 return false;
324
325 nsAutoString dummy;
326 if (NS_SUCCEEDED(appKey->ReadStringValue(
327 NS_LITERAL_STRING("NoOpenWith"), dummy)))
328 return false;
329
330 appKey->Close();
331
332 // HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command
333 applicationsPath.AssignLiteral("Applications\\");
334 applicationsPath.Append(appExeName);
335 if (!edit)
336 applicationsPath.AppendLiteral("\\shell\\open\\command");
337 else
338 applicationsPath.AppendLiteral("\\shell\\edit\\command");
339
340
341 rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
342 applicationsPath,
343 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
344 if (NS_FAILED(rv))
345 return false;
346
347 nsAutoString appFilesystemCommand;
348 if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(),
349 appFilesystemCommand))) {
350
351 // Expand environment vars, clean up any misc.
352 if (!nsOSHelperAppService::CleanupCmdHandlerPath(appFilesystemCommand))
353 return false;
354
355 applicationPath = appFilesystemCommand;
356 return true;
357 }
358 return false;
359 }
360
361 // Return a fully populated command string based on
362 // passing information. Used in launchWithFile to trace
363 // back to the full handler path based on the dll.
364 // (dll, targetfile, return args, open/edit)
365 bool nsMIMEInfoWin::GetDllLaunchInfo(nsIFile * aDll,
366 nsIFile * aFile,
367 nsAString& args,
368 bool edit)
369 {
370 if (!aDll || !aFile)
371 return false;
372
373 nsString appExeName;
374 aDll->GetLeafName(appExeName);
375
376 nsCOMPtr<nsIWindowsRegKey> appKey =
377 do_CreateInstance("@mozilla.org/windows-registry-key;1");
378 if (!appKey)
379 return false;
380
381 // HKEY_CLASSES_ROOT\Applications\iexplore.exe
382 nsAutoString applicationsPath;
383 applicationsPath.AppendLiteral("Applications\\");
384 applicationsPath.Append(appExeName);
385
386 nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
387 applicationsPath,
388 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
389 if (NS_FAILED(rv))
390 return false;
391
392 // Check for the NoOpenWith flag, if it exists
393 uint32_t value;
394 rv = appKey->ReadIntValue(NS_LITERAL_STRING("NoOpenWith"), &value);
395 if (NS_SUCCEEDED(rv) && value == 1)
396 return false;
397
398 nsAutoString dummy;
399 if (NS_SUCCEEDED(appKey->ReadStringValue(NS_LITERAL_STRING("NoOpenWith"),
400 dummy)))
401 return false;
402
403 appKey->Close();
404
405 // HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command
406 applicationsPath.AssignLiteral("Applications\\");
407 applicationsPath.Append(appExeName);
408 if (!edit)
409 applicationsPath.AppendLiteral("\\shell\\open\\command");
410 else
411 applicationsPath.AppendLiteral("\\shell\\edit\\command");
412
413 rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
414 applicationsPath,
415 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
416 if (NS_FAILED(rv))
417 return false;
418
419 nsAutoString appFilesystemCommand;
420 if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(),
421 appFilesystemCommand))) {
422 // Replace embedded environment variables.
423 uint32_t bufLength =
424 ::ExpandEnvironmentStringsW(appFilesystemCommand.get(),
425 L"", 0);
426 if (bufLength == 0) // Error
427 return false;
428
429 nsAutoArrayPtr<wchar_t> destination(new wchar_t[bufLength]);
430 if (!destination)
431 return false;
432 if (!::ExpandEnvironmentStringsW(appFilesystemCommand.get(),
433 destination,
434 bufLength))
435 return false;
436
437 appFilesystemCommand = static_cast<const wchar_t*>(destination);
438
439 // C:\Windows\System32\rundll32.exe "C:\Program Files\Windows
440 // Photo Gallery\PhotoViewer.dll", ImageView_Fullscreen %1
441 nsAutoString params;
442 NS_NAMED_LITERAL_STRING(rundllSegment, "rundll32.exe ");
443 int32_t index = appFilesystemCommand.Find(rundllSegment);
444 if (index > kNotFound) {
445 params.Append(Substring(appFilesystemCommand,
446 index + rundllSegment.Length()));
447 } else {
448 params.Append(appFilesystemCommand);
449 }
450
451 // check to make sure we have a %1 and fill it
452 NS_NAMED_LITERAL_STRING(percentOneParam, "%1");
453 index = params.Find(percentOneParam);
454 if (index == kNotFound) // no parameter
455 return false;
456
457 nsString target;
458 aFile->GetTarget(target);
459 params.Replace(index, 2, target);
460
461 args = params;
462
463 return true;
464 }
465 return false;
466 }
467
468 // Return the cleaned up file path associated with a progid command
469 // verb located in root.
470 bool nsMIMEInfoWin::GetProgIDVerbCommandHandler(const nsAString& appProgIDName,
471 nsAString& applicationPath,
472 bool edit)
473 {
474 nsCOMPtr<nsIWindowsRegKey> appKey =
475 do_CreateInstance("@mozilla.org/windows-registry-key;1");
476 if (!appKey)
477 return false;
478
479 nsAutoString appProgId(appProgIDName);
480
481 // HKEY_CLASSES_ROOT\Windows.XPSReachViewer\shell\open\command
482 if (!edit)
483 appProgId.AppendLiteral("\\shell\\open\\command");
484 else
485 appProgId.AppendLiteral("\\shell\\edit\\command");
486
487 nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
488 appProgId,
489 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
490 if (NS_FAILED(rv))
491 return false;
492
493 nsAutoString appFilesystemCommand;
494 if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(), appFilesystemCommand))) {
495
496 // Expand environment vars, clean up any misc.
497 if (!nsOSHelperAppService::CleanupCmdHandlerPath(appFilesystemCommand))
498 return false;
499
500 applicationPath = appFilesystemCommand;
501 return true;
502 }
503 return false;
504 }
505
506 // Helper routine used in tracking app lists. Converts path
507 // entries to lower case and stores them in the trackList array.
508 void nsMIMEInfoWin::ProcessPath(nsCOMPtr<nsIMutableArray>& appList,
509 nsTArray<nsString>& trackList,
510 const nsAString& appFilesystemCommand)
511 {
512 nsAutoString lower(appFilesystemCommand);
513 ToLowerCase(lower);
514
515 // Don't include firefox.exe in the list
516 WCHAR exe[MAX_PATH+1];
517 uint32_t len = GetModuleFileNameW(nullptr, exe, MAX_PATH);
518 if (len < MAX_PATH && len != 0) {
519 uint32_t index = lower.Find(exe);
520 if (index != -1)
521 return;
522 }
523
524 nsCOMPtr<nsILocalHandlerApp> aApp;
525 if (!GetLocalHandlerApp(appFilesystemCommand, aApp))
526 return;
527
528 // Save in our main tracking arrays
529 appList->AppendElement(aApp, false);
530 trackList.AppendElement(lower);
531 }
532
533 // Helper routine that handles a compare between a path
534 // and an array of paths.
535 static bool IsPathInList(nsAString& appPath,
536 nsTArray<nsString>& trackList)
537 {
538 // trackList data is always lowercase, see ProcessPath
539 // above.
540 nsAutoString tmp(appPath);
541 ToLowerCase(tmp);
542
543 for (uint32_t i = 0; i < trackList.Length(); i++) {
544 if (tmp.Equals(trackList[i]))
545 return true;
546 }
547 return false;
548 }
549
550 /**
551 * Returns a list of nsILocalHandlerApp objects containing local
552 * handlers associated with this mimeinfo. Implemented per
553 * platform using information in this object to generate the
554 * best list. Typically used for an "open with" style user
555 * option.
556 *
557 * @return nsIArray of nsILocalHandlerApp
558 */
559 NS_IMETHODIMP
560 nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray **_retval)
561 {
562 nsresult rv;
563
564 *_retval = nullptr;
565
566 nsCOMPtr<nsIMutableArray> appList =
567 do_CreateInstance("@mozilla.org/array;1");
568
569 if (!appList)
570 return NS_ERROR_FAILURE;
571
572 nsTArray<nsString> trackList;
573
574 nsAutoCString fileExt;
575 GetPrimaryExtension(fileExt);
576
577 nsCOMPtr<nsIWindowsRegKey> regKey =
578 do_CreateInstance("@mozilla.org/windows-registry-key;1");
579 if (!regKey)
580 return NS_ERROR_FAILURE;
581 nsCOMPtr<nsIWindowsRegKey> appKey =
582 do_CreateInstance("@mozilla.org/windows-registry-key;1");
583 if (!appKey)
584 return NS_ERROR_FAILURE;
585
586 nsAutoString workingRegistryPath;
587
588 bool extKnown = false;
589 if (fileExt.IsEmpty()) {
590 extKnown = true;
591 // Mime type discovery is possible in some cases, through
592 // HKEY_CLASSES_ROOT\MIME\Database\Content Type, however, a number
593 // of file extensions related to mime type are simply not defined,
594 // (application/rss+xml & application/atom+xml are good examples)
595 // in which case we can only provide a generic list.
596 nsAutoCString mimeType;
597 GetMIMEType(mimeType);
598 if (!mimeType.IsEmpty()) {
599 workingRegistryPath.AppendLiteral("MIME\\Database\\Content Type\\");
600 workingRegistryPath.Append(NS_ConvertASCIItoUTF16(mimeType));
601
602 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
603 workingRegistryPath,
604 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
605 if(NS_SUCCEEDED(rv)) {
606 nsAutoString mimeFileExt;
607 if (NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), mimeFileExt))) {
608 CopyUTF16toUTF8(mimeFileExt, fileExt);
609 extKnown = false;
610 }
611 }
612 }
613 }
614
615 nsAutoString fileExtToUse;
616 if (fileExt.First() != '.')
617 fileExtToUse = char16_t('.');
618 fileExtToUse.Append(NS_ConvertUTF8toUTF16(fileExt));
619
620 // Note, the order in which these occur has an effect on the
621 // validity of the resulting display list.
622
623 if (!extKnown) {
624 // 1) Get the default handler if it exists
625 workingRegistryPath = fileExtToUse;
626
627 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
628 workingRegistryPath,
629 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
630 if (NS_SUCCEEDED(rv)) {
631 nsAutoString appProgId;
632 if (NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), appProgId))) {
633 // Bug 358297 - ignore the embedded internet explorer handler
634 if (appProgId != NS_LITERAL_STRING("XPSViewer.Document")) {
635 nsAutoString appFilesystemCommand;
636 if (GetProgIDVerbCommandHandler(appProgId,
637 appFilesystemCommand,
638 false) &&
639 !IsPathInList(appFilesystemCommand, trackList)) {
640 ProcessPath(appList, trackList, appFilesystemCommand);
641 }
642 }
643 }
644 regKey->Close();
645 }
646
647
648 // 2) list HKEY_CLASSES_ROOT\.ext\OpenWithList
649
650 workingRegistryPath = fileExtToUse;
651 workingRegistryPath.AppendLiteral("\\OpenWithList");
652
653 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
654 workingRegistryPath,
655 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
656 if (NS_SUCCEEDED(rv)) {
657 uint32_t count = 0;
658 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
659 for (uint32_t index = 0; index < count; index++) {
660 nsAutoString appName;
661 if (NS_FAILED(regKey->GetValueName(index, appName)))
662 continue;
663
664 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
665 nsAutoString appFilesystemCommand;
666 if (!GetAppsVerbCommandHandler(appName,
667 appFilesystemCommand,
668 false) ||
669 IsPathInList(appFilesystemCommand, trackList))
670 continue;
671 ProcessPath(appList, trackList, appFilesystemCommand);
672 }
673 }
674 regKey->Close();
675 }
676
677
678 // 3) List HKEY_CLASSES_ROOT\.ext\OpenWithProgids, with the
679 // different step of resolving the progids for the command handler.
680
681 workingRegistryPath = fileExtToUse;
682 workingRegistryPath.AppendLiteral("\\OpenWithProgids");
683
684 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
685 workingRegistryPath,
686 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
687 if (NS_SUCCEEDED(rv)) {
688 uint32_t count = 0;
689 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
690 for (uint32_t index = 0; index < count; index++) {
691 // HKEY_CLASSES_ROOT\.ext\OpenWithProgids\Windows.XPSReachViewer
692 nsAutoString appProgId;
693 if (NS_FAILED(regKey->GetValueName(index, appProgId)))
694 continue;
695
696 nsAutoString appFilesystemCommand;
697 if (!GetProgIDVerbCommandHandler(appProgId,
698 appFilesystemCommand,
699 false) ||
700 IsPathInList(appFilesystemCommand, trackList))
701 continue;
702 ProcessPath(appList, trackList, appFilesystemCommand);
703 }
704 }
705 regKey->Close();
706 }
707
708
709 // 4) Add any non configured applications located in the MRU list
710
711 // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion
712 // \Explorer\FileExts\.ext\OpenWithList
713 workingRegistryPath =
714 NS_LITERAL_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
715 workingRegistryPath += fileExtToUse;
716 workingRegistryPath.AppendLiteral("\\OpenWithList");
717
718 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
719 workingRegistryPath,
720 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
721 if (NS_SUCCEEDED(rv)) {
722 uint32_t count = 0;
723 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
724 for (uint32_t index = 0; index < count; index++) {
725 nsAutoString appName, appValue;
726 if (NS_FAILED(regKey->GetValueName(index, appName)))
727 continue;
728 if (appName.EqualsLiteral("MRUList"))
729 continue;
730 if (NS_FAILED(regKey->ReadStringValue(appName, appValue)))
731 continue;
732
733 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
734 nsAutoString appFilesystemCommand;
735 if (!GetAppsVerbCommandHandler(appValue,
736 appFilesystemCommand,
737 false) ||
738 IsPathInList(appFilesystemCommand, trackList))
739 continue;
740 ProcessPath(appList, trackList, appFilesystemCommand);
741 }
742 }
743 }
744
745
746 // 5) Add any non configured progids in the MRU list, with the
747 // different step of resolving the progids for the command handler.
748
749 // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion
750 // \Explorer\FileExts\.ext\OpenWithProgids
751 workingRegistryPath =
752 NS_LITERAL_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
753 workingRegistryPath += fileExtToUse;
754 workingRegistryPath.AppendLiteral("\\OpenWithProgids");
755
756 regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
757 workingRegistryPath,
758 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
759 if (NS_SUCCEEDED(rv)) {
760 uint32_t count = 0;
761 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
762 for (uint32_t index = 0; index < count; index++) {
763 nsAutoString appIndex, appProgId;
764 if (NS_FAILED(regKey->GetValueName(index, appProgId)))
765 continue;
766
767 nsAutoString appFilesystemCommand;
768 if (!GetProgIDVerbCommandHandler(appProgId,
769 appFilesystemCommand,
770 false) ||
771 IsPathInList(appFilesystemCommand, trackList))
772 continue;
773 ProcessPath(appList, trackList, appFilesystemCommand);
774 }
775 }
776 regKey->Close();
777 }
778
779
780 // 6) Check the perceived type value, and use this to lookup the perceivedtype
781 // open with list.
782 // http://msdn2.microsoft.com/en-us/library/aa969373.aspx
783
784 workingRegistryPath = fileExtToUse;
785
786 regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
787 workingRegistryPath,
788 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
789 if (NS_SUCCEEDED(rv)) {
790 nsAutoString perceivedType;
791 rv = regKey->ReadStringValue(NS_LITERAL_STRING("PerceivedType"),
792 perceivedType);
793 if (NS_SUCCEEDED(rv)) {
794 nsAutoString openWithListPath(NS_LITERAL_STRING("SystemFileAssociations\\"));
795 openWithListPath.Append(perceivedType); // no period
796 openWithListPath.Append(NS_LITERAL_STRING("\\OpenWithList"));
797
798 nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
799 openWithListPath,
800 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
801 if (NS_SUCCEEDED(rv)) {
802 uint32_t count = 0;
803 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
804 for (uint32_t index = 0; index < count; index++) {
805 nsAutoString appName;
806 if (NS_FAILED(regKey->GetValueName(index, appName)))
807 continue;
808
809 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
810 nsAutoString appFilesystemCommand;
811 if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand,
812 false) ||
813 IsPathInList(appFilesystemCommand, trackList))
814 continue;
815 ProcessPath(appList, trackList, appFilesystemCommand);
816 }
817 }
818 }
819 }
820 }
821 } // extKnown == false
822
823
824 // 7) list global HKEY_CLASSES_ROOT\*\OpenWithList
825 // Listing general purpose handlers, not specific to a mime type or file extension
826
827 workingRegistryPath = NS_LITERAL_STRING("*\\OpenWithList");
828
829 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
830 workingRegistryPath,
831 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
832 if (NS_SUCCEEDED(rv)) {
833 uint32_t count = 0;
834 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
835 for (uint32_t index = 0; index < count; index++) {
836 nsAutoString appName;
837 if (NS_FAILED(regKey->GetValueName(index, appName)))
838 continue;
839
840 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
841 nsAutoString appFilesystemCommand;
842 if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand,
843 false) ||
844 IsPathInList(appFilesystemCommand, trackList))
845 continue;
846 ProcessPath(appList, trackList, appFilesystemCommand);
847 }
848 }
849 regKey->Close();
850 }
851
852
853 // 8) General application's list - not file extension specific on windows
854 workingRegistryPath = NS_LITERAL_STRING("Applications");
855
856 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
857 workingRegistryPath,
858 nsIWindowsRegKey::ACCESS_ENUMERATE_SUB_KEYS|
859 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
860 if (NS_SUCCEEDED(rv)) {
861 uint32_t count = 0;
862 if (NS_SUCCEEDED(regKey->GetChildCount(&count)) && count > 0) {
863 for (uint32_t index = 0; index < count; index++) {
864 nsAutoString appName;
865 if (NS_FAILED(regKey->GetChildName(index, appName)))
866 continue;
867
868 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
869 nsAutoString appFilesystemCommand;
870 if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand,
871 false) ||
872 IsPathInList(appFilesystemCommand, trackList))
873 continue;
874 ProcessPath(appList, trackList, appFilesystemCommand);
875 }
876 }
877 }
878
879 // Return to the caller
880 *_retval = appList;
881 NS_ADDREF(*_retval);
882
883 return NS_OK;
884 }

mercurial