feisty meow concerns codebase 2.140
windoze_helper.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : windoze_helper *
4* Author : Chris Koeritz *
5* *
6*******************************************************************************
7* Copyright (c) 1994-$now By Author. This program is free software; you can *
8* redistribute it and/or modify it under the terms of the GNU General Public *
9* License as published by the Free Software Foundation; either version 2 of *
10* the License or (at your option) any later version. This is online at: *
11* http://www.fsf.org/copyleft/gpl.html *
12* Please send any updates to: fred@gruntose.com *
13\*****************************************************************************/
14
15#include "windoze_helper.h"
18
21
22/*
23#ifdef __UNIX__
24 #include <limits.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/poll.h>
28 #include <sys/times.h>
29 #include <sys/utsname.h>
30 #include <sys/wait.h>
31 #include <time.h>
32 #include <unistd.h>
33#endif
34#ifdef __XWINDOWS__
35//hmmm: need code for the wait cursor stuff.
36#endif
37#ifdef __WIN32__
38 #include <mmsystem.h>
39 #include <process.h>
40 #include <shellapi.h>
41 #include <shlobj.h>
42#endif
43*/
44
45using namespace basis;
46using namespace loggers;
47using namespace structures;
48using namespace configuration;
49
50#undef static_class_name
51#define static_class_name() "windoze_helper"
52
53#define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
54
55/*
56//#define DEBUG_PORTABLE
57 // uncomment for noisy debugging.
58
59//#define DEBUG_UPTIME
60 // uncomment to get noisier reporting about system and rolling uptime.
61
62//#define JUMP_TIME_49_DAYS
63 // uncomment to make our uptimes start just before the 32 bit uptime rollover.
64//#define JUMP_TIME_497_DAYS
65 // uncomment to make our uptimes start just before the jiffies rollover.
66
67//#define ENABLE_ROLLOVER_BUG
68 // uncomment to get old behavior back where the uptime was not rolling
69 // over properly. this turns off our remainder calculation and leaves the
70 // conversion as a simple cast, which will fail and get stuck at 2^32-1.
71
72#define SUPPORT_SHELL_EXECUTE
73 // if this is not commented out, then the ShellExecute version of launch_
74 // -process() is available. when commented out, ShellExecute is turned off.
75 // disabling this support is the most common because the ShellExecute method
76 // in win32 was only supported for wk203 and wxp, that is only after
77 // windows2000 was already available. since nt and w2k don't support this,
78 // we just usually don't mess with it. it didn't answer a single one of our
79 // issues on windows vista (wfista) anyway, so it's not helping.
80
81// ensure we always have debugging turned on if the jump is enabled.
82#ifdef JUMP_TIME_49_DAYS
83 #undef DEBUG_UPTIME
84 #define DEBUG_UPTIME
85#endif
86#ifdef JUMP_TIME_497_DAYS
87 #undef DEBUG_UPTIME
88 #define DEBUG_UPTIME
89#endif
90// the JUMP..DAYS macros are mutually exclusive. use none or one, not both.
91#ifdef JUMP_TIME_497_DAYS
92 #ifdef JUMP_TIME_49_DAYS
93 #error One cannot use both 497 day and 49 day bug inducers
94 #endif
95#endif
96#ifdef JUMP_TIME_49_DAYS
97 #ifdef JUMP_TIME_497_DAYS
98 #error One cannot use both 49 day and 497 day bug inducers
99 #endif
100#endif
101*/
102
103
104namespace application {
105
106/*
107mutex BASIS_EXTERN &__uptime_synchronizer();
108 // used by our low-level uptime methods to protect singleton variables.
109mutex BASIS_EXTERN &__process_synchronizer();
110 // used for synchronizing our records of child processes.
111#ifdef __UNIX__
112int_set BASIS_EXTERN &__our_kids();
113 // the static list of processes we've started.
114#endif
115
116const int MAXIMUM_COMMAND_LINE = 32 * KILOBYTE;
117 // maximum command line that we'll deal with here.
118
119#ifdef __UNIX__
120 const char *UPTIME_REPORT_FILE = "/tmp/uptime_report.log";
121#endif
122#ifdef __WIN32__
123 const char *UPTIME_REPORT_FILE = "c:/uptime_report.log";
124#endif
125
126#undef LOG
127#define LOG(s) STAMPED_EMERGENCY_LOG(program_wide_logger(), s);
128
129#define COMPLAIN(to_print) { \
130 guards::write_to_console((isprintf("basis/portable::%s: ", func) + to_print).s()); \
131}
132
133static const double __rollover_point = 2.0 * double(MAXINT);
134 // this number is our rollover point for 32 bit integers.
135
136double rolling_uptime()
137{
138 auto_synchronizer l(__uptime_synchronizer());
139 // protect our rollover records.
140
141 static u_int __last_ticks = 0;
142 static int __rollovers = 0;
143
144 u_int ticks_up = system_uptime();
145 // acquire the current uptime as a 32 bit unsigned int.
146
147 if (ticks_up < __last_ticks) {
148 // rollover happened. increment our tracker.
149 __rollovers++;
150 }
151 __last_ticks = ticks_up;
152
153 double to_return = double(__rollovers) * __rollover_point + double(ticks_up);
154
155#ifdef DEBUG_UPTIME
156 #ifdef __WIN32__
157 static FILE *__outfile = fopen(UPTIME_REPORT_FILE, "a+b");
158 static double old_value = 0;
159 if (absolute_value(old_value - to_return) > 9.9999) {
160 // only report when the time changes by more than 10 ms.
161 fprintf(__outfile, "-> uptime=%.0f\n", to_return);
162 fflush(__outfile);
163 old_value = to_return;
164 if (__rollover_point - to_return <= 40.00001) {
165 fprintf(__outfile, "---> MAXIMUM UPTIME SOON!\n");
166 fflush(__outfile);
167 }
168 }
169 #endif
170#endif
171
172 return to_return;
173}
174
175u_int system_uptime()
176{
177#ifdef __WIN32__
178 return timeGetTime();
179#else
180 auto_synchronizer l(__uptime_synchronizer());
181
182 static clock_t __ctps = sysconf(_SC_CLK_TCK); // clock ticks per second.
183 static const double __multiplier = 1000.0 / double(__ctps);
184 // the multiplier gives us our full range for the tick counter.
185
186#ifdef DEBUG_UPTIME
187 static FILE *__outfile = fopen(UPTIME_REPORT_FILE, "wb");
188 if (__multiplier - u_int(__multiplier) > 0.000001) {
189 fprintf(__outfile, "uptime multiplier is "
190 "non-integral (%f)!\n", __multiplier);
191 fflush(__outfile);
192 }
193#endif
194
195 // read uptime info from the OS.
196 tms uptime;
197 u_int real_ticks = times(&uptime);
198
199#ifdef JUMP_TIME_497_DAYS
200 static u_int old_value_497 = 0;
201 bool report_497 = (absolute_value(real_ticks - old_value_497) > 99);
202 if (report_497) {
203 old_value_497 = real_ticks; // update before changing it.
204 fprintf(__outfile, "pre kludge497 tix=%u\n", real_ticks);
205 fflush(__outfile);
206 }
207 real_ticks += u_int(49.0 * double(DAY_ms) + 17.0 * double(HOUR_ms));
208 if (report_497) {
209 fprintf(__outfile, "post kludge497 tix=%u\n", real_ticks);
210 fflush(__outfile);
211 }
212#endif
213
214 // now turn this into the number of milliseconds.
215 double ticks_up = (double)real_ticks;
216 ticks_up = ticks_up * __multiplier; // convert to time here.
217
218#ifdef JUMP_TIME_497_DAYS
219 #ifndef ENABLE_ROLLOVER_BUG
220 // add in additional time so we don't have to wait forever. we make the
221 // big number above rollover, but that's still got 27.5 or so minutes before
222 // we really rollover. so we add that part of the fraction (lost in the
223 // haze of the multiplier) in here. we don't add this in unless they are
224 // not exercising the rollover bug, because we already know that the 497
225 // day bug will show without the addition. but when we're already fixing
226 // the uptime, we jump time a bit forward so we only have to wait a couple
227 // minutes instead of 27.
228 ticks_up += 25.0 * MINUTE_ms;
229 #endif
230#endif
231
232#ifdef JUMP_TIME_49_DAYS
233 static u_int old_value_49 = 0;
234 bool report_49 = (absolute_value(u_int(ticks_up) - old_value_49) > 999);
235 if (report_49) {
236 old_value_49 = u_int(ticks_up); // update before changing it.
237 fprintf(__outfile, "pre kludge49 up=%f\n", ticks_up);
238 fflush(__outfile);
239 }
240 ticks_up += 49.0 * double(DAY_ms) + 17.0 * double(HOUR_ms);
241 if (report_49) {
242 fprintf(__outfile, "post kludge49 up=%f\n", ticks_up);
243 fflush(__outfile);
244 }
245#endif
246
247#ifndef ENABLE_ROLLOVER_BUG
248 // fix the return value if is has actually gone over the 2^32 limit for uint.
249 // casting a double larger than 2*MAXINT to a u_int on some platforms does
250 // not calculate a rolled-over value, but instead leaves the int at 2*MAXINT.
251 // thus we make sure it will be correct, as long as there are no more than
252 // 2^32-1 rollovers, which would be about 584,542 millenia. it's unlikely
253 // earth will last that long, so this calculation seems safe.
254 u_int divided = u_int(ticks_up / __rollover_point);
255 double to_return = ticks_up - (double(divided) * __rollover_point);
256#else
257 // we use the previous version of this calculation, which expected a u_int
258 // to double conversion to provide a modulo operation rather than just leaving
259 // the u_int at its maximum value (2^32-1). however, that expectation is not
260 // guaranteed on some platforms (e.g., ARM processor with floating point
261 // emulation) and thus it becomes a bug around 49 days and 17 hours into
262 // OS uptime because the value gets stuck at 2^32-1 and never rolls over.
263 double to_return = ticks_up;
264#endif
265
266#ifdef DEBUG_UPTIME
267 static u_int old_value = 0;
268 int to_print = int(u_int(to_return));
269 if (absolute_value(int(old_value) - to_print) > 9) {
270 // only report when the time changes by more than 10 ms.
271 fprintf(__outfile, "-> uptime=%u\n", to_print);
272 fflush(__outfile);
273 old_value = u_int(to_print);
274 if (__rollover_point - to_return <= 40.00001) {
275 fprintf(__outfile, "---> MAXIMUM UPTIME SOON!\n");
276 fflush(__outfile);
277 }
278 }
279#endif
280
281 return u_int(to_return);
282#endif
283}
284
285void sleep_ms(u_int msec)
286{
287#ifdef __UNIX__
288 usleep(msec * 1000);
289#endif
290#ifdef __WIN32__
291 Sleep(msec);
292#endif
293}
294
295istring null_device()
296{
297#ifdef __WIN32__
298 return "null:";
299#else
300 return "/dev/null";
301#endif
302}
303*/
304
305#ifdef __WIN32__
306bool event_poll(MSG &message)
307{
308 message.hwnd = 0;
309 message.message = 0;
310 message.wParam = 0;
311 message.lParam = 0;
312 if (!PeekMessage(&message, NULL_POINTER, 0, 0, PM_REMOVE))
313 return false;
314 TranslateMessage(&message);
315 DispatchMessage(&message);
316 return true;
317}
318#endif
319
320/*
321
322// makes a complaint about a failure.
323#ifndef EMBEDDED_BUILD
324 #define COMPLAIN_QUERY(to_print) { \
325 unlink(tmpfile.s()); \
326 COMPLAIN(to_print); \
327 }
328#else
329 #define COMPLAIN_QUERY(to_print) { \
330 COMPLAIN(to_print); \
331 }
332#endif
333
334#ifdef __UNIX__
335istring get_cmdline_from_proc()
336{
337 FUNCDEF("get_cmdline_from_proc");
338 isprintf cmds_filename("/proc/%d/cmdline", portable::process_id());
339 FILE *cmds_file = fopen(cmds_filename.s(), "r");
340 if (!cmds_file) {
341 COMPLAIN("failed to open our process's command line file.\n");
342 return "unknown";
343 }
344 size_t size = 2000;
345 char *buff = new char[size + 1];
346 ssize_t chars_read = getline(&buff, &size, cmds_file);
347 // read the first line, giving ample space for how long it might be.
348 fclose(cmds_file); // drop the file again.
349 if (!chars_read || negative(chars_read)) {
350 COMPLAIN("failed to get any characters from our process's cmdline file.\n");
351 return "unknown";
352 }
353 istring buffer = buff;
354 delete [] buff;
355 // clean out quote characters from the name.
356 for (int i = buffer.length() - 1; i >= 0; i--) {
357 if (buffer[i] == '"') buffer.zap(i, i);
358 }
359 return buffer;
360}
361
362// deprecated; better to use the /proc/pid/cmdline file.
363istring query_for_process_info()
364{
365 FUNCDEF("query_for_process_info");
366 istring to_return = "unknown";
367 // we ask the operating system about our process identifier and store
368 // the results in a temporary file.
369 chaos rando;
370 isprintf tmpfile("/tmp/proc_name_check_%d_%d.txt", portable::process_id(),
371 rando.inclusive(0, 128000));
372 isprintf cmd("ps h --format \"%%a\" %d >%s", portable::process_id(),
373 tmpfile.s());
374 // run the command to locate our process info.
375 int sysret = system(cmd.s());
376 if (negative(sysret)) {
377 COMPLAIN_QUERY("failed to run ps command to get process info");
378 return to_return;
379 }
380 // open the output file for reading.
381 FILE *output = fopen(tmpfile.s(), "r");
382 if (!output) {
383 COMPLAIN_QUERY("failed to open the ps output file");
384 return to_return;
385 }
386 // read the file's contents into a string buffer.
387 char buff[MAXIMUM_COMMAND_LINE];
388 size_t size_read = fread(buff, 1, MAXIMUM_COMMAND_LINE, output);
389 if (size_read > 0) {
390 // success at finding some text in the file at least.
391 while (size_read > 0) {
392 const char to_check = buff[size_read - 1];
393 if ( !to_check || (to_check == '\r') || (to_check == '\n')
394 || (to_check == '\t') )
395 size_read--;
396 else break;
397 }
398 to_return.reset(istring::UNTERMINATED, buff, size_read);
399 } else {
400 // couldn't read anything.
401 COMPLAIN_QUERY("could not read output of process list");
402 }
403 unlink(tmpfile.s());
404 return to_return;
405}
406#endif
407
408istring module_name(const void *module_handle)
409{
410#ifdef __UNIX__
411//hmmm: implement module name for linux if that makes sense.
412 if (module_handle) {}
413 return application_name();
414#elif defined(__WIN32__)
415 flexichar low_buff[MAX_ABS_PATH + 1];
416 GetModuleFileName((HMODULE)module_handle, low_buff, MAX_ABS_PATH - 1);
417 istring buff = from_unicode_temp(low_buff);
418 buff.to_lower();
419 return buff;
420#else
421 #pragma message("module_name unknown for this operating system.")
422 return application_name();
423#endif
424}
425
426u_int system_error()
427{
428#if defined(__UNIX__)
429 return errno;
430#elif defined(__WIN32__)
431 return GetLastError();
432#else
433 #pragma error("hmmm: no code for error number for this operating system")
434 return 0;
435#endif
436}
437
438istring system_error_text(u_int to_name)
439{
440#if defined(__UNIX__)
441 return strerror(to_name);
442#elif defined(__WIN32__)
443 char error_text[1000];
444 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL_POINTER, to_name,
445 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)error_text,
446 sizeof(error_text) - 1, NULL_POINTER);
447 istring to_return = error_text;
448 // trim off the ridiculous carriage return they add.
449 while ( (to_return[to_return.end()] == '\r')
450 || (to_return[to_return.end()] == '\n') )
451 to_return.zap(to_return.end(), to_return.end());
452 return to_return;
453#else
454 #pragma error("hmmm: no code for error text for this operating system")
455 return "";
456#endif
457}
458
459#ifdef __WIN32__
460
461bool is_address_valid(const void *address, int size_expected, bool writable)
462{
463 return address && !IsBadReadPtr(address, size_expected)
464 && !(writable && IsBadWritePtr((void *)address, size_expected));
465}
466
467#endif // win32
468
469version get_OS_version()
470{
471 version to_return;
472#ifdef __UNIX__
473 utsname kernel_parms;
474 uname(&kernel_parms);
475 to_return = version(kernel_parms.release);
476#elif defined(__WIN32__)
477 OSVERSIONINFO info;
478 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
479 ::GetVersionEx(&info);
480 to_return = version(isprintf("%u.%u.%u.%u", u_short(info.dwMajorVersion),
481 u_short(info.dwMinorVersion), u_short(info.dwPlatformId),
482 u_short(info.dwBuildNumber)));
483#elif defined(EMBEDDED_BUILD)
484 // no version support.
485#else
486 #pragma error("hmmm: need version info for this OS!")
487#endif
488 return to_return;
489}
490
491// for non-win32 and non-unix OSes, this might not work.
492#if defined(__UNIX__) || defined(__WIN32__)
493 u_int process_id() { return getpid(); }
494#else
495 #pragma error("hmmm: need process id implementation for this OS!")
496 u_int process_id() { return 0; }
497#endif
498
499istring current_directory()
500{
501 istring to_return;
502#ifdef __UNIX__
503 char buff[MAX_ABS_PATH];
504 getcwd(buff, MAX_ABS_PATH - 1);
505 to_return = buff;
506#elif defined(__WIN32__)
507 flexichar low_buff[MAX_ABS_PATH + 1];
508 GetCurrentDirectory(MAX_ABS_PATH, low_buff);
509 to_return = from_unicode_temp(low_buff);
510#else
511 #pragma error("hmmm: need support for current directory on this OS.")
512 to_return = ".";
513#endif
514 return to_return;
515}
516
517timeval fill_timeval_ms(int duration)
518{
519 timeval time_out; // timeval has tv_sec=seconds, tv_usec=microseconds.
520 if (!duration) {
521 // duration is immediate for the check; just a quick poll.
522 time_out.tv_sec = 0;
523 time_out.tv_usec = 0;
524#ifdef DEBUG_PORTABLE
525// LOG("no duration specified");
526#endif
527 } else {
528 // a non-zero duration means we need to compute secs and usecs.
529 time_out.tv_sec = duration / 1000;
530 // set the number of seconds from the input in milliseconds.
531 duration -= time_out.tv_sec * 1000;
532 // now take out the chunk we've already recorded as seconds.
533 time_out.tv_usec = duration * 1000;
534 // set the number of microseconds from the remaining milliseconds.
535#ifdef DEBUG_PORTABLE
536// LOG(isprintf("duration of %d ms went to %d sec and %d usec.", duration,
537// time_out.tv_sec, time_out.tv_usec));
538#endif
539 }
540 return time_out;
541}
542
543//hmmm: this doesn't seem to account for quoting properly at all?
544basis::char_star_array break_line(istring &app, const istring &parameters)
545{
546 basis::char_star_array to_return;
547 int_array posns;
548 int num = 0;
549 // find the positions of the spaces and count them.
550 for (int j = 0; j < parameters.length(); j++) {
551 if (parameters[j] == ' ') {
552 num++;
553 posns += j;
554 }
555 }
556 // first, add the app name to the list of parms.
557 to_return += new char[app.length() + 1];
558 app.stuff(to_return[0], app.length());
559 int last_posn = 0;
560 // now add each space-separated parameter to the list.
561 for (int i = 0; i < num; i++) {
562 int len = posns[i] - last_posn;
563 to_return += new char[len + 1];
564 parameters.substring(last_posn, posns[i] - 1).stuff(to_return[i + 1], len);
565 last_posn = posns[i] + 1;
566 }
567 // catch anything left after last separator.
568 if (last_posn < parameters.length() - 1) {
569 int len = parameters.length() - last_posn;
570 to_return += new char[len + 1];
571 parameters.substring(last_posn, parameters.length() - 1)
572 .stuff(to_return[to_return.last()], len);
573 }
574 // add the sentinel to the list of strings.
575 to_return += NULL_POINTER;
576#ifdef DEBUG_PORTABLE
577 for (int q = 0; to_return[q]; q++) {
578 printf("%d: %s\n", q, to_return[q]);
579 }
580#endif
581 // now a special detour; fix the app name to remove quotes, which are
582 // not friendly to pass to exec.
583 if (app[0] == '"') app.zap(0, 0);
584 if (app[app.end()] == '"') app.zap(app.end(), app.end());
585 return to_return;
586}
587
588#ifdef __UNIX__
589
590void exiting_child_signal_handler(int sig_num)
591{
592 FUNCDEF("exiting_child_signal_handler");
593 if (sig_num != SIGCHLD) {
594 // uhhh, this seems wrong.
595 }
596 auto_synchronizer l(__process_synchronizer());
597 for (int i = 0; i < __our_kids().length(); i++) {
598 int status;
599 pid_t exited = waitpid(__our_kids()[i], &status, WNOHANG);
600 if ( (exited == -1) || (exited == __our_kids()[i]) ) {
601 // negative one denotes an error, which we are going to assume means the
602 // process has exited via some other method than our wait. if the value
603 // is the same as the process we waited for, that means it exited.
604 __our_kids().zap(i, i);
605 i--;
606 } else if (exited != 0) {
607 // zero would be okay; this result we do not understand.
608#ifdef DEBUG_PORTABLE
609 printf("unknown result %d waiting for process %d", exited,
610 __our_kids()[i]);
611#endif
612 }
613 }
614}
615#endif
616
617u_int launch_process(const istring &app_name_in, const istring &command_line,
618 int flag, u_int &child_id)
619{
620 child_id = 0;
621 istring app_name = app_name_in;
622 if (app_name[0] != '"')
623 app_name.insert(0, "\"");
624 if (app_name[app_name.end()] != '"')
625 app_name += "\"";
626#ifdef __UNIX__
627 // unix / linux implementation.
628 if (flag & RETURN_IMMEDIATELY) {
629 // they want to get back right away.
630 pid_t kid_pid = fork();
631#ifdef DEBUG_PORTABLE
632 printf("launch fork returned %d\n", kid_pid);
633#endif
634 if (!kid_pid) {
635 // this is the child; we now need to launch into what we were asked for.
636#ifdef DEBUG_PORTABLE
637 printf((isprintf("process %d execing ", process_id()) + app_name
638 + " parms " + command_line + "\n").s());
639#endif
640 basis::char_star_array parms = break_line(app_name, command_line);
641 execv(app_name.s(), parms.observe());
642 // oops. failed to exec if we got to here.
643#ifdef DEBUG_PORTABLE
644 printf((isprintf("child of fork (pid %d) failed to exec, "
645 "error is ", process_id()) + system_error_text(system_error())
646 + "\n").s());
647#endif
648 exit(0); // leave since this is a failed child process.
649 } else {
650 // this is the parent. let's see if the launch worked.
651 if (kid_pid == -1) {
652 // failure.
653 u_int to_return = system_error();
654#ifdef DEBUG_PORTABLE
655 printf((isprintf("parent %d is returning after failing to create, "
656 "error is ", process_id()) + system_error_text(to_return)
657 + "\n").s());
658#endif
659 return to_return;
660 } else {
661 // yes, launch worked okay.
662 child_id = kid_pid;
663 {
664 auto_synchronizer l(__process_synchronizer());
665 __our_kids() += kid_pid;
666 }
667 // hook in our child exit signal handler.
668 signal(SIGCHLD, exiting_child_signal_handler);
669
670#ifdef DEBUG_PORTABLE
671 printf((isprintf("parent %d is returning after successfully "
672 "creating %d ", process_id(), kid_pid) + app_name
673 + " parms " + command_line + "\n").s());
674#endif
675 return 0;
676 }
677 }
678 } else {
679 // assume they want to wait.
680 return system((app_name + " " + command_line).s());
681 }
682#elif defined(__WIN32__)
683
684//checking on whether we have admin rights for the launch.
685//if (IsUserAnAdmin()) {
686// MessageBox(0, (istring("IS admin with ") + app_name_in + " " + command_line).s(), "launch process", MB_OK);
687//} else {
688// MessageBox(0, (istring("NOT admin for ") + app_name_in + " " + command_line).s(), "launch process", MB_OK);
689//}
690
691 PROCESS_INFORMATION process_info;
692 ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
693
694#ifdef SUPPORT_SHELL_EXECUTE
695 if (flag & SHELL_EXECUTE) {
696 // new code for using shell execute method--required on vista for proper
697 // launching with the right security tokens.
698 int show_cmd = 0;
699 if (flag & HIDE_APP_WINDOW) {
700 // magic that hides a console window for mswindows.
701 show_cmd = SW_HIDE;
702 } else {
703 show_cmd = SW_SHOWNORMAL;
704 }
705
706 SHELLEXECUTEINFO exec_info;
707 ZeroMemory(&exec_info, sizeof(SHELLEXECUTEINFO));
708 exec_info.cbSize = sizeof(SHELLEXECUTEINFO);
709 exec_info.fMask = SEE_MASK_NOCLOSEPROCESS // get the process info.
710 | SEE_MASK_FLAG_NO_UI; // turn off any visible error dialogs.
711 exec_info.hwnd = GetDesktopWindow();
712//hmmm: is get desktop window always appropriate?
713 to_unicode_persist(temp_verb, "open");
714//does "runas" work on xp also? or anywhere?
715 exec_info.lpVerb = temp_verb;
716 to_unicode_persist(temp_file, app_name);
717 exec_info.lpFile = temp_file;
718 to_unicode_persist(temp_parms, command_line);
719 exec_info.lpParameters = temp_parms;
720 exec_info.nShow = show_cmd;
721// exec_info.hProcess = &process_info;
722
723 BOOL worked = ShellExecuteEx(&exec_info);
724 if (!worked)
725 return system_error();
726 // copy out the returned process handle.
727 process_info.hProcess = exec_info.hProcess;
728 process_info.dwProcessId = GetProcessId(exec_info.hProcess);
729 } else {
730#endif //shell exec
731 // standard windows implementation using CreateProcess.
732 STARTUPINFO startup_info;
733 ZeroMemory(&startup_info, sizeof(STARTUPINFO));
734 startup_info.cb = sizeof(STARTUPINFO);
735 int create_flag = 0;
736 if (flag & HIDE_APP_WINDOW) {
737 // magic that hides a console window for mswindows.
738// version ver = portable::get_OS_version();
739// version vista_version(6, 0);
740// if (ver < vista_version) {
741// // we suspect that this flag is hosing us in vista.
742 create_flag = CREATE_NO_WINDOW;
743// }
744 }
745 istring parms = app_name + " " + command_line;
746 bool success = CreateProcess(NULL_POINTER, to_unicode_temp(parms), NULL_POINTER, NULL_POINTER, false,
747 create_flag, NULL_POINTER, NULL_POINTER, &startup_info, &process_info);
748 if (!success)
749 return system_error();
750 // success then, merge back into stream.
751
752#ifdef SUPPORT_SHELL_EXECUTE
753 }
754#endif //shell exec
755
756 // common handling for CreateProcess and ShellExecuteEx.
757 child_id = process_info.dwProcessId;
758 u_long retval = 0;
759 if (flag & AWAIT_VIA_POLLING) {
760 // this type of waiting is done without blocking on the process.
761 while (true) {
762 MSG msg;
763 event_poll(msg);
764 // check if the process is gone yet.
765 BOOL ret = GetExitCodeProcess(process_info.hProcess, &retval);
766 if (!ret) {
767 break;
768 } else {
769 // if they aren't saying it's still active, then we will leave.
770 if (retval != STILL_ACTIVE)
771 break;
772 }
773 sleep_ms(14);
774 }
775 } else if (flag & AWAIT_APP_EXIT) {
776 // they want to wait for the process to exit.
777 WaitForInputIdle(process_info.hProcess, INFINITE);
778 WaitForSingleObject(process_info.hProcess, INFINITE);
779 GetExitCodeProcess(process_info.hProcess, &retval);
780 }
781 // drop the process and thread handles.
782 if (process_info.hProcess)
783 CloseHandle(process_info.hProcess);
784 if (process_info.hThread)
785 CloseHandle(process_info.hThread);
786 return (u_int)retval;
787#else
788 #pragma error("hmmm: launch_process: no implementation for this OS.")
789#endif
790 return 0;
791}
792
794
795#ifdef __UNIX__
796
797char *itoa(int to_convert, char *buffer, int radix)
798{
799 // slow implementation; may need enhancement for serious speed.
800 // ALSO: only supports base 10 and base 16 currently.
801 const char *formatter = "%d";
802 if (radix == 16) formatter = "%x";
803 isprintf printed(formatter, to_convert);
804 printed.stuff(buffer, printed.length() + 1);
805 return buffer;
806}
807
808#endif
809*/
810
811#ifdef __WIN32__
812
813/*
814void show_wait_cursor() { SetCursor(LoadCursor(NULL, IDC_WAIT)); }
815
816void show_normal_cursor() { SetCursor(LoadCursor(NULL, IDC_ARROW)); }
817
818istring rc_string(UINT id, application_instance instance)
819{
820 flexichar temp[MAX_ABS_PATH + 1];
821 int ret = LoadString(instance, id, temp, MAX_ABS_PATH);
822 if (!ret) return istring();
823 return istring(from_unicode_temp(temp));
824}
825
826istring rc_string(u_int id) { return rc_string(id, GET_INSTANCE_HANDLE()); }
827*/
828
829const char *opsystem_name(known_operating_systems which)
830{
831 switch (which) {
832 case WIN_95: return "WIN_95";
833 case WIN_NT: return "WIN_NT";
834 case WIN_2K: return "WIN_2K";
835 case WIN_XP: return "WIN_XP";
836 case WIN_SRV2K3: return "WIN_SRV2K3";
837 case WIN_VISTA: return "WIN_VISTA";
838 case WIN_7: return "WIN_7";
839 case WIN_8: return "WIN_8";
840 case WIN_10: return "WIN_10";
841 default: return "UNKNOWN_OS";
842 }
843}
844
845known_operating_systems determine_OS()
846{
847 FUNCDEF("determine_OS");
849 if ( (osver.v_major() == 4) && (osver.v_minor() == 0) ) {
850 if (osver.v_revision() == VER_PLATFORM_WIN32_WINDOWS) return WIN_95;
851 if (osver.v_revision() == VER_PLATFORM_WIN32_NT) return WIN_NT;
852 } else if ( (osver.v_major() == 5) && (osver.v_minor() == 0) ) {
853 return WIN_2K;
854 } else if ( (osver.v_major() == 5) && (osver.v_minor() == 1) ) {
855 return WIN_XP;
856 } else if ( (osver.v_major() == 5) && (osver.v_minor() == 2) ) {
857 return WIN_SRV2K3;
858 } else if ( (osver.v_major() == 6) && (osver.v_minor() == 0) ) {
859 return WIN_VISTA;
860// } else if ( (osver.v_major() == 6) && (osver.v_minor() == 1) ) {
861// return WIN_SRV2K8;
862 } else if ( (osver.v_major() == 6) && (osver.v_minor() == 1) ) {
863 return WIN_7;
864 } else if ( (osver.v_major() == 6) && (osver.v_minor() == 2) ) {
865 return WIN_8;
866 } else if ( (osver.v_major() == 10) && (osver.v_minor() == 0) ) {
867 return WIN_10;
868 }
869
870//temp
871LOG(a_sprintf("got a major OS of %d and minor OS of %d", osver.v_major(), osver.v_minor()));
872
873 return UNKNOWN_OS;
874}
875
876#endif // win32
877
878} // namespace.
879
880#undef static_class_name
881
#define LOG(s)
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
static structures::version get_OS_version()
returns the operating system's version information.
Holds a file's version identifier.
int v_minor() const
minor version number.
int v_major() const
major version number.
int v_revision() const
revision level.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
Implements an application lock to ensure only one is running at once.
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
A logger that sends to the console screen using the standard output device.
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
Aids in achievement of platform independence.