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