Added net stuff, some fixes to gsock code for WinCE
[wxWidgets.git] / src / msw / utils.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/utils.cpp
3 // Purpose: Various utilities
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/utils.h"
29 #include "wx/app.h"
30 #include "wx/intl.h"
31 #include "wx/log.h"
32 #endif //WX_PRECOMP
33
34 #include "wx/apptrait.h"
35
36 #include "wx/msw/private.h" // includes <windows.h>
37 #include "wx/msw/missing.h" // CHARSET_HANGUL
38
39 #if defined(__GNUWIN32_OLD__) || defined(__WXWINCE__)
40 // apparently we need to include winsock.h to get WSADATA and other stuff
41 // used in wxGetFullHostName() with the old mingw32 versions
42 #include <winsock.h>
43 #endif
44
45 #include "wx/timer.h"
46
47 #if !defined(__GNUWIN32__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
48 #include <direct.h>
49
50 #ifndef __MWERKS__
51 #include <dos.h>
52 #endif
53 #endif //GNUWIN32
54
55 #if defined(__CYGWIN__)
56 #include <sys/unistd.h>
57 #include <sys/stat.h>
58 #include <sys/cygwin.h> // for cygwin_conv_to_full_win32_path()
59 #endif //GNUWIN32
60
61 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs
62 // this (3.1 I believe) and how to test for it.
63 // If this works for Borland 4.0 as well, then no worries.
64 #include <dir.h>
65 #endif
66
67 // VZ: there is some code using NetXXX() functions to get the full user name:
68 // I don't think it's a good idea because they don't work under Win95 and
69 // seem to return the same as wxGetUserId() under NT. If you really want
70 // to use them, just #define USE_NET_API
71 #undef USE_NET_API
72
73 #ifdef USE_NET_API
74 #include <lm.h>
75 #endif // USE_NET_API
76
77 #if defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
78 #ifndef __UNIX__
79 #include <io.h>
80 #endif
81
82 #ifndef __GNUWIN32__
83 #include <shellapi.h>
84 #endif
85 #endif
86
87 #ifndef __WATCOMC__
88 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
89 #include <errno.h>
90 #endif
91 #endif
92
93 // ----------------------------------------------------------------------------
94 // module globals
95 // ----------------------------------------------------------------------------
96
97 #if wxUSE_ON_FATAL_EXCEPTION
98 static bool gs_handleExceptions = FALSE;
99 #endif
100
101 // ----------------------------------------------------------------------------
102 // constants
103 // ----------------------------------------------------------------------------
104
105 // In the WIN.INI file
106 static const wxChar WX_SECTION[] = wxT("wxWindows");
107 static const wxChar eUSERNAME[] = wxT("UserName");
108
109 // these are only used under Win16
110 #if !defined(__WIN32__) && !defined(__WXMICROWIN__)
111 static const wxChar eHOSTNAME[] = wxT("HostName");
112 static const wxChar eUSERID[] = wxT("UserId");
113 #endif // !Win32
114
115 // ============================================================================
116 // implementation
117 // ============================================================================
118
119 // ----------------------------------------------------------------------------
120 // get host name and related
121 // ----------------------------------------------------------------------------
122
123 // Get hostname only (without domain name)
124 bool wxGetHostName(wxChar *buf, int maxSize)
125 {
126 #if defined(__WXWINCE__)
127 return FALSE;
128 #elif defined(__WIN32__) && !defined(__WXMICROWIN__)
129 DWORD nSize = maxSize;
130 if ( !::GetComputerName(buf, &nSize) )
131 {
132 wxLogLastError(wxT("GetComputerName"));
133
134 return FALSE;
135 }
136
137 return TRUE;
138 #else
139 wxChar *sysname;
140 const wxChar *default_host = wxT("noname");
141
142 if ((sysname = wxGetenv(wxT("SYSTEM_NAME"))) == NULL) {
143 GetProfileString(WX_SECTION, eHOSTNAME, default_host, buf, maxSize - 1);
144 } else
145 wxStrncpy(buf, sysname, maxSize - 1);
146 buf[maxSize] = wxT('\0');
147 return *buf ? TRUE : FALSE;
148 #endif
149 }
150
151 // get full hostname (with domain name if possible)
152 bool wxGetFullHostName(wxChar *buf, int maxSize)
153 {
154 #if defined(__WIN32__) && !defined(__WXMICROWIN__) && ! (defined(__GNUWIN32__) && !defined(__MINGW32__))
155 // TODO should use GetComputerNameEx() when available
156
157 // the idea is that if someone had set wxUSE_SOCKETS to 0 the code
158 // shouldn't use winsock.dll (a.k.a. ws2_32.dll) at all so only use this
159 // code if we link with it anyhow
160 #if wxUSE_SOCKETS
161 WSADATA wsa;
162 if ( WSAStartup(MAKEWORD(1, 1), &wsa) == 0 )
163 {
164 wxString host;
165 char bufA[256];
166 if ( gethostname(bufA, WXSIZEOF(bufA)) == 0 )
167 {
168 // gethostname() won't usually include the DNS domain name, for
169 // this we need to work a bit more
170 if ( !strchr(bufA, '.') )
171 {
172 struct hostent *pHostEnt = gethostbyname(bufA);
173
174 if ( pHostEnt )
175 {
176 // Windows will use DNS internally now
177 pHostEnt = gethostbyaddr(pHostEnt->h_addr, 4, AF_INET);
178 }
179
180 if ( pHostEnt )
181 {
182 host = wxString::FromAscii(pHostEnt->h_name);
183 }
184 }
185 }
186
187 WSACleanup();
188
189 if ( !host.empty() )
190 {
191 wxStrncpy(buf, host, maxSize);
192
193 return TRUE;
194 }
195 }
196
197 #endif // wxUSE_SOCKETS
198
199 #endif // Win32
200
201 return wxGetHostName(buf, maxSize);
202 }
203
204 // Get user ID e.g. jacs
205 bool wxGetUserId(wxChar *buf, int maxSize)
206 {
207 #if defined(__WXWINCE__)
208 return FALSE;
209 #elif defined(__WIN32__) && !defined(__win32s__) && !defined(__WXMICROWIN__)
210 DWORD nSize = maxSize;
211 if ( ::GetUserName(buf, &nSize) == 0 )
212 {
213 // actually, it does happen on Win9x if the user didn't log on
214 DWORD res = ::GetEnvironmentVariable(wxT("username"), buf, maxSize);
215 if ( res == 0 )
216 {
217 // not found
218 return FALSE;
219 }
220 }
221
222 return TRUE;
223 #else // Win16 or Win32s
224 wxChar *user;
225 const wxChar *default_id = wxT("anonymous");
226
227 // Can't assume we have NIS (PC-NFS) or some other ID daemon
228 // So we ...
229 if ( (user = wxGetenv(wxT("USER"))) == NULL &&
230 (user = wxGetenv(wxT("LOGNAME"))) == NULL )
231 {
232 // Use wxWindows configuration data (comming soon)
233 GetProfileString(WX_SECTION, eUSERID, default_id, buf, maxSize - 1);
234 }
235 else
236 {
237 wxStrncpy(buf, user, maxSize - 1);
238 }
239
240 return *buf ? TRUE : FALSE;
241 #endif
242 }
243
244 // Get user name e.g. Julian Smart
245 bool wxGetUserName(wxChar *buf, int maxSize)
246 {
247 #if defined(__WXWINCE__)
248 return FALSE;
249 #elif defined(USE_NET_API)
250 CHAR szUserName[256];
251 if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) )
252 return FALSE;
253
254 // TODO how to get the domain name?
255 CHAR *szDomain = "";
256
257 // the code is based on the MSDN example (also see KB article Q119670)
258 WCHAR wszUserName[256]; // Unicode user name
259 WCHAR wszDomain[256];
260 LPBYTE ComputerName;
261
262 USER_INFO_2 *ui2; // User structure
263
264 // Convert ANSI user name and domain to Unicode
265 MultiByteToWideChar( CP_ACP, 0, szUserName, strlen(szUserName)+1,
266 wszUserName, WXSIZEOF(wszUserName) );
267 MultiByteToWideChar( CP_ACP, 0, szDomain, strlen(szDomain)+1,
268 wszDomain, WXSIZEOF(wszDomain) );
269
270 // Get the computer name of a DC for the domain.
271 if ( NetGetDCName( NULL, wszDomain, &ComputerName ) != NERR_Success )
272 {
273 wxLogError(wxT("Can not find domain controller"));
274
275 goto error;
276 }
277
278 // Look up the user on the DC
279 NET_API_STATUS status = NetUserGetInfo( (LPWSTR)ComputerName,
280 (LPWSTR)&wszUserName,
281 2, // level - we want USER_INFO_2
282 (LPBYTE *) &ui2 );
283 switch ( status )
284 {
285 case NERR_Success:
286 // ok
287 break;
288
289 case NERR_InvalidComputer:
290 wxLogError(wxT("Invalid domain controller name."));
291
292 goto error;
293
294 case NERR_UserNotFound:
295 wxLogError(wxT("Invalid user name '%s'."), szUserName);
296
297 goto error;
298
299 default:
300 wxLogSysError(wxT("Can't get information about user"));
301
302 goto error;
303 }
304
305 // Convert the Unicode full name to ANSI
306 WideCharToMultiByte( CP_ACP, 0, ui2->usri2_full_name, -1,
307 buf, maxSize, NULL, NULL );
308
309 return TRUE;
310
311 error:
312 wxLogError(wxT("Couldn't look up full user name."));
313
314 return FALSE;
315 #else // !USE_NET_API
316 // Could use NIS, MS-Mail or other site specific programs
317 // Use wxWindows configuration data
318 bool ok = GetProfileString(WX_SECTION, eUSERNAME, wxEmptyString, buf, maxSize - 1) != 0;
319 if ( !ok )
320 {
321 ok = wxGetUserId(buf, maxSize);
322 }
323
324 if ( !ok )
325 {
326 wxStrncpy(buf, wxT("Unknown User"), maxSize);
327 }
328 #endif // Win32/16
329
330 return TRUE;
331 }
332
333 const wxChar* wxGetHomeDir(wxString *pstr)
334 {
335 wxString& strDir = *pstr;
336
337 #if defined(__UNIX__)
338 const wxChar *szHome = wxGetenv("HOME");
339 if ( szHome == NULL ) {
340 // we're homeless...
341 wxLogWarning(_("can't find user's HOME, using current directory."));
342 strDir = wxT(".");
343 }
344 else
345 strDir = szHome;
346
347 // add a trailing slash if needed
348 if ( strDir.Last() != wxT('/') )
349 strDir << wxT('/');
350
351 #ifdef __CYGWIN__
352 // Cygwin returns unix type path but that does not work well
353 static wxChar windowsPath[MAX_PATH];
354 cygwin_conv_to_full_win32_path(strDir, windowsPath);
355 strDir = windowsPath;
356 #endif
357 #elif defined(__WXWINCE__)
358 // Nothing
359 #else
360 #ifdef __WIN32__
361 strDir.clear();
362
363 // If we have a valid HOME directory, as is used on many machines that
364 // have unix utilities on them, we should use that.
365 const wxChar *szHome = wxGetenv(wxT("HOME"));
366
367 if ( szHome != NULL )
368 {
369 strDir = szHome;
370 }
371 else // no HOME, try HOMEDRIVE/PATH
372 {
373 szHome = wxGetenv(wxT("HOMEDRIVE"));
374 if ( szHome != NULL )
375 strDir << szHome;
376 szHome = wxGetenv(wxT("HOMEPATH"));
377
378 if ( szHome != NULL )
379 {
380 strDir << szHome;
381
382 // the idea is that under NT these variables have default values
383 // of "%systemdrive%:" and "\\". As we don't want to create our
384 // config files in the root directory of the system drive, we will
385 // create it in our program's dir. However, if the user took care
386 // to set HOMEPATH to something other than "\\", we suppose that he
387 // knows what he is doing and use the supplied value.
388 if ( wxStrcmp(szHome, wxT("\\")) == 0 )
389 strDir.clear();
390 }
391 }
392
393 if ( strDir.empty() )
394 {
395 // If we have a valid USERPROFILE directory, as is the case in
396 // Windows NT, 2000 and XP, we should use that as our home directory.
397 szHome = wxGetenv(wxT("USERPROFILE"));
398
399 if ( szHome != NULL )
400 strDir = szHome;
401 }
402
403 if ( !strDir.empty() )
404 {
405 return strDir.c_str();
406 }
407 //else: fall back to the prograrm directory
408 #else // Win16
409 // Win16 has no idea about home, so use the executable directory instead
410 #endif // WIN16/32
411
412 // 260 was taken from windef.h
413 #ifndef MAX_PATH
414 #define MAX_PATH 260
415 #endif
416
417 wxString strPath;
418 ::GetModuleFileName(::GetModuleHandle(NULL),
419 strPath.GetWriteBuf(MAX_PATH), MAX_PATH);
420 strPath.UngetWriteBuf();
421
422 // extract the dir name
423 wxSplitPath(strPath, &strDir, NULL, NULL);
424
425 #endif // UNIX/Win
426
427 return strDir.c_str();
428 }
429
430 wxChar *wxGetUserHome(const wxString& WXUNUSED(user))
431 {
432 // VZ: the old code here never worked for user != "" anyhow! Moreover, it
433 // returned sometimes a malloc()'d pointer, sometimes a pointer to a
434 // static buffer and sometimes I don't even know what.
435 static wxString s_home;
436
437 return (wxChar *)wxGetHomeDir(&s_home);
438 }
439
440 bool wxDirExists(const wxString& dir)
441 {
442 #ifdef __WXMICROWIN__
443 return wxPathExist(dir);
444 #elif defined(__WIN32__)
445 DWORD attribs = GetFileAttributes(dir);
446 return ((attribs != (DWORD)-1) && (attribs & FILE_ATTRIBUTE_DIRECTORY));
447 #else // Win16
448 #ifdef __BORLANDC__
449 struct ffblk fileInfo;
450 #else
451 struct find_t fileInfo;
452 #endif
453 // In Borland findfirst has a different argument
454 // ordering from _dos_findfirst. But _dos_findfirst
455 // _should_ be ok in both MS and Borland... why not?
456 #ifdef __BORLANDC__
457 return (findfirst(dir, &fileInfo, _A_SUBDIR) == 0 &&
458 (fileInfo.ff_attrib & _A_SUBDIR) != 0);
459 #else
460 return (_dos_findfirst(dir, _A_SUBDIR, &fileInfo) == 0) &&
461 ((fileInfo.attrib & _A_SUBDIR) != 0);
462 #endif
463 #endif // Win32/16
464 }
465
466 bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
467 {
468 #ifdef __WXWINCE__
469 return FALSE;
470 #else
471 if ( path.empty() )
472 return FALSE;
473
474 // old w32api don't have ULARGE_INTEGER
475 #if defined(__WIN32__) && \
476 (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION( 0, 3 ))
477 // GetDiskFreeSpaceEx() is not available under original Win95, check for
478 // it
479 typedef BOOL (WINAPI *GetDiskFreeSpaceEx_t)(LPCTSTR,
480 PULARGE_INTEGER,
481 PULARGE_INTEGER,
482 PULARGE_INTEGER);
483
484 GetDiskFreeSpaceEx_t
485 pGetDiskFreeSpaceEx = (GetDiskFreeSpaceEx_t)::GetProcAddress
486 (
487 ::GetModuleHandle(_T("kernel32.dll")),
488 #if wxUSE_UNICODE
489 "GetDiskFreeSpaceExW"
490 #else
491 "GetDiskFreeSpaceExA"
492 #endif
493 );
494
495 if ( pGetDiskFreeSpaceEx )
496 {
497 ULARGE_INTEGER bytesFree, bytesTotal;
498
499 // may pass the path as is, GetDiskFreeSpaceEx() is smart enough
500 if ( !pGetDiskFreeSpaceEx(path,
501 &bytesFree,
502 &bytesTotal,
503 NULL) )
504 {
505 wxLogLastError(_T("GetDiskFreeSpaceEx"));
506
507 return FALSE;
508 }
509
510 // ULARGE_INTEGER is a union of a 64 bit value and a struct containing
511 // two 32 bit fields which may be or may be not named - try to make it
512 // compile in all cases
513 #if defined(__BORLANDC__) && !defined(_ANONYMOUS_STRUCT)
514 #define UL(ul) ul.u
515 #else // anon union
516 #define UL(ul) ul
517 #endif
518 if ( pTotal )
519 {
520 *pTotal = wxLongLong(UL(bytesTotal).HighPart, UL(bytesTotal).LowPart);
521 }
522
523 if ( pFree )
524 {
525 *pFree = wxLongLong(UL(bytesFree).HighPart, UL(bytesFree).LowPart);
526 }
527 }
528 else
529 #endif // Win32
530 {
531 // there's a problem with drives larger than 2GB, GetDiskFreeSpaceEx()
532 // should be used instead - but if it's not available, fall back on
533 // GetDiskFreeSpace() nevertheless...
534
535 DWORD lSectorsPerCluster,
536 lBytesPerSector,
537 lNumberOfFreeClusters,
538 lTotalNumberOfClusters;
539
540 // FIXME: this is wrong, we should extract the root drive from path
541 // instead, but this is the job for wxFileName...
542 if ( !::GetDiskFreeSpace(path,
543 &lSectorsPerCluster,
544 &lBytesPerSector,
545 &lNumberOfFreeClusters,
546 &lTotalNumberOfClusters) )
547 {
548 wxLogLastError(_T("GetDiskFreeSpace"));
549
550 return FALSE;
551 }
552
553 wxLongLong lBytesPerCluster = lSectorsPerCluster;
554 lBytesPerCluster *= lBytesPerSector;
555
556 if ( pTotal )
557 {
558 *pTotal = lBytesPerCluster;
559 *pTotal *= lTotalNumberOfClusters;
560 }
561
562 if ( pFree )
563 {
564 *pFree = lBytesPerCluster;
565 *pFree *= lNumberOfFreeClusters;
566 }
567 }
568
569 return TRUE;
570 #endif
571 // __WXWINCE__
572 }
573
574 // ----------------------------------------------------------------------------
575 // env vars
576 // ----------------------------------------------------------------------------
577
578 bool wxGetEnv(const wxString& var, wxString *value)
579 {
580 #ifdef __WXWINCE__
581 return FALSE;
582 #elif defined(__WIN16__)
583 const wxChar* ret = wxGetenv(var);
584 if ( !ret )
585 return FALSE;
586
587 if ( value )
588 {
589 *value = ret;
590 }
591
592 return TRUE;
593 #else // Win32
594 // first get the size of the buffer
595 DWORD dwRet = ::GetEnvironmentVariable(var, NULL, 0);
596 if ( !dwRet )
597 {
598 // this means that there is no such variable
599 return FALSE;
600 }
601
602 if ( value )
603 {
604 (void)::GetEnvironmentVariable(var, value->GetWriteBuf(dwRet), dwRet);
605 value->UngetWriteBuf();
606 }
607
608 return TRUE;
609 #endif // Win16/32
610 }
611
612 bool wxSetEnv(const wxString& var, const wxChar *value)
613 {
614 // some compilers have putenv() or _putenv() or _wputenv() but it's better
615 // to always use Win32 function directly instead of dealing with them
616 #if defined(__WIN32__) && !defined(__WXWINCE__)
617 if ( !::SetEnvironmentVariable(var, value) )
618 {
619 wxLogLastError(_T("SetEnvironmentVariable"));
620
621 return FALSE;
622 }
623
624 return TRUE;
625 #else // no way to set env vars
626 return FALSE;
627 #endif
628 }
629
630 // ----------------------------------------------------------------------------
631 // process management
632 // ----------------------------------------------------------------------------
633
634 // structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
635 struct wxFindByPidParams
636 {
637 wxFindByPidParams() { hwnd = 0; pid = 0; }
638
639 // the HWND used to return the result
640 HWND hwnd;
641
642 // the PID we're looking from
643 DWORD pid;
644
645 DECLARE_NO_COPY_CLASS(wxFindByPidParams)
646 };
647
648 // wxKill helper: EnumWindows() callback which is used to find the first (top
649 // level) window belonging to the given process
650 BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
651 {
652 DWORD pid;
653 (void)::GetWindowThreadProcessId(hwnd, &pid);
654
655 wxFindByPidParams *params = (wxFindByPidParams *)lParam;
656 if ( pid == params->pid )
657 {
658 // remember the window we found
659 params->hwnd = hwnd;
660
661 // return FALSE to stop the enumeration
662 return FALSE;
663 }
664
665 // continue enumeration
666 return TRUE;
667 }
668
669 int wxKill(long pid, wxSignal sig, wxKillError *krc)
670 {
671 // get the process handle to operate on
672 HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
673 PROCESS_TERMINATE |
674 PROCESS_QUERY_INFORMATION,
675 FALSE, // not inheritable
676 (DWORD)pid);
677 if ( hProcess == NULL )
678 {
679 if ( krc )
680 {
681 if ( ::GetLastError() == ERROR_ACCESS_DENIED )
682 {
683 *krc = wxKILL_ACCESS_DENIED;
684 }
685 else
686 {
687 *krc = wxKILL_NO_PROCESS;
688 }
689 }
690
691 return -1;
692 }
693
694 bool ok = TRUE;
695 switch ( sig )
696 {
697 case wxSIGKILL:
698 // kill the process forcefully returning -1 as error code
699 if ( !::TerminateProcess(hProcess, (UINT)-1) )
700 {
701 wxLogSysError(_("Failed to kill process %d"), pid);
702
703 if ( krc )
704 {
705 // this is not supposed to happen if we could open the
706 // process
707 *krc = wxKILL_ERROR;
708 }
709
710 ok = FALSE;
711 }
712 break;
713
714 case wxSIGNONE:
715 // do nothing, we just want to test for process existence
716 break;
717
718 default:
719 // any other signal means "terminate"
720 {
721 wxFindByPidParams params;
722 params.pid = (DWORD)pid;
723
724 // EnumWindows() has nice semantics: it returns 0 if it found
725 // something or if an error occured and non zero if it
726 // enumerated all the window
727 if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)&params) )
728 {
729 // did we find any window?
730 if ( params.hwnd )
731 {
732 // tell the app to close
733 //
734 // NB: this is the harshest way, the app won't have
735 // opportunity to save any files, for example, but
736 // this is probably what we want here. If not we
737 // can also use SendMesageTimeout(WM_CLOSE)
738 if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) )
739 {
740 wxLogLastError(_T("PostMessage(WM_QUIT)"));
741 }
742 }
743 else // it was an error then
744 {
745 wxLogLastError(_T("EnumWindows"));
746
747 ok = FALSE;
748 }
749 }
750 else // no windows for this PID
751 {
752 if ( krc )
753 {
754 *krc = wxKILL_ERROR;
755 }
756
757 ok = FALSE;
758 }
759 }
760 }
761
762 // the return code
763 DWORD rc;
764
765 if ( ok )
766 {
767 // as we wait for a short time, we can use just WaitForSingleObject()
768 // and not MsgWaitForMultipleObjects()
769 switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) )
770 {
771 case WAIT_OBJECT_0:
772 // process terminated
773 if ( !::GetExitCodeProcess(hProcess, &rc) )
774 {
775 wxLogLastError(_T("GetExitCodeProcess"));
776 }
777 break;
778
779 default:
780 wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") );
781 // fall through
782
783 case WAIT_FAILED:
784 wxLogLastError(_T("WaitForSingleObject"));
785 // fall through
786
787 case WAIT_TIMEOUT:
788 if ( krc )
789 {
790 *krc = wxKILL_ERROR;
791 }
792
793 rc = STILL_ACTIVE;
794 break;
795 }
796 }
797 else // !ok
798 {
799 // just to suppress the warnings about uninitialized variable
800 rc = 0;
801 }
802
803 ::CloseHandle(hProcess);
804
805 // the return code is the same as from Unix kill(): 0 if killed
806 // successfully or -1 on error
807 //
808 // be careful to interpret rc correctly: for wxSIGNONE we return success if
809 // the process exists, for all the other sig values -- if it doesn't
810 if ( ok &&
811 ((sig == wxSIGNONE) == (rc == STILL_ACTIVE)) )
812 {
813 if ( krc )
814 {
815 *krc = wxKILL_OK;
816 }
817
818 return 0;
819 }
820
821 // error
822 return -1;
823 }
824
825 // Execute a program in an Interactive Shell
826 bool wxShell(const wxString& command)
827 {
828 #ifdef __WXWINCE__
829 return FALSE;
830 #else
831 wxChar *shell = wxGetenv(wxT("COMSPEC"));
832 if ( !shell )
833 shell = (wxChar*) wxT("\\COMMAND.COM");
834
835 wxString cmd;
836 if ( !command )
837 {
838 // just the shell
839 cmd = shell;
840 }
841 else
842 {
843 // pass the command to execute to the command processor
844 cmd.Printf(wxT("%s /c %s"), shell, command.c_str());
845 }
846
847 return wxExecute(cmd, wxEXEC_SYNC) == 0;
848 #endif
849 }
850
851 // Shutdown or reboot the PC
852 bool wxShutdown(wxShutdownFlags wFlags)
853 {
854 #ifdef __WXWINCE__
855 return FALSE;
856 #elif defined(__WIN32__)
857 bool bOK = TRUE;
858
859 if ( wxGetOsVersion(NULL, NULL) == wxWINDOWS_NT ) // if is NT or 2K
860 {
861 // Get a token for this process.
862 HANDLE hToken;
863 bOK = ::OpenProcessToken(GetCurrentProcess(),
864 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
865 &hToken) != 0;
866 if ( bOK )
867 {
868 TOKEN_PRIVILEGES tkp;
869
870 // Get the LUID for the shutdown privilege.
871 ::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
872 &tkp.Privileges[0].Luid);
873
874 tkp.PrivilegeCount = 1; // one privilege to set
875 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
876
877 // Get the shutdown privilege for this process.
878 ::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
879 (PTOKEN_PRIVILEGES)NULL, 0);
880
881 // Cannot test the return value of AdjustTokenPrivileges.
882 bOK = ::GetLastError() == ERROR_SUCCESS;
883 }
884 }
885
886 if ( bOK )
887 {
888 UINT flags = EWX_SHUTDOWN | EWX_FORCE;
889 switch ( wFlags )
890 {
891 case wxSHUTDOWN_POWEROFF:
892 flags |= EWX_POWEROFF;
893 break;
894
895 case wxSHUTDOWN_REBOOT:
896 flags |= EWX_REBOOT;
897 break;
898
899 default:
900 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
901 return FALSE;
902 }
903
904 bOK = ::ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE | EWX_REBOOT, 0) != 0;
905 }
906
907 return bOK;
908 #else // Win16
909 return FALSE;
910 #endif // Win32/16
911 }
912
913 // ----------------------------------------------------------------------------
914 // misc
915 // ----------------------------------------------------------------------------
916
917 // Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
918 long wxGetFreeMemory()
919 {
920 #if defined(__WIN32__) && !defined(__BORLANDC__)
921 MEMORYSTATUS memStatus;
922 memStatus.dwLength = sizeof(MEMORYSTATUS);
923 GlobalMemoryStatus(&memStatus);
924 return memStatus.dwAvailPhys;
925 #else
926 return (long)GetFreeSpace(0);
927 #endif
928 }
929
930 unsigned long wxGetProcessId()
931 {
932 #ifdef __WIN32__
933 return ::GetCurrentProcessId();
934 #else
935 return 0;
936 #endif
937 }
938
939 // Emit a beeeeeep
940 void wxBell()
941 {
942 ::MessageBeep((UINT)-1); // default sound
943 }
944
945 wxString wxGetOsDescription()
946 {
947 #ifdef __WIN32__
948 wxString str;
949
950 OSVERSIONINFO info;
951 wxZeroMemory(info);
952
953 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
954 if ( ::GetVersionEx(&info) )
955 {
956 switch ( info.dwPlatformId )
957 {
958 case VER_PLATFORM_WIN32s:
959 str = _("Win32s on Windows 3.1");
960 break;
961
962 case VER_PLATFORM_WIN32_WINDOWS:
963 str.Printf(_("Windows 9%c"),
964 info.dwMinorVersion == 0 ? _T('5') : _T('8'));
965 if ( !wxIsEmpty(info.szCSDVersion) )
966 {
967 str << _T(" (") << info.szCSDVersion << _T(')');
968 }
969 break;
970
971 case VER_PLATFORM_WIN32_NT:
972 str.Printf(_T("Windows NT %lu.%lu (build %lu"),
973 info.dwMajorVersion,
974 info.dwMinorVersion,
975 info.dwBuildNumber);
976 if ( !wxIsEmpty(info.szCSDVersion) )
977 {
978 str << _T(", ") << info.szCSDVersion;
979 }
980 str << _T(')');
981 break;
982 }
983 }
984 else
985 {
986 wxFAIL_MSG( _T("GetVersionEx() failed") ); // should never happen
987 }
988
989 return str;
990 #else // Win16
991 return _("Windows 3.1");
992 #endif // Win32/16
993 }
994
995 int wxAppTraits::GetOSVersion(int *verMaj, int *verMin)
996 {
997 // cache the version info, it's not going to change
998 //
999 // NB: this is MT-safe, we may use these static vars from different threads
1000 // but as they always have the same value it doesn't matter
1001 static int s_ver = -1,
1002 s_major = -1,
1003 s_minor = -1;
1004
1005 if ( s_ver == -1 )
1006 {
1007 OSVERSIONINFO info;
1008 wxZeroMemory(info);
1009
1010 s_ver = wxWINDOWS;
1011 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1012 if ( ::GetVersionEx(&info) )
1013 {
1014 s_major = info.dwMajorVersion;
1015 s_minor = info.dwMinorVersion;
1016
1017 switch ( info.dwPlatformId )
1018 {
1019 case VER_PLATFORM_WIN32s:
1020 s_ver = wxWIN32S;
1021 break;
1022
1023 case VER_PLATFORM_WIN32_WINDOWS:
1024 s_ver = wxWIN95;
1025 break;
1026
1027 case VER_PLATFORM_WIN32_NT:
1028 s_ver = wxWINDOWS_NT;
1029 break;
1030 #ifdef __WXWINCE__
1031 case VER_PLATFORM_WIN32_CE:
1032 s_ver = wxWINDOWS_CE;
1033 break;
1034 #endif
1035 }
1036 }
1037 }
1038
1039 if ( verMaj )
1040 *verMaj = s_major;
1041 if ( verMin )
1042 *verMin = s_minor;
1043
1044 return s_ver;
1045 }
1046
1047 // ----------------------------------------------------------------------------
1048 // sleep functions
1049 // ----------------------------------------------------------------------------
1050
1051 void wxUsleep(unsigned long milliseconds)
1052 {
1053 ::Sleep(milliseconds);
1054 }
1055
1056 void wxSleep(int nSecs)
1057 {
1058 wxUsleep(1000*nSecs);
1059 }
1060
1061 // ----------------------------------------------------------------------------
1062 // font encoding <-> Win32 codepage conversion functions
1063 // ----------------------------------------------------------------------------
1064
1065 extern WXDLLIMPEXP_BASE long wxEncodingToCharset(wxFontEncoding encoding)
1066 {
1067 switch ( encoding )
1068 {
1069 // although this function is supposed to return an exact match, do do
1070 // some mappings here for the most common case of "standard" encoding
1071 case wxFONTENCODING_SYSTEM:
1072 return DEFAULT_CHARSET;
1073
1074 case wxFONTENCODING_ISO8859_1:
1075 case wxFONTENCODING_ISO8859_15:
1076 case wxFONTENCODING_CP1252:
1077 return ANSI_CHARSET;
1078
1079 #if !defined(__WXMICROWIN__)
1080 // The following four fonts are multi-byte charsets
1081 case wxFONTENCODING_CP932:
1082 return SHIFTJIS_CHARSET;
1083
1084 case wxFONTENCODING_CP936:
1085 return GB2312_CHARSET;
1086
1087 case wxFONTENCODING_CP949:
1088 return HANGUL_CHARSET;
1089
1090 case wxFONTENCODING_CP950:
1091 return CHINESEBIG5_CHARSET;
1092
1093 // The rest are single byte encodings
1094 case wxFONTENCODING_CP1250:
1095 return EASTEUROPE_CHARSET;
1096
1097 case wxFONTENCODING_CP1251:
1098 return RUSSIAN_CHARSET;
1099
1100 case wxFONTENCODING_CP1253:
1101 return GREEK_CHARSET;
1102
1103 case wxFONTENCODING_CP1254:
1104 return TURKISH_CHARSET;
1105
1106 case wxFONTENCODING_CP1255:
1107 return HEBREW_CHARSET;
1108
1109 case wxFONTENCODING_CP1256:
1110 return ARABIC_CHARSET;
1111
1112 case wxFONTENCODING_CP1257:
1113 return BALTIC_CHARSET;
1114
1115 case wxFONTENCODING_CP874:
1116 return THAI_CHARSET;
1117 #endif // !__WXMICROWIN__
1118
1119 case wxFONTENCODING_CP437:
1120 return OEM_CHARSET;
1121
1122 default:
1123 // no way to translate this encoding into a Windows charset
1124 return -1;
1125 }
1126 }
1127
1128 // we have 2 versions of wxCharsetToCodepage(): the old one which directly
1129 // looks up the vlaues in the registry and the new one which is more
1130 // politically correct and has more chances to work on other Windows versions
1131 // as well but the old version is still needed for !wxUSE_FONTMAP case
1132 #if wxUSE_FONTMAP
1133
1134 #include "wx/fontmap.h"
1135
1136 extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding)
1137 {
1138 // translate encoding into the Windows CHARSET
1139 long charset = wxEncodingToCharset(encoding);
1140 if ( charset == -1 )
1141 return -1;
1142
1143 // translate CHARSET to code page
1144 CHARSETINFO csetInfo;
1145 if ( !::TranslateCharsetInfo((DWORD *)(DWORD)charset,
1146 &csetInfo,
1147 TCI_SRCCHARSET) )
1148 {
1149 wxLogLastError(_T("TranslateCharsetInfo(TCI_SRCCHARSET)"));
1150
1151 return -1;
1152 }
1153
1154 return csetInfo.ciACP;
1155 }
1156
1157 extern long wxCharsetToCodepage(const wxChar *name)
1158 {
1159 // first get the font encoding for this charset
1160 if ( !name )
1161 return -1;
1162
1163 wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(name, FALSE);
1164 if ( enc == wxFONTENCODING_SYSTEM )
1165 return -1;
1166
1167 // the use the helper function
1168 return wxEncodingToCodepage(enc);
1169 }
1170
1171 #else // !wxUSE_FONTMAP
1172
1173 #include "wx/msw/registry.h"
1174
1175 // this should work if Internet Exploiter is installed
1176 extern long wxCharsetToCodepage(const wxChar *name)
1177 {
1178 if (!name)
1179 return GetACP();
1180
1181 long CP = -1;
1182
1183 wxString path(wxT("MIME\\Database\\Charset\\"));
1184 wxString cn(name);
1185
1186 // follow the alias loop
1187 for ( ;; )
1188 {
1189 wxRegKey key(wxRegKey::HKCR, path + cn);
1190
1191 if (!key.Exists())
1192 break;
1193
1194 // two cases: either there's an AliasForCharset string,
1195 // or there are Codepage and InternetEncoding dwords.
1196 // The InternetEncoding gives us the actual encoding,
1197 // the Codepage just says which Windows character set to
1198 // use when displaying the data.
1199 if (key.HasValue(wxT("InternetEncoding")) &&
1200 key.QueryValue(wxT("InternetEncoding"), &CP))
1201 break;
1202
1203 // no encoding, see if it's an alias
1204 if (!key.HasValue(wxT("AliasForCharset")) ||
1205 !key.QueryValue(wxT("AliasForCharset"), cn))
1206 break;
1207 }
1208
1209 return CP;
1210 }
1211
1212 #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
1213
1214 // ----------------------------------------------------------------------------
1215 // wxApp::OnFatalException() support
1216 // ----------------------------------------------------------------------------
1217
1218 bool wxHandleFatalExceptions(bool doit)
1219 {
1220 #if wxUSE_ON_FATAL_EXCEPTION
1221 // assume this can only be called from the main thread
1222 gs_handleExceptions = doit;
1223
1224 return TRUE;
1225 #else
1226 wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to use this function"));
1227
1228 (void)doit;
1229 return FALSE;
1230 #endif
1231 }
1232
1233 #if wxUSE_ON_FATAL_EXCEPTION
1234
1235 extern unsigned long wxGlobalSEHandler()
1236 {
1237 if ( gs_handleExceptions && wxTheApp )
1238 {
1239 // give the user a chance to do something special about this
1240 wxTheApp->OnFatalException();
1241
1242 // this will execute our handler and terminate the process
1243 return EXCEPTION_EXECUTE_HANDLER;
1244 }
1245
1246 return EXCEPTION_CONTINUE_SEARCH;
1247 }
1248
1249 #endif // wxUSE_ON_FATAL_EXCEPTION
1250