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