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