static bool WriteUninstallerRegistryInfo(HKEY hkey) { bool success = true; ScopedMem<WCHAR> uninstallerPath(GetUninstallerPath()); ScopedMem<WCHAR> installedExePath(GetInstalledExePath()); ScopedMem<WCHAR> installDate(GetInstallDate()); ScopedMem<WCHAR> installDir(path::GetDir(installedExePath)); success &= WriteRegStr(hkey, REG_PATH_UNINST, DISPLAY_ICON, installedExePath); success &= WriteRegStr(hkey, REG_PATH_UNINST, DISPLAY_NAME, TAPP); success &= WriteRegStr(hkey, REG_PATH_UNINST, DISPLAY_VERSION, CURR_VERSION_STR); // Windows XP doesn't allow to view the version number at a glance, // so include it in the DisplayName if (!IsVistaOrGreater()) success &= WriteRegStr(hkey, REG_PATH_UNINST, DISPLAY_NAME, TAPP L" " CURR_VERSION_STR); DWORD size = GetDirSize(gGlobalData.installDir) / 1024; success &= WriteRegDWORD(hkey, REG_PATH_UNINST, ESTIMATED_SIZE, size); success &= WriteRegStr(hkey, REG_PATH_UNINST, INSTALL_DATE, installDate); success &= WriteRegStr(hkey, REG_PATH_UNINST, INSTALL_LOCATION, installDir); success &= WriteRegDWORD(hkey, REG_PATH_UNINST, NO_MODIFY, 1); success &= WriteRegDWORD(hkey, REG_PATH_UNINST, NO_REPAIR, 1); success &= WriteRegStr(hkey, REG_PATH_UNINST, PUBLISHER, TEXT(PUBLISHER_STR)); success &= WriteRegStr(hkey, REG_PATH_UNINST, UNINSTALL_STRING, uninstallerPath); success &= WriteRegStr(hkey, REG_PATH_UNINST, URL_INFO_ABOUT, L"http://blog.kowalczyk.info/software/sumatrapdf/"); success &= WriteRegStr(hkey, REG_PATH_UNINST, URL_UPDATE_INFO, L"http://blog.kowalczyk.info/software/sumatrapdf/news.html"); return success; }
static bool WriteUninstallerRegistryInfo(HKEY hkey) { bool ok = true; ScopedMem<WCHAR> installedExePath(GetInstalledExePath()); ScopedMem<WCHAR> installDate(GetInstallDate()); ScopedMem<WCHAR> installDir(path::GetDir(installedExePath)); ScopedMem<WCHAR> uninstallCmdLine(str::Format(L"\"%s\"", ScopedMem<WCHAR>(GetUninstallerPath()))); ok &= WriteRegStr(hkey, REG_PATH_UNINST, DISPLAY_ICON, installedExePath); ok &= WriteRegStr(hkey, REG_PATH_UNINST, DISPLAY_NAME, APP_NAME_STR); ok &= WriteRegStr(hkey, REG_PATH_UNINST, DISPLAY_VERSION, CURR_VERSION_STR); // Windows XP doesn't allow to view the version number at a glance, // so include it in the DisplayName if (!IsVistaOrGreater()) ok &= WriteRegStr(hkey, REG_PATH_UNINST, DISPLAY_NAME, APP_NAME_STR L" " CURR_VERSION_STR); DWORD size = GetDirSize(gGlobalData.installDir) / 1024; ok &= WriteRegDWORD(hkey, REG_PATH_UNINST, ESTIMATED_SIZE, size); ok &= WriteRegStr(hkey, REG_PATH_UNINST, INSTALL_DATE, installDate); ok &= WriteRegStr(hkey, REG_PATH_UNINST, INSTALL_LOCATION, installDir); ok &= WriteRegDWORD(hkey, REG_PATH_UNINST, NO_MODIFY, 1); ok &= WriteRegDWORD(hkey, REG_PATH_UNINST, NO_REPAIR, 1); ok &= WriteRegStr(hkey, REG_PATH_UNINST, PUBLISHER, TEXT(PUBLISHER_STR)); ok &= WriteRegStr(hkey, REG_PATH_UNINST, UNINSTALL_STRING, uninstallCmdLine); ok &= WriteRegStr(hkey, REG_PATH_UNINST, URL_INFO_ABOUT, L"http://www.sumatrapdfreader.org/"); ok &= WriteRegStr(hkey, REG_PATH_UNINST, URL_UPDATE_INFO, L"http://www.sumatrapdfreader.org/news.html"); return ok; }
/* Undo what DoAssociateExeWithPdfExtension() in AppTools.cpp did */ static void UnregisterFromBeingDefaultViewer(HKEY hkey) { ScopedMem<WCHAR> curr(ReadRegStr(hkey, REG_CLASSES_PDF, NULL)); ScopedMem<WCHAR> prev(ReadRegStr(hkey, REG_CLASSES_APP, L"previous.pdf")); if (!curr || !str::Eq(curr, TAPP)) { // not the default, do nothing } else if (prev) { WriteRegStr(hkey, REG_CLASSES_PDF, NULL, prev); } else { SHDeleteValue(hkey, REG_CLASSES_PDF, NULL); } // the following settings overrule HKEY_CLASSES_ROOT\.pdf ScopedMem<WCHAR> buf(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, PROG_ID)); if (str::Eq(buf, TAPP)) { LONG res = SHDeleteValue(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, PROG_ID); if (res != ERROR_SUCCESS) LogLastError(res); } buf.Set(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, APPLICATION)); if (str::EqI(buf, EXENAME)) { LONG res = SHDeleteValue(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, APPLICATION); if (res != ERROR_SUCCESS) LogLastError(res); } buf.Set(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT L"\\UserChoice", PROG_ID)); if (str::Eq(buf, TAPP)) DeleteRegKey(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT L"\\UserChoice", true); }
/* Undo what DoAssociateExeWithPdfExtension() in AppTools.cpp did */ static void UnregisterFromBeingDefaultViewer(HKEY hkey) { ScopedMem<WCHAR> curr(ReadRegStr(hkey, REG_CLASSES_PDF, nullptr)); ScopedMem<WCHAR> prev(ReadRegStr(hkey, REG_CLASSES_APP, L"previous.pdf")); if (!curr || !str::Eq(curr, APP_NAME_STR)) { // not the default, do nothing } else if (prev) { WriteRegStr(hkey, REG_CLASSES_PDF, nullptr, prev); } else { #pragma warning(push) #pragma warning(disable : 6387) // silence /analyze: '_Param_(3)' could be '0': this does not adhere to the specification for the function 'SHDeleteValueW' SHDeleteValue(hkey, REG_CLASSES_PDF, nullptr); #pragma warning(pop) } // the following settings overrule HKEY_CLASSES_ROOT\.pdf ScopedMem<WCHAR> buf(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, PROG_ID)); if (str::Eq(buf, APP_NAME_STR)) { LONG res = SHDeleteValue(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, PROG_ID); if (res != ERROR_SUCCESS) LogLastError(res); } buf.Set(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, APPLICATION)); if (str::EqI(buf, EXENAME)) { LONG res = SHDeleteValue(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT, APPLICATION); if (res != ERROR_SUCCESS) LogLastError(res); } buf.Set(ReadRegStr(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT L"\\UserChoice", PROG_ID)); if (str::Eq(buf, APP_NAME_STR)) DeleteRegKey(HKEY_CURRENT_USER, REG_EXPLORER_PDF_EXT L"\\UserChoice", true); }
// cf. http://msdn.microsoft.com/en-us/library/cc144148(v=vs.85).aspx static bool WriteExtendedFileExtensionInfo(HKEY hkey) { bool success = true; ScopedMem<WCHAR> exePath(GetInstalledExePath()); if (HKEY_LOCAL_MACHINE == hkey) success &= WriteRegStr(hkey, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" EXENAME, NULL, exePath); // mirroring some of what DoAssociateExeWithPdfExtension() does (cf. AppTools.cpp) ScopedMem<WCHAR> iconPath(str::Join(exePath, L",1")); success &= WriteRegStr(hkey, REG_CLASSES_APPS L"\\DefaultIcon", NULL, iconPath); ScopedMem<WCHAR> cmdPath(str::Format(L"\"%s\" \"%%1\" %%*", exePath)); success &= WriteRegStr(hkey, REG_CLASSES_APPS L"\\Shell\\Open\\Command", NULL, cmdPath); ScopedMem<WCHAR> printPath(str::Format(L"\"%s\" -print-to-default \"%%1\"", exePath)); success &= WriteRegStr(hkey, REG_CLASSES_APPS L"\\Shell\\Print\\Command", NULL, printPath); ScopedMem<WCHAR> printToPath(str::Format(L"\"%s\" -print-to \"%%2\" \"%%1\"", exePath)); success &= WriteRegStr(hkey, REG_CLASSES_APPS L"\\Shell\\PrintTo\\Command", NULL, printToPath); // don't add REG_CLASSES_APPS L"\\SupportedTypes", as that prevents SumatraPDF.exe to // potentially appear in the Open With lists for other filetypes (such as single images) // add the installed SumatraPDF.exe to the Open With lists of the supported file extensions for (int i = 0; NULL != gSupportedExts[i]; i++) { ScopedMem<WCHAR> keyname(str::Join(L"Software\\Classes\\", gSupportedExts[i], L"\\OpenWithList\\" EXENAME)); success &= CreateRegKey(hkey, keyname); // TODO: stop removing this after version 1.8 (was wrongly created for version 1.6) keyname.Set(str::Join(L"Software\\Classes\\", gSupportedExts[i], L"\\OpenWithList\\" APP_NAME_STR)); DeleteRegKey(hkey, keyname); } // in case these values don't exist yet (we won't delete these at uninstallation) success &= WriteRegStr(hkey, REG_CLASSES_PDF, L"Content Type", L"application/pdf"); success &= WriteRegStr(hkey, L"Software\\Classes\\MIME\\Database\\Content Type\\application/pdf", L"Extension", L".pdf"); return success; }
void DoAssociateExeWithPdfExtension(HKEY hkey) { ScopedMem<WCHAR> exePath(GetExePath()); if (!exePath) return; ScopedMem<WCHAR> prevHandler(nullptr); // Remember the previous default app for the Uninstaller prevHandler.Set(ReadRegStr(hkey, REG_CLASSES_PDF, nullptr)); if (prevHandler && !str::Eq(prevHandler, APP_NAME_STR)) WriteRegStr(hkey, REG_CLASSES_APP, L"previous.pdf", prevHandler); WriteRegStr(hkey, REG_CLASSES_APP, nullptr, _TR("PDF Document")); WCHAR *icon_path = str::Join(exePath, L",1"); WriteRegStr(hkey, REG_CLASSES_APP L"\\DefaultIcon", nullptr, icon_path); free(icon_path); WriteRegStr(hkey, REG_CLASSES_APP L"\\shell", nullptr, L"open"); ScopedMem<WCHAR> cmdPath(str::Format(L"\"%s\" \"%%1\" %%*", exePath.Get())); // "${exePath}" "%1" %* bool ok = WriteRegStr(hkey, REG_CLASSES_APP L"\\shell\\open\\command", nullptr, cmdPath); // also register for printing cmdPath.Set(str::Format(L"\"%s\" -print-to-default \"%%1\"", exePath.Get())); // "${exePath}" -print-to-default "%1" WriteRegStr(hkey, REG_CLASSES_APP L"\\shell\\print\\command", nullptr, cmdPath); // also register for printing to specific printer cmdPath.Set(str::Format(L"\"%s\" -print-to \"%%2\" \"%%1\"", exePath.Get())); // "${exePath}" -print-to "%2" "%1" WriteRegStr(hkey, REG_CLASSES_APP L"\\shell\\printto\\command", nullptr, cmdPath); // Only change the association if we're confident, that we've registered ourselves well enough if (!ok) return; WriteRegStr(hkey, REG_CLASSES_PDF, nullptr, APP_NAME_STR); // TODO: also add SumatraPDF to the Open With lists for the other supported extensions? WriteRegStr(hkey, REG_CLASSES_PDF L"\\OpenWithProgids", APP_NAME_STR, L""); if (hkey == HKEY_CURRENT_USER) { WriteRegStr(hkey, REG_EXPLORER_PDF_EXT, L"Progid", APP_NAME_STR); CrashIf(hkey == 0); // to appease prefast SHDeleteValue(hkey, REG_EXPLORER_PDF_EXT, L"Application"); DeleteRegKey(hkey, REG_EXPLORER_PDF_EXT L"\\UserChoice", true); } }
// cf. http://msdn.microsoft.com/en-us/library/cc144148(v=vs.85).aspx static bool WriteExtendedFileExtensionInfo(HKEY hkey) { bool ok = true; ScopedMem<WCHAR> exePath(GetInstalledExePath()); if (HKEY_LOCAL_MACHINE == hkey) ok &= WriteRegStr(hkey, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" EXENAME, nullptr, exePath); // mirroring some of what DoAssociateExeWithPdfExtension() does (cf. AppTools.cpp) ScopedMem<WCHAR> iconPath(str::Join(exePath, L",1")); ok &= WriteRegStr(hkey, REG_CLASSES_APPS L"\\DefaultIcon", nullptr, iconPath); ScopedMem<WCHAR> cmdPath(str::Format(L"\"%s\" \"%%1\" %%*", exePath)); ok &= WriteRegStr(hkey, REG_CLASSES_APPS L"\\Shell\\Open\\Command", nullptr, cmdPath); ScopedMem<WCHAR> printPath(str::Format(L"\"%s\" -print-to-default \"%%1\"", exePath)); ok &= WriteRegStr(hkey, REG_CLASSES_APPS L"\\Shell\\Print\\Command", nullptr, printPath); ScopedMem<WCHAR> printToPath(str::Format(L"\"%s\" -print-to \"%%2\" \"%%1\"", exePath)); ok &= WriteRegStr(hkey, REG_CLASSES_APPS L"\\Shell\\PrintTo\\Command", nullptr, printToPath); // don't add REG_CLASSES_APPS L"\\SupportedTypes", as that prevents SumatraPDF.exe to // potentially appear in the Open With lists for other filetypes (such as single images) // add the installed SumatraPDF.exe to the Open With lists of the supported file extensions // TODO: per http://msdn.microsoft.com/en-us/library/cc144148(v=vs.85).aspx we shouldn't be // using OpenWithList but OpenWithProgIds. Also, it doesn't seem to work on my win7 32bit // (HKLM\Software\Classes\.mobi\OpenWithList\SumatraPDF.exe key is present but "Open With" // menu item doesn't even exist for .mobi files // It's not so easy, though, because if we just set it to SumatraPDF, // all gSupportedExts will be reported as "PDF Document" by Explorer, so this needs // to be more intelligent. We should probably mimic Windows Media Player scheme i.e. // set OpenWithProgIds to SumatraPDF.AssocFile.Mobi etc. and create apropriate // \SOFTWARE\Classes\CLSID\{GUID}\ProgID etc. entries // Also, if Sumatra is the only program handling those docs, our // PDF icon will be shown (we need icons and properly configure them) for (int i = 0; nullptr != gSupportedExts[i]; i++) { ScopedMem<WCHAR> keyname(str::Join(L"Software\\Classes\\", gSupportedExts[i], L"\\OpenWithList\\" EXENAME)); ok &= CreateRegKey(hkey, keyname); } // in case these values don't exist yet (we won't delete these at uninstallation) ok &= WriteRegStr(hkey, REG_CLASSES_PDF, L"Content Type", L"application/pdf"); ok &= WriteRegStr(hkey, L"Software\\Classes\\MIME\\Database\\Content Type\\application/pdf", L"Extension", L".pdf"); return ok; }
DLLEXPORT STDAPI DllRegisterServer(VOID) { if (!EnsureRegKey(g_lpRegKey)) return E_UNEXPECTED; WCHAR szPath[MAX_PATH]; GetModuleFileName(g_hInstance, szPath, MAX_PATH); if (!SetRegValue(g_lpRegKey, L"Description", L"SumatraPDF Browser Plugin") || !SetRegValue(g_lpRegKey, L"Path", szPath) || !SetRegValue(g_lpRegKey, L"Version", L"0") || !SetRegValue(g_lpRegKey, L"ProductName", L"SumatraPDF Browser Plugin")) { return E_UNEXPECTED; } ScopedMem<WCHAR> mimeType(str::Join(g_lpRegKey, L"\\MimeTypes\\application/pdf")); EnsureRegKey(mimeType); mimeType.Set(str::Join(g_lpRegKey, L"\\MimeTypes\\application/vnd.ms-xpsdocument")); EnsureRegKey(mimeType); mimeType.Set(str::Join(g_lpRegKey, L"\\MimeTypes\\application/oxps")); EnsureRegKey(mimeType); mimeType.Set(str::Join(g_lpRegKey, L"\\MimeTypes\\image/vnd.djvu")); EnsureRegKey(mimeType); mimeType.Set(str::Join(g_lpRegKey, L"\\MimeTypes\\image/x-djvu")); EnsureRegKey(mimeType); mimeType.Set(str::Join(g_lpRegKey, L"\\MimeTypes\\image/x.djvu")); EnsureRegKey(mimeType); // Work around Mozilla bug https://bugzilla.mozilla.org/show_bug.cgi?id=581848 which // makes Firefox up to version 3.6.* ignore all but the first plugin for a given MIME type // (per http://code.google.com/p/sumatrapdf/issues/detail?id=1254#c12 Foxit does the same) *(WCHAR *)path::GetBaseName(szPath) = '\0'; if (SHGetValue(HKEY_CURRENT_USER, L"Environment", L"MOZ_PLUGIN_PATH", NULL, NULL, NULL) == ERROR_FILE_NOT_FOUND) { WriteRegStr(HKEY_CURRENT_USER, L"Environment", L"MOZ_PLUGIN_PATH", szPath); SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)L"Environment", SMTO_ABORTIFHUNG, 5000, NULL); } return S_OK; }
bool SetRegValue(const WCHAR *lpKey, const WCHAR *lpName, const WCHAR *lpValue) { WriteRegStr(HKEY_LOCAL_MACHINE, lpKey, lpName, lpValue); return WriteRegStr(HKEY_CURRENT_USER, lpKey, lpName, lpValue); }
bool SetRegValue(LPCTSTR lpKey, LPCTSTR lpName, LPCTSTR lpValue) { WriteRegStr(HKEY_LOCAL_MACHINE, lpKey, lpName, lpValue); return WriteRegStr(HKEY_CURRENT_USER, lpKey, lpName, lpValue); }