changeset 101206:3f0ac2f6febc

(main): Try using COM to create start menu shortcuts before resorting to DDE (Bug#202) Remove second command-line argument.
author Jason Rumney <jasonr@gnu.org>
date Thu, 15 Jan 2009 15:02:55 +0000
parents 46b81879fc09
children 0dbba2a00904
files nt/addpm.c
diffstat 1 files changed, 123 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/nt/addpm.c	Thu Jan 15 13:59:50 2009 +0000
+++ b/nt/addpm.c	Thu Jan 15 15:02:55 2009 +0000
@@ -23,10 +23,24 @@
  *
  * 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.
  */
 
+/* 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.  */
+#define _WIN32_IE 0x400
+/* Request C Object macros for COM interfaces.  */
+#define COBJMACROS 1
+
 #include <windows.h>
+#include <shlobj.h>
 #include <ddeml.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -41,7 +55,7 @@
 }
 
 #define DdeCommand(str) 	\
-	DdeClientTransaction (str, strlen (str)+1, HConversation, (HSZ)NULL, \
+	DdeClientTransaction (str, strlen (str)+1, conversation, (HSZ)NULL, \
 		              CF_TEXT, XTYP_EXECUTE, 30000, NULL)
 
 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
@@ -165,24 +179,18 @@
      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;
   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] == '-')
@@ -213,7 +221,7 @@
 	}
       else
 	{
-	  fprintf (stderr, "usage: addpm emacs_path [icon_path]\n");
+	  fprintf (stderr, "usage: addpm emacs_path\n");
 	  exit (1);
 	}
 
@@ -237,31 +245,115 @@
   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))
+	{
+	  BOOL retval;
 
-      DdeDisconnect (HConversation);
+	  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 (!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))
+	{
+	  BOOL retval;
+
+	  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);
+		  
+		}
+	    }
+	}      
+    }
 
-  DdeUninitialize (idDde);
+  if (com_available)
+    IShellLinkA_Release (shortcut);
+
+  /* Need to call uninitialize, even if ComInitialize failed.  */
+  CoUninitialize ();
+
+  /* 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];
 
-  return (0);
+      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);
+	}
+
+      DdeFreeStringHandle (dde, progman);
+      DdeUninitialize (dde);
+   }
+
+  return 0;
 }
 
 /* arch-tag: f923609d-b781-4ef4-abce-ca0da29cbbf0