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