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