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