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