Mercurial > mxe-octave
comparison installer-files/octave-launch.c @ 5956:b8e9589b7794
octave-launch: Use Unicode strings in Windows API functions.
* installer-files/octave-launch.c: Use wchar_t and Unicode Windows API
functions. Use safe functions where applicable.
* binary-dist-rules.mk: Compile as Unicode-aware executable.
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Sat, 20 Nov 2021 14:09:41 +0100 |
parents | f42752ce0ae3 |
children | 9cd5425b033b |
comparison
equal
deleted
inserted
replaced
5955:f42752ce0ae3 | 5956:b8e9589b7794 |
---|---|
1 /* | 1 /* |
2 * Wrapper application to set octave env variables and then run octave | 2 * Wrapper application to set octave env variables and then run octave |
3 * compile with gcc -o octave-launch octave-launch.c -Wl,--subsystem,windows -lshlwapi | |
4 * | 3 * |
5 * Copyright (C) 2020 John Donoghue <john.donoghue@ieee.org> | 4 * Copyright (C) 2020-2021 John Donoghue <john.donoghue@ieee.org> |
6 * | 5 * |
7 * This program is free software; you can redistribute it and/or modify it under | 6 * This program is free software; you can redistribute it and/or modify it under |
8 * the terms of the GNU General Public License as published by the Free Software | 7 * the terms of the GNU General Public License as published by the Free Software |
9 * Foundation; either version 3 of the License, or (at your option) any later | 8 * Foundation; either version 3 of the License, or (at your option) any later |
10 * version. | 9 * version. |
18 * this program; if not, see <http: *www.gnu.org/licenses/>. | 17 * this program; if not, see <http: *www.gnu.org/licenses/>. |
19 */ | 18 */ |
20 | 19 |
21 #include <windows.h> | 20 #include <windows.h> |
22 #include <shlwapi.h> | 21 #include <shlwapi.h> |
23 | 22 #include <strsafe.h> |
24 static int ParentDir (char *dir) | 23 |
24 static int ParentDir (wchar_t *dir) | |
25 { | 25 { |
26 int len = strlen (dir); | 26 int len = lstrlenW (dir); |
27 while (len > 0 && dir[len] != '\\') | 27 while (len > 0 && dir[len] != L'\\') |
28 len --; | 28 len --; |
29 dir[len] = 0; | 29 dir[len] = 0; |
30 return len; | 30 return len; |
31 } | 31 } |
32 | 32 |
33 char * FilePart (char *dir) | 33 wchar_t * FilePart (wchar_t *dir) |
34 { | 34 { |
35 int len = strlen (dir); | 35 int len = lstrlenW (dir); |
36 while (len > 0 && dir[len-1] != '\\') | 36 while (len > 0 && dir[len-1] != L'\\') |
37 len --; | 37 len --; |
38 return &dir[len]; | 38 return &dir[len]; |
39 } | 39 } |
40 | 40 |
41 // Set up environment and launch octave.exe with appropriate | 41 // Set up environment and launch octave.exe with appropriate |
42 // arguments. NOTE: There are corresponding VBS and BAT script | 42 // arguments. NOTE: There are corresponding VBS and BAT script |
43 // versions of this program so any changes here may need to be made in | 43 // versions of this program so any changes here may need to be made in |
44 // those scripts as well. | 44 // those scripts as well. |
45 | 45 |
46 int main (int argc, char **argv) | 46 int wmain (int argc, wchar_t **argv) |
47 { | 47 { |
48 PROCESS_INFORMATION pi; | 48 PROCESS_INFORMATION pi; |
49 | 49 |
50 // FIXME: There are currently have no checks to ensure that the | 50 // FIXME: There are currently have no checks to ensure that the |
51 // following fixed-size buffers are sufficiently large. Maybe it | 51 // following fixed-size buffers are sufficiently large. MAX_PATH is |
52 // would be better if we used C++ and std::string objects? For | 52 // 260 on Winndows by default. But a user might have increased that |
53 // buffers that are passed to Windows library functions to hold | 53 // limit to 32767 characters by manually changing policy settings. |
54 // output values, is 1024 the correct way to define the size of the | 54 // Maybe it would be better if we used C++ and std::string objects? |
55 // buffer? Note that the use of sizeof(path)-1 below will fail if | 55 // Note that the use of sizeof(path)-1 will fail if we switch to |
56 // we switch to using | 56 // using |
57 // | 57 // |
58 // char *path = (char *) malloc (...); | 58 // wchar_t *path = (wchar_t *) malloc (...); |
59 // | 59 // |
60 // instead of literal character arrays. | 60 // instead of literal character arrays. |
61 | 61 |
62 char msyspath[1024]; | 62 #define PATH_SZ 1024 |
63 char rootpath[1024]; | 63 wchar_t msyspath[PATH_SZ]; |
64 char path[1024]; | 64 wchar_t rootpath[PATH_SZ]; |
65 char binpath[1024]; | 65 wchar_t path[PATH_SZ]; |
66 wchar_t binpath[PATH_SZ]; | |
66 | 67 |
67 int gui_arg_found = 0; | 68 int gui_arg_found = 0; |
68 int no_gui_arg_found = 0; | 69 int no_gui_arg_found = 0; |
69 int no_gui_libs = 0; | 70 int no_gui_libs = 0; |
70 int i; | 71 int i; |
71 | 72 |
72 /* get path of us which we will assume is the root of the install */ | 73 /* get path of us which we will assume is the root of the install */ |
73 | 74 |
74 DWORD nSize = GetModuleFileName (NULL, path, sizeof(path)-1); | 75 DWORD nSize = GetModuleFileNameW (NULL, path, PATH_SZ-1); |
75 if (nSize) | 76 if (nSize) |
76 { | 77 { |
77 while (nSize > 0 && path[nSize] != '\\') | 78 while (nSize > 0 && path[nSize] != L'\\') |
78 nSize --; | 79 nSize --; |
79 path[nSize] = '\0'; | 80 path[nSize] = L'\0'; |
80 } | 81 } |
81 | 82 |
82 nSize = GetShortPathName (path, rootpath, sizeof(rootpath)-1); | 83 /* transform to short paths to work around issues with spaces in |
84 paths */ | |
85 /* FIXME: This won't help on systems with de-activated short paths */ | |
86 nSize = GetShortPathNameW (path, rootpath, PATH_SZ-1); | |
83 if (nSize == 0) | 87 if (nSize == 0) |
84 StrCpy (rootpath, path); | 88 StringCchCopyW (rootpath, PATH_SZ, path); |
85 | 89 |
86 SetEnvironmentVariable ("MXE_ROOT", rootpath); | 90 SetEnvironmentVariableW (L"MXE_ROOT", rootpath); |
87 | 91 |
88 /* get msys path and set env */ | 92 /* get msys path and set env */ |
89 | 93 |
90 StrCpy (msyspath, rootpath); | 94 StringCchCopyW (msyspath, PATH_SZ, rootpath); |
91 | 95 |
92 StrCpy (path, rootpath); | 96 StringCchCopyW (path, PATH_SZ, rootpath); |
93 StrCat (path, "\\mingw64\\bin\\octave.exe"); | 97 StringCchCatW (path, PATH_SZ, L"\\mingw64\\bin\\octave.exe"); |
94 if (PathFileExists (path)) | 98 if (PathFileExistsW (path)) |
95 { | 99 { |
96 SetEnvironmentVariable ("MSYSTEM", "MINGW64"); | 100 SetEnvironmentVariableW (L"MSYSTEM", L"MINGW64"); |
97 StrCat (msyspath, "\\usr"); | 101 StringCchCatW (msyspath, PATH_SZ, L"\\usr"); |
98 SetEnvironmentVariable ("MSYSPATH", msyspath); | 102 SetEnvironmentVariableW (L"MSYSPATH", msyspath); |
99 | 103 |
100 StrCat (msyspath, "\\bin"); | 104 StringCchCatW (msyspath, PATH_SZ, L"\\bin"); |
101 | 105 |
102 StrCpy (binpath, rootpath); | 106 StringCchCopyW (binpath, PATH_SZ, rootpath); |
103 StrCat (binpath, "\\mingw64\\bin"); | 107 StringCchCatW (binpath, PATH_SZ, L"\\mingw64\\bin"); |
104 } | 108 } |
105 else | 109 else |
106 { | 110 { |
107 StrCpy (path, rootpath); | 111 StringCchCopyW (path, PATH_SZ, rootpath); |
108 StrCat (path, "\\mingw32\\bin\\octave.exe"); | 112 StringCchCatW (path, PATH_SZ, L"\\mingw32\\bin\\octave.exe"); |
109 if (PathFileExists (path)) | 113 if (PathFileExistsW (path)) |
110 { | 114 { |
111 SetEnvironmentVariable ("MSYSTEM", "MINGW32"); | 115 SetEnvironmentVariableW (L"MSYSTEM", L"MINGW32"); |
112 StrCat (msyspath, "\\usr"); | 116 StringCchCatW (msyspath, PATH_SZ, L"\\usr"); |
113 SetEnvironmentVariable ("MSYSPATH", msyspath); | 117 SetEnvironmentVariableW (L"MSYSPATH", msyspath); |
114 | 118 |
115 StrCat (msyspath, "\\bin"); | 119 StringCchCatW (msyspath, PATH_SZ, L"\\bin"); |
116 | 120 |
117 StrCpy (binpath, rootpath); | 121 StringCchCopyW (binpath, PATH_SZ, rootpath); |
118 StrCat (binpath, "\\mingw32\\bin"); | 122 StringCchCatW (binpath, PATH_SZ, L"\\mingw32\\bin"); |
119 } | 123 } |
120 else | 124 else |
121 { | 125 { |
122 SetEnvironmentVariable ("MSYSTEM", "MSYS"); | 126 SetEnvironmentVariableW (L"MSYSTEM", L"MSYS"); |
123 SetEnvironmentVariable ("MSYSPATH", msyspath); | 127 SetEnvironmentVariableW (L"MSYSPATH", msyspath); |
124 | 128 |
125 StrCat (msyspath, "\\bin"); | 129 StringCchCatW (msyspath, PATH_SZ, L"\\bin"); |
126 | 130 |
127 StrCpy (binpath, rootpath); | 131 StringCchCopyW (binpath, PATH_SZ, rootpath); |
128 StrCat (binpath, "\\bin"); | 132 StringCchCatW (binpath, PATH_SZ, L"\\bin"); |
129 } | 133 } |
130 } | 134 } |
131 | 135 |
132 /* binpath is to the octave bin dir so get the parent */ | 136 /* binpath is to the octave bin dir so get the parent */ |
133 StrCpy (path, binpath); | 137 StringCchCopyW (path, PATH_SZ, binpath); |
134 ParentDir (path); | 138 ParentDir (path); |
135 | 139 |
136 #ifdef SHOW_PATHS | 140 #ifdef SHOW_PATHS |
137 MessageBox (NULL, rootpath, "octroot", MB_OK); | 141 MessageBoxW (NULL, rootpath, L"octroot", MB_OK); |
138 MessageBox (NULL, path, "octhome", MB_OK); | 142 MessageBoxW (NULL, path, L"octhome", MB_OK); |
139 MessageBox (NULL, binpath, "octbin", MB_OK); | 143 MessageBoxW (NULL, binpath, L"octbin", MB_OK); |
140 MessageBox (NULL, msyspath, "msysbin", MB_OK); | 144 MessageBoxW (NULL, msyspath, L"msysbin", MB_OK); |
141 #endif | 145 #endif |
142 | 146 |
143 /* qt paths | 147 /* qt paths |
144 * either %OCT_HOME%\qt5\plugins | 148 * either %OCT_HOME%\qt5\plugins |
145 * or %OCT_HOME\plugins | 149 * or %OCT_HOME\plugins |
146 */ | 150 */ |
147 nSize = strlen (path); | 151 nSize = lstrlenW (path); |
148 StrCat (path, "\\qt5\\plugins"); | 152 StringCchCatW (path, PATH_SZ, L"\\qt5\\plugins"); |
149 SetEnvironmentVariable ("QT_PLUGIN_PATH", path); | 153 SetEnvironmentVariableW (L"QT_PLUGIN_PATH", path); |
150 | 154 |
151 path[nSize] = '\0'; | 155 path[nSize] = L'\0'; |
152 | 156 |
153 /* exe paths */ | 157 /* exe paths */ |
154 { | 158 { |
155 char pathbuffer[8096]; | 159 #define PATHBUF_SZ 8096 |
156 char newpathbuffer[8096]; | 160 wchar_t pathbuffer[PATHBUF_SZ]; |
157 | 161 wchar_t newpathbuffer[PATHBUF_SZ]; |
158 nSize = GetEnvironmentVariable ("PATH", pathbuffer, sizeof(pathbuffer)-1); | 162 |
163 nSize = GetEnvironmentVariableW (L"PATH", pathbuffer, PATHBUF_SZ-1); | |
159 pathbuffer[nSize] = '\0'; | 164 pathbuffer[nSize] = '\0'; |
160 | 165 |
161 /* set our paths first */ | 166 /* set our paths first */ |
162 StrCpy (newpathbuffer, binpath); | 167 StringCchCopyW (newpathbuffer, PATHBUF_SZ, binpath); |
163 StrCat (newpathbuffer, ";"); | 168 StringCchCatW (newpathbuffer, PATHBUF_SZ, L";"); |
164 StrCat (newpathbuffer, msyspath); | 169 StringCchCatW (newpathbuffer, PATHBUF_SZ, msyspath); |
165 StrCat (newpathbuffer, ";"); | 170 StringCchCatW (newpathbuffer, PATHBUF_SZ, L";"); |
166 StrCat (newpathbuffer, pathbuffer); | 171 StringCchCatW (newpathbuffer, PATHBUF_SZ, pathbuffer); |
167 | 172 |
168 SetEnvironmentVariable ("PATH", newpathbuffer); | 173 SetEnvironmentVariableW (L"PATH", newpathbuffer); |
169 } | 174 } |
170 | 175 |
171 /* other env */ | 176 /* other env */ |
172 SetEnvironmentVariable ("TERM", "cygwin"); | 177 SetEnvironmentVariableW (L"TERM", L"cygwin"); |
173 SetEnvironmentVariable ("GNUTERM", "wxt"); | 178 SetEnvironmentVariableW (L"GNUTERM", L"wxt"); |
174 SetEnvironmentVariable ("GS", "gs.exe"); | 179 SetEnvironmentVariableW (L"GS", L"gs.exe"); |
175 | 180 |
176 /* home set */ | 181 /* home set */ |
177 nSize = GetEnvironmentVariable ("HOME", path, sizeof(path)-1); | 182 nSize = GetEnvironmentVariableW (L"HOME", path, PATH_SZ-1); |
178 if (nSize == 0 || path[0] == 0) | 183 if (nSize == 0 || path[0] == 0) |
179 { | 184 { |
180 char newhome[1024]; | 185 wchar_t newhome[PATH_SZ]; |
181 | 186 |
182 nSize = GetEnvironmentVariable ("USERPROFILE", path, sizeof(path)-1); | 187 nSize = GetEnvironmentVariableW (L"USERPROFILE", path, PATH_SZ-1); |
183 if (nSize == 0 || path[0] == 0) | 188 if (nSize == 0 || path[0] == 0) |
184 { | 189 { |
185 /* build dir from drive and path */ | 190 /* build dir from drive and path */ |
186 char tmpbuff[1024]; | 191 wchar_t tmpbuff[PATH_SZ]; |
187 nSize = GetEnvironmentVariable ("HOMEDRIVE", tmpbuff, sizeof(tmpbuff)-1); | 192 nSize = GetEnvironmentVariableW (L"HOMEDRIVE", tmpbuff, PATH_SZ-1); |
188 if (nSize) | 193 if (nSize) |
189 StrCpy (path, tmpbuff); | 194 StringCchCopyW (path, PATH_SZ, tmpbuff); |
190 else | 195 else |
191 path[0] = '\0'; | 196 path[0] = '\0'; |
192 | 197 |
193 nSize = GetEnvironmentVariable ("HOMEPATH", tmpbuff, sizeof(tmpbuff)-1); | 198 nSize = GetEnvironmentVariableW (L"HOMEPATH", tmpbuff, PATH_SZ-1); |
194 if (nSize) StrCat (path, tmpbuff); | 199 if (nSize) |
195 } | 200 StringCchCopyW (path, PATH_SZ, tmpbuff); |
196 | 201 } |
197 nSize = GetShortPathName (path, newhome, sizeof(newhome)-1); | 202 |
203 /* transform to short paths to work around issues with spaces in | |
204 paths */ | |
205 /* FIXME: This won't help on systems with de-activated short | |
206 paths */ | |
207 nSize = GetShortPathNameW (path, newhome, PATH_SZ-1); | |
198 | 208 |
199 if (nSize == 0) | 209 if (nSize == 0) |
200 { | 210 StringCchCopyW (newhome, PATH_SZ, path); |
201 StrCpy (newhome, path); | 211 |
202 } | 212 SetEnvironmentVariableW (L"HOME", newhome); |
203 | |
204 SetEnvironmentVariable ("HOME", newhome); | |
205 } | 213 } |
206 | 214 |
207 /* check for gui mode */ | 215 /* check for gui mode */ |
208 for (i = 1; i < argc; i++) | 216 for (i = 1; i < argc; i++) |
209 { | 217 { |
210 if (StrCmp (argv[i], "--no-gui-libs") == 0) | 218 if (StrCmpW (argv[i], L"--no-gui-libs") == 0) |
211 { | 219 { |
212 if (gui_arg_found) | 220 if (gui_arg_found) |
213 { | 221 { |
214 /* Inconsistent options. We can't start the GUI without gui libs. | 222 /* Inconsistent options. We can't start the GUI without gui libs. |
215 How should we fail? For now, --no-gui-libs will | 223 How should we fail? For now, --no-gui-libs will |
216 override the other options. */ | 224 override the other options. */ |
217 } | 225 } |
218 | 226 |
219 no_gui_libs = 1; | 227 no_gui_libs = 1; |
220 } | 228 } |
221 else if (StrCmp (argv[i], "--gui") == 0 | 229 else if (StrCmpW (argv[i], L"--gui") == 0 |
222 || StrCmp (argv[i], "--force-gui") == 0) | 230 || StrCmpW (argv[i], L"--force-gui") == 0) |
223 { | 231 { |
224 if (no_gui_libs) | 232 if (no_gui_libs) |
225 { | 233 { |
226 /* Inconsistent options. We can't start the GUI without gui libs. | 234 /* Inconsistent options. We can't start the GUI without gui libs. |
227 How should we fail? For now, --no-gui-libs will | 235 How should we fail? For now, --no-gui-libs will |
228 override the other options. */ | 236 override the other options. */ |
229 } | 237 } |
230 | 238 |
231 gui_arg_found = 1; | 239 gui_arg_found = 1; |
232 } | 240 } |
233 else if (StrCmp (argv[i], "--no-gui") == 0) | 241 else if (StrCmpW (argv[i], L"--no-gui") == 0) |
234 no_gui_arg_found = 1; | 242 no_gui_arg_found = 1; |
235 | 243 |
236 /* NOTE: specifying both --no-gui and --gui is also an | 244 /* NOTE: specifying both --no-gui and --gui is also an |
237 inconsistent set of options but we leave it to octave.exe to | 245 inconsistent set of options but we leave it to octave.exe to |
238 detect that. */ | 246 detect that. */ |
239 } | 247 } |
240 | 248 |
241 /* set up process args and start it */ | 249 /* set up process args and start it */ |
242 { | 250 { |
243 STARTUPINFO si; | 251 STARTUPINFO si; |
244 char argbuffer[4096]; | 252 #define ARGBUF_SZ 4096 |
245 | 253 wchar_t argbuffer[ARGBUF_SZ]; |
246 ZeroMemory (&si, sizeof(si)); | 254 |
247 si.cb = sizeof(si); | 255 ZeroMemory (&si, sizeof (si)); |
248 ZeroMemory (&pi, sizeof(pi)); | 256 si.cb = sizeof (si); |
249 | 257 ZeroMemory (&pi, sizeof (pi)); |
250 StrCpy (path, binpath); | 258 |
251 | 259 StringCchCopyW (path, PATH_SZ, binpath); |
252 StrCpy (argbuffer, "octave.exe "); | 260 |
253 StrCat (path, "\\octave.exe"); | 261 StringCchCopyW (argbuffer, ARGBUF_SZ, L"octave.exe "); |
262 StringCchCatW (path, PATH_SZ, L"\\octave.exe"); | |
254 | 263 |
255 if (! (no_gui_libs || no_gui_arg_found)) | 264 if (! (no_gui_libs || no_gui_arg_found)) |
256 { | 265 { |
257 /* Unless --no-gui or --no-gui-libs is specified, we will use a GUI window. */ | 266 /* Unless --no-gui or --no-gui-libs is specified, we will use a GUI window. */ |
258 si.dwFlags = STARTF_USESHOWWINDOW; | 267 si.dwFlags = STARTF_USESHOWWINDOW; |
260 /* If none of the options --no-gui, --gui, or --force-gui | 269 /* If none of the options --no-gui, --gui, or --force-gui |
261 were specified, then we'll add --gui to start the gui as | 270 were specified, then we'll add --gui to start the gui as |
262 most Windows users would expect. */ | 271 most Windows users would expect. */ |
263 | 272 |
264 if (! gui_arg_found) | 273 if (! gui_arg_found) |
265 StrCat (argbuffer, "--gui "); | 274 StringCchCatW (argbuffer, ARGBUF_SZ, L"--gui "); |
266 } | 275 } |
267 | 276 |
268 /* quote and append each arg */ | 277 /* quote and append each arg */ |
269 for (i = 1; i < argc; i++) | 278 for (i = 1; i < argc; i++) |
270 { | 279 { |
271 StrCat (argbuffer, "\""); | 280 StringCchCatW (argbuffer, ARGBUF_SZ, L"\""); |
272 StrCat (argbuffer, argv[i]); | 281 StringCchCatW (argbuffer, ARGBUF_SZ, argv[i]); |
273 StrCat (argbuffer, "\" "); | 282 StringCchCatW (argbuffer, ARGBUF_SZ, L"\" "); |
274 } | 283 } |
275 | 284 |
276 /* Start the child process */ | 285 /* Start the child process */ |
277 int status = CreateProcess (path, // Module name | 286 int status = CreateProcessW (path, // Module name |
278 argbuffer, // Command line | 287 argbuffer, // Command line |
279 NULL, // Process handle not inheritable | 288 NULL, // Process handle not inheritable |
280 NULL, // Thread handle not inheritable | 289 NULL, // Thread handle not inheritable |
281 FALSE, // Set handle inheritance to FALSE | 290 FALSE, // Set handle inheritance to FALSE |
282 0, // No creation flags | 291 0, // No creation flags |
283 NULL, // Use parent's environment block | 292 NULL, // Use parent's environment block |
284 NULL, // Use parent's starting directory | 293 NULL, // Use parent's starting directory |
285 &si, // Pointer to STARTUPINFO | 294 &si, // Pointer to STARTUPINFO |
286 &pi); // Pointer to PROCESS_INFORMATION | 295 &pi); // Pointer to PROCESS_INFORMATION |
287 | 296 |
288 if (! status) | 297 if (! status) |
289 return 1; | 298 return 1; |
290 } | 299 } |
291 | 300 |