1 /* runemacs --- Simple program to start Emacs with its console window hidden.
3 Copyright (C) 2001-2012 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 Simple program to start Emacs with its console window hidden.
24 This program is provided purely for convenience, since most users will
25 use Emacs in windowing (GUI) mode, and will not want to have an extra
26 console window lying around. */
29 You may want to define this if you want to be able to install updated
30 emacs binaries even when other users are using the current version.
31 The problem with some file servers (notably Novell) is that an open
32 file cannot be overwritten, deleted, or even renamed. So if someone
33 is running emacs.exe already, you cannot install a newer version.
34 By defining CHOOSE_NEWEST_EXE, you can name your new emacs.exe
35 something else which matches "emacs*.exe", and runemacs will
36 automatically select the newest emacs executable in the bin directory.
37 (So you'll probably be able to delete the old version some hours/days
41 /* #define CHOOSE_NEWEST_EXE */
47 static void set_user_model_id (void);
48 static int ensure_unicows_dll (void);
51 WinMain (HINSTANCE hSelf
, HINSTANCE hPrev
, LPSTR cmdline
, int nShow
)
54 SECURITY_ATTRIBUTES sec_attrs
;
55 PROCESS_INFORMATION child
;
56 int wait_for_child
= FALSE
;
57 DWORD priority_class
= NORMAL_PRIORITY_CLASS
;
61 char modname
[MAX_PATH
];
63 if (!ensure_unicows_dll ())
68 if (!GetModuleFileName (NULL
, modname
, MAX_PATH
))
70 if ((p
= strrchr (modname
, '\\')) == NULL
)
74 new_cmdline
= alloca (MAX_PATH
+ strlen (cmdline
) + 3);
75 /* Quote executable name in case of spaces in the path. */
77 strcpy (new_cmdline
+ 1, modname
);
79 #ifdef CHOOSE_NEWEST_EXE
81 /* Silly hack to allow new versions to be installed on
82 server even when current version is in use. */
84 char * best_name
= alloca (MAX_PATH
+ 1);
85 FILETIME best_time
= {0,0};
88 p
= new_cmdline
+ strlen (new_cmdline
);
89 strcpy (p
, "\\emacs*.exe\" ");
90 fh
= FindFirstFile (new_cmdline
, &wfd
);
91 if (fh
== INVALID_HANDLE_VALUE
)
95 if (wfd
.ftLastWriteTime
.dwHighDateTime
> best_time
.dwHighDateTime
96 || (wfd
.ftLastWriteTime
.dwHighDateTime
== best_time
.dwHighDateTime
97 && wfd
.ftLastWriteTime
.dwLowDateTime
> best_time
.dwLowDateTime
))
99 best_time
= wfd
.ftLastWriteTime
;
100 strcpy (best_name
, wfd
.cFileName
);
103 while (FindNextFile (fh
, &wfd
));
106 strcpy (p
, best_name
);
110 strcat (new_cmdline
, "\\emacs.exe\" ");
113 /* Append original arguments if any; first look for arguments we
114 recognize (-wait, -high, and -low), and apply them ourselves. */
115 while (cmdline
[0] == '-' || cmdline
[0] == '/')
117 if (strncmp (cmdline
+1, "wait", 4) == 0)
119 wait_for_child
= TRUE
;
122 else if (strncmp (cmdline
+1, "high", 4) == 0)
124 priority_class
= HIGH_PRIORITY_CLASS
;
127 else if (strncmp (cmdline
+1, "low", 3) == 0)
129 priority_class
= IDLE_PRIORITY_CLASS
;
134 /* Look for next argument. */
135 while (*++cmdline
== ' ');
138 strcat (new_cmdline
, cmdline
);
140 /* Set emacs_dir variable if runemacs was in "%emacs_dir%\bin". */
141 if ((p
= strrchr (modname
, '\\')) && stricmp (p
, "\\bin") == 0)
144 for (p
= modname
; *p
; p
++)
145 if (*p
== '\\') *p
= '/';
146 SetEnvironmentVariable ("emacs_dir", modname
);
149 memset (&start
, 0, sizeof (start
));
150 start
.cb
= sizeof (start
);
151 start
.dwFlags
= STARTF_USESHOWWINDOW
| STARTF_USECOUNTCHARS
;
152 start
.wShowWindow
= SW_HIDE
;
153 /* Ensure that we don't waste memory if the user has specified a huge
154 default screen buffer for command windows. */
155 start
.dwXCountChars
= 80;
156 start
.dwYCountChars
= 25;
158 sec_attrs
.nLength
= sizeof (sec_attrs
);
159 sec_attrs
.lpSecurityDescriptor
= NULL
;
160 sec_attrs
.bInheritHandle
= FALSE
;
162 if (CreateProcess (NULL
, new_cmdline
, &sec_attrs
, NULL
, TRUE
, priority_class
,
163 NULL
, NULL
, &start
, &child
))
167 WaitForSingleObject (child
.hProcess
, INFINITE
);
168 GetExitCodeProcess (child
.hProcess
, &ret_code
);
170 CloseHandle (child
.hThread
);
171 CloseHandle (child
.hProcess
);
175 return (int) ret_code
;
178 MessageBox (NULL
, "Could not start Emacs.", "Error", MB_ICONSTOP
);
183 set_user_model_id (void)
186 HRESULT (WINAPI
* set_user_model
) (wchar_t * id
);
188 /* On Windows 7 and later, we need to set the user model ID
189 to associate emacsclient launched files with Emacs frames
191 shell
= LoadLibrary ("shell32.dll");
195 = (void *) GetProcAddress (shell
,
196 "SetCurrentProcessExplicitAppUserModelID");
198 /* If the function is defined, then we are running on Windows 7
199 or newer, and the UI uses this to group related windows
200 together. Since emacs, runemacs, emacsclient are related, we
201 want them grouped even though the executables are different,
202 so we need to set a consistent ID between them. */
204 set_user_model (L
"GNU.Emacs");
211 ensure_unicows_dll (void)
213 OSVERSIONINFO os_ver
;
216 ZeroMemory (&os_ver
, sizeof (OSVERSIONINFO
));
217 os_ver
.dwOSVersionInfoSize
= sizeof (OSVERSIONINFO
);
218 if (!GetVersionEx (&os_ver
))
221 if (os_ver
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
)
223 h
= LoadLibrary ("Unicows.dll");
228 button
= MessageBox (NULL
,
229 "Emacs cannot load the UNICOWS.DLL library.\n"
230 "This library is essential for using Emacs\n"
231 "on this system. You need to install it.\n\n"
232 "However, you can still use Emacs by invoking\n"
233 "it with the '-nw' command-line option.\n\n"
234 "Emacs will exit when you click OK.",
235 "Emacs cannot load UNICOWS.DLL",
236 MB_ICONERROR
| MB_TASKMODAL
237 | MB_SETFOREGROUND
| MB_OK
);