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