/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim:set ts=2 sts=2 sw=2 et cin: * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
nsOSHelperAppService::~nsOSHelperAppService() { if (mAppAssoc) mAppAssoc->Release();
mAppAssoc = nullptr;
CoUninitialize();
}
// The windows registry provides a mime database key which lists a set of mime // types and corresponding "Extension" values. we can use this to look up our // mime type to see if there is a preferred extension for the mime type. static nsresult GetExtensionFromWindowsMimeDatabase(const nsACString& aMimeType,
nsString& aFileExtension) {
nsAutoString mimeDatabaseKey;
mimeDatabaseKey.AssignLiteral("MIME\\Database\\Content Type\\");
AppendASCIItoUTF16(aMimeType, mimeDatabaseKey);
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1"); if (!regKey) return NS_ERROR_NOT_AVAILABLE;
if (NS_SUCCEEDED(rv))
regKey->ReadStringValue(u"Extension"_ns, aFileExtension);
return NS_OK;
}
nsresult nsOSHelperAppService::OSProtocolHandlerExists( constchar* aProtocolScheme, bool* aHandlerExists) { // look up the protocol scheme in the windows registry....if we find a match // then we have a handler for it...
*aHandlerExists = false; if (aProtocolScheme && *aProtocolScheme) {
NS_ENSURE_TRUE(mAppAssoc, NS_ERROR_NOT_AVAILABLE); wchar_t* pResult = nullptr;
NS_ConvertASCIItoUTF16 scheme(aProtocolScheme); // We are responsible for freeing returned strings.
HRESULT hr = mAppAssoc->QueryCurrentDefault(scheme.get(), AT_URLPROTOCOL,
AL_EFFECTIVE, &pResult); if (SUCCEEDED(hr)) {
CoTaskMemFree(pResult);
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1"); if (!regKey) { return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
nsDependentString(scheme.get()),
nsIWindowsRegKey::ACCESS_QUERY_VALUE); if (NS_FAILED(rv)) { // Open will fail if the registry key path doesn't exist. return NS_OK;
}
bool hasValue;
rv = regKey->HasValue(u"URL Protocol"_ns, &hasValue); if (NS_FAILED(rv)) { return NS_ERROR_FAILURE;
} if (!hasValue) { return NS_OK;
}
// Find the progID wchar_t* pResult = nullptr;
HRESULT hr = mAppAssoc->QueryCurrentDefault(buf.get(), AT_URLPROTOCOL,
AL_EFFECTIVE, &pResult); if (FAILED(hr)) { return NS_ERROR_FAILURE;
}
nsAutoString progID(pResult); // We are responsible for freeing returned strings.
CoTaskMemFree(pResult);
// Find the default executable.
nsAutoString description;
nsCOMPtr<nsIFile> appFile;
nsresult rv = GetDefaultAppInfo(progID, description, getter_AddRefs(appFile)); if (NS_FAILED(rv)) { return rv;
} // Determine if the default executable is our executable.
nsCOMPtr<nsIFile> ourBinary;
XRE_GetBinaryPath(getter_AddRefs(ourBinary)); bool isSame = false;
rv = appFile->Equals(ourBinary, &isSame); if (NS_FAILED(rv)) { return rv;
}
*_retval = isSame; return NS_OK;
}
// GetMIMEInfoFromRegistry: This function obtains the values of some of the // nsIMIMEInfo attributes for the mimeType/extension associated with the input // registry key. The default entry for that key is the name of a registry key // under HKEY_CLASSES_ROOT. The default value for *that* key is the descriptive // name of the type. The EditFlags value is a binary value; the low order bit // of the third byte of which indicates that the user does not need to be // prompted. // // This function sets only the Description attribute of the input nsIMIMEInfo. /* static */
nsresult nsOSHelperAppService::GetMIMEInfoFromRegistry(const nsString& fileType,
nsIMIMEInfo* pInfo) {
nsresult rv = NS_OK;
NS_ENSURE_ARG(pInfo);
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1"); if (!regKey) return NS_ERROR_NOT_AVAILABLE;
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, fileType,
nsIWindowsRegKey::ACCESS_QUERY_VALUE); if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
// OK, the default value here is the description of the type.
nsAutoString description;
rv = regKey->ReadStringValue(u""_ns, description); if (NS_SUCCEEDED(rv)) pInfo->SetDescription(description);
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////////////////////// // method overrides used to gather information from the windows registry for // various mime types. ////////////////////////////////////////////////////////////////////////////////////////////////
/// Looks up the type for the extension aExt and compares it to aType /* static */ bool nsOSHelperAppService::typeFromExtEquals(const char16_t* aExt, constchar* aType) { if (!aType) returnfalse;
nsAutoString fileExtToUse; if (aExt[0] != char16_t('.')) fileExtToUse = char16_t('.');
// The "real" name of a given helper app (as specified by the path to the // executable file held in various registry keys) is stored n the VERSIONINFO // block in the file's resources. We need to find the path to the executable // and then retrieve the "FileDescription" field value from the file.
nsresult nsOSHelperAppService::GetDefaultAppInfo( const nsAString& aAppInfo, nsAString& aDefaultDescription,
nsIFile** aDefaultApplication) {
nsAutoString handlerCommand;
// If all else fails, use the file type key name, which will be // something like "pngfile" for .pngs, "WMVFile" for .wmvs, etc.
aDefaultDescription = aAppInfo;
*aDefaultApplication = nullptr;
if (aAppInfo.IsEmpty()) return NS_ERROR_FAILURE;
// aAppInfo may be a file, file path, program id, or // Applications reference - // c:\dir\app.exe // Applications\appfile.exe/dll (shell\open...) // ProgID.progid (shell\open...)
nsAutoString handlerKeyName(aAppInfo);
nsCOMPtr<nsIWindowsRegKey> chkKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1"); if (!chkKey) return NS_ERROR_FAILURE;
nsresult rv =
chkKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, handlerKeyName,
nsIWindowsRegKey::ACCESS_QUERY_VALUE); if (NS_FAILED(rv)) { // It's a file system path to a handler
handlerCommand.Assign(aAppInfo);
} else {
handlerKeyName.AppendLiteral("\\shell\\open\\command");
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1"); if (!regKey) return NS_ERROR_FAILURE;
nsresult rv =
regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, handlerKeyName,
nsIWindowsRegKey::ACCESS_QUERY_VALUE); if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
// OK, the default value here is the description of the type.
rv = regKey->ReadStringValue(u""_ns, handlerCommand); if (NS_FAILED(rv)) { // Check if there is a DelegateExecute string
nsAutoString delegateExecute;
rv = regKey->ReadStringValue(u"DelegateExecute"_ns, delegateExecute);
NS_ENSURE_SUCCESS(rv, rv);
// XXX FIXME: If this fails, the UI will display the full command // string. // There are some rare cases this can happen - ["url.dll" -foo] // for example won't resolve correctly to the system dir. The // subsequent launch of the helper app will work though.
nsCOMPtr<nsILocalFileWin> lf = new nsLocalFile();
rv = lf->InitWithCommandLine(handlerCommand);
NS_ENSURE_SUCCESS(rv, rv);
lf.forget(aDefaultApplication);
if (primaryExt.IsEmpty()) { return NS_ERROR_FAILURE;
}
// windows registry assumes your file extension is going to include the '.', // but our APIs don't have it, so add it:
nsAutoString assocType = NS_ConvertUTF8toUTF16(primaryExt); if (assocType.First() != char16_t('.')) {
assocType.Insert(char16_t('.'), 0);
}
nsAutoString appInfo; bool found;
// Retrieve the default application for this extension
NS_ENSURE_TRUE(mAppAssoc, NS_ERROR_NOT_AVAILABLE); wchar_t* pResult = nullptr;
HRESULT hr = mAppAssoc->QueryCurrentDefault(assocType.get(), AT_FILEEXTENSION,
AL_EFFECTIVE, &pResult); if (SUCCEEDED(hr)) {
found = true;
appInfo.Assign(pResult);
CoTaskMemFree(pResult);
} else {
found = false;
}
// Bug 358297 - ignore the default handler, force the user to choose app if (appInfo.EqualsLiteral("XPSViewer.Document")) found = false;
if (!found) { return NS_ERROR_NOT_AVAILABLE;
}
// Get other nsIMIMEInfo fields from registry, if possible.
nsAutoString defaultDescription;
nsCOMPtr<nsIFile> defaultApplication;
if (NS_FAILED(GetDefaultAppInfo(appInfo, defaultDescription,
getter_AddRefs(defaultApplication)))) { return NS_ERROR_NOT_AVAILABLE;
}
/* XXX The octet-stream check is a gross hack to wallpaper over the most * common Win32 extension issues caused by the fix for bug 116938. See bug * 120327, comment 271 for why this is needed. Not even sure we * want to remove this once we have fixed all this stuff to work * right; any info we get from the OS on this type is pretty much * useless....
*/ bool haveMeaningfulMimeType =
!aMIMEType.IsEmpty() &&
!aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM);
LOG("Extension lookup on '%S' with mimetype '%s'%s\n", fileExtension.getW(),
flatType.get(), haveMeaningfulMimeType ? " (treated as meaningful)" : "");
RefPtr<nsMIMEInfoWin> mi;
// We should have *something* to go on here.
nsAutoString extensionFromMimeType; if (haveMeaningfulMimeType) {
GetExtensionFromWindowsMimeDatabase(aMIMEType, extensionFromMimeType);
} if (fileExtension.IsEmpty() && extensionFromMimeType.IsEmpty()) { // Without an extension from the mimetype or the file, we can't // do anything here.
mi = new nsMIMEInfoWin(flatType.get());
mi.forget(aMIMEInfo); return NS_OK;
}
// Either fileExtension or extensionFromMimeType must now be non-empty.
*aFound = true;
// On Windows, we prefer the file extension for lookups over the mimetype, // because that's how windows does things. // If we have no file extension or it doesn't match the mimetype, use the // mime type's default file extension instead. bool usedMimeTypeExtensionForLookup = false; if (fileExtension.IsEmpty() ||
(!extensionFromMimeType.IsEmpty() &&
!typeFromExtEquals(fileExtension.get(), flatType.get()))) {
usedMimeTypeExtensionForLookup = true;
fileExtension = extensionFromMimeType;
LOG("Now using '%s' mimetype's default file extension '%S' for lookup\n",
flatType.get(), fileExtension.getW());
}
// If we have an extension, use it for lookup:
mi = GetByExtension(fileExtension, flatType.get());
LOG("Extension lookup on '%S' found: 0x%p\n", fileExtension.getW(), mi.get());
if (mi) { bool hasDefault = false;
mi->GetHasDefaultHandler(&hasDefault); // If we don't find a default handler description, see if we can find one // using the mimetype. if (!hasDefault && !usedMimeTypeExtensionForLookup) {
RefPtr<nsMIMEInfoWin> miFromMimeType =
GetByExtension(extensionFromMimeType, flatType.get());
LOG("Mime-based ext. lookup for '%S' found 0x%p\n",
extensionFromMimeType.getW(), miFromMimeType.get()); if (miFromMimeType) {
nsAutoString desc;
miFromMimeType->GetDefaultDescription(desc);
mi->SetDefaultDescription(desc);
}
}
mi.forget(aMIMEInfo); return NS_OK;
}
// The extension didn't work. Try the extension from the mimetype if // different: if (!extensionFromMimeType.IsEmpty() && !usedMimeTypeExtensionForLookup) {
mi = GetByExtension(extensionFromMimeType, flatType.get());
LOG("Mime-based ext. lookup for '%S' found 0x%p\n",
extensionFromMimeType.getW(), mi.get());
} if (mi) {
mi.forget(aMIMEInfo); return NS_OK;
} // This didn't work either, so just return an empty dummy mimeinfo.
*aFound = false;
mi = new nsMIMEInfoWin(flatType.get()); // If we didn't resort to the mime type's extension, we must have had a // valid extension, so stick its lowercase version on the mime info. if (!usedMimeTypeExtensionForLookup) {
nsAutoCString lowerFileExt;
ToLowerCase(aFileExt, lowerFileExt);
mi->AppendExtension(lowerFileExt);
}
mi.forget(aMIMEInfo); return NS_OK;
}
// windows registry assumes your file extension is going to include the '.'. // so make sure it's there...
nsAutoString fileExtToUse; if (aExtension.First() != '.') fileExtToUse = char16_t('.');
AppendUTF8toUTF16(aExtension, fileExtToUse);
// Try to get an entry from the windows registry.
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1"); if (!regKey) returnfalse;
nsresult rv =
regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT, fileExtToUse,
nsIWindowsRegKey::ACCESS_QUERY_VALUE); if (NS_FAILED(rv)) returnfalse;
nsAutoString mimeType; if (NS_FAILED(regKey->ReadStringValue(u"Content Type"_ns, mimeType)) ||
mimeType.IsEmpty()) { returnfalse;
} // Content-Type is always in ASCII
aMIMEType.Truncate();
LossyAppendUTF16toASCII(mimeType, aMIMEType); returntrue;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.