1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Various utilities 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21 // #pragma implementation "utils.h"   // Note: this is done in utilscmn.cpp now. 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  37     #include "wx/cursor.h" 
  41 #include "wx/msw/private.h"     // includes <windows.h> 
  45 #if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__) 
  53 #if defined(__CYGWIN__) && !defined(__TWIN32__) 
  54     #include <sys/unistd.h> 
  56     #include <sys/cygwin.h> // for cygwin_conv_to_full_win32_path() 
  59 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs 
  60                     // this (3.1 I believe) and how to test for it. 
  61                     // If this works for Borland 4.0 as well, then no worries. 
  65 // VZ: there is some code using NetXXX() functions to get the full user name: 
  66 //     I don't think it's a good idea because they don't work under Win95 and 
  67 //     seem to return the same as wxGetUserId() under NT. If you really want 
  68 //     to use them, just #define USE_NET_API 
  75 #if defined(__WIN32__) && !defined(__WXWINE__) && !defined(__WXMICROWIN__) 
  84     #if !(defined(_MSC_VER) && (_MSC_VER > 800)) 
  89 //// BEGIN for console support: VC++ only 
  92 #include "wx/msw/msvcrt.h" 
  96 #include "wx/ioswrap.h" 
  98 /* Need to undef new if including crtdbg.h */ 
 107 #  if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS && wxUSE_DEBUG_NEW_ALWAYS 
 108 #  define new new(__TFILE__,__LINE__) 
 113 /// END for console support 
 115 // ---------------------------------------------------------------------------- 
 117 // ---------------------------------------------------------------------------- 
 119 // In the WIN.INI file 
 120 static const wxChar WX_SECTION
[] = wxT("wxWindows"); 
 121 static const wxChar eUSERNAME
[]  = wxT("UserName"); 
 123 // these are only used under Win16 
 124 #if !defined(__WIN32__) && !defined(__WXMICROWIN__) 
 125 static const wxChar eHOSTNAME
[]  = wxT("HostName"); 
 126 static const wxChar eUSERID
[]    = wxT("UserId"); 
 129 #ifndef __WXMICROWIN__ 
 131 // ============================================================================ 
 133 // ============================================================================ 
 135 // ---------------------------------------------------------------------------- 
 136 // get host name and related 
 137 // ---------------------------------------------------------------------------- 
 139 // Get hostname only (without domain name) 
 140 bool wxGetHostName(wxChar 
*buf
, int maxSize
) 
 142 #if defined(__WIN32__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__) 
 143     DWORD nSize 
= maxSize
; 
 144     if ( !::GetComputerName(buf
, &nSize
) ) 
 146         wxLogLastError(wxT("GetComputerName")); 
 154     const wxChar 
*default_host 
= wxT("noname"); 
 156     if ((sysname 
= wxGetenv(wxT("SYSTEM_NAME"))) == NULL
) { 
 157         GetProfileString(WX_SECTION
, eHOSTNAME
, default_host
, buf
, maxSize 
- 1); 
 159         wxStrncpy(buf
, sysname
, maxSize 
- 1); 
 160     buf
[maxSize
] = wxT('\0'); 
 161     return *buf 
? TRUE 
: FALSE
; 
 165 // get full hostname (with domain name if possible) 
 166 bool wxGetFullHostName(wxChar 
*buf
, int maxSize
) 
 168 #if defined(__WIN32__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__) && ! (defined(__GNUWIN32__) && !defined(__MINGW32__)) 
 169     // TODO should use GetComputerNameEx() when available 
 171     // the idea is that if someone had set wxUSE_SOCKETS to 0 the code 
 172     // shouldn't use winsock.dll (a.k.a. ws2_32.dll) at all so only use this 
 173     // code if we link with it anyhow 
 176     if ( WSAStartup(MAKEWORD(1, 1), &wsa
) == 0 ) 
 180         if ( gethostname(bufA
, WXSIZEOF(bufA
)) == 0 ) 
 182             // gethostname() won't usually include the DNS domain name, for 
 183             // this we need to work a bit more 
 184             if ( !strchr(bufA
, '.') ) 
 186                 struct hostent 
*pHostEnt 
=  gethostbyname(bufA
); 
 190                     // Windows will use DNS internally now 
 191                     pHostEnt 
= gethostbyaddr(pHostEnt
->h_addr
, 4, AF_INET
); 
 196                     host 
= pHostEnt
->h_name
; 
 205             wxStrncpy(buf
, host
, maxSize
); 
 210 #endif // wxUSE_SOCKETS 
 214     return wxGetHostName(buf
, maxSize
); 
 217 // Get user ID e.g. jacs 
 218 bool wxGetUserId(wxChar 
*buf
, int maxSize
) 
 220 #if defined(__WIN32__) && !defined(__win32s__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__) 
 221     DWORD nSize 
= maxSize
; 
 222     if ( ::GetUserName(buf
, &nSize
) == 0 ) 
 224         // actually, it does happen on Win9x if the user didn't log on 
 225         DWORD res 
= ::GetEnvironmentVariable(wxT("username"), buf
, maxSize
); 
 234 #else   // Win16 or Win32s 
 236     const wxChar 
*default_id 
= wxT("anonymous"); 
 238     // Can't assume we have NIS (PC-NFS) or some other ID daemon 
 240     if (  (user 
= wxGetenv(wxT("USER"))) == NULL 
&& 
 241             (user 
= wxGetenv(wxT("LOGNAME"))) == NULL 
) 
 243         // Use wxWindows configuration data (comming soon) 
 244         GetProfileString(WX_SECTION
, eUSERID
, default_id
, buf
, maxSize 
- 1); 
 248         wxStrncpy(buf
, user
, maxSize 
- 1); 
 251     return *buf 
? TRUE 
: FALSE
; 
 255 // Get user name e.g. Julian Smart 
 256 bool wxGetUserName(wxChar 
*buf
, int maxSize
) 
 258 #if wxUSE_PENWINDOWS && !defined(__WATCOMC__) && !defined(__GNUWIN32__) 
 259     extern HANDLE g_hPenWin
; // PenWindows Running? 
 262         // PenWindows Does have a user concept! 
 263         // Get the current owner of the recognizer 
 264         GetPrivateProfileString("Current", "User", default_name
, wxBuffer
, maxSize 
- 1, "PENWIN.INI"); 
 265         strncpy(buf
, wxBuffer
, maxSize 
- 1); 
 271         CHAR szUserName
[256]; 
 272         if ( !wxGetUserId(szUserName
, WXSIZEOF(szUserName
)) ) 
 275         // TODO how to get the domain name? 
 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]; 
 283         USER_INFO_2 
