declare smobs in alloc.c
[bpt/emacs.git] / nt / runemacs.c
CommitLineData
95df8112
GM
1/* runemacs --- Simple program to start Emacs with its console window hidden.
2
ba318903 3Copyright (C) 2001-2014 Free Software Foundation, Inc.
b65d8176
TTN
4
5This file is part of GNU Emacs.
6
eef0be9e 7GNU Emacs is free software: you can redistribute it and/or modify
b65d8176 8it under the terms of the GNU General Public License as published by
eef0be9e
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
b65d8176
TTN
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
eef0be9e 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
b65d8176
TTN
19
20
c911543b
GV
21/*
22 Simple program to start Emacs with its console window hidden.
23
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. */
27
662463d9
RS
28/*
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
4da0d3f7 36 automatically select the newest emacs executable in the bin directory.
662463d9
RS
37 (So you'll probably be able to delete the old version some hours/days
38 later).
39*/
40
41/* #define CHOOSE_NEWEST_EXE */
42
c911543b
GV
43#include <windows.h>
44#include <string.h>
45#include <malloc.h>
46
361358ea 47static void set_user_model_id (void);
fc5f9b45 48static int ensure_unicows_dll (void);
ff90fbde 49
c911543b
GV
50int WINAPI
51WinMain (HINSTANCE hSelf, HINSTANCE hPrev, LPSTR cmdline, int nShow)
52{
53 STARTUPINFO start;
54 SECURITY_ATTRIBUTES sec_attrs;
c911543b
GV
55 PROCESS_INFORMATION child;
56 int wait_for_child = FALSE;
05c4be3c 57 DWORD priority_class = NORMAL_PRIORITY_CLASS;
c911543b 58 DWORD ret_code = 0;
662463d9
RS
59 char *new_cmdline;
60 char *p;
c911543b
GV
61 char modname[MAX_PATH];
62
fc5f9b45
EZ
63 if (!ensure_unicows_dll ())
64 goto error;
65
ff90fbde
JR
66 set_user_model_id ();
67
c911543b
GV
68 if (!GetModuleFileName (NULL, modname, MAX_PATH))
69 goto error;
70 if ((p = strrchr (modname, '\\')) == NULL)
71 goto error;
72 *p = 0;
73
0ac7bf6c
JR
74 new_cmdline = alloca (MAX_PATH + strlen (cmdline) + 3);
75 /* Quote executable name in case of spaces in the path. */
76 *new_cmdline = '"';
77 strcpy (new_cmdline + 1, modname);
3e2af348
EZ
78 /* Detect and handle un-installed runemacs.exe in nt/ subdirectory,
79 while emacs.exe is in src/. */
80 if ((p = strrchr (new_cmdline, '\\')) != NULL
81 && stricmp (p, "\\nt") == 0)
82 strcpy (p, "\\src");
c911543b 83
662463d9 84#ifdef CHOOSE_NEWEST_EXE
c911543b 85 {
662463d9
RS
86 /* Silly hack to allow new versions to be installed on
87 server even when current version is in use. */
88
89 char * best_name = alloca (MAX_PATH + 1);
90 FILETIME best_time = {0,0};
91 WIN32_FIND_DATA wfd;
92 HANDLE fh;
93 p = new_cmdline + strlen (new_cmdline);
0ac7bf6c 94 strcpy (p, "\\emacs*.exe\" ");
662463d9
RS
95 fh = FindFirstFile (new_cmdline, &wfd);
96 if (fh == INVALID_HANDLE_VALUE)
97 goto error;
98 do
99 {
4da0d3f7
JB
100 if (wfd.ftLastWriteTime.dwHighDateTime > best_time.dwHighDateTime
101 || (wfd.ftLastWriteTime.dwHighDateTime == best_time.dwHighDateTime
102 && wfd.ftLastWriteTime.dwLowDateTime > best_time.dwLowDateTime))
103 {
104 best_time = wfd.ftLastWriteTime;
105 strcpy (best_name, wfd.cFileName);
106 }
662463d9
RS
107 }
108 while (FindNextFile (fh, &wfd));
109 FindClose (fh);
110 *p++ = '\\';
111 strcpy (p, best_name);
112 strcat (p, " ");
c911543b 113 }
662463d9 114#else
0ac7bf6c 115 strcat (new_cmdline, "\\emacs.exe\" ");
662463d9
RS
116#endif
117
05c4be3c 118 /* Append original arguments if any; first look for arguments we
e1dbe924 119 recognize (-wait, -high, and -low), and apply them ourselves. */
05c4be3c 120 while (cmdline[0] == '-' || cmdline[0] == '/')
662463d9 121 {
05c4be3c
GV
122 if (strncmp (cmdline+1, "wait", 4) == 0)
123 {
4da0d3f7
JB
124 wait_for_child = TRUE;
125 cmdline += 5;
126 }
05c4be3c
GV
127 else if (strncmp (cmdline+1, "high", 4) == 0)
128 {
129 priority_class = HIGH_PRIORITY_CLASS;
130 cmdline += 5;
131 }
132 else if (strncmp (cmdline+1, "low", 3) == 0)
133 {
134 priority_class = IDLE_PRIORITY_CLASS;
135 cmdline += 4;
136 }
137 else
138 break;
4da0d3f7
JB
139 /* Look for next argument. */
140 while (*++cmdline == ' ');
05c4be3c 141 }
4da0d3f7 142
c911543b
GV
143 strcat (new_cmdline, cmdline);
144
662463d9 145 /* Set emacs_dir variable if runemacs was in "%emacs_dir%\bin". */
c911543b 146 if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
662463d9
RS
147 {
148 *p = 0;
149 for (p = modname; *p; p++)
150 if (*p == '\\') *p = '/';
151 SetEnvironmentVariable ("emacs_dir", modname);
152 }
c911543b
GV
153
154 memset (&start, 0, sizeof (start));
155 start.cb = sizeof (start);
3bb69bbd 156 start.dwFlags = STARTF_USESHOWWINDOW | STARTF_USECOUNTCHARS;
c911543b 157 start.wShowWindow = SW_HIDE;
3bb69bbd
JR
158 /* Ensure that we don't waste memory if the user has specified a huge
159 default screen buffer for command windows. */
160 start.dwXCountChars = 80;
161 start.dwYCountChars = 25;
c911543b
GV
162
163 sec_attrs.nLength = sizeof (sec_attrs);
164 sec_attrs.lpSecurityDescriptor = NULL;
165 sec_attrs.bInheritHandle = FALSE;
166
05c4be3c 167 if (CreateProcess (NULL, new_cmdline, &sec_attrs, NULL, TRUE, priority_class,
1e3c9713 168 NULL, NULL, &start, &child))
c911543b
GV
169 {
170 if (wait_for_child)
171 {
172 WaitForSingleObject (child.hProcess, INFINITE);
173 GetExitCodeProcess (child.hProcess, &ret_code);
174 }
175 CloseHandle (child.hThread);
176 CloseHandle (child.hProcess);
177 }
178 else
179 goto error;
180 return (int) ret_code;
181
182error:
183 MessageBox (NULL, "Could not start Emacs.", "Error", MB_ICONSTOP);
184 return 1;
185}
ab5796a9 186
7c3320d8
JB
187void
188set_user_model_id (void)
ff90fbde
JR
189{
190 HMODULE shell;
0a3472c7 191 HRESULT (WINAPI * set_user_model) (wchar_t * id);
ff90fbde
JR
192
193 /* On Windows 7 and later, we need to set the user model ID
194 to associate emacsclient launched files with Emacs frames
195 in the UI. */
196 shell = LoadLibrary ("shell32.dll");
197 if (shell)
198 {
199 set_user_model
200 = (void *) GetProcAddress (shell,
201 "SetCurrentProcessExplicitAppUserModelID");
202
203 /* If the function is defined, then we are running on Windows 7
204 or newer, and the UI uses this to group related windows
205 together. Since emacs, runemacs, emacsclient are related, we
206 want them grouped even though the executables are different,
207 so we need to set a consistent ID between them. */
208 if (set_user_model)
209 set_user_model (L"GNU.Emacs");
210
211 FreeLibrary (shell);
212 }
213}
214
fc5f9b45
EZ
215static int
216ensure_unicows_dll (void)
217{
218 OSVERSIONINFO os_ver;
219 HMODULE h;
220
221 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
222 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
223 if (!GetVersionEx (&os_ver))
224 return 0;
225
226 if (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
227 {
228 h = LoadLibrary ("Unicows.dll");
229 if (!h)
230 {
231 int button;
232
233 button = MessageBox (NULL,
234 "Emacs cannot load the UNICOWS.DLL library.\n"
235 "This library is essential for using Emacs\n"
236 "on this system. You need to install it.\n\n"
fc5f9b45
EZ
237 "Emacs will exit when you click OK.",
238 "Emacs cannot load UNICOWS.DLL",
239 MB_ICONERROR | MB_TASKMODAL
240 | MB_SETFOREGROUND | MB_OK);
241 switch (button)
242 {
243 case IDOK:
244 default:
245 return 0;
246 }
247 }
248 FreeLibrary (h);
249 return 1;
250 }
251 return 1;
252}