]> git.saurik.com Git - wxWidgets.git/blame - src/msw/utils.cpp
Avoid core dumps when SetImageList is used.
[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
JS
8// Copyright: (c) Julian Smart
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
223d09f6 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
JS
121#if defined(__WXWINCE__)
122 return FALSE;
123#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
b568d04f
VZ
124 DWORD nSize = maxSize;
125 if ( !::GetComputerName(buf, &nSize) )
126 {
f6bcfd97 127 wxLogLastError(wxT("GetComputerName"));
b568d04f
VZ
128
129 return FALSE;
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
JS
233#if defined(__WXWINCE__)
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 {
258 // Use wxWindows configuration data (comming soon)
259 GetProfileString(WX_SECTION, eUSERID, default_id, buf, maxSize - 1);
260 }
261 else
262 {
263 wxStrncpy(buf, user, maxSize - 1);
264 }
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
JS
273#if defined(__WXWINCE__)
274 return FALSE;
275#elif defined(USE_NET_API)
3e3be693
VZ
276 CHAR szUserName[256];
277 if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) )
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
VZ
342 // Could use NIS, MS-Mail or other site specific programs
343 // Use wxWindows 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
JS
471#ifdef __WXWINCE__
472 return FALSE;
473#else
eadd7bd2
VZ
474 if ( path.empty() )
475 return FALSE;
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{
4676948b
JS
820#ifdef __WXWINCE__
821 return FALSE;
822#else
b568d04f
VZ
823 wxChar *shell = wxGetenv(wxT("COMSPEC"));
824 if ( !shell )
ba14d986 825 shell = (wxChar*) wxT("\\COMMAND.COM");
b568d04f
VZ
826
827 wxString cmd;
828 if ( !command )
829 {
830 // just the shell
831 cmd = shell;
832 }
833 else
834 {
835 // pass the command to execute to the command processor
836 cmd.Printf(wxT("%s /c %s"), shell, command.c_str());
837 }
838
011a524e 839 return wxExecute(cmd, wxEXEC_SYNC) == 0;
4676948b 840#endif
2bda0e17
KB
841}
842
d8c65cf4 843// Shutdown or reboot the PC
f6ba47d9
VZ
844bool wxShutdown(wxShutdownFlags wFlags)
845{
4676948b
JS
846#ifdef __WXWINCE__
847 return FALSE;
848#elif defined(__WIN32__)
f6ba47d9
VZ
849 bool bOK = TRUE;
850
851 if ( wxGetOsVersion(NULL, NULL) == wxWINDOWS_NT ) // if is NT or 2K
852 {
d8c65cf4
RD
853 // Get a token for this process.
854 HANDLE hToken;
f6ba47d9
VZ
855 bOK = ::OpenProcessToken(GetCurrentProcess(),
856 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
857 &hToken) != 0;
858 if ( bOK )
859 {
d8c65cf4 860 TOKEN_PRIVILEGES tkp;
f6ba47d9 861
d8c65cf4 862 // Get the LUID for the shutdown privilege.
f6ba47d9 863 ::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
d8c65cf4 864 &tkp.Privileges[0].Luid);
f6ba47d9 865
d8c65cf4
RD
866 tkp.PrivilegeCount = 1; // one privilege to set
867 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
f6ba47d9 868
d8c65cf4 869 // Get the shutdown privilege for this process.
f6ba47d9 870 ::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
d8c65cf4 871 (PTOKEN_PRIVILEGES)NULL, 0);
f6ba47d9 872
d8c65cf4 873 // Cannot test the return value of AdjustTokenPrivileges.
f6ba47d9
VZ
874 bOK = ::GetLastError() == ERROR_SUCCESS;
875 }
876 }
877
878 if ( bOK )
879 {
880 UINT flags = EWX_SHUTDOWN | EWX_FORCE;
881 switch ( wFlags )
882 {
883 case wxSHUTDOWN_POWEROFF:
884 flags |= EWX_POWEROFF;
885 break;
886
887 case wxSHUTDOWN_REBOOT:
888 flags |= EWX_REBOOT;
889 break;
890
891 default:
892 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
893 return FALSE;
894 }
895
999836aa 896 bOK = ::ExitWindowsEx(flags, 0) != 0;
f6ba47d9
VZ
897 }
898
899 return bOK;
f6ba47d9
VZ
900#endif // Win32/16
901}
902
b568d04f
VZ
903// ----------------------------------------------------------------------------
904// misc
905// ----------------------------------------------------------------------------
906
907// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
908long wxGetFreeMemory()
2bda0e17 909{
b39dbf34 910#if defined(__WIN32__) && !defined(__BORLANDC__)
b568d04f
VZ
911 MEMORYSTATUS memStatus;
912 memStatus.dwLength = sizeof(MEMORYSTATUS);
913 GlobalMemoryStatus(&memStatus);
914 return memStatus.dwAvailPhys;
915#else
916 return (long)GetFreeSpace(0);
917#endif
2bda0e17
KB
918}
919
c1cb4153
VZ
920unsigned long wxGetProcessId()
921{
c1cb4153 922 return ::GetCurrentProcessId();
c1cb4153
VZ
923}
924
2bda0e17 925// Emit a beeeeeep
634903fd 926void wxBell()
2bda0e17 927{
b568d04f 928 ::MessageBeep((UINT)-1); // default sound
2bda0e17
KB
929}
930
bdc72a22 931wxString wxGetOsDescription()
2bda0e17 932{
bdc72a22
VZ
933 wxString str;
934
935 OSVERSIONINFO info;
936 wxZeroMemory(info);
937
938 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
939 if ( ::GetVersionEx(&info) )
940 {
941 switch ( info.dwPlatformId )
942 {
943 case VER_PLATFORM_WIN32s:
944 str = _("Win32s on Windows 3.1");
945 break;
946
947 case VER_PLATFORM_WIN32_WINDOWS:
948 str.Printf(_("Windows 9%c"),
a46a73a6 949 info.dwMinorVersion == 0 ? _T('5') : _T('8'));
bdc72a22
VZ
950 if ( !wxIsEmpty(info.szCSDVersion) )
951 {
952 str << _T(" (") << info.szCSDVersion << _T(')');
953 }
954 break;
955
956 case VER_PLATFORM_WIN32_NT:
957 str.Printf(_T("Windows NT %lu.%lu (build %lu"),
958 info.dwMajorVersion,
959 info.dwMinorVersion,
960 info.dwBuildNumber);
961 if ( !wxIsEmpty(info.szCSDVersion) )
962 {
963 str << _T(", ") << info.szCSDVersion;
964 }
965 str << _T(')');
966 break;
967 }
968 }
969 else
970 {
971 wxFAIL_MSG( _T("GetVersionEx() failed") ); // should never happen
972 }
973
974 return str;
bdc72a22 975}
6f65e337 976
324899f6 977wxToolkitInfo& wxAppTraits::GetToolkitInfo()
bdc72a22 978{
2739d4f0
VZ
979 // cache the version info, it's not going to change
980 //
981 // NB: this is MT-safe, we may use these static vars from different threads
982 // but as they always have the same value it doesn't matter
983 static int s_ver = -1,
984 s_major = -1,
985 s_minor = -1;
96c21216 986
2739d4f0 987 if ( s_ver == -1 )
bdc72a22 988 {
6af638ed
VS
989 OSVERSIONINFO info;
990 wxZeroMemory(info);
ec5d7799 991
2739d4f0 992 s_ver = wxWINDOWS;
6af638ed
VS
993 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
994 if ( ::GetVersionEx(&info) )
bdc72a22 995 {
2739d4f0
VZ
996 s_major = info.dwMajorVersion;
997 s_minor = info.dwMinorVersion;
bdc72a22 998
6af638ed
VS
999 switch ( info.dwPlatformId )
1000 {
1001 case VER_PLATFORM_WIN32s:
2739d4f0 1002 s_ver = wxWIN32S;
6af638ed 1003 break;
bdc72a22 1004
6af638ed 1005 case VER_PLATFORM_WIN32_WINDOWS:
2739d4f0 1006 s_ver = wxWIN95;
6af638ed
VS
1007 break;
1008
1009 case VER_PLATFORM_WIN32_NT:
2739d4f0 1010 s_ver = wxWINDOWS_NT;
6af638ed 1011 break;
471085e4 1012#ifdef __WXWINCE__
f07dc2e2
JS
1013 case VER_PLATFORM_WIN32_CE:
1014 s_ver = wxWINDOWS_CE;
1015 break;
eccd1992 1016#endif
6af638ed 1017 }
bdc72a22
VZ
1018 }
1019 }
1020
eccd1992 1021 static wxToolkitInfo info;
a8eaaeb2
VS
1022 info.versionMajor = s_major;
1023 info.versionMinor = s_minor;
1024 info.os = s_ver;
1025 info.name = _T("wxBase");
324899f6 1026 return info;
2bda0e17
KB
1027}
1028
b568d04f
VZ
1029// ----------------------------------------------------------------------------
1030// sleep functions
1031// ----------------------------------------------------------------------------
1032
b568d04f
VZ
1033void wxUsleep(unsigned long milliseconds)
1034{
1035 ::Sleep(milliseconds);
1036}
1037
1038void wxSleep(int nSecs)
1039{
1040 wxUsleep(1000*nSecs);
1041}
1042
b568d04f 1043// ----------------------------------------------------------------------------
e2478fde 1044// font encoding <-> Win32 codepage conversion functions
b568d04f
VZ
1045// ----------------------------------------------------------------------------
1046
bddd7a8d 1047extern WXDLLIMPEXP_BASE long wxEncodingToCharset(wxFontEncoding encoding)
b568d04f 1048{
e2478fde 1049 switch ( encoding )
b568d04f 1050 {
e2478fde
VZ
1051 // although this function is supposed to return an exact match, do do
1052 // some mappings here for the most common case of "standard" encoding
1053 case wxFONTENCODING_SYSTEM:
1054 return DEFAULT_CHARSET;
2bda0e17 1055
e2478fde
VZ
1056 case wxFONTENCODING_ISO8859_1:
1057 case wxFONTENCODING_ISO8859_15:
1058 case wxFONTENCODING_CP1252:
1059 return ANSI_CHARSET;
2bda0e17 1060
e2478fde
VZ
1061#if !defined(__WXMICROWIN__)
1062 // The following four fonts are multi-byte charsets
1063 case wxFONTENCODING_CP932:
1064 return SHIFTJIS_CHARSET;
2bda0e17 1065
e2478fde
VZ
1066 case wxFONTENCODING_CP936:
1067 return GB2312_CHARSET;
2bda0e17 1068
e2478fde
VZ
1069 case wxFONTENCODING_CP949:
1070 return HANGUL_CHARSET;
634903fd 1071
e2478fde
VZ
1072 case wxFONTENCODING_CP950:
1073 return CHINESEBIG5_CHARSET;
2bda0e17 1074
e2478fde
VZ
1075 // The rest are single byte encodings
1076 case wxFONTENCODING_CP1250:
1077 return EASTEUROPE_CHARSET;
bfbd6dc1 1078
e2478fde
VZ
1079 case wxFONTENCODING_CP1251:
1080 return RUSSIAN_CHARSET;
2bda0e17 1081
e2478fde
VZ
1082 case wxFONTENCODING_CP1253:
1083 return GREEK_CHARSET;
b07135ba 1084
e2478fde
VZ
1085 case wxFONTENCODING_CP1254:
1086 return TURKISH_CHARSET;
2bda0e17 1087
e2478fde
VZ
1088 case wxFONTENCODING_CP1255:
1089 return HEBREW_CHARSET;
2bda0e17 1090
e2478fde
VZ
1091 case wxFONTENCODING_CP1256:
1092 return ARABIC_CHARSET;
b568d04f 1093
e2478fde
VZ
1094 case wxFONTENCODING_CP1257:
1095 return BALTIC_CHARSET;
634903fd 1096
e2478fde
VZ
1097 case wxFONTENCODING_CP874:
1098 return THAI_CHARSET;
5acc0d5f 1099#endif // !__WXMICROWIN__
cc2b7472 1100
e2478fde
VZ
1101 case wxFONTENCODING_CP437:
1102 return OEM_CHARSET;
ea28b885
VZ
1103
1104 default:
1105 // no way to translate this encoding into a Windows charset
69557827 1106 return -1;
e2478fde 1107 }
373658eb 1108}
7f555861 1109
e2478fde
VZ
1110// we have 2 versions of wxCharsetToCodepage(): the old one which directly
1111// looks up the vlaues in the registry and the new one which is more
1112// politically correct and has more chances to work on other Windows versions
1113// as well but the old version is still needed for !wxUSE_FONTMAP case
1114#if wxUSE_FONTMAP
c030b70f 1115
373658eb 1116#include "wx/fontmap.h"
c030b70f 1117
bddd7a8d 1118extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding)
c030b70f 1119{
373658eb 1120 // translate encoding into the Windows CHARSET
e2478fde
VZ
1121 long charset = wxEncodingToCharset(encoding);
1122 if ( charset == -1 )
373658eb
VZ
1123 return -1;
1124
1125 // translate CHARSET to code page
1126 CHARSETINFO csetInfo;
e2478fde 1127 if ( !::TranslateCharsetInfo((DWORD *)(DWORD)charset,
373658eb
VZ
1128 &csetInfo,
1129 TCI_SRCCHARSET) )
1130 {
1131 wxLogLastError(_T("TranslateCharsetInfo(TCI_SRCCHARSET)"));
1132
1133 return -1;
1134 }
1135
1136 return csetInfo.ciACP;
c030b70f 1137}
373658eb 1138
373658eb 1139extern long wxCharsetToCodepage(const wxChar *name)
c030b70f 1140{
373658eb
VZ
1141 // first get the font encoding for this charset
1142 if ( !name )
1143 return -1;
1144
142b3bc2 1145 wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(name, FALSE);
373658eb
VZ
1146 if ( enc == wxFONTENCODING_SYSTEM )
1147 return -1;
1148
1149 // the use the helper function
1150 return wxEncodingToCodepage(enc);
c030b70f 1151}
c030b70f 1152
e2478fde 1153#else // !wxUSE_FONTMAP
373658eb
VZ
1154
1155#include "wx/msw/registry.h"
1156
1157// this should work if Internet Exploiter is installed
1158extern long wxCharsetToCodepage(const wxChar *name)
04ef50df 1159{
373658eb
VZ
1160 if (!name)
1161 return GetACP();
1162
e2478fde 1163 long CP = -1;
373658eb 1164
e2478fde 1165 wxString path(wxT("MIME\\Database\\Charset\\"));
373658eb 1166 wxString cn(name);
373658eb 1167
e2478fde
VZ
1168 // follow the alias loop
1169 for ( ;; )
1170 {
1171 wxRegKey key(wxRegKey::HKCR, path + cn);
1172
1173 if (!key.Exists())
1174 break;
373658eb
VZ
1175
1176 // two cases: either there's an AliasForCharset string,
1177 // or there are Codepage and InternetEncoding dwords.
1178 // The InternetEncoding gives us the actual encoding,
1179 // the Codepage just says which Windows character set to
1180 // use when displaying the data.
1181 if (key.HasValue(wxT("InternetEncoding")) &&
e2478fde
VZ
1182 key.QueryValue(wxT("InternetEncoding"), &CP))
1183 break;
373658eb
VZ
1184
1185 // no encoding, see if it's an alias
1186 if (!key.HasValue(wxT("AliasForCharset")) ||
e2478fde
VZ
1187 !key.QueryValue(wxT("AliasForCharset"), cn))
1188 break;
1189 }
373658eb
VZ
1190
1191 return CP;
04ef50df 1192}
373658eb 1193
e2478fde 1194#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
c030b70f 1195
eccd1992
VZ
1196/*
1197 Creates a hidden window with supplied window proc registering the class for
1198 it if necesssary (i.e. the first time only). Caller is responsible for
1199 destroying the window and unregistering the class (note that this must be
1200 done because wxWindows may be used as a DLL and so may be loaded/unloaded
1201 multiple times into/from the same process so we cna't rely on automatic
1202 Windows class unregistration).
1203
1204 pclassname is a pointer to a caller stored classname, which must initially be
1205 NULL. classname is the desired wndclass classname. If function succesfully
1206 registers the class, pclassname will be set to classname.
1207 */
487f2d58 1208extern "C" WXDLLIMPEXP_BASE HWND
eccd1992
VZ
1209wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc)
1210{
1211 wxCHECK_MSG( classname && pclassname && wndproc, NULL,
1212 _T("NULL parameter in wxCreateHiddenWindow") );
1213
1214 // register the class fi we need to first
1215 if ( *pclassname == NULL )
1216 {
1217 WNDCLASS wndclass;
1218 wxZeroMemory(wndclass);
1219
1220 wndclass.lpfnWndProc = wndproc;
1221 wndclass.hInstance = wxGetInstance();
1222 wndclass.lpszClassName = classname;
1223
1224 if ( !::RegisterClass(&wndclass) )
1225 {
1226 wxLogLastError(wxT("RegisterClass() in wxCreateHiddenWindow"));
1227
1228 return NULL;
1229 }
1230
1231 *pclassname = classname;
1232 }
1233
1234 // next create the window
1235 HWND hwnd = ::CreateWindow
1236 (
1237 *pclassname,
1238 NULL,
1239 0, 0, 0, 0,
1240 0,
1241 (HWND) NULL,
1242 (HMENU)NULL,
1243 wxGetInstance(),
1244 (LPVOID) NULL
1245 );
1246
1247 if ( !hwnd )
1248 {
1249 wxLogLastError(wxT("CreateWindow() in wxCreateHiddenWindow"));
1250 }
1251
1252 return hwnd;
1253}
1254