From eaba4ec6b6ee90688108b3a4ed1c9817b9e1c506 Mon Sep 17 00:00:00 2001 From: Bryan Chin Date: Wed, 21 Aug 2013 14:36:21 -0500 Subject: [PATCH] first-pass implementation of shell registration of file types --- appshell/appshell_extensions.cpp | 5 +- appshell/appshell_extensions.js | 8 ++ appshell/appshell_extensions_mac.mm | 5 + appshell/appshell_extensions_platform.h | 2 + appshell/appshell_extensions_win.cpp | 146 +++++++++++++++++++++++- appshell/config.h | 1 + 6 files changed, 164 insertions(+), 3 deletions(-) diff --git a/appshell/appshell_extensions.cpp b/appshell/appshell_extensions.cpp index cc16a9136..58ed7f5a8 100644 --- a/appshell/appshell_extensions.cpp +++ b/appshell/appshell_extensions.cpp @@ -661,7 +661,10 @@ class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate { } else if (message_name == "DragWindow") { // Parameters: none DragWindow(browser); - } + } else if (message_name == "RegisterAsDefaultEditorForCommonFileTypes") { + // Parameters - none + RegisterAsDefaultEditorForCommonFileTypes(); + } else { fprintf(stderr, "Native function not implemented yet: %s\n", message_name.c_str()); return false; diff --git a/appshell/appshell_extensions.js b/appshell/appshell_extensions.js index 8ca687080..63ee76deb 100644 --- a/appshell/appshell_extensions.js +++ b/appshell/appshell_extensions.js @@ -764,6 +764,14 @@ if (!appshell.app) { appshell.app.dragWindow = function () { DragWindow(); }; + + /** + * Registers application as the default program to open common web files + */ + native function RegisterAsDefaultEditorForCommonFileTypes(); + appshell.app.registerAsDefaultEditorForCommonFileTypes = function () { + RegisterAsDefaultEditorForCommonFileTypes(); + }; // Alias the appshell object to brackets. This is temporary and should be removed. brackets = appshell; diff --git a/appshell/appshell_extensions_mac.mm b/appshell/appshell_extensions_mac.mm index 6a9736515..003d4a666 100644 --- a/appshell/appshell_extensions_mac.mm +++ b/appshell/appshell_extensions_mac.mm @@ -1118,3 +1118,8 @@ void DragWindow(CefRefPtr browser) [win displayIfNeeded]; } } + +void RegisterAsDefaultEditorForCommonFileTypes() +{ + // not implemented +} diff --git a/appshell/appshell_extensions_platform.h b/appshell/appshell_extensions_platform.h index 4cbfcb78c..e42223445 100644 --- a/appshell/appshell_extensions_platform.h +++ b/appshell/appshell_extensions_platform.h @@ -140,3 +140,5 @@ int32 SetMenuItemShortcut(CefRefPtr browser, ExtensionString command int32 GetMenuPosition(CefRefPtr browser, const ExtensionString& commandId, ExtensionString& parentId, int& index); void DragWindow(CefRefPtr browser); + +void RegisterAsDefaultEditorForCommonFileTypes(); diff --git a/appshell/appshell_extensions_win.cpp b/appshell/appshell_extensions_win.cpp index 9ed454e50..ac98b85db 100644 --- a/appshell/appshell_extensions_win.cpp +++ b/appshell/appshell_extensions_win.cpp @@ -21,6 +21,11 @@ * */ +#ifndef OS_WIN +#define OS_WIN 1 +#endif + +#include "config.h" #include "appshell_extensions.h" #include "native_menu_model.h" #include "client_handler.h" @@ -34,6 +39,7 @@ #include #include #include +#include #define CLOSING_PROP L"CLOSING" #define UNICODE_MINUS 0x2212 @@ -1684,11 +1690,147 @@ int32 RemoveMenuItem(CefRefPtr browser, const ExtensionString& comma return NO_ERROR; } -void DragWindow(CefRefPtr browser) { +void DragWindow(CefRefPtr browser) +{ ReleaseCapture(); HWND browserHwnd = (HWND)getMenuParent(browser); SendMessage(browserHwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0); } - +// Explorer File Association Registry functions + +// returns the Registry Root string +static LPCWSTR GetProductRegistryRoot() +{ + static std::wstring wstrProductRegistryRoot; // cached Registry Root + if (wstrProductRegistryRoot.empty()) + { + wstrProductRegistryRoot = APP_NAME; // default + + HMODULE module = GetModuleHandle(NULL); + TCHAR executablePath[MAX_PATH+1] = {0}; + GetModuleFileName(module, executablePath, MAX_PATH); + + DWORD dwSize = GetFileVersionInfoSize(executablePath, NULL); + if (dwSize > 0) + { + BYTE *pVersionInfo = new BYTE[dwSize]; + if (::GetFileVersionInfo(executablePath, 0, dwSize, pVersionInfo)) + { + VS_FIXEDFILEINFO *pFileInfo = NULL; + UINT pLenFileInfo = 0; + if (VerQueryValue(pVersionInfo, TEXT("\\"), (LPVOID*) &pFileInfo, &pLenFileInfo)) + { + std::wostringstream versionStream(L""); + versionStream << ((pFileInfo->dwFileVersionMS) & 0xffff); + wstrProductRegistryRoot = APP_REGISTRY_ROOT_PREFIX; + wstrProductRegistryRoot += versionStream.str(); + } + delete[] pVersionInfo; + } + } + } + return (LPCWSTR)wstrProductRegistryRoot.c_str(); +} + +// returns the ProgId string +static LPCWSTR GetApplicationProgId() +{ + static std::wstring wstrApplicationProgId; // cached ProgId + if (wstrApplicationProgId.empty()) + { + //std::wstring wstrFileVer; + //GetFileVersionString(wstrFileVer, true); + //wstrApplicationProgId = APP_NAME L".Document." + wstrFileVer; + } + return (LPCWSTR)wstrApplicationProgId.c_str(); +} + +// register the application, version-specific Prog Id and Shell verbs +static bool RegisterProgIdKeys() +{ + bool result = false; + + ////; Define ProgID + ////[HKEY_CURRENT_USER\SOFTWARE\Classes\Brackets.Document.XX.YY] + ////@="Brackets Document" + //std::wstring wstr = L"SOFTWARE\\Classes\\"; + //wstr += GetApplicationProgId(); + //HKEY hKey; + //if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, wstr.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL)) + //{ + // wstr = APP_NAME L" Document"; // Prog ID short name + // RegSetValueEx(hKey, NULL, 0, REG_SZ, (LPBYTE)wstr.c_str(), (wstr.length() + 1) * sizeof (WCHAR)); + + // //[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Brackets.Document.XX.YY\Shell] + // //@="Open" + // HKEY hShellKey; + // if (ERROR_SUCCESS == RegCreateKeyEx(hKey, L"Shell", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hShellKey, NULL)) + // { + // wstr = L"Open"; + // RegSetValueEx(hShellKey, NULL, 0, REG_SZ, (LPBYTE)wstr.c_str(), (wstr.length() + 1) * sizeof(WCHAR)); + + // //[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Brackets.Document.XX.YY\Shell\Open\Command] + // //@="C:\\...\\Brackets.exe \"%1\"" + // HKEY hCmdKey; + // if (ERROR_SUCCESS == RegCreateKeyEx(hShellKey, L"Open\\Command", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hCmdKey, NULL)) + // { + // HMODULE module = GetModuleHandle(NULL); + // WCHAR executablePath[MAX_PATH+1] = {0}; + // GetModuleFileName(module, executablePath, MAX_PATH); + // wstr = executablePath; + // wstr += L" \"%1\""; + // RegSetValueEx(hCmdKey, NULL, 0, REG_SZ, (LPBYTE)wstr.c_str(), (wstr.length() + 1) * sizeof(WCHAR)); + + // RegCloseKey(hCmdKey); + // result = true; + // } + // RegCloseKey(hShellKey); + // } + // RegCloseKey(hKey); + //} + + return result; +} + +// register for Explorer "Open With..." menu or dialog for an given file extension +static bool RegisterOpenWithByExtensionKeys(LPCWSTR pFileExtension) +{ + bool result = false; + + //if (pFileExtension != NULL && wcslen(pFileExtension) > 0) + //{ + // std::wstring wstrKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"; + // wstrKey += pFileExtension; + // wstrKey += L"\\OpenWithProgids"; + + // //; Register with Open With... menu by Extension + // //[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.js\OpenWithProgids] + // HKEY hKey; + // if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, wstrKey.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL)) + // { + // if (ERROR_SUCCESS == RegSetValueEx(hKey, GetApplicationProgId(), 0, REG_SZ, NULL, 0)) + // result = true; + // RegCloseKey(hKey); + // } + //} + + return result; +} +void RegisterAsDefaultEditorForCommonFileTypes() +{ + // Register the top-level Prog Id + // note: on Win7 and above, will need admin access. + RegisterProgIdKeys(); + + // Register as default shell open for individual file extensions + static const std::wstring wstrExtensions[] = { + L".html", L".htm", + L".js", + L".css", + L"" // last entry + }; + for (int idx=0; !wstrExtensions[idx].empty(); ++idx) + RegisterOpenWithByExtensionKeys(wstrExtensions[idx].c_str()); +} \ No newline at end of file diff --git a/appshell/config.h b/appshell/config.h index e43c5f6f2..5dc58e657 100644 --- a/appshell/config.h +++ b/appshell/config.h @@ -30,6 +30,7 @@ // This must be an empty string (for no group), or a string that ends with "\\" #define GROUP_NAME L"" #define APP_NAME L"Brackets" +#define APP_REGISTRY_ROOT_PREFIX L"Brackets Sprint " #define WINDOW_TITLE APP_NAME // Paths for node resources are relative to the location of the appshell executable