/* Add entries to the GNU Emacs Program Manager folder.
- Copyright (C) 1995, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1995, 2001-2016 Free Software Foundation, Inc.
This file is part of GNU Emacs.
*
* Usage:
* argv[1] = install path for emacs
- * argv[2] = full path to icon for emacs (optional)
+ *
+ * argv[2] used to be an optional argument for setting the icon.
+ * But now Emacs has a professional looking icon of its own.
+ * If users really want to change it, they can go into the settings of
+ * the shortcut that is created and do it there.
*/
-#include <windows.h>
-#include <ddeml.h>
+/* Use parts of shell API that were introduced by the merge of IE4
+ into the desktop shell. If Windows 95 or NT4 users do not have IE4
+ installed, then the DDE fallback for creating icons the Windows 3.1
+ progman way will be used instead, but that is prone to lockups
+ caused by other applications not servicing their message queues. */
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
+/* MinGW64 barfs if _WIN32_IE is defined to anything below 0x500. */
+#ifndef MINGW_W64
+#define _WIN32_IE 0x400
+#endif
+/* Request C Object macros for COM interfaces. */
+#define COBJMACROS 1
+
+#include <windows.h>
+#include <shlobj.h>
+#include <ddeml.h>
+
+#ifndef OLD_PATHS
+#include "../src/epaths.h"
+#endif
+
HDDEDATA CALLBACK
DdeCallback (UINT uType, UINT uFmt, HCONV hconv,
HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
}
#define DdeCommand(str) \
- DdeClientTransaction (str, strlen (str)+1, HConversation, (HSZ)NULL, \
+ DdeClientTransaction ((LPBYTE)str, strlen (str)+1, conversation, (HSZ)NULL, \
CF_TEXT, XTYP_EXECUTE, 30000, NULL)
#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
-#define REG_GTK "SOFTWARE\\GTK\\2.0"
#define REG_APP_PATH \
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\emacs.exe"
static struct entry
{
- char *name;
- char *value;
+ const char *name;
+ const char *value;
}
env_vars[] =
{
+#ifdef OLD_PATHS
{"emacs_dir", NULL},
- {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp;%emacs_dir%/leim"},
+ {"EMACSLOADPATH", "%emacs_dir%/site-lisp;%emacs_dir%/../site-lisp;%emacs_dir%/lisp"},
{"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
{"EMACSDATA", "%emacs_dir%/etc"},
{"EMACSPATH", "%emacs_dir%/bin"},
/* {"INFOPATH", "%emacs_dir%/info"}, */
{"EMACSDOC", "%emacs_dir%/etc"},
{"TERM", "cmd"}
+#else /* !OLD_PATHS */
+ {"emacs_dir", NULL},
+ {"EMACSLOADPATH", PATH_SITELOADSEARCH ";" PATH_LOADSEARCH},
+ {"SHELL", PATH_EXEC "/cmdproxy.exe"},
+ {"EMACSDATA", PATH_DATA},
+ {"EMACSPATH", PATH_EXEC},
+ /* We no longer set INFOPATH because Info-default-directory-list
+ is then ignored. */
+ /* {"INFOPATH", "%emacs_dir%/info"}, */
+ {"EMACSDOC", PATH_DOC},
+ {"TERM", "cmd"}
+#endif
};
-BOOL
-add_registry (path)
- char *path;
+void
+add_registry (const char *path)
{
HKEY hrootkey = NULL;
int i;
- BOOL ok = TRUE;
- DWORD size;
/* Record the location of Emacs to the App Paths key if we have
sufficient permissions to do so. This helps Windows find emacs quickly
affect the general operation of other installations of Emacs, and we
are blindly overwriting the Start Menu entries already.
*/
- if (RegCreateKeyEx (HKEY_LOCAL_MACHINE, REG_APP_PATH, 0, "",
+ if (RegCreateKeyEx (HKEY_LOCAL_MACHINE, REG_APP_PATH, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
&hrootkey, NULL) == ERROR_SUCCESS)
{
int len;
char *emacs_path;
- HKEY gtk_key = NULL;
len = strlen (path) + 15; /* \bin\emacs.exe + terminator. */
emacs_path = (char *) alloca (len);
sprintf (emacs_path, "%s\\bin\\emacs.exe", path);
- RegSetValueEx (hrootkey, NULL, 0, REG_SZ, emacs_path, len);
-
- /* Look for a GTK installation. If found, add it to the library search
- path for Emacs so that the image libraries it provides are available
- to Emacs regardless of whether it is in the path or not. */
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_GTK, REG_OPTION_NON_VOLATILE,
- KEY_READ, >k_key) == ERROR_SUCCESS)
- {
- if (RegQueryValueEx (gtk_key, "DllPath", NULL, NULL,
- NULL, &size) == ERROR_SUCCESS)
- {
- char *gtk_path = (char *) alloca (size);
- if (RegQueryValueEx (gtk_key, "DllPath", NULL, NULL,
- gtk_path, &size) == ERROR_SUCCESS)
- {
- /* Make sure the emacs bin directory continues to be searched
- first by including it as well. */
- char *dll_paths;
- len = strlen (path) + 5 + size;
- dll_paths = (char *) alloca (size + strlen (path) + 1);
- sprintf (dll_paths, "%s\\bin;%s", path, gtk_path);
- RegSetValueEx (hrootkey, "Path", 0, REG_SZ, dll_paths, len);
- }
- }
- RegCloseKey (gtk_key);
- }
+ RegSetValueEx (hrootkey, NULL, 0, REG_EXPAND_SZ, emacs_path, len);
RegCloseKey (hrootkey);
}
/* Check both the current user and the local machine to see if we
have any resources. */
- if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT,
- REG_OPTION_NON_VOLATILE,
- KEY_WRITE, &hrootkey) != ERROR_SUCCESS
- && RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT,
- REG_OPTION_NON_VOLATILE,
- KEY_WRITE, &hrootkey) != ERROR_SUCCESS)
- {
- return FALSE;
- }
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0,
+ KEY_WRITE | KEY_QUERY_VALUE, &hrootkey) != ERROR_SUCCESS
+ && RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0,
+ KEY_WRITE | KEY_QUERY_VALUE, &hrootkey) != ERROR_SUCCESS)
+ return;
for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
{
- char * value = env_vars[i].value ? env_vars[i].value : path;
+ const char * value = env_vars[i].value ? env_vars[i].value : path;
- if (RegSetValueEx (hrootkey, env_vars[i].name,
- 0, REG_EXPAND_SZ,
- value, lstrlen (value) + 1) != ERROR_SUCCESS)
- ok = FALSE;
+ /* Replace only those settings that already exist. */
+ if (RegQueryValueEx (hrootkey, env_vars[i].name, NULL,
+ NULL, NULL, NULL) == ERROR_SUCCESS)
+ RegSetValueEx (hrootkey, env_vars[i].name, 0, REG_EXPAND_SZ,
+ value, lstrlen (value) + 1);
}
RegCloseKey (hrootkey);
-
- return (ok);
}
int
-main (argc, argv)
- int argc;
- char *argv[];
+main (int argc, char *argv[])
{
- DWORD idDde = 0;
- HCONV HConversation;
- HSZ ProgMan;
+ char start_folder[MAX_PATH + 1];
+ int shortcuts_created = 0;
+ int com_available = 1;
char modname[MAX_PATH];
- char additem[MAX_PATH*2 + 100];
- char *prog_name;
- char *emacs_path;
+ const char *prog_name;
+ const char *emacs_path;
char *p;
int quiet = 0;
+ HRESULT result;
+ IShellLinkA *shortcut;
/* If no args specified, use our location to set emacs_path. */
-#if 0
- if (argc < 2 || argc > 3)
- {
- fprintf (stderr, "usage: addpm [-q] [emacs_path [icon_path]]\n");
- exit (1);
- }
-#endif
if (argc > 1
&& (argv[1][0] == '/' || argv[1][0] == '-')
}
else
{
- fprintf (stderr, "usage: addpm emacs_path [icon_path]\n");
+ fprintf (stderr, "usage: addpm emacs_path\n");
exit (1);
}
MB_OKCANCEL | MB_ICONQUESTION);
if (result != IDOK)
{
- fprintf (stderr, "Install cancelled\n");
+ fprintf (stderr, "Install canceled\n");
exit (1);
}
}
add_registry (emacs_path);
prog_name = "runemacs.exe";
- DdeInitialize (&idDde, (PFNCALLBACK)DdeCallback, APPCMD_CLIENTONLY, 0);
+ /* Try to install globally. */
- ProgMan = DdeCreateStringHandle (idDde, "PROGMAN", CP_WINANSI);
+ if (!SUCCEEDED (CoInitialize (NULL))
+ || !SUCCEEDED (CoCreateInstance (&CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER, &IID_IShellLinkA,
+ (void **) &shortcut)))
+ {
+ com_available = 0;
+ }
- HConversation = DdeConnect (idDde, ProgMan, ProgMan, NULL);
- if (HConversation != 0)
+ if (com_available
+ && SHGetSpecialFolderPath (NULL, start_folder, CSIDL_COMMON_PROGRAMS, 0))
{
- DdeCommand ("[CreateGroup (\"Gnu Emacs\")]");
- DdeCommand ("[ReplaceItem (Emacs)]");
- if (argc > 2)
- sprintf (additem, "[AddItem (\"%s\\bin\\%s\", Emacs, \"%s\")]",
- emacs_path, prog_name, argv[2]);
- else
- sprintf (additem, "[AddItem (\"%s\\bin\\%s\", Emacs)]",
- emacs_path, prog_name);
- DdeCommand (additem);
+ if (strlen (start_folder) < (MAX_PATH - 20))
+ {
+ strcat (start_folder, "\\Gnu Emacs");
+ if (CreateDirectory (start_folder, NULL)
+ || GetLastError () == ERROR_ALREADY_EXISTS)
+ {
+ char full_emacs_path[MAX_PATH + 1];
+ IPersistFile *lnk;
+ strcat (start_folder, "\\Emacs.lnk");
+ sprintf (full_emacs_path, "%s\\bin\\%s", emacs_path, prog_name);
+ IShellLinkA_SetPath (shortcut, full_emacs_path);
+ IShellLinkA_SetDescription (shortcut, "GNU Emacs");
+ result = IShellLinkA_QueryInterface (shortcut, &IID_IPersistFile,
+ (void **) &lnk);
+ if (SUCCEEDED (result))
+ {
+ wchar_t unicode_path[MAX_PATH];
+ MultiByteToWideChar (CP_ACP, 0, start_folder, -1,
+ unicode_path, MAX_PATH);
+ if (SUCCEEDED (IPersistFile_Save (lnk, unicode_path, TRUE)))
+ shortcuts_created = 1;
+ IPersistFile_Release (lnk);
+ }
+ }
+ }
+ }
- DdeDisconnect (HConversation);
+ if (!shortcuts_created && com_available
+ && SHGetSpecialFolderPath (NULL, start_folder, CSIDL_PROGRAMS, 0))
+ {
+ /* Ensure there is enough room for "...\GNU Emacs\Emacs.lnk". */
+ if (strlen (start_folder) < (MAX_PATH - 20))
+ {
+ strcat (start_folder, "\\Gnu Emacs");
+ if (CreateDirectory (start_folder, NULL)
+ || GetLastError () == ERROR_ALREADY_EXISTS)
+ {
+ char full_emacs_path[MAX_PATH + 1];
+ IPersistFile *lnk;
+ strcat (start_folder, "\\Emacs.lnk");
+ sprintf (full_emacs_path, "%s\\bin\\%s", emacs_path, prog_name);
+ IShellLinkA_SetPath (shortcut, full_emacs_path);
+ IShellLinkA_SetDescription (shortcut, "GNU Emacs");
+ result = IShellLinkA_QueryInterface (shortcut, &IID_IPersistFile,
+ (void **) &lnk);
+ if (SUCCEEDED (result))
+ {
+ wchar_t unicode_path[MAX_PATH];
+ MultiByteToWideChar (CP_ACP, 0, start_folder, -1,
+ unicode_path, MAX_PATH);
+ if (SUCCEEDED (IPersistFile_Save (lnk, unicode_path, TRUE)))
+ shortcuts_created = 1;
+ IPersistFile_Release (lnk);
+
+ }
+ }
+ }
}
- DdeFreeStringHandle (idDde, ProgMan);
+ if (com_available)
+ IShellLinkA_Release (shortcut);
- DdeUninitialize (idDde);
+ /* Need to call uninitialize, even if ComInitialize failed. */
+ CoUninitialize ();
- return (0);
-}
+ /* Fallback on old DDE method if the above failed. */
+ if (!shortcuts_created)
+ {
+ DWORD dde = 0;
+ HCONV conversation;
+ HSZ progman;
+ char add_item[MAX_PATH*2 + 100];
+
+ DdeInitialize (&dde, (PFNCALLBACK) DdeCallback, APPCMD_CLIENTONLY, 0);
+ progman = DdeCreateStringHandle (dde, "PROGMAN", CP_WINANSI);
+ conversation = DdeConnect (dde, progman, progman, NULL);
+ if (conversation)
+ {
+ DdeCommand ("[CreateGroup (\"Gnu Emacs\")]");
+ DdeCommand ("[ReplaceItem (Emacs)]");
+ sprintf (add_item, "[AddItem (\"%s\\bin\\%s\", Emacs)]",
+ emacs_path, prog_name);
+ DdeCommand (add_item);
+
+ DdeDisconnect (conversation);
+ }
-/* arch-tag: f923609d-b781-4ef4-abce-ca0da29cbbf0
- (do not change this comment) */
+ DdeFreeStringHandle (dde, progman);
+ DdeUninitialize (dde);
+ }
+
+ return 0;
+}