Bug 426991 - Form submission extremely slow on large forms (with form Form history...
[wine-gecko.git] / uriloader / exthandler / win / nsMIMEInfoWin.cpp
blobf8ec12e4a093548538a4be9d15cc1af65c38ddf1
1 /* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is the Mozilla browser.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications, Inc.
20 * Portions created by the Initial Developer are Copyright (C) 1999
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Scott MacGregor <mscott@netscape.com>
25 * Christian Biesinger <cbiesinger@web.de>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsArrayEnumerator.h"
42 #include "nsCOMArray.h"
43 #include "nsILocalFile.h"
44 #include "nsIVariant.h"
45 #include "nsMIMEInfoWin.h"
46 #include "nsNetUtil.h"
47 #include <windows.h>
48 #include <shellapi.h>
49 #include "nsAutoPtr.h"
50 #include "nsIMutableArray.h"
51 #include "nsTArray.h"
52 #include "shlobj.h"
53 #include "windows.h"
54 #include "nsIWindowsRegKey.h"
55 #include "nsIProcess.h"
56 #include "nsOSHelperAppService.h"
57 #include "nsUnicharUtils.h"
59 NS_IMPL_ISUPPORTS_INHERITED1(nsMIMEInfoWin, nsMIMEInfoBase, nsIPropertyBag)
61 nsMIMEInfoWin::~nsMIMEInfoWin()
65 nsresult
66 nsMIMEInfoWin::LaunchDefaultWithFile(nsIFile* aFile)
68 // Launch the file, unless it is an executable.
69 nsCOMPtr<nsILocalFile> local(do_QueryInterface(aFile));
70 if (!local)
71 return NS_ERROR_FAILURE;
73 PRBool executable = PR_TRUE;
74 local->IsExecutable(&executable);
75 if (executable)
76 return NS_ERROR_FAILURE;
78 return local->Launch();
81 NS_IMETHODIMP
82 nsMIMEInfoWin::LaunchWithFile(nsIFile* aFile)
84 nsresult rv;
86 // it doesn't make any sense to call this on protocol handlers
87 NS_ASSERTION(mClass == eMIMEInfo,
88 "nsMIMEInfoBase should have mClass == eMIMEInfo");
90 if (mPreferredAction == useSystemDefault) {
91 return LaunchDefaultWithFile(aFile);
94 if (mPreferredAction == useHelperApp) {
95 if (!mPreferredApplication)
96 return NS_ERROR_FILE_NOT_FOUND;
98 // at the moment, we only know how to hand files off to local handlers
99 nsCOMPtr<nsILocalHandlerApp> localHandler =
100 do_QueryInterface(mPreferredApplication, &rv);
101 NS_ENSURE_SUCCESS(rv, rv);
103 nsCOMPtr<nsIFile> executable;
104 rv = localHandler->GetExecutable(getter_AddRefs(executable));
105 NS_ENSURE_SUCCESS(rv, rv);
107 nsCAutoString path;
108 aFile->GetNativePath(path);
110 // Deal with local dll based handlers
111 nsCString filename;
112 executable->GetNativeLeafName(filename);
113 if (filename.Length() > 4) {
114 nsCString extension(Substring(filename, filename.Length() - 4, 4));
116 if (extension.LowerCaseEqualsLiteral(".dll")) {
117 nsAutoString args;
119 // executable is rundll32, everything else is a list of parameters,
120 // including the dll handler.
121 nsCOMPtr<nsILocalFile> locFile(do_QueryInterface(aFile));
123 if (!GetDllLaunchInfo(executable, locFile, args, PR_FALSE))
124 return NS_ERROR_INVALID_ARG;
126 PRUint32 result = (PRUint32)
127 ::ShellExecuteW(NULL, NULL, L"rundll32.exe", args.get(),
128 NULL, SW_SHOWNORMAL);
129 // Returns a value greater than 32 if successful. See msdn.
130 if (result >= 32)
131 return NS_OK;
133 switch (result) {
134 case 0:
135 case SE_ERR_OOM:
136 return NS_ERROR_OUT_OF_MEMORY;
137 case ERROR_FILE_NOT_FOUND:
138 return NS_ERROR_FILE_NOT_FOUND;
139 case ERROR_PATH_NOT_FOUND:
140 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
141 case ERROR_BAD_FORMAT:
142 return NS_ERROR_FILE_CORRUPTED;
143 case SE_ERR_ACCESSDENIED:
144 return NS_ERROR_FILE_ACCESS_DENIED;
145 case SE_ERR_ASSOCINCOMPLETE:
146 case SE_ERR_NOASSOC:
147 return NS_ERROR_UNEXPECTED;
148 case SE_ERR_DDEBUSY:
149 case SE_ERR_DDEFAIL:
150 case SE_ERR_DDETIMEOUT:
151 return NS_ERROR_NOT_AVAILABLE;
152 case SE_ERR_DLLNOTFOUND:
153 return NS_ERROR_FAILURE;
154 case SE_ERR_SHARE:
155 return NS_ERROR_FILE_IS_LOCKED;
157 return NS_ERROR_FILE_EXECUTION_FAILED;
160 return LaunchWithIProcess(executable, path);
163 return NS_ERROR_INVALID_ARG;
166 NS_IMETHODIMP
167 nsMIMEInfoWin::GetHasDefaultHandler(PRBool * _retval)
169 // We have a default application if we have a description
170 // We can ShellExecute anything; however, callers are probably interested if
171 // there is really an application associated with this type of file
172 *_retval = !mDefaultAppDescription.IsEmpty();
173 return NS_OK;
176 NS_IMETHODIMP
177 nsMIMEInfoWin::GetEnumerator(nsISimpleEnumerator* *_retval)
179 nsCOMArray<nsIVariant> properties;
181 nsCOMPtr<nsIVariant> variant;
182 GetProperty(NS_LITERAL_STRING("defaultApplicationIconURL"), getter_AddRefs(variant));
183 if (variant)
184 properties.AppendObject(variant);
186 GetProperty(NS_LITERAL_STRING("customApplicationIconURL"), getter_AddRefs(variant));
187 if (variant)
188 properties.AppendObject(variant);
190 return NS_NewArrayEnumerator(_retval, properties);
193 static nsresult GetIconURLVariant(nsIFile* aApplication, nsIVariant* *_retval)
195 nsresult rv = CallCreateInstance("@mozilla.org/variant;1", _retval);
196 if (NS_FAILED(rv))
197 return rv;
198 nsCAutoString fileURLSpec;
199 NS_GetURLSpecFromFile(aApplication, fileURLSpec);
200 nsCAutoString iconURLSpec; iconURLSpec.AssignLiteral("moz-icon://");
201 iconURLSpec += fileURLSpec;
202 nsCOMPtr<nsIWritableVariant> writable(do_QueryInterface(*_retval));
203 writable->SetAsAUTF8String(iconURLSpec);
204 return NS_OK;
207 NS_IMETHODIMP
208 nsMIMEInfoWin::GetProperty(const nsAString& aName, nsIVariant* *_retval)
210 nsresult rv;
211 if (mDefaultApplication && aName.EqualsLiteral(PROPERTY_DEFAULT_APP_ICON_URL)) {
212 rv = GetIconURLVariant(mDefaultApplication, _retval);
213 NS_ENSURE_SUCCESS(rv, rv);
214 } else if (mPreferredApplication &&
215 aName.EqualsLiteral(PROPERTY_CUSTOM_APP_ICON_URL)) {
216 nsCOMPtr<nsILocalHandlerApp> localHandler =
217 do_QueryInterface(mPreferredApplication, &rv);
218 NS_ENSURE_SUCCESS(rv, rv);
220 nsCOMPtr<nsIFile> executable;
221 rv = localHandler->GetExecutable(getter_AddRefs(executable));
222 NS_ENSURE_SUCCESS(rv, rv);
224 rv = GetIconURLVariant(executable, _retval);
225 NS_ENSURE_SUCCESS(rv, rv);
228 return NS_OK;
231 typedef HRESULT (STDMETHODCALLTYPE *MySHParseDisplayName)
232 (PCWSTR pszName,
233 IBindCtx *pbc,
234 LPITEMIDLIST *ppidl,
235 SFGAOF sfgaoIn,
236 SFGAOF *psfgaoOut);
238 // this implementation was pretty much copied verbatime from
239 // Tony Robinson's code in nsExternalProtocolWin.cpp
240 nsresult
241 nsMIMEInfoWin::LoadUriInternal(nsIURI * aURL)
243 nsresult rv = NS_OK;
245 // 1. Find the default app for this protocol
246 // 2. Set up the command line
247 // 3. Launch the app.
249 // For now, we'll just cheat essentially, check for the command line
250 // then just call ShellExecute()!
252 if (aURL)
254 // extract the url spec from the url
255 nsCAutoString urlSpec;
256 aURL->GetAsciiSpec(urlSpec);
258 // Some versions of windows (Win2k before SP3, Win XP before SP1)
259 // crash in ShellExecute on long URLs (bug 161357).
260 // IE 5 and 6 support URLS of 2083 chars in length, 2K is safe
261 const PRUint32 maxSafeURL(2048);
262 if (urlSpec.Length() > maxSafeURL)
263 return NS_ERROR_FAILURE;
265 LPITEMIDLIST pidl;
266 SFGAOF sfgao;
268 // Bug 394974
269 HMODULE hDll = ::LoadLibraryW(L"shell32.dll");
270 MySHParseDisplayName pMySHParseDisplayName = NULL;
271 // Version 6.0 and higher
272 if (pMySHParseDisplayName =
273 (MySHParseDisplayName)::GetProcAddress(hDll,
274 "SHParseDisplayName")) {
275 if (SUCCEEDED(pMySHParseDisplayName(NS_ConvertUTF8toUTF16(urlSpec).get(),
276 NULL, &pidl, 0, &sfgao))) {
277 static const PRUnichar cmdVerb[] = L"open";
278 SHELLEXECUTEINFOW sinfo;
279 memset(&sinfo, 0, sizeof(sinfo));
280 sinfo.cbSize = sizeof(sinfo);
281 sinfo.fMask = SEE_MASK_FLAG_DDEWAIT |
282 SEE_MASK_FLAG_NO_UI |
283 SEE_MASK_INVOKEIDLIST;
284 sinfo.hwnd = NULL;
285 sinfo.lpVerb = (LPWSTR)&cmdVerb;
286 sinfo.nShow = SW_SHOWNORMAL;
287 sinfo.lpIDList = pidl;
289 BOOL result = ShellExecuteExW(&sinfo);
291 CoTaskMemFree(pidl);
293 if (!result || ((int)sinfo.hInstApp) < 32)
294 rv = NS_ERROR_FAILURE;
296 } else {
297 // Version of shell32.dll < 6.0
298 int r = (int) ::ShellExecuteW(NULL, L"open", NS_ConvertUTF8toUTF16(urlSpec).get(),
299 NULL, NULL, SW_SHOWNORMAL);
300 if (r < 32)
301 rv = NS_ERROR_FAILURE;
303 if (hDll)
304 ::FreeLibrary(hDll);
307 return rv;
310 // Given a path to a local file, return its nsILocalHandlerApp instance.
311 PRBool nsMIMEInfoWin::GetLocalHandlerApp(const nsAString& aCommandHandler,
312 nsCOMPtr<nsILocalHandlerApp>& aApp)
314 nsCOMPtr<nsILocalFile> locfile;
315 nsresult rv =
316 NS_NewLocalFile(aCommandHandler, PR_TRUE, getter_AddRefs(locfile));
317 if (NS_FAILED(rv))
318 return PR_FALSE;
320 aApp = do_CreateInstance("@mozilla.org/uriloader/local-handler-app;1");
321 if (!aApp)
322 return PR_FALSE;
324 aApp->SetExecutable(locfile);
325 return PR_TRUE;
328 // Return the cleaned up file path associated with a command verb
329 // located in root/Applications.
330 PRBool nsMIMEInfoWin::GetAppsVerbCommandHandler(const nsAString& appExeName,
331 nsAString& applicationPath,
332 PRBool edit)
334 nsCOMPtr<nsIWindowsRegKey> appKey =
335 do_CreateInstance("@mozilla.org/windows-registry-key;1");
336 if (!appKey)
337 return PR_FALSE;
339 // HKEY_CLASSES_ROOT\Applications\iexplore.exe
340 nsAutoString applicationsPath;
341 applicationsPath.AppendLiteral("Applications\\");
342 applicationsPath.Append(appExeName);
344 nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
345 applicationsPath,
346 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
347 if (NS_FAILED(rv))
348 return PR_FALSE;
350 // Check for the NoOpenWith flag, if it exists
351 PRUint32 value;
352 if (NS_SUCCEEDED(appKey->ReadIntValue(
353 NS_LITERAL_STRING("NoOpenWith"), &value)) &&
354 value == 1)
355 return PR_FALSE;
357 nsAutoString dummy;
358 if (NS_SUCCEEDED(appKey->ReadStringValue(
359 NS_LITERAL_STRING("NoOpenWith"), dummy)))
360 return PR_FALSE;
362 appKey->Close();
364 // HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command
365 applicationsPath.AssignLiteral("Applications\\");
366 applicationsPath.Append(appExeName);
367 if (!edit)
368 applicationsPath.AppendLiteral("\\shell\\open\\command");
369 else
370 applicationsPath.AppendLiteral("\\shell\\edit\\command");
373 rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
374 applicationsPath,
375 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
376 if (NS_FAILED(rv))
377 return PR_FALSE;
379 nsAutoString appFilesystemCommand;
380 if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(),
381 appFilesystemCommand))) {
383 // Expand environment vars, clean up any misc.
384 if (!nsOSHelperAppService::CleanupCmdHandlerPath(appFilesystemCommand))
385 return PR_FALSE;
387 applicationPath = appFilesystemCommand;
388 return PR_TRUE;
390 return PR_FALSE;
393 // Return a fully populated command string based on
394 // passing information. Used in launchWithFile to trace
395 // back to the full handler path based on the dll.
396 // (dll, targetfile, return args, open/edit)
397 PRBool nsMIMEInfoWin::GetDllLaunchInfo(nsIFile * aDll,
398 nsILocalFile * aFile,
399 nsAString& args,
400 PRBool edit)
402 if (!aDll || !aFile)
403 return PR_FALSE;
405 nsCOMPtr<nsILocalFile> localDll(do_QueryInterface(aDll));
406 if (!localDll)
407 return PR_FALSE;
409 nsString appExeName;
410 localDll->GetLeafName(appExeName);
412 nsCOMPtr<nsIWindowsRegKey> appKey =
413 do_CreateInstance("@mozilla.org/windows-registry-key;1");
414 if (!appKey)
415 return PR_FALSE;
417 // HKEY_CLASSES_ROOT\Applications\iexplore.exe
418 nsAutoString applicationsPath;
419 applicationsPath.AppendLiteral("Applications\\");
420 applicationsPath.Append(appExeName);
422 nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
423 applicationsPath,
424 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
425 if (NS_FAILED(rv))
426 return PR_FALSE;
428 // Check for the NoOpenWith flag, if it exists
429 PRUint32 value;
430 rv = appKey->ReadIntValue(NS_LITERAL_STRING("NoOpenWith"), &value);
431 if (NS_SUCCEEDED(rv) && value == 1)
432 return PR_FALSE;
434 nsAutoString dummy;
435 if (NS_SUCCEEDED(appKey->ReadStringValue(NS_LITERAL_STRING("NoOpenWith"),
436 dummy)))
437 return PR_FALSE;
439 appKey->Close();
441 // HKEY_CLASSES_ROOT\Applications\iexplore.exe\shell\open\command
442 applicationsPath.AssignLiteral("Applications\\");
443 applicationsPath.Append(appExeName);
444 if (!edit)
445 applicationsPath.AppendLiteral("\\shell\\open\\command");
446 else
447 applicationsPath.AppendLiteral("\\shell\\edit\\command");
449 rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
450 applicationsPath,
451 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
452 if (NS_FAILED(rv))
453 return PR_FALSE;
455 nsAutoString appFilesystemCommand;
456 if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(),
457 appFilesystemCommand))) {
458 // Replace embedded environment variables.
459 PRUint32 bufLength =
460 ::ExpandEnvironmentStringsW(appFilesystemCommand.get(),
461 L"", 0);
462 if (bufLength == 0) // Error
463 return PR_FALSE;
465 nsAutoArrayPtr<PRUnichar> destination(new PRUnichar[bufLength]);
466 if (!destination)
467 return PR_FALSE;
468 if (!::ExpandEnvironmentStringsW(appFilesystemCommand.get(),
469 destination,
470 bufLength))
471 return PR_FALSE;
473 appFilesystemCommand = destination;
475 // C:\Windows\System32\rundll32.exe "C:\Program Files\Windows
476 // Photo Gallery\PhotoViewer.dll", ImageView_Fullscreen %1
477 nsAutoString params;
478 NS_NAMED_LITERAL_STRING(rundllSegment, "rundll32.exe ");
479 PRInt32 index = appFilesystemCommand.Find(rundllSegment);
480 if (index > kNotFound) {
481 params.Append(Substring(appFilesystemCommand,
482 index + rundllSegment.Length()));
483 } else {
484 params.Append(appFilesystemCommand);
487 // check to make sure we have a %1 and fill it
488 NS_NAMED_LITERAL_STRING(percentOneParam, "%1");
489 index = params.Find(percentOneParam);
490 if (index == kNotFound) // no parameter
491 return PR_FALSE;
493 nsString target;
494 aFile->GetTarget(target);
495 params.Replace(index, 2, target);
497 args = params;
499 return PR_TRUE;
501 return PR_FALSE;
504 // Return the cleaned up file path associated with a progid command
505 // verb located in root.
506 PRBool nsMIMEInfoWin::GetProgIDVerbCommandHandler(const nsAString& appProgIDName,
507 nsAString& applicationPath,
508 PRBool edit)
510 nsCOMPtr<nsIWindowsRegKey> appKey =
511 do_CreateInstance("@mozilla.org/windows-registry-key;1");
512 if (!appKey)
513 return PR_FALSE;
515 nsAutoString appProgId(appProgIDName);
517 // HKEY_CLASSES_ROOT\Windows.XPSReachViewer\shell\open\command
518 if (!edit)
519 appProgId.AppendLiteral("\\shell\\open\\command");
520 else
521 appProgId.AppendLiteral("\\shell\\edit\\command");
523 nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
524 appProgId,
525 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
526 if (NS_FAILED(rv))
527 return PR_FALSE;
529 nsAutoString appFilesystemCommand;
530 if (NS_SUCCEEDED(appKey->ReadStringValue(EmptyString(), appFilesystemCommand))) {
532 // Expand environment vars, clean up any misc.
533 if (!nsOSHelperAppService::CleanupCmdHandlerPath(appFilesystemCommand))
534 return PR_FALSE;
536 applicationPath = appFilesystemCommand;
537 return PR_TRUE;
539 return PR_FALSE;
542 // Helper routine used in tracking app lists. Converts path
543 // entries to lower case and stores them in the trackList array.
544 void nsMIMEInfoWin::ProcessPath(nsCOMPtr<nsIMutableArray>& appList,
545 nsTArray<nsString>& trackList,
546 const nsAString& appFilesystemCommand)
548 nsAutoString lower(appFilesystemCommand);
549 ToLowerCase(lower);
551 // Don't include firefox.exe in the list
552 WCHAR exe[MAX_PATH+1];
553 PRUint32 len = GetModuleFileNameW(NULL, exe, MAX_PATH);
554 if (len < MAX_PATH && len != 0) {
555 PRUint32 index = lower.Find(exe);
556 if (index != -1)
557 return;
560 nsCOMPtr<nsILocalHandlerApp> aApp;
561 if (!GetLocalHandlerApp(appFilesystemCommand, aApp))
562 return;
564 // Save in our main tracking arrays
565 appList->AppendElement(aApp, PR_FALSE);
566 trackList.AppendElement(lower);
569 // Helper routine that handles a compare between a path
570 // and an array of paths.
571 static PRBool IsPathInList(nsAString& appPath,
572 nsTArray<nsString>& trackList)
574 // trackList data is always lowercase, see ProcessPath
575 // above.
576 nsAutoString tmp(appPath);
577 ToLowerCase(tmp);
579 for (PRUint32 i = 0; i < trackList.Length(); i++) {
580 if (tmp.Equals(trackList[i]))
581 return PR_TRUE;
583 return PR_FALSE;
586 /**
587 * Returns a list of nsILocalHandlerApp objects containing local
588 * handlers associated with this mimeinfo. Implemented per
589 * platform using information in this object to generate the
590 * best list. Typically used for an "open with" style user
591 * option.
593 * @return nsIArray of nsILocalHandlerApp
595 NS_IMETHODIMP
596 nsMIMEInfoWin::GetPossibleLocalHandlers(nsIArray **_retval)
598 nsresult rv;
600 *_retval = nsnull;
602 nsCOMPtr<nsIMutableArray> appList =
603 do_CreateInstance("@mozilla.org/array;1");
605 if (!appList)
606 return NS_ERROR_FAILURE;
608 nsTArray<nsString> trackList;
610 nsCAutoString fileExt;
611 GetPrimaryExtension(fileExt);
613 nsCOMPtr<nsIWindowsRegKey> regKey =
614 do_CreateInstance("@mozilla.org/windows-registry-key;1");
615 if (!regKey)
616 return NS_ERROR_FAILURE;
617 nsCOMPtr<nsIWindowsRegKey> appKey =
618 do_CreateInstance("@mozilla.org/windows-registry-key;1");
619 if (!appKey)
620 return NS_ERROR_FAILURE;
622 nsAutoString workingRegistryPath;
624 PRBool extKnown = PR_FALSE;
625 if (fileExt.IsEmpty()) {
626 extKnown = PR_TRUE;
627 // Mime type discovery is possible in some cases, through
628 // HKEY_CLASSES_ROOT\MIME\Database\Content Type, however, a number
629 // of file extensions related to mime type are simply not defined,
630 // (application/rss+xml & application/atom+xml are good examples)
631 // in which case we can only provide a generic list.
632 nsCAutoString mimeType;
633 GetMIMEType(mimeType);
634 if (!mimeType.IsEmpty()) {
635 workingRegistryPath.AppendLiteral("MIME\\Database\\Content Type\\");
636 workingRegistryPath.Append(NS_ConvertASCIItoUTF16(mimeType));
638 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
639 workingRegistryPath,
640 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
641 if(NS_SUCCEEDED(rv)) {
642 nsAutoString mimeFileExt;
643 if (NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), mimeFileExt))) {
644 CopyUTF16toUTF8(mimeFileExt, fileExt);
645 extKnown = PR_FALSE;
651 nsAutoString fileExtToUse;
652 if (fileExt.First() != '.')
653 fileExtToUse = PRUnichar('.');
654 fileExtToUse.Append(NS_ConvertUTF8toUTF16(fileExt));
656 // Note, the order in which these occur has an effect on the
657 // validity of the resulting display list.
659 if (!extKnown) {
660 // 1) Get the default handler if it exists
661 workingRegistryPath = fileExtToUse;
663 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
664 workingRegistryPath,
665 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
666 if (NS_SUCCEEDED(rv)) {
667 nsAutoString appProgId;
668 if (NS_SUCCEEDED(regKey->ReadStringValue(EmptyString(), appProgId))) {
669 // Bug 358297 - ignore the embedded internet explorer handler
670 if (appProgId != NS_LITERAL_STRING("XPSViewer.Document")) {
671 nsAutoString appFilesystemCommand;
672 if (GetProgIDVerbCommandHandler(appProgId,
673 appFilesystemCommand,
674 PR_FALSE) &&
675 !IsPathInList(appFilesystemCommand, trackList)) {
676 ProcessPath(appList, trackList, appFilesystemCommand);
680 regKey->Close();
684 // 2) list HKEY_CLASSES_ROOT\.ext\OpenWithList\
686 workingRegistryPath = fileExtToUse;
687 workingRegistryPath.AppendLiteral("\\OpenWithList");
689 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
690 workingRegistryPath,
691 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
692 if (NS_SUCCEEDED(rv)) {
693 PRUint32 count = 0;
694 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
695 for (PRUint32 index = 0; index < count; index++) {
696 nsAutoString appName;
697 if (NS_FAILED(regKey->GetValueName(index, appName)))
698 continue;
700 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
701 nsAutoString appFilesystemCommand;
702 if (!GetAppsVerbCommandHandler(appName,
703 appFilesystemCommand,
704 PR_FALSE) ||
705 IsPathInList(appFilesystemCommand, trackList))
706 continue;
707 ProcessPath(appList, trackList, appFilesystemCommand);
710 regKey->Close();
714 // 3) List HKEY_CLASSES_ROOT\.ext\OpenWithProgids, with the
715 // different step of resolving the progids for the command handler.
717 workingRegistryPath = fileExtToUse;
718 workingRegistryPath.AppendLiteral("\\OpenWithProgids");
720 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
721 workingRegistryPath,
722 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
723 if (NS_SUCCEEDED(rv)) {
724 PRUint32 count = 0;
725 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
726 for (PRUint32 index = 0; index < count; index++) {
727 // HKEY_CLASSES_ROOT\.ext\OpenWithProgids\Windows.XPSReachViewer
728 nsAutoString appProgId;
729 if (NS_FAILED(regKey->GetValueName(index, appProgId)))
730 continue;
732 nsAutoString appFilesystemCommand;
733 if (!GetProgIDVerbCommandHandler(appProgId,
734 appFilesystemCommand,
735 PR_FALSE) ||
736 IsPathInList(appFilesystemCommand, trackList))
737 continue;
738 ProcessPath(appList, trackList, appFilesystemCommand);
741 regKey->Close();
745 // 4) Add any non configured applications located in the MRU list
747 // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\
748 // Explorer\FileExts\.ext\OpenWithList
749 workingRegistryPath =
750 NS_LITERAL_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
751 workingRegistryPath += fileExtToUse;
752 workingRegistryPath.AppendLiteral("\\OpenWithList");
754 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
755 workingRegistryPath,
756 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
757 if (NS_SUCCEEDED(rv)) {
758 PRUint32 count = 0;
759 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
760 for (PRUint32 index = 0; index < count; index++) {
761 nsAutoString appName, appValue;
762 if (NS_FAILED(regKey->GetValueName(index, appName)))
763 continue;
764 if (appName.EqualsLiteral("MRUList"))
765 continue;
766 if (NS_FAILED(regKey->ReadStringValue(appName, appValue)))
767 continue;
769 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
770 nsAutoString appFilesystemCommand;
771 if (!GetAppsVerbCommandHandler(appValue,
772 appFilesystemCommand,
773 PR_FALSE) ||
774 IsPathInList(appFilesystemCommand, trackList))
775 continue;
776 ProcessPath(appList, trackList, appFilesystemCommand);
782 // 5) Add any non configured progids in the MRU list, with the
783 // different step of resolving the progids for the command handler.
785 // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\
786 // Explorer\FileExts\.ext\OpenWithProgids
787 workingRegistryPath =
788 NS_LITERAL_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\");
789 workingRegistryPath += fileExtToUse;
790 workingRegistryPath.AppendLiteral("\\OpenWithProgids");
792 regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
793 workingRegistryPath,
794 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
795 if (NS_SUCCEEDED(rv)) {
796 PRUint32 count = 0;
797 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
798 for (PRUint32 index = 0; index < count; index++) {
799 nsAutoString appIndex, appProgId;
800 if (NS_FAILED(regKey->GetValueName(index, appProgId)))
801 continue;
803 nsAutoString appFilesystemCommand;
804 if (!GetProgIDVerbCommandHandler(appProgId,
805 appFilesystemCommand,
806 PR_FALSE) ||
807 IsPathInList(appFilesystemCommand, trackList))
808 continue;
809 ProcessPath(appList, trackList, appFilesystemCommand);
812 regKey->Close();
816 // 6) Check the perceived type value, and use this to lookup the perceivedtype
817 // open with list.
818 // http://msdn2.microsoft.com/en-us/library/aa969373.aspx
820 workingRegistryPath = fileExtToUse;
822 regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
823 workingRegistryPath,
824 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
825 if (NS_SUCCEEDED(rv)) {
826 nsAutoString perceivedType;
827 rv = regKey->ReadStringValue(NS_LITERAL_STRING("PerceivedType"),
828 perceivedType);
829 if (NS_SUCCEEDED(rv)) {
830 nsAutoString openWithListPath(NS_LITERAL_STRING("SystemFileAssociations\\"));
831 openWithListPath.Append(perceivedType); // no period
832 openWithListPath.Append(NS_LITERAL_STRING("\\OpenWithList"));
834 nsresult rv = appKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
835 openWithListPath,
836 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
837 if (NS_SUCCEEDED(rv)) {
838 PRUint32 count = 0;
839 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
840 for (PRUint32 index = 0; index < count; index++) {
841 nsAutoString appName;
842 if (NS_FAILED(regKey->GetValueName(index, appName)))
843 continue;
845 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
846 nsAutoString appFilesystemCommand;
847 if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand,
848 PR_FALSE) ||
849 IsPathInList(appFilesystemCommand, trackList))
850 continue;
851 ProcessPath(appList, trackList, appFilesystemCommand);
857 } // extKnown == PR_FALSE
860 // 7) list global HKEY_CLASSES_ROOT\*\OpenWithList\
861 // Listing general purpose handlers, not specific to a mime type or file extension
863 workingRegistryPath = NS_LITERAL_STRING("*\\OpenWithList");
865 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
866 workingRegistryPath,
867 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
868 if (NS_SUCCEEDED(rv)) {
869 PRUint32 count = 0;
870 if (NS_SUCCEEDED(regKey->GetValueCount(&count)) && count > 0) {
871 for (PRUint32 index = 0; index < count; index++) {
872 nsAutoString appName;
873 if (NS_FAILED(regKey->GetValueName(index, appName)))
874 continue;
876 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
877 nsAutoString appFilesystemCommand;
878 if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand,
879 PR_FALSE) ||
880 IsPathInList(appFilesystemCommand, trackList))
881 continue;
882 ProcessPath(appList, trackList, appFilesystemCommand);
885 regKey->Close();
889 // 8) General application's list - not file extension specific on windows
890 workingRegistryPath = NS_LITERAL_STRING("Applications");
892 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
893 workingRegistryPath,
894 nsIWindowsRegKey::ACCESS_ENUMERATE_SUB_KEYS|
895 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
896 if (NS_SUCCEEDED(rv)) {
897 PRUint32 count = 0;
898 if (NS_SUCCEEDED(regKey->GetChildCount(&count)) && count > 0) {
899 for (PRUint32 index = 0; index < count; index++) {
900 nsAutoString appName;
901 if (NS_FAILED(regKey->GetChildName(index, appName)))
902 continue;
904 // HKEY_CLASSES_ROOT\Applications\firefox.exe = "path params"
905 nsAutoString appFilesystemCommand;
906 if (!GetAppsVerbCommandHandler(appName, appFilesystemCommand,
907 PR_FALSE) ||
908 IsPathInList(appFilesystemCommand, trackList))
909 continue;
910 ProcessPath(appList, trackList, appFilesystemCommand);
915 // Return to the caller
916 *_retval = appList;
917 NS_ADDREF(*_retval);
919 return NS_OK;