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