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