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