Define SIZE_MAX for MSVC, part of bug #14409.
[bpt/emacs.git] / nt / runemacs.c
CommitLineData
95df8112
GM
1/* runemacs --- Simple program to start Emacs with its console window hidden.
2
ab422c4d 3Copyright (C) 2001-2013 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);
c911543b 78
662463d9 79#ifdef CHOOSE_NEWEST_EXE
c911543b 80 {
662463d9
RS
81 /* Silly hack to allow new versions to be installed on
82 server even when current version is in use. */
83
84 char * best_name = alloca (MAX_PATH + 1);
85 FILETIME best_time = {0,0};
86 WIN32_FIND_DATA wfd;
87 HANDLE fh;
88 p = new_cmdline + strlen (new_cmdline);
0ac7bf6c 89 strcpy (p, "\\emacs*.exe\" ");
662463d9
RS
90 fh = FindFirstFile (new_cmdline, &wfd);
91 if (fh == INVALID_HANDLE_VALUE)
92 goto error;
93 do
94 {
4da0d3f7
JB
95 if (wfd.ftLastWriteTime.dwHighDateTime > best_time.dwHighDateTime
96 || (wfd.ftLastWriteTime.dwHighDateTime == best_time.dwHighDateTime
97 && wfd.ftLastWriteTime.dwLowDateTime > best_time.dwLowDateTime))
98 {
99 best_time = wfd.ftLastWriteTime;
100 strcpy (best_name, wfd.cFileName);
101 }
662463d9
RS
102 }
103 while (FindNextFile (fh, &wfd));
104 FindClose (fh);
105 *p++ = '\\';
106 strcpy (p, best_name);
107 strcat (p, " ");
c911543b 108 }
662463d9 109#else
0ac7bf6c 110 strcat (new_cmdline, "\\emacs.exe\" ");
662463d9
RS
111#endif
112
05c4be3c 113 /* Append original arguments if any; first look for arguments we
e1dbe924 114 recognize (-wait, -high, and -low), and apply them ourselves. */
05c4be3c 115 while (cmdline[0] == '-' || cmdline[0] == '/')
662463d9 116 {
05c4be3c
GV
117 if (strncmp (cmdline+1, "wait", 4) == 0)
118 {
4da0d3f7
JB
119 wait_for_child = TRUE;
120 cmdline += 5;
121 }
05c4be3c
GV
122 else if (strncmp (cmdline+1, "high", 4) == 0)
123 {
124 priority_class = HIGH_PRIORITY_CLASS;
125 cmdline += 5;
126 }
127 else if (strncmp (cmdline+1, "low", 3) == 0)
128 {
129 priority_class = IDLE_PRIORITY_CLASS;
130 cmdline += 4;
131 }
132 else
133 break;
4da0d3f7
JB
134 /* Look for next argument. */
135 while (*++cmdline == ' ');
05c4be3c 136 }
4da0d3f7 137
c911543b
GV
138 strcat (new_cmdline, cmdline);
139
662463d9 140 /* Set emacs_dir variable if runemacs was in "%emacs_dir%\bin". */
c911543b 141 if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
662463d9
RS
142 {
143 *p = 0;
144 for (p = modname; *p; p++)
145 if (*p == '\\') *p = '/';
146 SetEnvironmentVariable ("emacs_dir", modname);
147 }
c911543b
GV
148
149 memset (&start, 0, sizeof (start));
150 start.cb = sizeof (start);
3bb69bbd 151 start.dwFlags = STARTF_USESHOWWINDOW | STARTF_USECOUNTCHARS;
c911543b 152 start.wShowWindow = SW_HIDE;
3bb69bbd
JR
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;
c911543b
GV
157
158 sec_attrs.nLength = sizeof (sec_attrs);
159 sec_attrs.lpSecurityDescriptor = NULL;
160 sec_attrs.bInheritHandle = FALSE;
161
05c4be3c 162 if (CreateProcess (NULL, new_cmdline, &sec_attrs, NULL, TRUE, priority_class,
1e3c9713 163 NULL, NULL, &start, &child))
c911543b
GV
164 {
165 if (wait_for_child)
166 {
167 WaitForSingleObject (child.hProcess, INFINITE);
168 GetExitCodeProcess (child.hProcess, &ret_code);
169 }
170 CloseHandle (child.hThread);
171 CloseHandle (child.hProcess);
172 }
173 else
174 goto error;
175 return (int) ret_code;
176
177error:
178 MessageBox (NULL, "Could not start Emacs.", "Error", MB_ICONSTOP);
179 return 1;
180}
ab5796a9 181
7c3320d8
JB
182void
183set_user_model_id (void)
ff90fbde
JR
184{
185 HMODULE shell;
0a3472c7 186 HRESULT (WINAPI * set_user_model) (wchar_t * id);
ff90fbde
JR
187
188 /* On Windows 7 and later, we need to set the user model ID
189 to associate emacsclient launched files with Emacs frames
190 in the UI. */
191 shell = LoadLibrary ("shell32.dll");
192 if (shell)
193 {
194 set_user_model
195 = (void *) GetProcAddress (shell,
196 "SetCurrentProcessExplicitAppUserModelID");
197
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. */
203 if (set_user_model)
204 set_user_model (L"GNU.Emacs");
205
206 FreeLibrary (shell);
207 }
208}
209
fc5f9b45
EZ
210static int
211ensure_unicows_dll (void)
212{
213 OSVERSIONINFO os_ver;
214 HMODULE h;
215
216 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
217 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
218 if (!GetVersionEx (&os_ver))
219 return 0;
220
221 if (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
222 {
223 h = LoadLibrary ("Unicows.dll");
224 if (!h)
225 {
226 int button;
227
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);
238 switch (button)
239 {
240 case IDOK:
241 default:
242 return 0;
243 }
244 }
245 FreeLibrary (h);
246 return 1;
247 }
248 return 1;
249}