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