]> git.saurik.com Git - wxWidgets.git/blame - src/msw/utils.cpp
Add support for IEC and SI size units to wxFileName::GetHumanReadableSize().
[wxWidgets.git] / src / msw / utils.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
119f7bb7 2// Name: src/msw/utils.cpp
2bda0e17
KB
3// Purpose: Various utilities
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
b568d04f
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
a4f96412 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
27#ifndef WX_PRECOMP
a4f96412
VZ
28 #include "wx/utils.h"
29 #include "wx/app.h"
1f0500b3
VZ
30 #include "wx/intl.h"
31 #include "wx/log.h"
743e0a66 32#endif //WX_PRECOMP
2bda0e17 33
66d84d11 34#include "wx/msw/registry.h"
2739d4f0 35#include "wx/apptrait.h"
23ee4b48 36#include "wx/dynlib.h"
15cdcf6a 37#include "wx/dynload.h"
a45fb5b4 38#include "wx/scopeguard.h"
b815db22 39#include "wx/filename.h"
2739d4f0 40
2dc357ea
VZ
41#include "wx/confbase.h" // for wxExpandEnvVars()
42
b568d04f 43#include "wx/msw/private.h" // includes <windows.h>
a6c2e2c7 44#include "wx/msw/missing.h" // for CHARSET_HANGUL
b568d04f 45
f6afe7fd
RN
46#if defined(__CYGWIN__)
47 //CYGWIN gives annoying warning about runtime stuff if we don't do this
48# define USE_SYS_TYPES_FD_SET
49# include <sys/types.h>
50#endif
51
7acf6a92
JS
52// Doesn't work with Cygwin at present
53#if wxUSE_SOCKETS && (defined(__GNUWIN32_OLD__) || defined(__WXWINCE__) || defined(__CYGWIN32__))
c1cb4153
VZ
54 // apparently we need to include winsock.h to get WSADATA and other stuff
55 // used in wxGetFullHostName() with the old mingw32 versions
56 #include <winsock.h>
57#endif
58
f172cb82 59#if !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
a4f96412 60 #include <direct.h>
ce3ed50d 61
a4f96412
VZ
62 #ifndef __MWERKS__
63 #include <dos.h>
64 #endif
743e0a66 65#endif //GNUWIN32
2bda0e17 66
b39dbf34 67#if defined(__CYGWIN__)
a4f96412
VZ
68 #include <sys/unistd.h>
69 #include <sys/stat.h>
3ffbc733 70 #include <sys/cygwin.h> // for cygwin_conv_to_full_win32_path()
743e0a66
VZ
71#endif //GNUWIN32
72
2bda0e17
KB
73#ifdef __BORLANDC__ // Please someone tell me which version of Borland needs
74 // this (3.1 I believe) and how to test for it.
75 // If this works for Borland 4.0 as well, then no worries.
a4f96412 76 #include <dir.h>
2bda0e17
KB
77#endif
78
a4f96412
VZ
79// VZ: there is some code using NetXXX() functions to get the full user name:
80// I don't think it's a good idea because they don't work under Win95 and
81// seem to return the same as wxGetUserId() under NT. If you really want
82// to use them, just #define USE_NET_API
83#undef USE_NET_API
84
85#ifdef USE_NET_API
86 #include <lm.h>
87#endif // USE_NET_API
88
4676948b 89#if defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2e38557f
JS
90 #ifndef __UNIX__
91 #include <io.h>
92 #endif
2bda0e17 93
a4f96412
VZ
94 #ifndef __GNUWIN32__
95 #include <shellapi.h>
96 #endif
2bda0e17
KB
97#endif
98
2bda0e17 99#ifndef __WATCOMC__
3f4a0c5b
VZ
100 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
101 #include <errno.h>
102 #endif
2bda0e17 103#endif
2bda0e17 104
e0f6b731
JS
105// For wxKillAllChildren
106#include <tlhelp32.h>
107
b568d04f
VZ
108// ----------------------------------------------------------------------------
109// constants
110// ----------------------------------------------------------------------------
111
2bda0e17 112// In the WIN.INI file
119f7bb7 113#if (!defined(USE_NET_API) && !defined(__WXWINCE__)) || defined(__WXMICROWIN__)
e7d9c398 114static const wxChar WX_SECTION[] = wxT("wxWindows");
119f7bb7
WS
115#endif
116
117#if (!defined(USE_NET_API) && !defined(__WXWINCE__))
b568d04f 118static const wxChar eUSERNAME[] = wxT("UserName");
119f7bb7 119#endif
b568d04f 120
b568d04f
VZ
121// ============================================================================
122// implementation
123// ============================================================================
2bda0e17 124
b568d04f
VZ
125// ----------------------------------------------------------------------------
126// get host name and related
127// ----------------------------------------------------------------------------
2bda0e17 128
1f0500b3 129// Get hostname only (without domain name)
32cdc453 130bool wxGetHostName(wxChar *buf, int maxSize)
2bda0e17 131{
4676948b 132#if defined(__WXWINCE__)
32cdc453
VZ
133 // GetComputerName() is not supported but the name seems to be stored in
134 // this location in the registry, at least for PPC2003 and WM5
135 wxString hostName;
136 wxRegKey regKey(wxRegKey::HKLM, wxT("Ident"));
137 if ( !regKey.HasValue(wxT("Name")) ||
138 !regKey.QueryValue(wxT("Name"), hostName) )
139 return false;
140
141 wxStrlcpy(buf, hostName.wx_str(), maxSize);
142#else // !__WXWINCE__
b568d04f
VZ
143 DWORD nSize = maxSize;
144 if ( !::GetComputerName(buf, &nSize) )
145 {
f6bcfd97 146 wxLogLastError(wxT("GetComputerName"));
b568d04f 147
7010702f 148 return false;
b568d04f 149 }
32cdc453 150#endif // __WXWINCE__/!__WXWINCE__
b568d04f 151
27d2dbbc 152 return true;
2bda0e17
KB
153}
154
1f0500b3 155// get full hostname (with domain name if possible)
b568d04f
VZ
156bool wxGetFullHostName(wxChar *buf, int maxSize)
157{
a8ff046b 158#if !defined( __WXMICROWIN__) && wxUSE_DYNLIB_CLASS && wxUSE_SOCKETS
1f0500b3 159 // TODO should use GetComputerNameEx() when available
79180098 160
15cdcf6a 161 // we don't want to always link with Winsock DLL as we might not use it at
7b28e0ed
VZ
162 // all, so load it dynamically here if needed (and don't complain if it is
163 // missing, we handle this)
164 wxLogNull noLog;
165
9a83f860 166 wxDynamicLibrary dllWinsock(wxT("ws2_32.dll"), wxDL_VERBATIM);
15cdcf6a 167 if ( dllWinsock.IsLoaded() )
1f0500b3 168 {
15cdcf6a
VZ
169 typedef int (PASCAL *WSAStartup_t)(WORD, WSADATA *);
170 typedef int (PASCAL *gethostname_t)(char *, int);
171 typedef hostent* (PASCAL *gethostbyname_t)(const char *);
172 typedef hostent* (PASCAL *gethostbyaddr_t)(const char *, int , int);
173 typedef int (PASCAL *WSACleanup_t)(void);
1f0500b3 174
15cdcf6a
VZ
175 #define LOAD_WINSOCK_FUNC(func) \
176 func ## _t \
9a83f860 177 pfn ## func = (func ## _t)dllWinsock.GetSymbol(wxT(#func))
1f0500b3 178
15cdcf6a
VZ
179 LOAD_WINSOCK_FUNC(WSAStartup);
180
181 WSADATA wsa;
182 if ( pfnWSAStartup && pfnWSAStartup(MAKEWORD(1, 1), &wsa) == 0 )
183 {
184 LOAD_WINSOCK_FUNC(gethostname);
185
186 wxString host;
187 if ( pfngethostname )
188 {
189 char bufA[256];
190 if ( pfngethostname(bufA, WXSIZEOF(bufA)) == 0 )
1f0500b3 191 {
15cdcf6a
VZ
192 // gethostname() won't usually include the DNS domain name,
193 // for this we need to work a bit more
194 if ( !strchr(bufA, '.') )
195 {
196 LOAD_WINSOCK_FUNC(gethostbyname);
197
198 struct hostent *pHostEnt = pfngethostbyname
199 ? pfngethostbyname(bufA)
200 : NULL;
201
202 if ( pHostEnt )
203 {
204 // Windows will use DNS internally now
205 LOAD_WINSOCK_FUNC(gethostbyaddr);
206
207 pHostEnt = pfngethostbyaddr
208 ? pfngethostbyaddr(pHostEnt->h_addr,
209 4, AF_INET)
210 : NULL;
211 }
212
213 if ( pHostEnt )
214 {
215 host = wxString::FromAscii(pHostEnt->h_name);
216 }
217 }
1f0500b3
VZ
218 }
219 }
1f0500b3 220
15cdcf6a
VZ
221 LOAD_WINSOCK_FUNC(WSACleanup);
222 if ( pfnWSACleanup )
223 pfnWSACleanup();
1f0500b3 224
1f0500b3 225
15cdcf6a
VZ
226 if ( !host.empty() )
227 {
64accea5 228 wxStrlcpy(buf, host.c_str(), maxSize);
15cdcf6a 229
27d2dbbc 230 return true;
15cdcf6a 231 }
1f0500b3
VZ
232 }
233 }
15cdcf6a 234#endif // !__WXMICROWIN__
1f0500b3 235
b568d04f
VZ
236 return wxGetHostName(buf, maxSize);
237}
238
2bda0e17 239// Get user ID e.g. jacs
7bea7b91
WS
240bool wxGetUserId(wxChar *WXUNUSED_IN_WINCE(buf),
241 int WXUNUSED_IN_WINCE(maxSize))
2bda0e17 242{
4676948b 243#if defined(__WXWINCE__)
040e5f77 244 // TODO-CE
7010702f 245 return false;
e408bf52 246#else
0a144271
VZ
247 DWORD nSize = maxSize;
248 if ( ::GetUserName(buf, &nSize) == 0 )
249 {
a4f96412 250 // actually, it does happen on Win9x if the user didn't log on
223d09f6 251 DWORD res = ::GetEnvironmentVariable(wxT("username"), buf, maxSize);
a4f96412
VZ
252 if ( res == 0 )
253 {
254 // not found
27d2dbbc 255 return false;
a4f96412 256 }
0a144271
VZ
257 }
258
27d2dbbc 259 return true;
2bda0e17
KB
260#endif
261}
262
263// Get user name e.g. Julian Smart
119f7bb7 264bool wxGetUserName(wxChar *buf, int maxSize)
2bda0e17 265{
119f7bb7 266 wxCHECK_MSG( buf && ( maxSize > 0 ), false,
9a83f860 267 wxT("empty buffer in wxGetUserName") );
f77c0fe3 268#if defined(__WXWINCE__) && wxUSE_REGKEY
66d84d11
WS
269 wxLogNull noLog;
270 wxRegKey key(wxRegKey::HKCU, wxT("ControlPanel\\Owner"));
119f7bb7
WS
271 if(!key.Open(wxRegKey::Read))
272 return false;
273 wxString name;
66d84d11 274 if(!key.QueryValue(wxT("Owner"),name))
119f7bb7 275 return false;
e408bf52 276 wxStrlcpy(buf, name.c_str(), maxSize);
119f7bb7 277 return true;
4676948b 278#elif defined(USE_NET_API)
3e3be693
VZ
279 CHAR szUserName[256];
280 if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) )
7010702f 281 return false;
a4f96412 282
3e3be693
VZ
283 // TODO how to get the domain name?
284 CHAR *szDomain = "";
a4f96412 285
3e3be693
VZ
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;
a4f96412 290
3e3be693 291 USER_INFO_2 *ui2; // User structure
a4f96412 292
3e3be693
VZ
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) );
a4f96412 298
3e3be693
VZ
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"));
a4f96412 303
3e3be693
VZ
304 goto error;
305 }
a4f96412 306
3e3be693
VZ
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;
a4f96412 317
3e3be693
VZ
318 case NERR_InvalidComputer:
319 wxLogError(wxT("Invalid domain controller name."));
a4f96412 320
3e3be693 321 goto error;
a4f96412 322
3e3be693
VZ
323 case NERR_UserNotFound:
324 wxLogError(wxT("Invalid user name '%s'."), szUserName);
a4f96412 325
3e3be693 326 goto error;
a4f96412 327
3e3be693
VZ
328 default:
329 wxLogSysError(wxT("Can't get information about user"));
a4f96412 330
3e3be693
VZ
331 goto error;
332 }
a4f96412 333
3e3be693
VZ
334 // Convert the Unicode full name to ANSI
335 WideCharToMultiByte( CP_ACP, 0, ui2->usri2_full_name, -1,
336 buf, maxSize, NULL, NULL );
a4f96412 337
27d2dbbc 338 return true;
a4f96412
VZ
339
340error:
3e3be693 341 wxLogError(wxT("Couldn't look up full user name."));
a4f96412 342
27d2dbbc 343 return false;
a4f96412 344#else // !USE_NET_API
3e3be693 345 // Could use NIS, MS-Mail or other site specific programs
77ffb593 346 // Use wxWidgets configuration data
fda7962d 347 bool ok = GetProfileString(WX_SECTION, eUSERNAME, wxEmptyString, buf, maxSize - 1) != 0;
3e3be693
VZ
348 if ( !ok )
349 {
350 ok = wxGetUserId(buf, maxSize);
351 }
0a144271 352
3e3be693
VZ
353 if ( !ok )
354 {
e408bf52 355 wxStrlcpy(buf, wxT("Unknown User"), maxSize);
b568d04f 356 }
0a144271 357
27d2dbbc 358 return true;
040e5f77 359#endif // Win32/16
2bda0e17
KB
360}
361
b568d04f 362const wxChar* wxGetHomeDir(wxString *pstr)
2bda0e17 363{
2dc357ea 364 wxString& strDir = *pstr;
2bda0e17 365
2dc357ea 366 // first branch is for Cygwin
dc484d49 367#if defined(__UNIX__) && !defined(__WINE__)
b568d04f
VZ
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;
2bda0e17 376
b568d04f
VZ
377 // add a trailing slash if needed
378 if ( strDir.Last() != wxT('/') )
379 strDir << wxT('/');
3ffbc733 380
e02e8816 381 #ifdef __CYGWIN__
2dc357ea
VZ
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;
3ffbc733 386 #endif
4676948b 387#elif defined(__WXWINCE__)
0367d339 388 strDir = wxT("\\");
4676948b 389#else
2dc357ea 390 strDir.clear();
96c21216 391
2dc357ea
VZ
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"));
96c21216 395
2dc357ea
VZ
396 if ( szHome != NULL )
397 {
96c21216 398 strDir = szHome;
2dc357ea
VZ
399 }
400 else // no HOME, try HOMEDRIVE/PATH
401 {
402 szHome = wxGetenv(wxT("HOMEDRIVE"));
403 if ( szHome != NULL )
96c21216 404 strDir << szHome;
2dc357ea 405 szHome = wxGetenv(wxT("HOMEPATH"));
96c21216 406
2dc357ea
VZ
407 if ( szHome != NULL )
408 {
96c21216
VZ
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 )
2dc357ea
VZ
418 strDir.clear();
419 }
420 }
96c21216 421
2dc357ea
VZ
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"));
2bda0e17 427
2dc357ea 428 if ( szHome != NULL )
96c21216 429 strDir = szHome;
2dc357ea 430 }
2bda0e17 431
2dc357ea
VZ
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 {
77d8d6cd 440 // extract the directory component of the program file name
bd365871 441 wxFileName::SplitPath(wxGetFullModuleName(), &strDir, NULL, NULL);
2dc357ea 442 }
4676948b 443#endif // UNIX/Win
b568d04f 444
2dc357ea 445 return strDir.c_str();
afb74891
VZ
446}
447
14d63513 448wxString wxGetUserHome(const wxString& user)
2bda0e17 449{
14d63513 450 wxString home;
2bda0e17 451
14d63513
VZ
452 if ( user.empty() || user == wxGetUserId() )
453 wxGetHomeDir(&home);
454
455 return home;
2bda0e17
KB
456}
457
7bea7b91 458bool wxGetDiskSpace(const wxString& WXUNUSED_IN_WINCE(path),
7ba7c4e6
VZ
459 wxDiskspaceSize_t *WXUNUSED_IN_WINCE(pTotal),
460 wxDiskspaceSize_t *WXUNUSED_IN_WINCE(pFree))
eadd7bd2 461{
4676948b 462#ifdef __WXWINCE__
040e5f77 463 // TODO-CE
7010702f 464 return false;
4676948b 465#else
eadd7bd2 466 if ( path.empty() )
7010702f 467 return false;
eadd7bd2 468
ee88cb34
MB
469// old w32api don't have ULARGE_INTEGER
470#if defined(__WIN32__) && \
471 (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION( 0, 3 ))
eadd7bd2
VZ
472 // GetDiskFreeSpaceEx() is not available under original Win95, check for
473 // it
9ee966ec
VZ
474 typedef BOOL (WINAPI *GetDiskFreeSpaceEx_t)(LPCTSTR,
475 PULARGE_INTEGER,
476 PULARGE_INTEGER,
477 PULARGE_INTEGER);
eadd7bd2
VZ
478
479 GetDiskFreeSpaceEx_t
bb0e27ee 480 pGetDiskFreeSpaceEx = (GetDiskFreeSpaceEx_t)::GetProcAddress
eadd7bd2 481 (
9a83f860 482 ::GetModuleHandle(wxT("kernel32.dll")),
eadd7bd2
VZ
483#if wxUSE_UNICODE
484 "GetDiskFreeSpaceExW"
485#else
486 "GetDiskFreeSpaceExA"
487#endif
488 );
489
490 if ( pGetDiskFreeSpaceEx )
491 {
492 ULARGE_INTEGER bytesFree, bytesTotal;
493
494 // may pass the path as is, GetDiskFreeSpaceEx() is smart enough
e0a050e3 495 if ( !pGetDiskFreeSpaceEx(path.fn_str(),
eadd7bd2
VZ
496 &bytesFree,
497 &bytesTotal,
498 NULL) )
499 {
9a83f860 500 wxLogLastError(wxT("GetDiskFreeSpaceEx"));
eadd7bd2 501
27d2dbbc 502 return false;
eadd7bd2
VZ
503 }
504
221e1181
VZ
505 // ULARGE_INTEGER is a union of a 64 bit value and a struct containing
506 // two 32 bit fields which may be or may be not named - try to make it
507 // compile in all cases
508#if defined(__BORLANDC__) && !defined(_ANONYMOUS_STRUCT)
509 #define UL(ul) ul.u
510#else // anon union
511 #define UL(ul) ul
512#endif
eadd7bd2
VZ
513 if ( pTotal )
514 {
7ba7c4e6
VZ
515#if wxUSE_LONGLONG
516 *pTotal = wxDiskspaceSize_t(UL(bytesTotal).HighPart, UL(bytesTotal).LowPart);
517#else
518 *pTotal = wxDiskspaceSize_t(UL(bytesTotal).LowPart);
519#endif
eadd7bd2
VZ
520 }
521
522 if ( pFree )
523 {
7ba7c4e6 524#if wxUSE_LONGLONG
221e1181 525 *pFree = wxLongLong(UL(bytesFree).HighPart, UL(bytesFree).LowPart);
7ba7c4e6
VZ
526#else
527 *pFree = wxDiskspaceSize_t(UL(bytesFree).LowPart);
528#endif
eadd7bd2
VZ
529 }
530 }
531 else
532#endif // Win32
533 {
bb0e27ee
VZ
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
eadd7bd2
VZ
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...
e0a050e3 545 if ( !::GetDiskFreeSpace(path.fn_str(),
eadd7bd2
VZ
546 &lSectorsPerCluster,
547 &lBytesPerSector,
548 &lNumberOfFreeClusters,
549 &lTotalNumberOfClusters) )
550 {
9a83f860 551 wxLogLastError(wxT("GetDiskFreeSpace"));
eadd7bd2 552
27d2dbbc 553 return false;
eadd7bd2
VZ
554 }
555
7ba7c4e6 556 wxDiskspaceSize_t lBytesPerCluster = (wxDiskspaceSize_t) lSectorsPerCluster;
eadd7bd2
VZ
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
27d2dbbc 572 return true;
4676948b
JS
573#endif
574 // __WXWINCE__
eadd7bd2
VZ
575}
576
308978f6
VZ
577// ----------------------------------------------------------------------------
578// env vars
579// ----------------------------------------------------------------------------
580
7bea7b91
WS
581bool wxGetEnv(const wxString& WXUNUSED_IN_WINCE(var),
582 wxString *WXUNUSED_IN_WINCE(value))
308978f6 583{
4676948b 584#ifdef __WXWINCE__
040e5f77 585 // no environment variables under CE
27d2dbbc 586 return false;
e622dd68 587#else // Win32
308978f6 588 // first get the size of the buffer
dc874fb4 589 DWORD dwRet = ::GetEnvironmentVariable(var.t_str(), NULL, 0);
308978f6
VZ
590 if ( !dwRet )
591 {
592 // this means that there is no such variable
27d2dbbc 593 return false;
308978f6
VZ
594 }
595
596 if ( value )
597 {
dc874fb4 598 (void)::GetEnvironmentVariable(var.t_str(),
e0a050e3 599 wxStringBuffer(*value, dwRet),
de564874 600 dwRet);
308978f6
VZ
601 }
602
27d2dbbc 603 return true;
3a5bcc4d 604#endif // WinCE/32
308978f6
VZ
605}
606
787de19a 607bool wxDoSetEnv(const wxString& var, const wxChar *value)
1fb45475 608{
7bea7b91
WS
609#ifdef __WXWINCE__
610 // no environment variables under CE
787de19a
VZ
611 wxUnusedVar(var);
612 wxUnusedVar(value);
7bea7b91 613 return false;
787de19a
VZ
614#else // !__WXWINCE__
615 // update the CRT environment if possible as people expect getenv() to also
616 // work and it is not affected by Win32 SetEnvironmentVariable() call (OTOH
617 // the CRT does use Win32 call to update the process environment block so
618 // there is no need to call it)
619 //
620 // TODO: add checks for the other compilers (and update wxSetEnv()
621 // documentation in interface/wx/utils.h accordingly)
622#if defined(__VISUALC__)
623 // notice that Microsoft _putenv() has different semantics from POSIX
624 // function with almost the same name: in particular it makes a copy of the
625 // string instead of using it as part of environment so we can safely call
626 // it here without going through all the troubles with wxSetEnvModule as in
627 // src/unix/utilsunx.cpp
628 wxString envstr = var;
629 envstr += '=';
630 if ( value )
631 envstr += value;
46b38b02 632 _tputenv(envstr.t_str());
787de19a 633#else // other compiler
dc874fb4 634 if ( !::SetEnvironmentVariable(var.t_str(), value) )
1fb45475 635 {
9a83f860 636 wxLogLastError(wxT("SetEnvironmentVariable"));
1fb45475 637
27d2dbbc 638 return false;
1fb45475 639 }
787de19a 640#endif // compiler
1fb45475 641
27d2dbbc 642 return true;
787de19a 643#endif // __WXWINCE__/!__WXWINCE__
1fb45475
VZ
644}
645
90a77e64
VS
646bool wxSetEnv(const wxString& variable, const wxString& value)
647{
dc874fb4 648 return wxDoSetEnv(variable, value.t_str());
90a77e64
VS
649}
650
651bool wxUnsetEnv(const wxString& variable)
652{
653 return wxDoSetEnv(variable, NULL);
654}
655
b568d04f
VZ
656// ----------------------------------------------------------------------------
657// process management
658// ----------------------------------------------------------------------------
659
50567b69
VZ
660// structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
661struct wxFindByPidParams
b568d04f 662{
50567b69
VZ
663 wxFindByPidParams() { hwnd = 0; pid = 0; }
664
665 // the HWND used to return the result
666 HWND hwnd;
667
668 // the PID we're looking from
669 DWORD pid;
22f3361e 670
c0c133e1 671 wxDECLARE_NO_COPY_CLASS(wxFindByPidParams);
50567b69
VZ
672};
673
674// wxKill helper: EnumWindows() callback which is used to find the first (top
675// level) window belonging to the given process
676BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
677{
678 DWORD pid;
679 (void)::GetWindowThreadProcessId(hwnd, &pid);
680
681 wxFindByPidParams *params = (wxFindByPidParams *)lParam;
682 if ( pid == params->pid )
683 {
684 // remember the window we found
685 params->hwnd = hwnd;
686
687 // return FALSE to stop the enumeration
688 return FALSE;
689 }
690
691 // continue enumeration
692 return TRUE;
693}
e949bf13 694
e0f6b731
JS
695int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
696
697int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags)
50567b69 698{
e0f6b731
JS
699 if (flags & wxKILL_CHILDREN)
700 wxKillAllChildren(pid, sig, krc);
9d8aca48 701
50567b69
VZ
702 // get the process handle to operate on
703 HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
704 PROCESS_TERMINATE |
705 PROCESS_QUERY_INFORMATION,
706 FALSE, // not inheritable
707 (DWORD)pid);
708 if ( hProcess == NULL )
e949bf13 709 {
50567b69 710 if ( krc )
e949bf13 711 {
a45fb5b4
VZ
712 // recognize wxKILL_ACCESS_DENIED as special because this doesn't
713 // mean that the process doesn't exist and this is important for
714 // wxProcess::Exists()
715 *krc = ::GetLastError() == ERROR_ACCESS_DENIED
716 ? wxKILL_ACCESS_DENIED
717 : wxKILL_NO_PROCESS;
50567b69
VZ
718 }
719
720 return -1;
721 }
722
a45fb5b4
VZ
723 wxON_BLOCK_EXIT1(::CloseHandle, hProcess);
724
27d2dbbc 725 bool ok = true;
50567b69
VZ
726 switch ( sig )
727 {
728 case wxSIGKILL:
729 // kill the process forcefully returning -1 as error code
730 if ( !::TerminateProcess(hProcess, (UINT)-1) )
731 {
732 wxLogSysError(_("Failed to kill process %d"), pid);
733
734 if ( krc )
e949bf13 735 {
50567b69
VZ
736 // this is not supposed to happen if we could open the
737 // process
738 *krc = wxKILL_ERROR;
e949bf13 739 }
50567b69 740
27d2dbbc 741 ok = false;
e949bf13 742 }
50567b69
VZ
743 break;
744
745 case wxSIGNONE:
746 // do nothing, we just want to test for process existence
a45fb5b4
VZ
747 if ( krc )
748 *krc = wxKILL_OK;
749 return 0;
50567b69
VZ
750
751 default:
752 // any other signal means "terminate"
753 {
754 wxFindByPidParams params;
755 params.pid = (DWORD)pid;
756
757 // EnumWindows() has nice semantics: it returns 0 if it found
3103e8a9 758 // something or if an error occurred and non zero if it
50567b69
VZ
759 // enumerated all the window
760 if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)&params) )
761 {
762 // did we find any window?
763 if ( params.hwnd )
764 {
765 // tell the app to close
766 //
3103e8a9 767 // NB: this is the harshest way, the app won't have an
50567b69
VZ
768 // opportunity to save any files, for example, but
769 // this is probably what we want here. If not we
770 // can also use SendMesageTimeout(WM_CLOSE)
771 if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) )
772 {
9a83f860 773 wxLogLastError(wxT("PostMessage(WM_QUIT)"));
50567b69
VZ
774 }
775 }
776 else // it was an error then
777 {
9a83f860 778 wxLogLastError(wxT("EnumWindows"));
50567b69 779
27d2dbbc 780 ok = false;
50567b69
VZ
781 }
782 }
783 else // no windows for this PID
784 {
785 if ( krc )
50567b69 786 *krc = wxKILL_ERROR;
50567b69 787
27d2dbbc 788 ok = false;
50567b69
VZ
789 }
790 }
791 }
792
793 // the return code
a45fb5b4 794 DWORD rc wxDUMMY_INITIALIZE(0);
50567b69
VZ
795 if ( ok )
796 {
797 // as we wait for a short time, we can use just WaitForSingleObject()
798 // and not MsgWaitForMultipleObjects()
799 switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) )
800 {
801 case WAIT_OBJECT_0:
802 // process terminated
803 if ( !::GetExitCodeProcess(hProcess, &rc) )
804 {
9a83f860 805 wxLogLastError(wxT("GetExitCodeProcess"));
50567b69
VZ
806 }
807 break;
808
809 default:
9a83f860 810 wxFAIL_MSG( wxT("unexpected WaitForSingleObject() return") );
50567b69
VZ
811 // fall through
812
813 case WAIT_FAILED:
9a83f860 814 wxLogLastError(wxT("WaitForSingleObject"));
50567b69
VZ
815 // fall through
816
817 case WAIT_TIMEOUT:
818 if ( krc )
50567b69 819 *krc = wxKILL_ERROR;
50567b69
VZ
820
821 rc = STILL_ACTIVE;
822 break;
e949bf13
JS
823 }
824 }
825
b568d04f 826
50567b69
VZ
827 // the return code is the same as from Unix kill(): 0 if killed
828 // successfully or -1 on error
a45fb5b4
VZ
829 if ( !ok || rc == STILL_ACTIVE )
830 return -1;
b1a28eef 831
a45fb5b4
VZ
832 if ( krc )
833 *krc = wxKILL_OK;
50567b69 834
a45fb5b4 835 return 0;
2bda0e17
KB
836}
837
78a054f6
WS
838typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_t)(DWORD,DWORD);
839typedef BOOL (WINAPI *Process32_t)(HANDLE,LPPROCESSENTRY32);
840
841CreateToolhelp32Snapshot_t lpfCreateToolhelp32Snapshot;
842Process32_t lpfProcess32First, lpfProcess32Next;
9d8aca48 843
e0f6b731
JS
844static void InitToolHelp32()
845{
846 static bool s_initToolHelpDone = false;
9d8aca48 847
e0f6b731
JS
848 if (s_initToolHelpDone)
849 return;
9d8aca48 850
e0f6b731
JS
851 s_initToolHelpDone = true;
852
853 lpfCreateToolhelp32Snapshot = NULL;
854 lpfProcess32First = NULL;
855 lpfProcess32Next = NULL;
9d8aca48 856
32c0c61c
WS
857#if wxUSE_DYNLIB_CLASS
858
9a83f860 859 wxDynamicLibrary dllKernel(wxT("kernel32.dll"), wxDL_VERBATIM);
9d8aca48 860
e0f6b731
JS
861 // Get procedure addresses.
862 // We are linking to these functions of Kernel32
863 // explicitly, because otherwise a module using
864 // this code would fail to load under Windows NT,
865 // which does not have the Toolhelp32
866 // functions in the Kernel 32.
78a054f6 867 lpfCreateToolhelp32Snapshot =
9a83f860 868 (CreateToolhelp32Snapshot_t)dllKernel.RawGetSymbol(wxT("CreateToolhelp32Snapshot"));
9d8aca48 869
78a054f6 870 lpfProcess32First =
9a83f860 871 (Process32_t)dllKernel.RawGetSymbol(wxT("Process32First"));
e0f6b731 872
78a054f6 873 lpfProcess32Next =
9a83f860 874 (Process32_t)dllKernel.RawGetSymbol(wxT("Process32Next"));
32c0c61c
WS
875
876#endif // wxUSE_DYNLIB_CLASS
e0f6b731
JS
877}
878
879// By John Skiff
880int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc)
881{
882 InitToolHelp32();
9d8aca48 883
e0f6b731
JS
884 if (krc)
885 *krc = wxKILL_OK;
9d8aca48 886
e0f6b731
JS
887 // If not implemented for this platform (e.g. NT 4.0), silently ignore
888 if (!lpfCreateToolhelp32Snapshot || !lpfProcess32First || !lpfProcess32Next)
889 return 0;
9d8aca48 890
e0f6b731
JS
891 // Take a snapshot of all processes in the system.
892 HANDLE hProcessSnap = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
893 if (hProcessSnap == INVALID_HANDLE_VALUE) {
894 if (krc)
895 *krc = wxKILL_ERROR;
896 return -1;
897 }
9d8aca48 898
e0f6b731 899 //Fill in the size of the structure before using it.
04a18b0d
WS
900 PROCESSENTRY32 pe;
901 wxZeroMemory(pe);
e0f6b731 902 pe.dwSize = sizeof(PROCESSENTRY32);
9d8aca48 903
e0f6b731
JS
904 // Walk the snapshot of the processes, and for each process,
905 // kill it if its parent is pid.
906 if (!lpfProcess32First(hProcessSnap, &pe)) {
907 // Can't get first process.
908 if (krc)
909 *krc = wxKILL_ERROR;
910 CloseHandle (hProcessSnap);
911 return -1;
912 }
9d8aca48 913
e0f6b731
JS
914 do {
915 if (pe.th32ParentProcessID == (DWORD) pid) {
916 if (wxKill(pe.th32ProcessID, sig, krc))
917 return -1;
918 }
919 } while (lpfProcess32Next (hProcessSnap, &pe));
9d8aca48
WS
920
921
e0f6b731
JS
922 return 0;
923}
924
b568d04f
VZ
925// Execute a program in an Interactive Shell
926bool wxShell(const wxString& command)
2bda0e17 927{
7010702f
WS
928 wxString cmd;
929
4676948b 930#ifdef __WXWINCE__
7010702f 931 cmd = command;
4676948b 932#else
b568d04f
VZ
933 wxChar *shell = wxGetenv(wxT("COMSPEC"));
934 if ( !shell )
ba14d986 935 shell = (wxChar*) wxT("\\COMMAND.COM");
b568d04f 936
b568d04f
VZ
937 if ( !command )
938 {
939 // just the shell
940 cmd = shell;
941 }
942 else
943 {
944 // pass the command to execute to the command processor
945 cmd.Printf(wxT("%s /c %s"), shell, command.c_str());
946 }
7010702f 947#endif
b568d04f 948
011a524e 949 return wxExecute(cmd, wxEXEC_SYNC) == 0;
2bda0e17
KB
950}
951
d8c65cf4 952// Shutdown or reboot the PC
118a41d9 953bool wxShutdown(int WXUNUSED_IN_WINCE(flags))
f6ba47d9 954{
4676948b 955#ifdef __WXWINCE__
040e5f77 956 // TODO-CE
27d2dbbc 957 return false;
4676948b 958#elif defined(__WIN32__)
27d2dbbc 959 bool bOK = true;
f6ba47d9 960
406d283a 961 if ( wxGetOsVersion(NULL, NULL) == wxOS_WINDOWS_NT ) // if is NT or 2K
f6ba47d9 962 {
d8c65cf4
RD
963 // Get a token for this process.
964 HANDLE hToken;
f6ba47d9
VZ
965 bOK = ::OpenProcessToken(GetCurrentProcess(),
966 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
967 &hToken) != 0;
968 if ( bOK )
969 {
d8c65cf4 970 TOKEN_PRIVILEGES tkp;
f6ba47d9 971
d8c65cf4 972 // Get the LUID for the shutdown privilege.
a2e50fc2
VZ
973 bOK = ::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
974 &tkp.Privileges[0].Luid) != 0;
f6ba47d9 975
a2e50fc2
VZ
976 if ( bOK )
977 {
978 tkp.PrivilegeCount = 1; // one privilege to set
979 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
980
981 // Get the shutdown privilege for this process.
982 ::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
983 (PTOKEN_PRIVILEGES)NULL, 0);
f6ba47d9 984
a2e50fc2
VZ
985 // Cannot test the return value of AdjustTokenPrivileges.
986 bOK = ::GetLastError() == ERROR_SUCCESS;
987 }
f6ba47d9 988
a2e50fc2 989 ::CloseHandle(hToken);
f6ba47d9
VZ
990 }
991 }
992
993 if ( bOK )
994 {
118a41d9
VZ
995 UINT wFlags = 0;
996 if ( flags & wxSHUTDOWN_FORCE )
997 {
998 wFlags = EWX_FORCE;
999 flags &= ~wxSHUTDOWN_FORCE;
1000 }
1001
1002 switch ( flags )
f6ba47d9
VZ
1003 {
1004 case wxSHUTDOWN_POWEROFF:
118a41d9 1005 wFlags |= EWX_POWEROFF;
f6ba47d9
VZ
1006 break;
1007
1008 case wxSHUTDOWN_REBOOT:
118a41d9
VZ
1009 wFlags |= EWX_REBOOT;
1010 break;
1011
1012 case wxSHUTDOWN_LOGOFF:
1013 wFlags |= EWX_LOGOFF;
f6ba47d9
VZ
1014 break;
1015
1016 default:
9a83f860 1017 wxFAIL_MSG( wxT("unknown wxShutdown() flag") );
27d2dbbc 1018 return false;
f6ba47d9
VZ
1019 }
1020
118a41d9 1021 bOK = ::ExitWindowsEx(wFlags, 0) != 0;
f6ba47d9
VZ
1022 }
1023
1024 return bOK;
118a41d9 1025#endif // WinCE/!WinCE
f6ba47d9
VZ
1026}
1027
b568d04f
VZ
1028// ----------------------------------------------------------------------------
1029// misc
1030// ----------------------------------------------------------------------------
1031
1032// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
9d8aca48 1033wxMemorySize wxGetFreeMemory()
2bda0e17 1034{
9d8aca48
WS
1035#if defined(__WIN64__)
1036 MEMORYSTATUSEX memStatex;
106d80ad
JS
1037 memStatex.dwLength = sizeof (memStatex);
1038 ::GlobalMemoryStatusEx (&memStatex);
1039 return (wxMemorySize)memStatex.ullAvailPhys;
2b7295c9 1040#else /* if defined(__WIN32__) */
b568d04f
VZ
1041 MEMORYSTATUS memStatus;
1042 memStatus.dwLength = sizeof(MEMORYSTATUS);
2b7295c9 1043 ::GlobalMemoryStatus(&memStatus);
9d8aca48 1044 return (wxMemorySize)memStatus.dwAvailPhys;
b568d04f 1045#endif
2bda0e17
KB
1046}
1047
c1cb4153
VZ
1048unsigned long wxGetProcessId()
1049{
c1cb4153 1050 return ::GetCurrentProcessId();
c1cb4153
VZ
1051}
1052
2bda0e17 1053// Emit a beeeeeep
634903fd 1054void wxBell()
2bda0e17 1055{
b568d04f 1056 ::MessageBeep((UINT)-1); // default sound
2bda0e17
KB
1057}
1058
c50a4038
VZ
1059bool wxIsDebuggerRunning()
1060{
532d575b 1061#if wxUSE_DYNLIB_CLASS
c50a4038 1062 // IsDebuggerPresent() is not available under Win95, so load it dynamically
9a83f860 1063 wxDynamicLibrary dll(wxT("kernel32.dll"), wxDL_VERBATIM);
c50a4038
VZ
1064
1065 typedef BOOL (WINAPI *IsDebuggerPresent_t)();
9a83f860 1066 if ( !dll.HasSymbol(wxT("IsDebuggerPresent")) )
c50a4038
VZ
1067 {
1068 // no way to know, assume no
1069 return false;
1070 }
1071
9a83f860 1072 return (*(IsDebuggerPresent_t)dll.GetSymbol(wxT("IsDebuggerPresent")))() != 0;
532d575b
WS
1073#else
1074 return false;
1075#endif
c50a4038
VZ
1076}
1077
1078// ----------------------------------------------------------------------------
1079// OS version
1080// ----------------------------------------------------------------------------
1081
66930b35
VZ
1082// check if we're running under a server or workstation Windows system: it
1083// returns true or false with obvious meaning as well as -1 if the system type
1084// couldn't be determined
1085//
1086// this function is currently private but we may want to expose it later if
1087// it's really useful
1088namespace
1089{
1090
1091int wxIsWindowsServer()
1092{
1093#ifdef VER_NT_WORKSTATION
1094 OSVERSIONINFOEX info;
1095 wxZeroMemory(info);
1096
1097 info.dwOSVersionInfoSize = sizeof(info);
5c33522f 1098 if ( ::GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&info)) )
66930b35
VZ
1099 {
1100 switch ( info.wProductType )
1101 {
1102 case VER_NT_WORKSTATION:
1103 return false;
1104
1105 case VER_NT_SERVER:
1106 case VER_NT_DOMAIN_CONTROLLER:
1107 return true;
1108 }
1109 }
1110#endif // VER_NT_WORKSTATION
1111
1112 return -1;
1113}
1114
1115} // anonymous namespace
1116
bdc72a22 1117wxString wxGetOsDescription()
2bda0e17 1118{
bdc72a22
VZ
1119 wxString str;
1120
1121 OSVERSIONINFO info;
1122 wxZeroMemory(info);
1123
1124 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1125 if ( ::GetVersionEx(&info) )
1126 {
1127 switch ( info.dwPlatformId )
1128 {
84dc0006
WS
1129#ifdef VER_PLATFORM_WIN32_CE
1130 case VER_PLATFORM_WIN32_CE:
1131 str.Printf(_("Windows CE (%d.%d)"),
1132 info.dwMajorVersion,
1133 info.dwMinorVersion);
1134 break;
1135#endif
bdc72a22
VZ
1136 case VER_PLATFORM_WIN32s:
1137 str = _("Win32s on Windows 3.1");
1138 break;
1139
1140 case VER_PLATFORM_WIN32_WINDOWS:
db1d0193
VZ
1141 switch (info.dwMinorVersion)
1142 {
1143 case 0:
1144 if ( info.szCSDVersion[1] == 'B' ||
1145 info.szCSDVersion[1] == 'C' )
1146 {
1147 str = _("Windows 95 OSR2");
1148 }
1149 else
1150 {
1151 str = _("Windows 95");
1152 }
1153 break;
1154 case 10:
1155 if ( info.szCSDVersion[1] == 'B' ||
1156 info.szCSDVersion[1] == 'C' )
1157 {
1158 str = _("Windows 98 SE");
1159 }
1160 else
1161 {
1162 str = _("Windows 98");
1163 }
1164 break;
1165 case 90:
1166 str = _("Windows ME");
1167 break;
1168 default:
1169 str.Printf(_("Windows 9x (%d.%d)"),
1170 info.dwMajorVersion,
1171 info.dwMinorVersion);
1172 break;
1173 }
bdc72a22
VZ
1174 if ( !wxIsEmpty(info.szCSDVersion) )
1175 {
9a83f860 1176 str << wxT(" (") << info.szCSDVersion << wxT(')');
bdc72a22
VZ
1177 }
1178 break;
1179
1180 case VER_PLATFORM_WIN32_NT:
a284cce8 1181 switch ( info.dwMajorVersion )
db1d0193 1182 {
a284cce8
VZ
1183 case 5:
1184 switch ( info.dwMinorVersion )
1185 {
1186 case 0:
1187 str.Printf(_("Windows 2000 (build %lu"),
1188 info.dwBuildNumber);
1189 break;
1190
66930b35
VZ
1191 case 2:
1192 // we can't distinguish between XP 64 and 2003
1193 // as they both are 5.2, so examine the product
1194 // type to resolve this ambiguity
575cabba 1195 if ( wxIsWindowsServer() == 1 )
66930b35
VZ
1196 {
1197 str.Printf(_("Windows Server 2003 (build %lu"),
1198 info.dwBuildNumber);
1199 break;
1200 }
1201 //else: must be XP, fall through
1202
a284cce8
VZ
1203 case 1:
1204 str.Printf(_("Windows XP (build %lu"),
1205 info.dwBuildNumber);
1206 break;
a284cce8
VZ
1207 }
1208 break;
1209
1210 case 6:
1211 if ( info.dwMinorVersion == 0 )
1212 {
1213 str.Printf(_("Windows Vista (build %lu"),
db1d0193 1214 info.dwBuildNumber);
a284cce8
VZ
1215 }
1216 break;
db1d0193 1217 }
a284cce8 1218
84dc0006 1219 if ( str.empty() )
db1d0193
VZ
1220 {
1221 str.Printf(_("Windows NT %lu.%lu (build %lu"),
bdc72a22
VZ
1222 info.dwMajorVersion,
1223 info.dwMinorVersion,
1224 info.dwBuildNumber);
db1d0193 1225 }
a284cce8 1226
bdc72a22
VZ
1227 if ( !wxIsEmpty(info.szCSDVersion) )
1228 {
9a83f860 1229 str << wxT(", ") << info.szCSDVersion;
bdc72a22 1230 }
9a83f860 1231 str << wxT(')');
d4885e10
VZ
1232
1233 if ( wxIsPlatform64Bit() )
1234 str << _(", 64-bit edition");
bdc72a22
VZ
1235 break;
1236 }
1237 }
1238 else
1239 {
9a83f860 1240 wxFAIL_MSG( wxT("GetVersionEx() failed") ); // should never happen
bdc72a22
VZ
1241 }
1242
1243 return str;
bdc72a22 1244}
6f65e337 1245
8bb6b2c0 1246bool wxIsPlatform64Bit()
bdc72a22 1247{
8bb6b2c0
VZ
1248#if defined(_WIN64)
1249 return true; // 64-bit programs run only on Win64
a8ff046b 1250#elif wxUSE_DYNLIB_CLASS // Win32
6deb397d
VZ
1251 // 32-bit programs run on both 32-bit and 64-bit Windows so check
1252 typedef BOOL (WINAPI *IsWow64Process_t)(HANDLE, BOOL *);
1253
9a83f860 1254 wxDynamicLibrary dllKernel32(wxT("kernel32.dll"));
b9d4a1b7 1255 IsWow64Process_t pfnIsWow64Process =
9a83f860 1256 (IsWow64Process_t)dllKernel32.RawGetSymbol(wxT("IsWow64Process"));
6deb397d
VZ
1257
1258 BOOL wow64 = FALSE;
1259 if ( pfnIsWow64Process )
1260 {
b9d4a1b7 1261 pfnIsWow64Process(::GetCurrentProcess(), &wow64);
6deb397d
VZ
1262 }
1263 //else: running under a system without Win64 support
1264
1265 return wow64 != FALSE;
a8ff046b
VZ
1266#else
1267 return false;
6deb397d 1268#endif // Win64/Win32
8bb6b2c0 1269}
ec5d7799 1270
8bb6b2c0
VZ
1271wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin)
1272{
5bc3ef05
VZ
1273 static struct
1274 {
1275 // this may be false, true or -1 if we tried to initialize but failed
1276 int initialized;
bdc72a22 1277
5bc3ef05
VZ
1278 wxOperatingSystemId os;
1279
1280 int verMaj,
1281 verMin;
1282 } s_version;
1283
1284 // query the OS info only once as it's not supposed to change
1285 if ( !s_version.initialized )
8bb6b2c0 1286 {
5bc3ef05
VZ
1287 OSVERSIONINFO info;
1288 wxZeroMemory(info);
1289 info.dwOSVersionInfoSize = sizeof(info);
1290 if ( ::GetVersionEx(&info) )
1291 {
1292 s_version.initialized = true;
1293
1294#if defined(__WXWINCE__)
1295 s_version.os = wxOS_WINDOWS_CE;
1296#elif defined(__WXMICROWIN__)
1297 s_version.os = wxOS_WINDOWS_MICRO;
1298#else // "normal" desktop Windows system, use run-time detection
1299 switch ( info.dwPlatformId )
1300 {
1301 case VER_PLATFORM_WIN32_NT:
1302 s_version.os = wxOS_WINDOWS_NT;
1303 break;
1304
1305 case VER_PLATFORM_WIN32_WINDOWS:
1306 s_version.os = wxOS_WINDOWS_9X;
1307 break;
1308 }
1309#endif // Windows versions
1310
1311 s_version.verMaj = info.dwMajorVersion;
1312 s_version.verMin = info.dwMinorVersion;
1313 }
1314 else // GetVersionEx() failed
1315 {
1316 s_version.initialized = -1;
1317 }
8bb6b2c0 1318 }
bdc72a22 1319
5bc3ef05 1320 if ( s_version.initialized == 1 )
8bb6b2c0 1321 {
5bc3ef05
VZ
1322 if ( verMaj )
1323 *verMaj = s_version.verMaj;
1324 if ( verMin )
1325 *verMin = s_version.verMin;
bdc72a22
VZ
1326 }
1327
5bc3ef05
VZ
1328 // this works even if we were not initialized successfully as the initial
1329 // values of this field is 0 which is wxOS_UNKNOWN and exactly what we need
1330 return s_version.os;
2bda0e17
KB
1331}
1332
4c5da5e4
VZ
1333wxWinVersion wxGetWinVersion()
1334{
1335 int verMaj,
1336 verMin;
1337 switch ( wxGetOsVersion(&verMaj, &verMin) )
1338 {
406d283a 1339 case wxOS_WINDOWS_9X:
4c5da5e4
VZ
1340 if ( verMaj == 4 )
1341 {
1342 switch ( verMin )
1343 {
1344 case 0:
1345 return wxWinVersion_95;
1346
1347 case 10:
1348 return wxWinVersion_98;
1349
1350 case 90:
1351 return wxWinVersion_ME;
1352 }
1353 }
1354 break;
1355
406d283a 1356 case wxOS_WINDOWS_NT:
4c5da5e4
VZ
1357 switch ( verMaj )
1358 {
1359 case 3:
1360 return wxWinVersion_NT3;
1361
1362 case 4:
1363 return wxWinVersion_NT4;
1364
1365 case 5:
1366 switch ( verMin )
1367 {
1368 case 0:
1369 return wxWinVersion_2000;
1370
1371 case 1:
1372 return wxWinVersion_XP;
1373
1374 case 2:
1375 return wxWinVersion_2003;
1376 }
1377 break;
1378
1379 case 6:
1380 return wxWinVersion_NT6;
1381 }
1382 break;
1383
449210a4
WS
1384 default:
1385 // Do nothing just to silence GCC warning
1386 break;
4c5da5e4
VZ
1387 }
1388
1389 return wxWinVersion_Unknown;
1390}
1391
b568d04f
VZ
1392// ----------------------------------------------------------------------------
1393// sleep functions
1394// ----------------------------------------------------------------------------
1395
08873d36 1396void wxMilliSleep(unsigned long milliseconds)
b568d04f
VZ
1397{
1398 ::Sleep(milliseconds);
1399}
1400
08873d36
VZ
1401void wxMicroSleep(unsigned long microseconds)
1402{
1403 wxMilliSleep(microseconds/1000);
1404}
1405
b568d04f
VZ
1406void wxSleep(int nSecs)
1407{
08873d36 1408 wxMilliSleep(1000*nSecs);
b568d04f
VZ
1409}
1410
b568d04f 1411// ----------------------------------------------------------------------------
e2478fde 1412// font encoding <-> Win32 codepage conversion functions
b568d04f
VZ
1413// ----------------------------------------------------------------------------
1414
bddd7a8d 1415extern WXDLLIMPEXP_BASE long wxEncodingToCharset(wxFontEncoding encoding)
b568d04f 1416{
e2478fde 1417 switch ( encoding )
b568d04f 1418 {
e2478fde
VZ
1419 // although this function is supposed to return an exact match, do do
1420 // some mappings here for the most common case of "standard" encoding
1421 case wxFONTENCODING_SYSTEM:
1422 return DEFAULT_CHARSET;
2bda0e17 1423
e2478fde
VZ
1424 case wxFONTENCODING_ISO8859_1:
1425 case wxFONTENCODING_ISO8859_15:
1426 case wxFONTENCODING_CP1252:
1427 return ANSI_CHARSET;
2bda0e17 1428
e2478fde
VZ
1429#if !defined(__WXMICROWIN__)
1430 // The following four fonts are multi-byte charsets
1431 case wxFONTENCODING_CP932:
1432 return SHIFTJIS_CHARSET;
2bda0e17 1433
e2478fde
VZ
1434 case wxFONTENCODING_CP936:
1435 return GB2312_CHARSET;
2bda0e17 1436
90805c24 1437#ifndef __WXWINCE__
e2478fde
VZ
1438 case wxFONTENCODING_CP949:
1439 return HANGUL_CHARSET;
90805c24 1440#endif
634903fd 1441
e2478fde
VZ
1442 case wxFONTENCODING_CP950:
1443 return CHINESEBIG5_CHARSET;
2bda0e17 1444
e2478fde
VZ
1445 // The rest are single byte encodings
1446 case wxFONTENCODING_CP1250:
1447 return EASTEUROPE_CHARSET;
bfbd6dc1 1448
e2478fde
VZ
1449 case wxFONTENCODING_CP1251:
1450 return RUSSIAN_CHARSET;
2bda0e17 1451
e2478fde
VZ
1452 case wxFONTENCODING_CP1253:
1453 return GREEK_CHARSET;
b07135ba 1454
e2478fde
VZ
1455 case wxFONTENCODING_CP1254:
1456 return TURKISH_CHARSET;
2bda0e17 1457
e2478fde
VZ
1458 case wxFONTENCODING_CP1255:
1459 return HEBREW_CHARSET;
2bda0e17 1460
e2478fde
VZ
1461 case wxFONTENCODING_CP1256:
1462 return ARABIC_CHARSET;
b568d04f 1463
e2478fde
VZ
1464 case wxFONTENCODING_CP1257:
1465 return BALTIC_CHARSET;
634903fd 1466
e2478fde
VZ
1467 case wxFONTENCODING_CP874:
1468 return THAI_CHARSET;
5acc0d5f 1469#endif // !__WXMICROWIN__
cc2b7472 1470
e2478fde
VZ
1471 case wxFONTENCODING_CP437:
1472 return OEM_CHARSET;
ea28b885
VZ
1473
1474 default:
1475 // no way to translate this encoding into a Windows charset
69557827 1476 return -1;
e2478fde 1477 }
373658eb 1478}
7f555861 1479
e2478fde
VZ
1480// we have 2 versions of wxCharsetToCodepage(): the old one which directly
1481// looks up the vlaues in the registry and the new one which is more
1482// politically correct and has more chances to work on other Windows versions
1483// as well but the old version is still needed for !wxUSE_FONTMAP case
1484#if wxUSE_FONTMAP
c030b70f 1485
373658eb 1486#include "wx/fontmap.h"
c030b70f 1487
bddd7a8d 1488extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding)
c030b70f 1489{
b169661f
RR
1490 // There don't seem to be symbolic names for
1491 // these under Windows so I just copied the
1492 // values from MSDN.
04a18b0d 1493
fa78de82 1494 unsigned int ret;
04a18b0d 1495
b169661f 1496 switch (encoding)
373658eb 1497 {
fa78de82
RR
1498 case wxFONTENCODING_ISO8859_1: ret = 28591; break;
1499 case wxFONTENCODING_ISO8859_2: ret = 28592; break;
1500 case wxFONTENCODING_ISO8859_3: ret = 28593; break;
1501 case wxFONTENCODING_ISO8859_4: ret = 28594; break;
1502 case wxFONTENCODING_ISO8859_5: ret = 28595; break;
1503 case wxFONTENCODING_ISO8859_6: ret = 28596; break;
1504 case wxFONTENCODING_ISO8859_7: ret = 28597; break;
1505 case wxFONTENCODING_ISO8859_8: ret = 28598; break;
1506 case wxFONTENCODING_ISO8859_9: ret = 28599; break;
1507 case wxFONTENCODING_ISO8859_10: ret = 28600; break;
5df3dbf9 1508 case wxFONTENCODING_ISO8859_11: ret = 874; break;
b169661f 1509 // case wxFONTENCODING_ISO8859_12, // doesn't exist currently, but put it
04a18b0d 1510 case wxFONTENCODING_ISO8859_13: ret = 28603; break;
5fdf0363 1511 // case wxFONTENCODING_ISO8859_14: ret = 28604; break; // no correspondence on Windows
fa78de82 1512 case wxFONTENCODING_ISO8859_15: ret = 28605; break;
bd5c3968 1513
fa78de82
RR
1514 case wxFONTENCODING_KOI8: ret = 20866; break;
1515 case wxFONTENCODING_KOI8_U: ret = 21866; break;
bd5c3968 1516
fa78de82
RR
1517 case wxFONTENCODING_CP437: ret = 437; break;
1518 case wxFONTENCODING_CP850: ret = 850; break;
1519 case wxFONTENCODING_CP852: ret = 852; break;
1520 case wxFONTENCODING_CP855: ret = 855; break;
1521 case wxFONTENCODING_CP866: ret = 866; break;
1522 case wxFONTENCODING_CP874: ret = 874; break;
1523 case wxFONTENCODING_CP932: ret = 932; break;
1524 case wxFONTENCODING_CP936: ret = 936; break;
1525 case wxFONTENCODING_CP949: ret = 949; break;
1526 case wxFONTENCODING_CP950: ret = 950; break;
1527 case wxFONTENCODING_CP1250: ret = 1250; break;
1528 case wxFONTENCODING_CP1251: ret = 1251; break;
1529 case wxFONTENCODING_CP1252: ret = 1252; break;
1530 case wxFONTENCODING_CP1253: ret = 1253; break;
1531 case wxFONTENCODING_CP1254: ret = 1254; break;
1532 case wxFONTENCODING_CP1255: ret = 1255; break;
1533 case wxFONTENCODING_CP1256: ret = 1256; break;
1534 case wxFONTENCODING_CP1257: ret = 1257; break;
bd5c3968 1535
a50ca843 1536 case wxFONTENCODING_EUC_JP: ret = 20932; break;
bd5c3968 1537
fa78de82
RR
1538 case wxFONTENCODING_MACROMAN: ret = 10000; break;
1539 case wxFONTENCODING_MACJAPANESE: ret = 10001; break;
1540 case wxFONTENCODING_MACCHINESETRAD: ret = 10002; break;
1541 case wxFONTENCODING_MACKOREAN: ret = 10003; break;
1542 case wxFONTENCODING_MACARABIC: ret = 10004; break;
1543 case wxFONTENCODING_MACHEBREW: ret = 10005; break;
1544 case wxFONTENCODING_MACGREEK: ret = 10006; break;
1545 case wxFONTENCODING_MACCYRILLIC: ret = 10007; break;
1546 case wxFONTENCODING_MACTHAI: ret = 10021; break;
1547 case wxFONTENCODING_MACCHINESESIMP: ret = 10008; break;
1548 case wxFONTENCODING_MACCENTRALEUR: ret = 10029; break;
1549 case wxFONTENCODING_MACCROATIAN: ret = 10082; break;
1550 case wxFONTENCODING_MACICELANDIC: ret = 10079; break;
1551 case wxFONTENCODING_MACROMANIAN: ret = 10009; break;
bd5c3968
VZ
1552
1553 case wxFONTENCODING_ISO2022_JP: ret = 50222; break;
1554
fa78de82
RR
1555 case wxFONTENCODING_UTF7: ret = 65000; break;
1556 case wxFONTENCODING_UTF8: ret = 65001; break;
bd5c3968 1557
fa78de82 1558 default: return -1;
373658eb 1559 }
04a18b0d 1560
fa78de82
RR
1561 if (::IsValidCodePage(ret) == 0)
1562 return -1;
04a18b0d 1563
fa78de82
RR
1564 CPINFO info;
1565 if (::GetCPInfo(ret, &info) == 0)
1566 return -1;
373658eb 1567
fa78de82 1568 return (long) ret;
c030b70f 1569}
373658eb 1570
86501081 1571extern long wxCharsetToCodepage(const char *name)
c030b70f 1572{
373658eb
VZ
1573 // first get the font encoding for this charset
1574 if ( !name )
1575 return -1;
1576
267e11c5 1577 wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false);
373658eb
VZ
1578 if ( enc == wxFONTENCODING_SYSTEM )
1579 return -1;
1580
1581 // the use the helper function
1582 return wxEncodingToCodepage(enc);
c030b70f 1583}
c030b70f 1584
e2478fde 1585#else // !wxUSE_FONTMAP
373658eb
VZ
1586
1587#include "wx/msw/registry.h"
1588
1589// this should work if Internet Exploiter is installed
86501081 1590extern long wxCharsetToCodepage(const char *name)
04ef50df 1591{
373658eb
VZ
1592 if (!name)
1593 return GetACP();
1594
e2478fde 1595 long CP = -1;
373658eb 1596
f77c0fe3 1597#if wxUSE_REGKEY
e2478fde 1598 wxString path(wxT("MIME\\Database\\Charset\\"));
373658eb 1599 wxString cn(name);
373658eb 1600
e2478fde
VZ
1601 // follow the alias loop
1602 for ( ;; )
1603 {
1604 wxRegKey key(wxRegKey::HKCR, path + cn);
1605
1606 if (!key.Exists())
1607 break;
373658eb
VZ
1608
1609 // two cases: either there's an AliasForCharset string,
1610 // or there are Codepage and InternetEncoding dwords.
1611 // The InternetEncoding gives us the actual encoding,
1612 // the Codepage just says which Windows character set to
1613 // use when displaying the data.
1614 if (key.HasValue(wxT("InternetEncoding")) &&
e2478fde
VZ
1615 key.QueryValue(wxT("InternetEncoding"), &CP))
1616 break;
373658eb
VZ
1617
1618 // no encoding, see if it's an alias
1619 if (!key.HasValue(wxT("AliasForCharset")) ||
e2478fde
VZ
1620 !key.QueryValue(wxT("AliasForCharset"), cn))
1621 break;
1622 }
f77c0fe3 1623#endif // wxUSE_REGKEY
373658eb
VZ
1624
1625 return CP;
04ef50df 1626}
373658eb 1627
e2478fde 1628#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
c030b70f 1629
eccd1992
VZ
1630/*
1631 Creates a hidden window with supplied window proc registering the class for
1632 it if necesssary (i.e. the first time only). Caller is responsible for
1633 destroying the window and unregistering the class (note that this must be
77ffb593 1634 done because wxWidgets may be used as a DLL and so may be loaded/unloaded
eccd1992
VZ
1635 multiple times into/from the same process so we cna't rely on automatic
1636 Windows class unregistration).
1637
1638 pclassname is a pointer to a caller stored classname, which must initially be
3103e8a9 1639 NULL. classname is the desired wndclass classname. If function successfully
eccd1992
VZ
1640 registers the class, pclassname will be set to classname.
1641 */
487f2d58 1642extern "C" WXDLLIMPEXP_BASE HWND
eccd1992
VZ
1643wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc)
1644{
1645 wxCHECK_MSG( classname && pclassname && wndproc, NULL,
9a83f860 1646 wxT("NULL parameter in wxCreateHiddenWindow") );
eccd1992
VZ
1647
1648 // register the class fi we need to first
1649 if ( *pclassname == NULL )
1650 {
1651 WNDCLASS wndclass;
1652 wxZeroMemory(wndclass);
1653
1654 wndclass.lpfnWndProc = wndproc;
1655 wndclass.hInstance = wxGetInstance();
1656 wndclass.lpszClassName = classname;
1657
1658 if ( !::RegisterClass(&wndclass) )
1659 {
1660 wxLogLastError(wxT("RegisterClass() in wxCreateHiddenWindow"));
1661
1662 return NULL;
1663 }
1664
1665 *pclassname = classname;
1666 }
1667
1668 // next create the window
1669 HWND hwnd = ::CreateWindow
1670 (
1671 *pclassname,
1672 NULL,
1673 0, 0, 0, 0,
1674 0,
1675 (HWND) NULL,
1676 (HMENU)NULL,
1677 wxGetInstance(),
1678 (LPVOID) NULL
1679 );
1680
1681 if ( !hwnd )
1682 {
1683 wxLogLastError(wxT("CreateWindow() in wxCreateHiddenWindow"));
1684 }
1685
1686 return hwnd;
1687}