*ui2
;         // User structure 
 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
) ); 
 291         // Get the computer name of a DC for the domain. 
 292         if ( NetGetDCName( NULL
, wszDomain
, &ComputerName 
) != NERR_Success 
) 
 294             wxLogError(wxT("Can not find domain controller")); 
 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 
 310             case NERR_InvalidComputer
: 
 311                 wxLogError(wxT("Invalid domain controller name.")); 
 315             case NERR_UserNotFound
: 
 316                 wxLogError(wxT("Invalid user name '%s'."), szUserName
); 
 321                 wxLogSysError(wxT("Can't get information about user")); 
 326         // Convert the Unicode full name to ANSI 
 327         WideCharToMultiByte( CP_ACP
, 0, ui2
->usri2_full_name
, -1, 
 328                 buf
, maxSize
, NULL
, NULL 
); 
 333         wxLogError(wxT("Couldn't look up full user name.")); 
 336 #else  // !USE_NET_API 
 337         // Could use NIS, MS-Mail or other site specific programs 
 338         // Use wxWindows configuration data 
 339         bool ok 
= GetProfileString(WX_SECTION
, eUSERNAME
, wxT(""), buf
, maxSize 
- 1) != 0; 
 342             ok 
= wxGetUserId(buf
, maxSize
); 
 347             wxStrncpy(buf
, wxT("Unknown User"), maxSize
); 
 355 const wxChar
* wxGetHomeDir(wxString 
*pstr
) 
 357   wxString
& strDir 
= *pstr
; 
 359   #if defined(__UNIX__) && !defined(__TWIN32__) 
 360     const wxChar 
