NEWS tweak
[emacs.git] / nt / runemacs.c
blobdbb18bcd82c93995f87a15bce94d6eb9eaf511f4
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
38 later).
41 /* #define CHOOSE_NEWEST_EXE */
43 #include <windows.h>
44 #include <string.h>
45 #include <malloc.h>
47 static void set_user_model_id (void);
48 static int ensure_unicows_dll (void);
50 int WINAPI
51 WinMain (HINSTANCE hSelf, HINSTANCE hPrev, LPSTR cmdline, int nShow)
53 STARTUPINFO start;
54 SECURITY_ATTRIBUTES sec_attrs;
55 PROCESS_INFORMATION child;
56 int wait_for_child = FALSE;
57 DWORD priority_class = NORMAL_PRIORITY_CLASS;
58 DWORD ret_code = 0;
59 char *new_cmdline;
60 char *p;
61 char modname[MAX_PATH];
63 if (!ensure_unicows_dll ())
64 goto error;
66 set_user_model_id ();
68 if (!GetModuleFileName (NULL, modname, MAX_PATH))
69 goto error;
70 if ((p = strrchr (modname, '\\')) == NULL)
71 goto error;
72 *p = 0;
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);
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};
86 WIN32_FIND_DATA wfd;
87 HANDLE fh;
88 p = new_cmdline + strlen (new_cmdline);
89 strcpy (p, "\\emacs*.exe\" ");
90 fh = FindFirstFile (new_cmdline, &wfd);
91 if (fh == INVALID_HANDLE_VALUE)
92 goto error;
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));
104 FindClose (fh);
105 *p++ = '\\';
106 strcpy (p, best_name);
107 strcat (p, " ");
109 #else
110 strcat (new_cmdline, "\\emacs.exe\" ");
111 #endif
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;
120 cmdline += 5;
122 else if (strncmp (cmdline+1, "high", 4) == 0)
124 priority_class = HIGH_PRIORITY_CLASS;
125 cmdline += 5;
127 else if (strncmp (cmdline+1, "low", 3) == 0)
129 priority_class = IDLE_PRIORITY_CLASS;
130 cmdline += 4;
132 else
133 break;
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)
143 *p = 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))
165 if (wait_for_child)
167 WaitForSingleObject (child.hProcess, INFINITE);
168 GetExitCodeProcess (child.hProcess, &ret_code);
170 CloseHandle (child.hThread);
171 CloseHandle (child.hProcess);
173 else
174 goto error;
175 return (int) ret_code;
177 error:
178 MessageBox (NULL, "Could not start Emacs.", "Error", MB_ICONSTOP);
179 return 1;
182 void
183 set_user_model_id (void)
185 HMODULE shell;
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
190 in the UI. */
191 shell = LoadLibrary ("shell32.dll");
192 if (shell)
194 set_user_model
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. */
203 if (set_user_model)
204 set_user_model (L"GNU.Emacs");
206 FreeLibrary (shell);
210 static int
211 ensure_unicows_dll (void)
213 OSVERSIONINFO os_ver;
214 HMODULE h;
216 ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
217 os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
218 if (!GetVersionEx (&os_ver))
219 return 0;
221 if (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
223 h = LoadLibrary ("Unicows.dll");
224 if (!h)
226 int button;
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)
240 case IDOK:
241 default:
242 return 0;
245 FreeLibrary (h);
246 return 1;
248 return 1;