| 1 | /* |
| 2 | Simple program to start Emacs with its console window hidden. |
| 3 | |
| 4 | This program is provided purely for convenience, since most users will |
| 5 | use Emacs in windowing (GUI) mode, and will not want to have an extra |
| 6 | console window lying around. */ |
| 7 | |
| 8 | /* |
| 9 | You may want to define this if you want to be able to install updated |
| 10 | emacs binaries even when other users are using the current version. |
| 11 | The problem with some file servers (notably Novell) is that an open |
| 12 | file cannot be overwritten, deleted, or even renamed. So if someone |
| 13 | is running emacs.exe already, you cannot install a newer version. |
| 14 | By defining CHOOSE_NEWEST_EXE, you can name your new emacs.exe |
| 15 | something else which matches "emacs*.exe", and runemacs will |
| 16 | automatically select the newest emacs executeable in the bin directory. |
| 17 | (So you'll probably be able to delete the old version some hours/days |
| 18 | later). |
| 19 | */ |
| 20 | |
| 21 | /* #define CHOOSE_NEWEST_EXE */ |
| 22 | |
| 23 | #include <windows.h> |
| 24 | #include <string.h> |
| 25 | #include <malloc.h> |
| 26 | |
| 27 | int WINAPI |
| 28 | WinMain (HINSTANCE hSelf, HINSTANCE hPrev, LPSTR cmdline, int nShow) |
| 29 | { |
| 30 | STARTUPINFO start; |
| 31 | SECURITY_ATTRIBUTES sec_attrs; |
| 32 | SECURITY_DESCRIPTOR sec_desc; |
| 33 | PROCESS_INFORMATION child; |
| 34 | int wait_for_child = FALSE; |
| 35 | DWORD priority_class = NORMAL_PRIORITY_CLASS; |
| 36 | DWORD ret_code = 0; |
| 37 | char *new_cmdline; |
| 38 | char *p; |
| 39 | char modname[MAX_PATH]; |
| 40 | |
| 41 | if (!GetModuleFileName (NULL, modname, MAX_PATH)) |
| 42 | goto error; |
| 43 | if ((p = strrchr (modname, '\\')) == NULL) |
| 44 | goto error; |
| 45 | *p = 0; |
| 46 | |
| 47 | new_cmdline = alloca (MAX_PATH + strlen (cmdline) + 3); |
| 48 | /* Quote executable name in case of spaces in the path. */ |
| 49 | *new_cmdline = '"'; |
| 50 | strcpy (new_cmdline + 1, modname); |
| 51 | |
| 52 | #ifdef CHOOSE_NEWEST_EXE |
| 53 | { |
| 54 | /* Silly hack to allow new versions to be installed on |
| 55 | server even when current version is in use. */ |
| 56 | |
| 57 | char * best_name = alloca (MAX_PATH + 1); |
| 58 | FILETIME best_time = {0,0}; |
| 59 | WIN32_FIND_DATA wfd; |
| 60 | HANDLE fh; |
| 61 | p = new_cmdline + strlen (new_cmdline); |
| 62 | strcpy (p, "\\emacs*.exe\" "); |
| 63 | fh = FindFirstFile (new_cmdline, &wfd); |
| 64 | if (fh == INVALID_HANDLE_VALUE) |
| 65 | goto error; |
| 66 | do |
| 67 | { |
| 68 | if (wfd.ftLastWriteTime.dwHighDateTime > best_time.dwHighDateTime |
| 69 | || (wfd.ftLastWriteTime.dwHighDateTime == best_time.dwHighDateTime |
| 70 | && wfd.ftLastWriteTime.dwLowDateTime > best_time.dwLowDateTime)) |
| 71 | { |
| 72 | best_time = wfd.ftLastWriteTime; |
| 73 | strcpy (best_name, wfd.cFileName); |
| 74 | } |
| 75 | } |
| 76 | while (FindNextFile (fh, &wfd)); |
| 77 | FindClose (fh); |
| 78 | *p++ = '\\'; |
| 79 | strcpy (p, best_name); |
| 80 | strcat (p, " "); |
| 81 | } |
| 82 | #else |
| 83 | strcat (new_cmdline, "\\emacs.exe\" "); |
| 84 | #endif |
| 85 | |
| 86 | /* Append original arguments if any; first look for arguments we |
| 87 | recognise (-wait, -high, and -low), and apply them ourselves. */ |
| 88 | while (cmdline[0] == '-' || cmdline[0] == '/') |
| 89 | { |
| 90 | if (strncmp (cmdline+1, "wait", 4) == 0) |
| 91 | { |
| 92 | wait_for_child = TRUE; |
| 93 | cmdline += 5; |
| 94 | } |
| 95 | else if (strncmp (cmdline+1, "high", 4) == 0) |
| 96 | { |
| 97 | priority_class = HIGH_PRIORITY_CLASS; |
| 98 | cmdline += 5; |
| 99 | } |
| 100 | else if (strncmp (cmdline+1, "low", 3) == 0) |
| 101 | { |
| 102 | priority_class = IDLE_PRIORITY_CLASS; |
| 103 | cmdline += 4; |
| 104 | } |
| 105 | else |
| 106 | break; |
| 107 | } |
| 108 | strcat (new_cmdline, cmdline); |
| 109 | |
| 110 | /* Set emacs_dir variable if runemacs was in "%emacs_dir%\bin". */ |
| 111 | if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0) |
| 112 | { |
| 113 | *p = 0; |
| 114 | for (p = modname; *p; p++) |
| 115 | if (*p == '\\') *p = '/'; |
| 116 | SetEnvironmentVariable ("emacs_dir", modname); |
| 117 | } |
| 118 | |
| 119 | memset (&start, 0, sizeof (start)); |
| 120 | start.cb = sizeof (start); |
| 121 | start.dwFlags = STARTF_USESHOWWINDOW; |
| 122 | start.wShowWindow = SW_HIDE; |
| 123 | |
| 124 | sec_attrs.nLength = sizeof (sec_attrs); |
| 125 | sec_attrs.lpSecurityDescriptor = NULL; |
| 126 | sec_attrs.bInheritHandle = FALSE; |
| 127 | |
| 128 | if (CreateProcess (NULL, new_cmdline, &sec_attrs, NULL, TRUE, priority_class, |
| 129 | NULL, NULL, &start, &child)) |
| 130 | { |
| 131 | if (wait_for_child) |
| 132 | { |
| 133 | WaitForSingleObject (child.hProcess, INFINITE); |
| 134 | GetExitCodeProcess (child.hProcess, &ret_code); |
| 135 | } |
| 136 | CloseHandle (child.hThread); |
| 137 | CloseHandle (child.hProcess); |
| 138 | } |
| 139 | else |
| 140 | goto error; |
| 141 | return (int) ret_code; |
| 142 | |
| 143 | error: |
| 144 | MessageBox (NULL, "Could not start Emacs.", "Error", MB_ICONSTOP); |
| 145 | return 1; |
| 146 | } |
| 147 | |
| 148 | /* arch-tag: 7e02df73-4df7-4aa0-baea-99c6d047a384 |
| 149 | (do not change this comment) */ |