*szHome 
= wxGetenv("HOME"); 
 361     if ( szHome 
== NULL 
) { 
 363       wxLogWarning(_("can't find user's HOME, using current directory.")); 
 369     // add a trailing slash if needed 
 370     if ( strDir
.Last() != wxT('/') ) 
 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
; 
 383       // If we have a valid HOME directory, as is used on many machines that 
 384       // have unix utilities on them, we should use that. 
 385       const wxChar 
*szHome 
= wxGetenv(wxT("HOME")); 
 387       if ( szHome 
!= NULL 
) 
 391       else // no HOME, try HOMEDRIVE/PATH 
 393           szHome 
= wxGetenv(wxT("HOMEDRIVE")); 
 394           if ( szHome 
!= NULL 
) 
 396           szHome 
= wxGetenv(wxT("HOMEPATH")); 
 398           if ( szHome 
!= NULL 
) 
 402             // the idea is that under NT these variables have default values 
 403             // of "%systemdrive%:" and "\\". As we don't want to create our 
 404             // config files in the root directory of the system drive, we will 
 405             // create it in our program's dir. However, if the user took care 
 406             // to set HOMEPATH to something other than "\\", we suppose that he 
 407             // knows what he is doing and use the supplied value. 
 408             if ( wxStrcmp(szHome
, wxT("\\")) == 0 ) 
 413       if ( strDir
.empty() ) 
 415           // If we have a valid USERPROFILE directory, as is the case in 
 416           // Windows NT, 2000 and XP, we should use that as our home directory. 
 417           szHome 
= wxGetenv(wxT("USERPROFILE")); 
 419           if ( szHome 
!= NULL 
) 
 423       if ( !strDir
.empty() ) 
 425           return strDir
.c_str(); 
 427       //else: fall back to the prograrm directory 
 429       // Win16 has no idea about home, so use the executable directory instead 
 432     // 260 was taken from windef.h 
 438     ::GetModuleFileName(::GetModuleHandle(NULL
), 
 439                         strPath
.GetWriteBuf(MAX_PATH
), MAX_PATH
); 
 440     strPath
.UngetWriteBuf(); 
 442     // extract the dir name 
 443     wxSplitPath(strPath
, &strDir
, NULL
, NULL
); 
 447   return strDir
.c_str(); 
 450 wxChar 
*wxGetUserHome(const wxString
& WXUNUSED(user
)) 
 452     // VZ: the old code here never worked for user != "" anyhow! Moreover, it 
 453     //     returned sometimes a malloc()'d pointer, sometimes a pointer to a 
 454     //     static buffer and sometimes I don't even know what. 
 455     static wxString s_home
; 
 457     return (wxChar 
*)wxGetHomeDir(&s_home
); 
 460 bool wxDirExists(const wxString
& dir
) 
 462 #ifdef __WXMICROWIN__ 
 463     return wxPathExist(dir
); 
 464 #elif defined(__WIN32__) 
 465     DWORD attribs 
= GetFileAttributes(dir
); 
 466     return ((attribs 
!= (DWORD
)-1) && (attribs 
& FILE_ATTRIBUTE_DIRECTORY
)); 
 469         struct ffblk fileInfo
; 
 471         struct find_t fileInfo
; 
 473     // In Borland findfirst has a different argument 
 474     // ordering from _dos_findfirst. But _dos_findfirst 
 475     // _should_ be ok in both MS and Borland... why not? 
 477         return (findfirst(dir
, &fileInfo
, _A_SUBDIR
) == 0 && 
 478                (fileInfo
.ff_attrib 
& _A_SUBDIR
) != 0); 
 480         return (_dos_findfirst(dir
, _A_SUBDIR
, &fileInfo
) == 0) && 
 481                ((fileInfo
.attrib 
& _A_SUBDIR
) != 0); 
 486 bool wxGetDiskSpace(const wxString
& path
, wxLongLong 
*pTotal
, wxLongLong 
*pFree
) 
 491 // old w32api don't have ULARGE_INTEGER 
 492 #if defined(__WIN32__) && \ 
 493     (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION( 0, 3 )) 
 494     // GetDiskFreeSpaceEx() is not available under original Win95, check for 
 496     typedef BOOL (WINAPI 
*GetDiskFreeSpaceEx_t
)(LPCTSTR
, 
 502         pGetDiskFreeSpaceEx 
= (GetDiskFreeSpaceEx_t
)::GetProcAddress
 
 504                                 ::GetModuleHandle(_T("kernel32.dll")), 
 506                                 "GetDiskFreeSpaceExW" 
 508                                 "GetDiskFreeSpaceExA" 
 512     if ( pGetDiskFreeSpaceEx 
) 
 514         ULARGE_INTEGER bytesFree
, bytesTotal
; 
 516         // may pass the path as is, GetDiskFreeSpaceEx() is smart enough 
 517         if ( !pGetDiskFreeSpaceEx(path
, 
 522             wxLogLastError(_T("GetDiskFreeSpaceEx")); 
 527         // ULARGE_INTEGER is a union of a 64 bit value and a struct containing 
 528         // two 32 bit fields which may be or may be not named - try to make it 
 529         // compile in all cases 
 530 #if defined(__BORLANDC__) && !defined(_ANONYMOUS_STRUCT) 
 537             *pTotal 
= wxLongLong(UL(bytesTotal
).HighPart
, UL(bytesTotal
).LowPart
); 
 542             *pFree 
= wxLongLong(UL(bytesFree
).HighPart
, UL(bytesFree
).LowPart
); 
 548         // there's a problem with drives larger than 2GB, GetDiskFreeSpaceEx() 
 549         // should be used instead - but if it's not available, fall back on 
 550         // GetDiskFreeSpace() nevertheless... 
 552         DWORD lSectorsPerCluster
, 
 554               lNumberOfFreeClusters
, 
 555               lTotalNumberOfClusters
; 
 557         // FIXME: this is wrong, we should extract the root drive from path 
 558         //        instead, but this is the job for wxFileName... 
 559         if ( !::GetDiskFreeSpace(path
, 
 562                                  &lNumberOfFreeClusters
, 
 563                                  &lTotalNumberOfClusters
) ) 
 565             wxLogLastError(_T("GetDiskFreeSpace")); 
 570         wxLongLong lBytesPerCluster 
= lSectorsPerCluster
; 
 571         lBytesPerCluster 
*= lBytesPerSector
; 
 575             *pTotal 
= lBytesPerCluster
; 
 576             *pTotal 
*= lTotalNumberOfClusters
; 
 581             *pFree 
= lBytesPerCluster
; 
 582             *pFree 
*= lNumberOfFreeClusters
; 
 589 // ---------------------------------------------------------------------------- 
 591 // ---------------------------------------------------------------------------- 
 593 bool wxGetEnv(const wxString
& var
, wxString 
*value
) 
 596     const wxChar
* ret 
= wxGetenv(var
); 
 605     // first get the size of the buffer 
 606     DWORD dwRet 
= ::GetEnvironmentVariable(var
, NULL
, 0); 
 609         // this means that there is no such variable 
 615         (void)::GetEnvironmentVariable(var
, value
->GetWriteBuf(dwRet
), dwRet
); 
 616         value
->UngetWriteBuf(); 
 623 bool wxSetEnv(const wxString
& var
, const wxChar 
*value
) 
 625     // some compilers have putenv() or _putenv() or _wputenv() but it's better 
 626     // to always use Win32 function directly instead of dealing with them 
 627 #if defined(__WIN32__) 
 628     if ( !::SetEnvironmentVariable(var
, value
) ) 
 630         wxLogLastError(_T("SetEnvironmentVariable")); 
 636 #else // no way to set env vars 
 641 // ---------------------------------------------------------------------------- 
 642 // process management 
 643 // ---------------------------------------------------------------------------- 
 647 // structure used to pass parameters from wxKill() to wxEnumFindByPidProc() 
 648 struct wxFindByPidParams
 
 650     wxFindByPidParams() { hwnd 
= 0; pid 
= 0; } 
 652     // the HWND used to return the result 
 655     // the PID we're looking from 
 659 // wxKill helper: EnumWindows() callback which is used to find the first (top 
 660 // level) window belonging to the given process 
 661 BOOL CALLBACK 
wxEnumFindByPidProc(HWND hwnd
, LPARAM lParam
) 
 664     (void)::GetWindowThreadProcessId(hwnd
, &pid
); 
 666     wxFindByPidParams 
*params 
= (wxFindByPidParams 
*)lParam
; 
 667     if ( pid 
== params
->pid 
) 
 669         // remember the window we found 
 672         // return FALSE to stop the enumeration 
 676     // continue enumeration 
 682 int wxKill(long pid
, wxSignal sig
, wxKillError 
*krc
) 
 685     // get the process handle to operate on 
 686     HANDLE hProcess 
= ::OpenProcess(SYNCHRONIZE 
| 
 688                                     PROCESS_QUERY_INFORMATION
, 
 689                                     FALSE
, // not inheritable 
 691     if ( hProcess 
== NULL 
) 
 695             if ( ::GetLastError() == ERROR_ACCESS_DENIED 
) 
 697                 *krc 
= wxKILL_ACCESS_DENIED
; 
 701                 *krc 
= wxKILL_NO_PROCESS
; 
 712             // kill the process forcefully returning -1 as error code 
 713             if ( !::TerminateProcess(hProcess
, (UINT
)-1) ) 
 715                 wxLogSysError(_("Failed to kill process %d"), pid
); 
 719                     // this is not supposed to happen if we could open the 
 729             // do nothing, we just want to test for process existence 
 733             // any other signal means "terminate" 
 735                 wxFindByPidParams params
; 
 736                 params
.pid 
= (DWORD
)pid
; 
 738                 // EnumWindows() has nice semantics: it returns 0 if it found 
 739                 // something or if an error occured and non zero if it 
 740                 // enumerated all the window 
 741                 if ( !::EnumWindows(wxEnumFindByPidProc
, (LPARAM
)¶ms
) ) 
 743                     // did we find any window? 
 746                         // tell the app to close 
 748                         // NB: this is the harshest way, the app won't have 
 749                         //     opportunity to save any files, for example, but 
 750                         //     this is probably what we want here. If not we 
 751                         //     can also use SendMesageTimeout(WM_CLOSE) 
 752                         if ( !::PostMessage(params
.hwnd
, WM_QUIT
, 0, 0) ) 
 754                             wxLogLastError(_T("PostMessage(WM_QUIT)")); 
 757                     else // it was an error then 
 759                         wxLogLastError(_T("EnumWindows")); 
 764                 else // no windows for this PID 
 781         // as we wait for a short time, we can use just WaitForSingleObject() 
 782         // and not MsgWaitForMultipleObjects() 
 783         switch ( ::WaitForSingleObject(hProcess
, 500 /* msec */) ) 
 786                 // process terminated 
 787                 if ( !::GetExitCodeProcess(hProcess
, &rc
) ) 
 789                     wxLogLastError(_T("GetExitCodeProcess")); 
 794                 wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") ); 
 798                 wxLogLastError(_T("WaitForSingleObject")); 
 813         // just to suppress the warnings about uninitialized variable 
 817     ::CloseHandle(hProcess
); 
 819     // the return code is the same as from Unix kill(): 0 if killed 
 820     // successfully or -1 on error 
 821     if ( sig 
== wxSIGNONE 
) 
 823         if ( ok 
&& rc 
== STILL_ACTIVE 
) 
 825             // there is such process => success 
 831         if ( ok 
&& rc 
!= STILL_ACTIVE 
) 
 838     wxFAIL_MSG( _T("not implemented") ); 
 839 #endif // Win32/Win16 
 845 // Execute a program in an Interactive Shell 
 846 bool wxShell(const wxString
& command
) 
 848     wxChar 
*shell 
= wxGetenv(wxT("COMSPEC")); 
 850         shell 
= (wxChar
*) wxT("\\COMMAND.COM"); 
 860         // pass the command to execute to the command processor 
 861         cmd
.Printf(wxT("%s /c %s"), shell
, command
.c_str()); 
 864     return wxExecute(cmd
, TRUE 
/* sync */) != 0; 
 867 // Shutdown or reboot the PC  
 868 bool wxShutdown(wxShutdownFlags wFlags
) 
 873     if ( wxGetOsVersion(NULL
, NULL
) == wxWINDOWS_NT 
) // if is NT or 2K 
 875         // Get a token for this process.  
 877         bOK 
= ::OpenProcessToken(GetCurrentProcess(), 
 878                                  TOKEN_ADJUST_PRIVILEGES 
| TOKEN_QUERY
, 
 882             TOKEN_PRIVILEGES tkp
;  
 884             // Get the LUID for the shutdown privilege.  
 885             ::LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, 
 886                                    &tkp
.Privileges
[0].Luid
);  
 888             tkp
.PrivilegeCount 
= 1;  // one privilege to set     
 889             tkp
.Privileges
[0].Attributes 
= SE_PRIVILEGE_ENABLED
;  
 891             // Get the shutdown privilege for this process.  
 892             ::AdjustTokenPrivileges(hToken
, FALSE
, &tkp
, 0, 
 893                                     (PTOKEN_PRIVILEGES
)NULL
, 0);  
 895             // Cannot test the return value of AdjustTokenPrivileges.  
 896             bOK 
= ::GetLastError() == ERROR_SUCCESS
; 
 902         UINT flags 
= EWX_SHUTDOWN 
| EWX_FORCE
; 
 905             case wxSHUTDOWN_POWEROFF
: 
 906                 flags 
|= EWX_POWEROFF
; 
 909             case wxSHUTDOWN_REBOOT
: 
 914                 wxFAIL_MSG( _T("unknown wxShutdown() flag") ); 
 918         bOK 
= ::ExitWindowsEx(EWX_SHUTDOWN 
| EWX_FORCE 
| EWX_REBOOT
, 0) != 0;  
 927 // ---------------------------------------------------------------------------- 
 929 // ---------------------------------------------------------------------------- 
 931 // Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX) 
 932 long wxGetFreeMemory() 
 934 #if defined(__WIN32__) && !defined(__BORLANDC__) && !defined(__TWIN32__) 
 935     MEMORYSTATUS memStatus
; 
 936     memStatus
.dwLength 
= sizeof(MEMORYSTATUS
); 
 937     GlobalMemoryStatus(&memStatus
); 
 938     return memStatus
.dwAvailPhys
; 
 940     return (long)GetFreeSpace(0); 
 947     ::MessageBeep((UINT
)-1);        // default sound 
 950 wxString 
wxGetOsDescription() 
 958     info
.dwOSVersionInfoSize 
= sizeof(OSVERSIONINFO
); 
 959     if ( ::GetVersionEx(&info
) ) 
 961         switch ( info
.dwPlatformId 
) 
 963             case VER_PLATFORM_WIN32s
: 
 964                 str 
= _("Win32s on Windows 3.1"); 
 967             case VER_PLATFORM_WIN32_WINDOWS
: 
 968                 str
.Printf(_("Windows 9%c"), 
 969                            info
.dwMinorVersion 
== 0 ? _T('5') : _T('8')); 
 970                 if ( !wxIsEmpty(info
.szCSDVersion
) ) 
 972                     str 
<< _T(" (") << info
.szCSDVersion 
<< _T(')'); 
 976             case VER_PLATFORM_WIN32_NT
: 
 977                 str
.Printf(_T("Windows NT %lu.%lu (build %lu"), 
 981                 if ( !wxIsEmpty(info
.szCSDVersion
) ) 
 983                     str 
<< _T(", ") << info
.szCSDVersion
; 
 991         wxFAIL_MSG( _T("GetVersionEx() failed") ); // should never happen 
 996     return _("Windows 3.1"); 
1000 int wxGetOsVersion(int *majorVsn
, int *minorVsn
) 
1002 #if defined(__WIN32__) && !defined(__SC__) 
1003     static int ver 
= -1, major 
= -1, minor 
= -1; 
1011         info
.dwOSVersionInfoSize 
= sizeof(OSVERSIONINFO
); 
1012         if ( ::GetVersionEx(&info
) ) 
1014             major 
= info
.dwMajorVersion
; 
1015             minor 
= info
.dwMinorVersion
; 
1017             switch ( info
.dwPlatformId 
) 
1019                 case VER_PLATFORM_WIN32s
: 
1023                 case VER_PLATFORM_WIN32_WINDOWS
: 
1027                 case VER_PLATFORM_WIN32_NT
: 
1034     if (majorVsn 
&& major 
!= -1) 
1036     if (minorVsn 
&& minor 
!= -1) 
1041     int retValue 
= wxWINDOWS
; 
1042     #ifdef __WINDOWS_386__ 
1043         retValue 
= wxWIN386
; 
1045         #if !defined(__WATCOMC__) && !defined(GNUWIN32) && wxUSE_PENWINDOWS 
1046             extern HANDLE g_hPenWin
; 
1047             retValue 
= g_hPenWin 
? wxPENWINDOWS 
: wxWINDOWS
; 
1060 // ---------------------------------------------------------------------------- 
1062 // ---------------------------------------------------------------------------- 
1068 // Sleep for nSecs seconds. Attempt a Windows implementation using timers. 
1069 static bool gs_inTimer 
= FALSE
; 
1071 class wxSleepTimer 
: public wxTimer
 
1074     virtual void Notify() 
1081 static wxTimer 
*wxTheSleepTimer 
= NULL
; 
1083 void wxUsleep(unsigned long milliseconds
) 
1086     ::Sleep(milliseconds
); 
1091     wxTheSleepTimer 
= new wxSleepTimer
; 
1093     wxTheSleepTimer
->Start(milliseconds
); 
1096         if (wxTheApp
->Pending()) 
1097             wxTheApp
->Dispatch(); 
1099     delete wxTheSleepTimer
; 
1100     wxTheSleepTimer 
= NULL
; 
1101 #endif // Win32/!Win32 
1104 void wxSleep(int nSecs
) 
1109     wxTheSleepTimer 
= new wxSleepTimer
; 
1111     wxTheSleepTimer
->Start(nSecs
*1000); 
1114         if (wxTheApp
->Pending()) 
1115             wxTheApp
->Dispatch(); 
1117     delete wxTheSleepTimer
; 
1118     wxTheSleepTimer 
= NULL
; 
1121 // Consume all events until no more left 
1122 void wxFlushEvents() 
1127 #endif // wxUSE_TIMER 
1129 #elif defined(__WIN32__) // wxUSE_GUI 
1131 void wxUsleep(unsigned long milliseconds
) 
1133     ::Sleep(milliseconds
); 
1136 void wxSleep(int nSecs
) 
1138     wxUsleep(1000*nSecs
); 
1141 #endif // wxUSE_GUI/!wxUSE_GUI 
1142 #endif // __WXMICROWIN__ 
1144 // ---------------------------------------------------------------------------- 
1145 // deprecated (in favour of wxLog) log functions 
1146 // ---------------------------------------------------------------------------- 
1148 #if WXWIN_COMPATIBILITY_2_2 
1150 // Output a debug mess., in a system dependent fashion. 
1151 #ifndef __WXMICROWIN__ 
1152 void wxDebugMsg(const wxChar 
*fmt 
...) 
1155   static wxChar buffer
[512]; 
1157   if (!wxTheApp
->GetWantDebugOutput()) 
1162   wvsprintf(buffer
,fmt
,ap
); 
1163   OutputDebugString((LPCTSTR
)buffer
); 
1168 // Non-fatal error: pop up message box and (possibly) continue 
1169 void wxError(const wxString
& msg
, const wxString
& title
) 
1171   wxSprintf(wxBuffer
, wxT("%s\nContinue?"), WXSTRINGCAST msg
); 
1172   if (MessageBox(NULL
, (LPCTSTR
)wxBuffer
, (LPCTSTR
)WXSTRINGCAST title
, 
1173              MB_ICONSTOP 
| MB_YESNO
) == IDNO
) 
1177 // Fatal error: pop up message box and abort 
1178 void wxFatalError(const wxString
& msg
, const wxString
& title
) 
1180   wxSprintf(wxBuffer
, wxT("%s: %s"), WXSTRINGCAST title
, WXSTRINGCAST msg
); 
1181   FatalAppExit(0, (LPCTSTR
)wxBuffer
); 
1183 #endif // __WXMICROWIN__ 
1185 #endif // WXWIN_COMPATIBILITY_2_2 
1189 // ---------------------------------------------------------------------------- 
1190 // functions to work with .INI files 
1191 // ---------------------------------------------------------------------------- 
1193 // Reading and writing resources (eg WIN.INI, .Xdefaults) 
1195 bool wxWriteResource(const wxString
& section
, const wxString
& entry
, const wxString
& value
, const wxString
& file
) 
1197   if (file 
!= wxT("")) 
1198 // Don't know what the correct cast should be, but it doesn't 
1199 // compile in BC++/16-bit without this cast. 
1200 #if !defined(__WIN32__) 
1201     return (WritePrivateProfileString((const char*) section
, (const char*) entry
, (const char*) value
, (const char*) file
) != 0); 
1203     return (WritePrivateProfileString((LPCTSTR
)WXSTRINGCAST section
, (LPCTSTR
)WXSTRINGCAST entry
, (LPCTSTR
)value
, (LPCTSTR
)WXSTRINGCAST file
) != 0); 
1206     return (WriteProfileString((LPCTSTR
)WXSTRINGCAST section
, (LPCTSTR
)WXSTRINGCAST entry
, (LPCTSTR
)WXSTRINGCAST value
) != 0); 
1209 bool wxWriteResource(const wxString
& section
, const wxString
& entry
, float value
, const wxString
& file
) 
1212     buf
.Printf(wxT("%.4f"), value
); 
1214     return wxWriteResource(section
, entry
, buf
, file
); 
1217 bool wxWriteResource(const wxString
& section
, const wxString
& entry
, long value
, const wxString
& file
) 
1220     buf
.Printf(wxT("%ld"), value
); 
1222     return wxWriteResource(section
, entry
, buf
, file
); 
1225 bool wxWriteResource(const wxString
& section
, const wxString
& entry
, int value
, const wxString
& file
) 
1228     buf
.Printf(wxT("%d"), value
); 
1230     return wxWriteResource(section
, entry
, buf
, file
); 
1233 bool wxGetResource(const wxString
& section
, const wxString
& entry
, wxChar 
**value
, const wxString
& file
) 
1235     static const wxChar defunkt
[] = wxT("$$default"); 
1236     if (file 
!= wxT("")) 
1238         int n 
= GetPrivateProfileString((LPCTSTR
)WXSTRINGCAST section
, (LPCTSTR
)WXSTRINGCAST entry
, (LPCTSTR
)defunkt
, 
1239                 (LPTSTR
)wxBuffer
, 1000, (LPCTSTR
)WXSTRINGCAST file
); 
1240         if (n 
== 0 || wxStrcmp(wxBuffer
, defunkt
) == 0) 
1245         int n 
= GetProfileString((LPCTSTR
)WXSTRINGCAST section
, (LPCTSTR
)WXSTRINGCAST entry
, (LPCTSTR
)defunkt
, 
1246                 (LPTSTR
)wxBuffer
, 1000); 
1247         if (n 
== 0 || wxStrcmp(wxBuffer
, defunkt
) == 0) 
1250     if (*value
) delete[] (*value
); 
1251     *value 
= copystring(wxBuffer
); 
1255 bool wxGetResource(const wxString
& section
, const wxString
& entry
, float *value
, const wxString
& file
) 
1258     bool succ 
= wxGetResource(section
, entry
, (wxChar 
**)&s
, file
); 
1261         *value 
= (float)wxStrtod(s
, NULL
); 
1268 bool wxGetResource(const wxString
& section
, const wxString
& entry
, long *value
, const wxString
& file
) 
1271     bool succ 
= wxGetResource(section
, entry
, (wxChar 
**)&s
, file
); 
1274         *value 
= wxStrtol(s
, NULL
, 10); 
1281 bool wxGetResource(const wxString
& section
, const wxString
& entry
, int *value
, const wxString
& file
) 
1284     bool succ 
= wxGetResource(section
, entry
, (wxChar 
**)&s
, file
); 
1287         *value 
= (int)wxStrtol(s
, NULL
, 10); 
1293 #endif // wxUSE_RESOURCES 
1295 // --------------------------------------------------------------------------- 
1296 // helper functions for showing a "busy" cursor 
1297 // --------------------------------------------------------------------------- 
1299 static HCURSOR gs_wxBusyCursor 
= 0;     // new, busy cursor 
1300 static HCURSOR gs_wxBusyCursorOld 
= 0;  // old cursor 
1301 static int gs_wxBusyCursorCount 
= 0; 
1303 extern HCURSOR 
wxGetCurrentBusyCursor() 
1305     return gs_wxBusyCursor
; 
1308 // Set the cursor to the busy cursor for all windows 
1309 void wxBeginBusyCursor(wxCursor 
*cursor
) 
1311     if ( gs_wxBusyCursorCount
++ == 0 ) 
1313         gs_wxBusyCursor 
= (HCURSOR
)cursor
->GetHCURSOR(); 
1314 #ifndef __WXMICROWIN__ 
1315         gs_wxBusyCursorOld 
= ::SetCursor(gs_wxBusyCursor
); 
1318     //else: nothing to do, already set 
1321 // Restore cursor to normal 
1322 void wxEndBusyCursor() 
1324     wxCHECK_RET( gs_wxBusyCursorCount 
> 0, 
1325                  wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") ); 
1327     if ( --gs_wxBusyCursorCount 
== 0 ) 
1329 #ifndef __WXMICROWIN__ 
1330         ::SetCursor(gs_wxBusyCursorOld
); 
1332         gs_wxBusyCursorOld 
= 0; 
1336 // TRUE if we're between the above two calls 
1339   return gs_wxBusyCursorCount 
> 0; 
1342 // Check whether this window wants to process messages, e.g. Stop button 
1343 // in long calculations. 
1344 bool wxCheckForInterrupt(wxWindow 
*wnd
) 
1346     wxCHECK( wnd
, FALSE 
); 
1349     while ( ::PeekMessage(&msg
, GetHwndOf(wnd
), 0, 0, PM_REMOVE
) ) 
1351         ::TranslateMessage(&msg
); 
1352         ::DispatchMessage(&msg
); 
1358 // MSW only: get user-defined resource from the .res file. 
1359 // Returns NULL or newly-allocated memory, so use delete[] to clean up. 
1361 #ifndef __WXMICROWIN__ 
1362 wxChar 
*wxLoadUserResource(const wxString
& resourceName
, const wxString
& resourceType
) 
1364     HRSRC hResource 
= ::FindResource(wxGetInstance(), resourceName
, resourceType
); 
1365     if ( hResource 
== 0 ) 
1368     HGLOBAL hData 
= ::LoadResource(wxGetInstance(), hResource
); 
1372     wxChar 
*theText 
= (wxChar 
*)::LockResource(hData
); 
1376     // Not all compilers put a zero at the end of the resource (e.g. BC++ doesn't). 
1377     // so we need to find the length of the resource. 
1378     int len 
= ::SizeofResource(wxGetInstance(), hResource
); 
1379     wxChar  
*s 
= new wxChar
[len
+1]; 
1380     wxStrncpy(s
,theText
,len
); 
1383     // wxChar *s = copystring(theText); 
1385     // Obsolete in WIN32 
1387     UnlockResource(hData
); 
1391     //  GlobalFree(hData); 
1395 #endif // __WXMICROWIN__ 
1397 // ---------------------------------------------------------------------------- 
1399 // ---------------------------------------------------------------------------- 
1401 // See also the wxGetMousePosition in window.cpp 
1402 // Deprecated: use wxPoint wxGetMousePosition() instead 
1403 void wxGetMousePosition( int* x
, int* y 
) 
1406     GetCursorPos( & pt 
); 
1411 // Return TRUE if we have a colour display 
1412 bool wxColourDisplay() 
1414 #ifdef __WXMICROWIN__ 
1418     // this function is called from wxDC ctor so it is called a *lot* of times 
1419     // hence we optimize it a bit but doign the check only once 
1421     // this should be MT safe as only the GUI thread (holding the GUI mutex) 
1423     static int s_isColour 
= -1; 
1425     if ( s_isColour 
== -1 ) 
1428         int noCols 
= ::GetDeviceCaps(dc
, NUMCOLORS
); 
1430         s_isColour 
= (noCols 
== -1) || (noCols 
> 2); 
1433     return s_isColour 
!= 0; 
1437 // Returns depth of screen 
1438 int wxDisplayDepth() 
1441     return GetDeviceCaps(dc
, PLANES
) * GetDeviceCaps(dc
, BITSPIXEL
); 
1444 // Get size of display 
1445 void wxDisplaySize(int *width
, int *height
) 
1447 #ifdef __WXMICROWIN__ 
1449     HWND hWnd 
= GetDesktopWindow(); 
1450     ::GetWindowRect(hWnd
, & rect
); 
1453         *width 
= rect
.right 
- rect
.left
; 
1455         *height 
= rect
.bottom 
- rect
.top
; 
1456 #else // !__WXMICROWIN__ 
1460         *width 
= ::GetDeviceCaps(dc
, HORZRES
); 
1462         *height 
= ::GetDeviceCaps(dc
, VERTRES
); 
1463 #endif // __WXMICROWIN__/!__WXMICROWIN__ 
1466 void wxDisplaySizeMM(int *width
, int *height
) 
1468 #ifdef __WXMICROWIN__ 
1478         *width 
= ::GetDeviceCaps(dc
, HORZSIZE
); 
1480         *height 
= ::GetDeviceCaps(dc
, VERTSIZE
); 
1484 void wxClientDisplayRect(int *x
, int *y
, int *width
, int *height
) 
1486 #if defined(__WIN16__) || defined(__WXMICROWIN__) 
1488     wxDisplaySize(width
, height
); 
1490     // Determine the desktop dimensions minus the taskbar and any other 
1491     // special decorations... 
1494     SystemParametersInfo(SPI_GETWORKAREA
, 0, &r
, 0); 
1497     if (width
)  *width 
= r
.right 
- r
.left
; 
1498     if (height
) *height 
= r
.bottom 
- r
.top
; 
1502 // --------------------------------------------------------------------------- 
1503 // window information functions 
1504 // --------------------------------------------------------------------------- 
1506 wxString WXDLLEXPORT 
wxGetWindowText(WXHWND hWnd
) 
1512         int len 
= GetWindowTextLength((HWND
)hWnd
) + 1; 
1513         ::GetWindowText((HWND
)hWnd
, str
.GetWriteBuf(len
), len
); 
1514         str
.UngetWriteBuf(); 
1520 wxString WXDLLEXPORT 
wxGetWindowClass(WXHWND hWnd
) 
1525 #ifndef __WXMICROWIN__ 
1528         int len 
= 256; // some starting value 
1532             int count 
= ::GetClassName((HWND
)hWnd
, str
.GetWriteBuf(len
), len
); 
1534             str
.UngetWriteBuf(); 
1537                 // the class name might have been truncated, retry with larger 
1547 #endif // !__WXMICROWIN__ 
1552 WXWORD WXDLLEXPORT 
wxGetWindowId(WXHWND hWnd
) 
1555     return (WXWORD
)GetWindowWord((HWND
)hWnd
, GWW_ID
); 
1557     return (WXWORD
)GetWindowLong((HWND
)hWnd
, GWL_ID
); 
1561 // ---------------------------------------------------------------------------- 
1563 // ---------------------------------------------------------------------------- 
1565 extern void PixelToHIMETRIC(LONG 
*x
, LONG 
*y
) 
1569     int iWidthMM 
= GetDeviceCaps(hdcRef
, HORZSIZE
), 
1570         iHeightMM 
= GetDeviceCaps(hdcRef
, VERTSIZE
), 
1571         iWidthPels 
= GetDeviceCaps(hdcRef
, HORZRES
), 
1572         iHeightPels 
= GetDeviceCaps(hdcRef
, VERTRES
); 
1574     *x 
*= (iWidthMM 
* 100); 
1576     *y 
*= (iHeightMM 
* 100); 
1580 extern void HIMETRICToPixel(LONG 
*x
, LONG 
*y
) 
1584     int iWidthMM 
= GetDeviceCaps(hdcRef
, HORZSIZE
), 
1585         iHeightMM 
= GetDeviceCaps(hdcRef
, VERTSIZE
), 
1586         iWidthPels 
= GetDeviceCaps(hdcRef
, HORZRES
), 
1587         iHeightPels 
= GetDeviceCaps(hdcRef
, VERTRES
); 
1590     *x 
/= (iWidthMM 
* 100); 
1592     *y 
/= (iHeightMM 
* 100); 
1597 #ifdef __WXMICROWIN__ 
1598 int wxGetOsVersion(int *majorVsn
, int *minorVsn
) 
1601     if (majorVsn
) *majorVsn 
= 0; 
1602     if (minorVsn
) *minorVsn 
= 0; 
1605 #endif // __WXMICROWIN__ 
1607 // ---------------------------------------------------------------------------- 
1608 // Win32 codepage conversion functions 
1609 // ---------------------------------------------------------------------------- 
1611 #if defined(__WIN32__) && !defined(__WXMICROWIN__) 
1613 // wxGetNativeFontEncoding() doesn't exist neither in wxBase nor in wxUniv 
1614 #if wxUSE_GUI && !defined(__WXUNIVERSAL__) 
1616 #include "wx/fontmap.h" 
1618 // VZ: the new version of wxCharsetToCodepage() is more politically correct 
1619 //     and should work on other Windows versions as well but the old version is 
1620 //     still needed for !wxUSE_FONTMAP || !wxUSE_GUI case 
1622 extern long wxEncodingToCodepage(wxFontEncoding encoding
) 
1624     // translate encoding into the Windows CHARSET 
1625     wxNativeEncodingInfo natveEncInfo
; 
1626     if ( !wxGetNativeFontEncoding(encoding
, &natveEncInfo
) ) 
1629     // translate CHARSET to code page 
1630     CHARSETINFO csetInfo
; 
1631     if ( !::TranslateCharsetInfo((DWORD 
*)(DWORD
)natveEncInfo
.charset
, 
1635         wxLogLastError(_T("TranslateCharsetInfo(TCI_SRCCHARSET)")); 
1640     return csetInfo
.ciACP
; 
1645 extern long wxCharsetToCodepage(const wxChar 
*name
) 
1647     // first get the font encoding for this charset 
1651     wxFontEncoding enc 
= wxFontMapper::Get()->CharsetToEncoding(name
, FALSE
); 
1652     if ( enc 
== wxFONTENCODING_SYSTEM 
) 
1655     // the use the helper function 
1656     return wxEncodingToCodepage(enc
); 
1659 #endif // wxUSE_FONTMAP 
1663 // include old wxCharsetToCodepage() by OK if needed 
1664 #if !wxUSE_GUI || !wxUSE_FONTMAP 
1666 #include "wx/msw/registry.h" 
1668 // this should work if Internet Exploiter is installed 
1669 extern long wxCharsetToCodepage(const wxChar 
*name
) 
1678         wxString 
path(wxT("MIME\\Database\\Charset\\")); 
1680         wxRegKey 
key(wxRegKey::HKCR
, path
); 
1682         if (!key
.Exists()) break; 
1684         // two cases: either there's an AliasForCharset string, 
1685         // or there are Codepage and InternetEncoding dwords. 
1686         // The InternetEncoding gives us the actual encoding, 
1687         // the Codepage just says which Windows character set to 
1688         // use when displaying the data. 
1689         if (key
.HasValue(wxT("InternetEncoding")) && 
1690             key
.QueryValue(wxT("InternetEncoding"), &CP
)) break; 
1692         // no encoding, see if it's an alias 
1693         if (!key
.HasValue(wxT("AliasForCharset")) || 
1694             !key
.QueryValue(wxT("AliasForCharset"), cn
)) break; 
1700 #endif // !wxUSE_GUI || !wxUSE_FONTMAP