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