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