diff --git a/appshell/appshell_extensions.cpp b/appshell/appshell_extensions.cpp index 55df11396..f249e7c8d 100644 --- a/appshell/appshell_extensions.cpp +++ b/appshell/appshell_extensions.cpp @@ -679,7 +679,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 24f5e2d9f..fb81ff99b 100644 --- a/appshell/appshell_extensions.js +++ b/appshell/appshell_extensions.js @@ -800,6 +800,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 439f5e38a..d457a93e9 100644 --- a/appshell/appshell_extensions_mac.mm +++ b/appshell/appshell_extensions_mac.mm @@ -1135,3 +1135,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 19fa1225c..06a8e20dd 100644 --- a/appshell/appshell_extensions_platform.h +++ b/appshell/appshell_extensions_platform.h @@ -142,3 +142,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 18141d02f..b8c77109f 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 @@ -1695,11 +1701,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()); +} 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