]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/utils.cpp
DMC/PCH info.
[wxWidgets.git] / src / msw / utils.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: msw/utils.cpp
3// Purpose: Various utilities
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#ifndef WX_PRECOMP
28 #include "wx/utils.h"
29 #include "wx/app.h"
30 #include "wx/intl.h"
31 #include "wx/log.h"
32#endif //WX_PRECOMP
33
34#include "wx/apptrait.h"
35#include "wx/dynlib.h"
36#include "wx/dynload.h"
37#include "wx/scopeguard.h"
38
39#include "wx/confbase.h" // for wxExpandEnvVars()
40
41#include "wx/msw/private.h" // includes <windows.h>
42#include "wx/msw/missing.h" // CHARSET_HANGUL
43
44#if defined(__CYGWIN__)
45 //CYGWIN gives annoying warning about runtime stuff if we don't do this
46# define USE_SYS_TYPES_FD_SET
47# include <sys/types.h>
48#endif
49
50// Doesn't work with Cygwin at present
51#if wxUSE_SOCKETS && (defined(__GNUWIN32_OLD__) || defined(__WXWINCE__) || defined(__CYGWIN32__))
52 // apparently we need to include winsock.h to get WSADATA and other stuff
53 // used in wxGetFullHostName() with the old mingw32 versions
54 #include <winsock.h>
55#endif
56
57#include "wx/timer.h"
58
59#if !defined(__GNUWIN32__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
60 #include <direct.h>
61
62 #ifndef __MWERKS__
63 #include <dos.h>
64 #endif
65#endif //GNUWIN32
66
67#if defined(__CYGWIN__)
68 #include <sys/unistd.h>
69 #include <sys/stat.h>
70 #include <sys/cygwin.h> // for cygwin_conv_to_full_win32_path()
71#endif //GNUWIN32
72
73#ifdef __BORLANDC__ // Please someone tell me which version of Borland needs
74 // this (3.1 I believe) and how to test for it.
75 // If this works for Borland 4.0 as well, then no worries.
76 #include <dir.h>
77#endif
78
79// VZ: there is some code using NetXXX() functions to get the full user name:
80// I don't think it's a good idea because they don't work under Win95 and
81// seem to return the same as wxGetUserId() under NT. If you really want
82// to use them, just #define USE_NET_API
83#undef USE_NET_API
84
85#ifdef USE_NET_API
86 #include <lm.h>
87#endif // USE_NET_API
88
89#if defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
90 #ifndef __UNIX__
91 #include <io.h>
92 #endif
93
94 #ifndef __GNUWIN32__
95 #include <shellapi.h>
96 #endif
97#endif
98
99#ifndef __WATCOMC__
100 #if !(defined(_MSC_VER) && (_MSC_VER > 800))
101 #include <errno.h>
102 #endif
103#endif
104
105// For wxKillAllChildren
106#include <tlhelp32.h>
107
108// ----------------------------------------------------------------------------
109// constants
110// ----------------------------------------------------------------------------
111
112// In the WIN.INI file
113static const wxChar WX_SECTION[] = wxT("wxWindows");
114static const wxChar eUSERNAME[] = wxT("UserName");
115
116// ============================================================================
117// implementation
118// ============================================================================
119
120// ----------------------------------------------------------------------------
121// get host name and related
122// ----------------------------------------------------------------------------
123
124// Get hostname only (without domain name)
125bool wxGetHostName(wxChar *buf, int maxSize)
126{
127#if defined(__WXWINCE__)
128 // TODO-CE
129 wxUnusedVar(buf);
130 wxUnusedVar(maxSize);
131 return false;
132#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
133 DWORD nSize = maxSize;
134 if ( !::GetComputerName(buf, &nSize) )
135 {
136 wxLogLastError(wxT("GetComputerName"));
137
138 return false;
139 }
140
141 return true;
142#else
143 wxChar *sysname;
144 const wxChar *default_host = wxT("noname");
145
146 if ((sysname = wxGetenv(wxT("SYSTEM_NAME"))) == NULL) {
147 GetProfileString(WX_SECTION, eHOSTNAME, default_host, buf, maxSize - 1);
148 } else
149 wxStrncpy(buf, sysname, maxSize - 1);
150 buf[maxSize] = wxT('\0');
151 return *buf ? true : false;
152#endif
153}
154
155// get full hostname (with domain name if possible)
156bool wxGetFullHostName(wxChar *buf, int maxSize)
157{
158#if !defined( __WXMICROWIN__) && wxUSE_DYNAMIC_LOADER && wxUSE_SOCKETS
159 // TODO should use GetComputerNameEx() when available
160
161 // we don't want to always link with Winsock DLL as we might not use it at
162 // all, so load it dynamically here if needed (and don't complain if it is
163 // missing, we handle this)
164 wxLogNull noLog;
165
166 wxDynamicLibrary dllWinsock(_T("ws2_32.dll"), wxDL_VERBATIM);
167 if ( dllWinsock.IsLoaded() )
168 {
169 typedef int (PASCAL *WSAStartup_t)(WORD, WSADATA *);
170 typedef int (PASCAL *gethostname_t)(char *, int);
171 typedef hostent* (PASCAL *gethostbyname_t)(const char *);
172 typedef hostent* (PASCAL *gethostbyaddr_t)(const char *, int , int);
173 typedef int (PASCAL *WSACleanup_t)(void);
174
175 #define LOAD_WINSOCK_FUNC(func) \
176 func ## _t \
177 pfn ## func = (func ## _t)dllWinsock.GetSymbol(_T(#func))
178
179 LOAD_WINSOCK_FUNC(WSAStartup);
180
181 WSADATA wsa;
182 if ( pfnWSAStartup && pfnWSAStartup(MAKEWORD(1, 1), &wsa) == 0 )
183 {
184 LOAD_WINSOCK_FUNC(gethostname);
185
186 wxString host;
187 if ( pfngethostname )
188 {
189 char bufA[256];
190 if ( pfngethostname(bufA, WXSIZEOF(bufA)) == 0 )
191 {
192 // gethostname() won't usually include the DNS domain name,
193 // for this we need to work a bit more
194 if ( !strchr(bufA, '.') )
195 {
196 LOAD_WINSOCK_FUNC(gethostbyname);
197
198 struct hostent *pHostEnt = pfngethostbyname
199 ? pfngethostbyname(bufA)
200 : NULL;
201
202 if ( pHostEnt )
203 {
204 // Windows will use DNS internally now
205 LOAD_WINSOCK_FUNC(gethostbyaddr);
206
207 pHostEnt = pfngethostbyaddr
208 ? pfngethostbyaddr(pHostEnt->h_addr,
209 4, AF_INET)
210 : NULL;
211 }
212
213 if ( pHostEnt )
214 {
215 host = wxString::FromAscii(pHostEnt->h_name);
216 }
217 }
218 }
219 }
220
221 LOAD_WINSOCK_FUNC(WSACleanup);
222 if ( pfnWSACleanup )
223 pfnWSACleanup();
224
225
226 if ( !host.empty() )
227 {
228 wxStrncpy(buf, host, maxSize);
229
230 return true;
231 }
232 }
233 }
234#endif // !__WXMICROWIN__
235
236 return wxGetHostName(buf, maxSize);
237}
238
239// Get user ID e.g. jacs
240bool wxGetUserId(wxChar *buf, int maxSize)
241{
242#if defined(__WXWINCE__)
243 // TODO-CE
244 wxUnusedVar(buf);
245 wxUnusedVar(maxSize);
246 return false;
247#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
248 DWORD nSize = maxSize;
249 if ( ::GetUserName(buf, &nSize) == 0 )
250 {
251 // actually, it does happen on Win9x if the user didn't log on
252 DWORD res = ::GetEnvironmentVariable(wxT("username"), buf, maxSize);
253 if ( res == 0 )
254 {
255 // not found
256 return false;
257 }
258 }
259
260 return true;
261#else // __WXMICROWIN__
262 wxChar *user;
263 const wxChar *default_id = wxT("anonymous");
264
265 // Can't assume we have NIS (PC-NFS) or some other ID daemon
266 // So we ...
267 if ( (user = wxGetenv(wxT("USER"))) == NULL &&
268 (user = wxGetenv(wxT("LOGNAME"))) == NULL )
269 {
270 // Use wxWidgets configuration data (comming soon)
271 GetProfileString(WX_SECTION, eUSERID, default_id, buf, maxSize - 1);
272 }
273 else
274 {
275 wxStrncpy(buf, user, maxSize - 1);
276 }
277
278 return *buf ? true : false;
279#endif
280}
281
282// Get user name e.g. Julian Smart
283bool wxGetUserName(wxChar *buf, int maxSize)
284{
285#if defined(__WXWINCE__)
286 // TODO-CE
287 wxUnusedVar(buf);
288 wxUnusedVar(maxSize);
289 return false;
290#elif defined(USE_NET_API)
291 CHAR szUserName[256];
292 if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) )
293 return false;
294
295 // TODO how to get the domain name?
296 CHAR *szDomain = "";
297
298 // the code is based on the MSDN example (also see KB article Q119670)
299 WCHAR wszUserName[256]; // Unicode user name
300 WCHAR wszDomain[256];
301 LPBYTE ComputerName;
302
303 USER_INFO_2 *ui2; // User structure
304
305 // Convert ANSI user name and domain to Unicode
306 MultiByteToWideChar( CP_ACP, 0, szUserName, strlen(szUserName)+1,
307 wszUserName, WXSIZEOF(wszUserName) );
308 MultiByteToWideChar( CP_ACP, 0, szDomain, strlen(szDomain)+1,
309 wszDomain, WXSIZEOF(wszDomain) );
310
311 // Get the computer name of a DC for the domain.
312 if ( NetGetDCName( NULL, wszDomain, &ComputerName ) != NERR_Success )
313 {
314 wxLogError(wxT("Can not find domain controller"));
315
316 goto error;
317 }
318
319 // Look up the user on the DC
320 NET_API_STATUS status = NetUserGetInfo( (LPWSTR)ComputerName,
321 (LPWSTR)&wszUserName,
322 2, // level - we want USER_INFO_2
323 (LPBYTE *) &ui2 );
324 switch ( status )
325 {
326 case NERR_Success:
327 // ok
328 break;
329
330 case NERR_InvalidComputer:
331 wxLogError(wxT("Invalid domain controller name."));
332
333 goto error;
334
335 case NERR_UserNotFound:
336 wxLogError(wxT("Invalid user name '%s'."), szUserName);
337
338 goto error;
339
340 default:
341 wxLogSysError(wxT("Can't get information about user"));
342
343 goto error;
344 }
345
346 // Convert the Unicode full name to ANSI
347 WideCharToMultiByte( CP_ACP, 0, ui2->usri2_full_name, -1,
348 buf, maxSize, NULL, NULL );
349
350 return true;
351
352error:
353 wxLogError(wxT("Couldn't look up full user name."));
354
355 return false;
356#else // !USE_NET_API
357 // Could use NIS, MS-Mail or other site specific programs
358 // Use wxWidgets configuration data
359 bool ok = GetProfileString(WX_SECTION, eUSERNAME, wxEmptyString, buf, maxSize - 1) != 0;
360 if ( !ok )
361 {
362 ok = wxGetUserId(buf, maxSize);
363 }
364
365 if ( !ok )
366 {
367 wxStrncpy(buf, wxT("Unknown User"), maxSize);
368 }
369
370 return true;
371#endif // Win32/16
372}
373
374const wxChar* wxGetHomeDir(wxString *pstr)
375{
376 wxString& strDir = *pstr;
377
378 // first branch is for Cygwin
379#if defined(__UNIX__)
380 const wxChar *szHome = wxGetenv("HOME");
381 if ( szHome == NULL ) {
382 // we're homeless...
383 wxLogWarning(_("can't find user's HOME, using current directory."));
384 strDir = wxT(".");
385 }
386 else
387 strDir = szHome;
388
389 // add a trailing slash if needed
390 if ( strDir.Last() != wxT('/') )
391 strDir << wxT('/');
392
393 #ifdef __CYGWIN__
394 // Cygwin returns unix type path but that does not work well
395 static wxChar windowsPath[MAX_PATH];
396 cygwin_conv_to_full_win32_path(strDir, windowsPath);
397 strDir = windowsPath;
398 #endif
399#elif defined(__WXWINCE__)
400 strDir = wxT("\\");
401#else
402 strDir.clear();
403
404 // If we have a valid HOME directory, as is used on many machines that
405 // have unix utilities on them, we should use that.
406 const wxChar *szHome = wxGetenv(wxT("HOME"));
407
408 if ( szHome != NULL )
409 {
410 strDir = szHome;
411 }
412 else // no HOME, try HOMEDRIVE/PATH
413 {
414 szHome = wxGetenv(wxT("HOMEDRIVE"));
415 if ( szHome != NULL )
416 strDir << szHome;
417 szHome = wxGetenv(wxT("HOMEPATH"));
418
419 if ( szHome != NULL )
420 {
421 strDir << szHome;
422
423 // the idea is that under NT these variables have default values
424 // of "%systemdrive%:" and "\\". As we don't want to create our
425 // config files in the root directory of the system drive, we will
426 // create it in our program's dir. However, if the user took care
427 // to set HOMEPATH to something other than "\\", we suppose that he
428 // knows what he is doing and use the supplied value.
429 if ( wxStrcmp(szHome, wxT("\\")) == 0 )
430 strDir.clear();
431 }
432 }
433
434 if ( strDir.empty() )
435 {
436 // If we have a valid USERPROFILE directory, as is the case in
437 // Windows NT, 2000 and XP, we should use that as our home directory.
438 szHome = wxGetenv(wxT("USERPROFILE"));
439
440 if ( szHome != NULL )
441 strDir = szHome;
442 }
443
444 if ( !strDir.empty() )
445 {
446 // sometimes the value of HOME may be "%USERPROFILE%", so reexpand the
447 // value once again, it shouldn't hurt anyhow
448 strDir = wxExpandEnvVars(strDir);
449 }
450 else // fall back to the program directory
451 {
452 // extract the directory component of the program file name
453 wxSplitPath(wxGetFullModuleName(), &strDir, NULL, NULL);
454 }
455#endif // UNIX/Win
456
457 return strDir.c_str();
458}
459
460wxChar *wxGetUserHome(const wxString& WXUNUSED(user))
461{
462 // VZ: the old code here never worked for user != "" anyhow! Moreover, it
463 // returned sometimes a malloc()'d pointer, sometimes a pointer to a
464 // static buffer and sometimes I don't even know what.
465 static wxString s_home;
466
467 return (wxChar *)wxGetHomeDir(&s_home);
468}
469
470bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
471{
472#ifdef __WXWINCE__
473 // TODO-CE
474 wxUnusedVar(path);
475 wxUnusedVar(pTotal);
476 wxUnusedVar(pFree);
477 return false;
478#else
479 if ( path.empty() )
480 return false;
481
482// old w32api don't have ULARGE_INTEGER
483#if defined(__WIN32__) && \
484 (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION( 0, 3 ))
485 // GetDiskFreeSpaceEx() is not available under original Win95, check for
486 // it
487 typedef BOOL (WINAPI *GetDiskFreeSpaceEx_t)(LPCTSTR,
488 PULARGE_INTEGER,
489 PULARGE_INTEGER,
490 PULARGE_INTEGER);
491
492 GetDiskFreeSpaceEx_t
493 pGetDiskFreeSpaceEx = (GetDiskFreeSpaceEx_t)::GetProcAddress
494 (
495 ::GetModuleHandle(_T("kernel32.dll")),
496#if wxUSE_UNICODE
497 "GetDiskFreeSpaceExW"
498#else
499 "GetDiskFreeSpaceExA"
500#endif
501 );
502
503 if ( pGetDiskFreeSpaceEx )
504 {
505 ULARGE_INTEGER bytesFree, bytesTotal;
506
507 // may pass the path as is, GetDiskFreeSpaceEx() is smart enough
508 if ( !pGetDiskFreeSpaceEx(path,
509 &bytesFree,
510 &bytesTotal,
511 NULL) )
512 {
513 wxLogLastError(_T("GetDiskFreeSpaceEx"));
514
515 return false;
516 }
517
518 // ULARGE_INTEGER is a union of a 64 bit value and a struct containing
519 // two 32 bit fields which may be or may be not named - try to make it
520 // compile in all cases
521#if defined(__BORLANDC__) && !defined(_ANONYMOUS_STRUCT)
522 #define UL(ul) ul.u
523#else // anon union
524 #define UL(ul) ul
525#endif
526 if ( pTotal )
527 {
528 *pTotal = wxLongLong(UL(bytesTotal).HighPart, UL(bytesTotal).LowPart);
529 }
530
531 if ( pFree )
532 {
533 *pFree = wxLongLong(UL(bytesFree).HighPart, UL(bytesFree).LowPart);
534 }
535 }
536 else
537#endif // Win32
538 {
539 // there's a problem with drives larger than 2GB, GetDiskFreeSpaceEx()
540 // should be used instead - but if it's not available, fall back on
541 // GetDiskFreeSpace() nevertheless...
542
543 DWORD lSectorsPerCluster,
544 lBytesPerSector,
545 lNumberOfFreeClusters,
546 lTotalNumberOfClusters;
547
548 // FIXME: this is wrong, we should extract the root drive from path
549 // instead, but this is the job for wxFileName...
550 if ( !::GetDiskFreeSpace(path,
551 &lSectorsPerCluster,
552 &lBytesPerSector,
553 &lNumberOfFreeClusters,
554 &lTotalNumberOfClusters) )
555 {
556 wxLogLastError(_T("GetDiskFreeSpace"));
557
558 return false;
559 }
560
561 wxLongLong lBytesPerCluster = lSectorsPerCluster;
562 lBytesPerCluster *= lBytesPerSector;
563
564 if ( pTotal )
565 {
566 *pTotal = lBytesPerCluster;
567 *pTotal *= lTotalNumberOfClusters;
568 }
569
570 if ( pFree )
571 {
572 *pFree = lBytesPerCluster;
573 *pFree *= lNumberOfFreeClusters;
574 }
575 }
576
577 return true;
578#endif
579 // __WXWINCE__
580}
581
582// ----------------------------------------------------------------------------
583// env vars
584// ----------------------------------------------------------------------------
585
586bool wxGetEnv(const wxString& var, wxString *value)
587{
588#ifdef __WXWINCE__
589 // no environment variables under CE
590 wxUnusedVar(var);
591 wxUnusedVar(value);
592 return false;
593#else // Win32
594 // first get the size of the buffer
595 DWORD dwRet = ::GetEnvironmentVariable(var, NULL, 0);
596 if ( !dwRet )
597 {
598 // this means that there is no such variable
599 return false;
600 }
601
602 if ( value )
603 {
604 (void)::GetEnvironmentVariable(var, wxStringBuffer(*value, dwRet),
605 dwRet);
606 }
607
608 return true;
609#endif // WinCE/32
610}
611
612bool wxSetEnv(const wxString& var, const wxChar *value)
613{
614 // some compilers have putenv() or _putenv() or _wputenv() but it's better
615 // to always use Win32 function directly instead of dealing with them
616#if defined(__WIN32__) && !defined(__WXWINCE__)
617 if ( !::SetEnvironmentVariable(var, value) )
618 {
619 wxLogLastError(_T("SetEnvironmentVariable"));
620
621 return false;
622 }
623
624 return true;
625#else // no way to set env vars
626 // no environment variables under CE
627 wxUnusedVar(var);
628 wxUnusedVar(value);
629 return false;
630#endif
631}
632
633// ----------------------------------------------------------------------------
634// process management
635// ----------------------------------------------------------------------------
636
637// structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
638struct wxFindByPidParams
639{
640 wxFindByPidParams() { hwnd = 0; pid = 0; }
641
642 // the HWND used to return the result
643 HWND hwnd;
644
645 // the PID we're looking from
646 DWORD pid;
647
648 DECLARE_NO_COPY_CLASS(wxFindByPidParams)
649};
650
651// wxKill helper: EnumWindows() callback which is used to find the first (top
652// level) window belonging to the given process
653BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
654{
655 DWORD pid;
656 (void)::GetWindowThreadProcessId(hwnd, &pid);
657
658 wxFindByPidParams *params = (wxFindByPidParams *)lParam;
659 if ( pid == params->pid )
660 {
661 // remember the window we found
662 params->hwnd = hwnd;
663
664 // return FALSE to stop the enumeration
665 return FALSE;
666 }
667
668 // continue enumeration
669 return TRUE;
670}
671
672int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
673
674int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags)
675{
676 if (flags & wxKILL_CHILDREN)
677 wxKillAllChildren(pid, sig, krc);
678
679 // get the process handle to operate on
680 HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
681 PROCESS_TERMINATE |
682 PROCESS_QUERY_INFORMATION,
683 FALSE, // not inheritable
684 (DWORD)pid);
685 if ( hProcess == NULL )
686 {
687 if ( krc )
688 {
689 // recognize wxKILL_ACCESS_DENIED as special because this doesn't
690 // mean that the process doesn't exist and this is important for
691 // wxProcess::Exists()
692 *krc = ::GetLastError() == ERROR_ACCESS_DENIED
693 ? wxKILL_ACCESS_DENIED
694 : wxKILL_NO_PROCESS;
695 }
696
697 return -1;
698 }
699
700 wxON_BLOCK_EXIT1(::CloseHandle, hProcess);
701
702 bool ok = true;
703 switch ( sig )
704 {
705 case wxSIGKILL:
706 // kill the process forcefully returning -1 as error code
707 if ( !::TerminateProcess(hProcess, (UINT)-1) )
708 {
709 wxLogSysError(_("Failed to kill process %d"), pid);
710
711 if ( krc )
712 {
713 // this is not supposed to happen if we could open the
714 // process
715 *krc = wxKILL_ERROR;
716 }
717
718 ok = false;
719 }
720 break;
721
722 case wxSIGNONE:
723 // do nothing, we just want to test for process existence
724 if ( krc )
725 *krc = wxKILL_OK;
726 return 0;
727
728 default:
729 // any other signal means "terminate"
730 {
731 wxFindByPidParams params;
732 params.pid = (DWORD)pid;
733
734 // EnumWindows() has nice semantics: it returns 0 if it found
735 // something or if an error occurred and non zero if it
736 // enumerated all the window
737 if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)&params) )
738 {
739 // did we find any window?
740 if ( params.hwnd )
741 {
742 // tell the app to close
743 //
744 // NB: this is the harshest way, the app won't have an
745 // opportunity to save any files, for example, but
746 // this is probably what we want here. If not we
747 // can also use SendMesageTimeout(WM_CLOSE)
748 if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) )
749 {
750 wxLogLastError(_T("PostMessage(WM_QUIT)"));
751 }
752 }
753 else // it was an error then
754 {
755 wxLogLastError(_T("EnumWindows"));
756
757 ok = false;
758 }
759 }
760 else // no windows for this PID
761 {
762 if ( krc )
763 *krc = wxKILL_ERROR;
764
765 ok = false;
766 }
767 }
768 }
769
770 // the return code
771 DWORD rc wxDUMMY_INITIALIZE(0);
772 if ( ok )
773 {
774 // as we wait for a short time, we can use just WaitForSingleObject()
775 // and not MsgWaitForMultipleObjects()
776 switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) )
777 {
778 case WAIT_OBJECT_0:
779 // process terminated
780 if ( !::GetExitCodeProcess(hProcess, &rc) )
781 {
782 wxLogLastError(_T("GetExitCodeProcess"));
783 }
784 break;
785
786 default:
787 wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") );
788 // fall through
789
790 case WAIT_FAILED:
791 wxLogLastError(_T("WaitForSingleObject"));
792 // fall through
793
794 case WAIT_TIMEOUT:
795 if ( krc )
796 *krc = wxKILL_ERROR;
797
798 rc = STILL_ACTIVE;
799 break;
800 }
801 }
802
803
804 // the return code is the same as from Unix kill(): 0 if killed
805 // successfully or -1 on error
806 if ( !ok || rc == STILL_ACTIVE )
807 return -1;
808
809 if ( krc )
810 *krc = wxKILL_OK;
811
812 return 0;
813}
814
815HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ;
816BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ;
817BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ;
818
819static void InitToolHelp32()
820{
821 static bool s_initToolHelpDone = false;
822
823 if (s_initToolHelpDone)
824 return;
825
826 s_initToolHelpDone = true;
827
828 lpfCreateToolhelp32Snapshot = NULL;
829 lpfProcess32First = NULL;
830 lpfProcess32Next = NULL;
831
832 HINSTANCE hInstLib = LoadLibrary( wxT("Kernel32.DLL") ) ;
833 if( hInstLib == NULL )
834 return ;
835
836 // Get procedure addresses.
837 // We are linking to these functions of Kernel32
838 // explicitly, because otherwise a module using
839 // this code would fail to load under Windows NT,
840 // which does not have the Toolhelp32
841 // functions in the Kernel 32.
842 lpfCreateToolhelp32Snapshot=
843 (HANDLE(WINAPI *)(DWORD,DWORD))
844 GetProcAddress( hInstLib,
845#ifdef __WXWINCE__
846 wxT("CreateToolhelp32Snapshot")
847#else
848 "CreateToolhelp32Snapshot"
849#endif
850 ) ;
851
852 lpfProcess32First=
853 (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
854 GetProcAddress( hInstLib,
855#ifdef __WXWINCE__
856 wxT("Process32First")
857#else
858 "Process32First"
859#endif
860 ) ;
861
862 lpfProcess32Next=
863 (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
864 GetProcAddress( hInstLib,
865#ifdef __WXWINCE__
866 wxT("Process32Next")
867#else
868 "Process32Next"
869#endif
870 ) ;
871
872 FreeLibrary( hInstLib ) ;
873}
874
875// By John Skiff
876int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc)
877{
878 InitToolHelp32();
879
880 if (krc)
881 *krc = wxKILL_OK;
882
883 // If not implemented for this platform (e.g. NT 4.0), silently ignore
884 if (!lpfCreateToolhelp32Snapshot || !lpfProcess32First || !lpfProcess32Next)
885 return 0;
886
887 // Take a snapshot of all processes in the system.
888 HANDLE hProcessSnap = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
889 if (hProcessSnap == INVALID_HANDLE_VALUE) {
890 if (krc)
891 *krc = wxKILL_ERROR;
892 return -1;
893 }
894
895 //Fill in the size of the structure before using it.
896 PROCESSENTRY32 pe;
897 wxZeroMemory(pe);
898 pe.dwSize = sizeof(PROCESSENTRY32);
899
900 // Walk the snapshot of the processes, and for each process,
901 // kill it if its parent is pid.
902 if (!lpfProcess32First(hProcessSnap, &pe)) {
903 // Can't get first process.
904 if (krc)
905 *krc = wxKILL_ERROR;
906 CloseHandle (hProcessSnap);
907 return -1;
908 }
909
910 do {
911 if (pe.th32ParentProcessID == (DWORD) pid) {
912 if (wxKill(pe.th32ProcessID, sig, krc))
913 return -1;
914 }
915 } while (lpfProcess32Next (hProcessSnap, &pe));
916
917
918 return 0;
919}
920
921// Execute a program in an Interactive Shell
922bool wxShell(const wxString& command)
923{
924 wxString cmd;
925
926#ifdef __WXWINCE__
927 cmd = command;
928#else
929 wxChar *shell = wxGetenv(wxT("COMSPEC"));
930 if ( !shell )
931 shell = (wxChar*) wxT("\\COMMAND.COM");
932
933 if ( !command )
934 {
935 // just the shell
936 cmd = shell;
937 }
938 else
939 {
940 // pass the command to execute to the command processor
941 cmd.Printf(wxT("%s /c %s"), shell, command.c_str());
942 }
943#endif
944
945 return wxExecute(cmd, wxEXEC_SYNC) == 0;
946}
947
948// Shutdown or reboot the PC
949bool wxShutdown(wxShutdownFlags wFlags)
950{
951#ifdef __WXWINCE__
952 // TODO-CE
953 wxUnusedVar(wFlags);
954 return false;
955#elif defined(__WIN32__)
956 bool bOK = true;
957
958 if ( wxGetOsVersion(NULL, NULL) == wxWINDOWS_NT ) // if is NT or 2K
959 {
960 // Get a token for this process.
961 HANDLE hToken;
962 bOK = ::OpenProcessToken(GetCurrentProcess(),
963 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
964 &hToken) != 0;
965 if ( bOK )
966 {
967 TOKEN_PRIVILEGES tkp;
968
969 // Get the LUID for the shutdown privilege.
970 ::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
971 &tkp.Privileges[0].Luid);
972
973 tkp.PrivilegeCount = 1; // one privilege to set
974 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
975
976 // Get the shutdown privilege for this process.
977 ::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
978 (PTOKEN_PRIVILEGES)NULL, 0);
979
980 // Cannot test the return value of AdjustTokenPrivileges.
981 bOK = ::GetLastError() == ERROR_SUCCESS;
982 }
983 }
984
985 if ( bOK )
986 {
987 UINT flags = EWX_SHUTDOWN | EWX_FORCE;
988 switch ( wFlags )
989 {
990 case wxSHUTDOWN_POWEROFF:
991 flags |= EWX_POWEROFF;
992 break;
993
994 case wxSHUTDOWN_REBOOT:
995 flags |= EWX_REBOOT;
996 break;
997
998 default:
999 wxFAIL_MSG( _T("unknown wxShutdown() flag") );
1000 return false;
1001 }
1002
1003 bOK = ::ExitWindowsEx(flags, 0) != 0;
1004 }
1005
1006 return bOK;
1007#endif // Win32/16
1008}
1009
1010wxPowerType wxGetPowerType()
1011{
1012 // TODO
1013 return wxPOWER_UNKNOWN;
1014}
1015
1016wxBatteryState wxGetBatteryState()
1017{
1018 // TODO
1019 return wxBATTERY_UNKNOWN_STATE;
1020}
1021
1022// ----------------------------------------------------------------------------
1023// misc
1024// ----------------------------------------------------------------------------
1025
1026// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
1027wxMemorySize wxGetFreeMemory()
1028{
1029#if defined(__WIN64__)
1030 MEMORYSTATUSEX memStatex;
1031 memStatex.dwLength = sizeof (memStatex);
1032 ::GlobalMemoryStatusEx (&memStatex);
1033 return (wxMemorySize)memStatex.ullAvailPhys;
1034#else /* if defined(__WIN32__) */
1035 MEMORYSTATUS memStatus;
1036 memStatus.dwLength = sizeof(MEMORYSTATUS);
1037 ::GlobalMemoryStatus(&memStatus);
1038 return (wxMemorySize)memStatus.dwAvailPhys;
1039#endif
1040}
1041
1042unsigned long wxGetProcessId()
1043{
1044 return ::GetCurrentProcessId();
1045}
1046
1047// Emit a beeeeeep
1048void wxBell()
1049{
1050 ::MessageBeep((UINT)-1); // default sound
1051}
1052
1053bool wxIsDebuggerRunning()
1054{
1055#if wxUSE_DYNLIB_CLASS
1056 // IsDebuggerPresent() is not available under Win95, so load it dynamically
1057 wxDynamicLibrary dll(_T("kernel32.dll"), wxDL_VERBATIM);
1058
1059 typedef BOOL (WINAPI *IsDebuggerPresent_t)();
1060 if ( !dll.HasSymbol(_T("IsDebuggerPresent")) )
1061 {
1062 // no way to know, assume no
1063 return false;
1064 }
1065
1066 return (*(IsDebuggerPresent_t)dll.GetSymbol(_T("IsDebuggerPresent")))() != 0;
1067#else
1068 return false;
1069#endif
1070}
1071
1072// ----------------------------------------------------------------------------
1073// OS version
1074// ----------------------------------------------------------------------------
1075
1076wxString wxGetOsDescription()
1077{
1078 wxString str;
1079
1080 OSVERSIONINFO info;
1081 wxZeroMemory(info);
1082
1083 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1084 if ( ::GetVersionEx(&info) )
1085 {
1086 switch ( info.dwPlatformId )
1087 {
1088 case VER_PLATFORM_WIN32s:
1089 str = _("Win32s on Windows 3.1");
1090 break;
1091
1092 case VER_PLATFORM_WIN32_WINDOWS:
1093 switch (info.dwMinorVersion)
1094 {
1095 case 0:
1096 if ( info.szCSDVersion[1] == 'B' ||
1097 info.szCSDVersion[1] == 'C' )
1098 {
1099 str = _("Windows 95 OSR2");
1100 }
1101 else
1102 {
1103 str = _("Windows 95");
1104 }
1105 break;
1106 case 10:
1107 if ( info.szCSDVersion[1] == 'B' ||
1108 info.szCSDVersion[1] == 'C' )
1109 {
1110 str = _("Windows 98 SE");
1111 }
1112 else
1113 {
1114 str = _("Windows 98");
1115 }
1116 break;
1117 case 90:
1118 str = _("Windows ME");
1119 break;
1120 default:
1121 str.Printf(_("Windows 9x (%d.%d)"),
1122 info.dwMajorVersion,
1123 info.dwMinorVersion);
1124 break;
1125 }
1126 if ( !wxIsEmpty(info.szCSDVersion) )
1127 {
1128 str << _T(" (") << info.szCSDVersion << _T(')');
1129 }
1130 break;
1131
1132 case VER_PLATFORM_WIN32_NT:
1133 if ( info.dwMajorVersion == 5 )
1134 {
1135 switch ( info.dwMinorVersion )
1136 {
1137 case 0:
1138 str.Printf(_("Windows 2000 (build %lu"),
1139 info.dwBuildNumber);
1140 break;
1141 case 1:
1142 str.Printf(_("Windows XP (build %lu"),
1143 info.dwBuildNumber);
1144 break;
1145 case 2:
1146 str.Printf(_("Windows Server 2003 (build %lu"),
1147 info.dwBuildNumber);
1148 break;
1149 }
1150 }
1151 if ( wxIsEmpty(str) )
1152 {
1153 str.Printf(_("Windows NT %lu.%lu (build %lu"),
1154 info.dwMajorVersion,
1155 info.dwMinorVersion,
1156 info.dwBuildNumber);
1157 }
1158 if ( !wxIsEmpty(info.szCSDVersion) )
1159 {
1160 str << _T(", ") << info.szCSDVersion;
1161 }
1162 str << _T(')');
1163 break;
1164 }
1165 }
1166 else
1167 {
1168 wxFAIL_MSG( _T("GetVersionEx() failed") ); // should never happen
1169 }
1170
1171 return str;
1172}
1173
1174wxToolkitInfo& wxAppTraits::GetToolkitInfo()
1175{
1176 // cache the version info, it's not going to change
1177 //
1178 // NB: this is MT-safe, we may use these static vars from different threads
1179 // but as they always have the same value it doesn't matter
1180 static int s_ver = -1,
1181 s_major = -1,
1182 s_minor = -1;
1183
1184 if ( s_ver == -1 )
1185 {
1186 OSVERSIONINFO info;
1187 wxZeroMemory(info);
1188
1189 s_ver = wxWINDOWS;
1190 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1191 if ( ::GetVersionEx(&info) )
1192 {
1193 s_major = info.dwMajorVersion;
1194 s_minor = info.dwMinorVersion;
1195
1196#ifdef __SMARTPHONE__
1197 s_ver = wxWINDOWS_SMARTPHONE;
1198#elif defined(__POCKETPC__)
1199 s_ver = wxWINDOWS_POCKETPC;
1200#else
1201 switch ( info.dwPlatformId )
1202 {
1203 case VER_PLATFORM_WIN32s:
1204 s_ver = wxWIN32S;
1205 break;
1206
1207 case VER_PLATFORM_WIN32_WINDOWS:
1208 s_ver = wxWIN95;
1209 break;
1210
1211 case VER_PLATFORM_WIN32_NT:
1212 s_ver = wxWINDOWS_NT;
1213 break;
1214#ifdef __WXWINCE__
1215 case VER_PLATFORM_WIN32_CE:
1216 s_ver = wxWINDOWS_CE;
1217#endif
1218 }
1219#endif
1220 }
1221 }
1222
1223 static wxToolkitInfo info;
1224 info.versionMajor = s_major;
1225 info.versionMinor = s_minor;
1226 info.os = s_ver;
1227 info.name = _T("wxBase");
1228 return info;
1229}
1230
1231wxWinVersion wxGetWinVersion()
1232{
1233 int verMaj,
1234 verMin;
1235 switch ( wxGetOsVersion(&verMaj, &verMin) )
1236 {
1237 case wxWIN95:
1238 if ( verMaj == 4 )
1239 {
1240 switch ( verMin )
1241 {
1242 case 0:
1243 return wxWinVersion_95;
1244
1245 case 10:
1246 return wxWinVersion_98;
1247
1248 case 90:
1249 return wxWinVersion_ME;
1250 }
1251 }
1252 break;
1253
1254 case wxWINDOWS_NT:
1255 switch ( verMaj )
1256 {
1257 case 3:
1258 return wxWinVersion_NT3;
1259
1260 case 4:
1261 return wxWinVersion_NT4;
1262
1263 case 5:
1264 switch ( verMin )
1265 {
1266 case 0:
1267 return wxWinVersion_2000;
1268
1269 case 1:
1270 return wxWinVersion_XP;
1271
1272 case 2:
1273 return wxWinVersion_2003;
1274 }
1275 break;
1276
1277 case 6:
1278 return wxWinVersion_NT6;
1279 }
1280 break;
1281
1282 }
1283
1284 return wxWinVersion_Unknown;
1285}
1286
1287// ----------------------------------------------------------------------------
1288// sleep functions
1289// ----------------------------------------------------------------------------
1290
1291void wxMilliSleep(unsigned long milliseconds)
1292{
1293 ::Sleep(milliseconds);
1294}
1295
1296void wxMicroSleep(unsigned long microseconds)
1297{
1298 wxMilliSleep(microseconds/1000);
1299}
1300
1301void wxSleep(int nSecs)
1302{
1303 wxMilliSleep(1000*nSecs);
1304}
1305
1306// ----------------------------------------------------------------------------
1307// font encoding <-> Win32 codepage conversion functions
1308// ----------------------------------------------------------------------------
1309
1310extern WXDLLIMPEXP_BASE long wxEncodingToCharset(wxFontEncoding encoding)
1311{
1312 switch ( encoding )
1313 {
1314 // although this function is supposed to return an exact match, do do
1315 // some mappings here for the most common case of "standard" encoding
1316 case wxFONTENCODING_SYSTEM:
1317 return DEFAULT_CHARSET;
1318
1319 case wxFONTENCODING_ISO8859_1:
1320 case wxFONTENCODING_ISO8859_15:
1321 case wxFONTENCODING_CP1252:
1322 return ANSI_CHARSET;
1323
1324#if !defined(__WXMICROWIN__)
1325 // The following four fonts are multi-byte charsets
1326 case wxFONTENCODING_CP932:
1327 return SHIFTJIS_CHARSET;
1328
1329 case wxFONTENCODING_CP936:
1330 return GB2312_CHARSET;
1331
1332#ifndef __WXWINCE__
1333 case wxFONTENCODING_CP949:
1334 return HANGUL_CHARSET;
1335#endif
1336
1337 case wxFONTENCODING_CP950:
1338 return CHINESEBIG5_CHARSET;
1339
1340 // The rest are single byte encodings
1341 case wxFONTENCODING_CP1250:
1342 return EASTEUROPE_CHARSET;
1343
1344 case wxFONTENCODING_CP1251:
1345 return RUSSIAN_CHARSET;
1346
1347 case wxFONTENCODING_CP1253:
1348 return GREEK_CHARSET;
1349
1350 case wxFONTENCODING_CP1254:
1351 return TURKISH_CHARSET;
1352
1353 case wxFONTENCODING_CP1255:
1354 return HEBREW_CHARSET;
1355
1356 case wxFONTENCODING_CP1256:
1357 return ARABIC_CHARSET;
1358
1359 case wxFONTENCODING_CP1257:
1360 return BALTIC_CHARSET;
1361
1362 case wxFONTENCODING_CP874:
1363 return THAI_CHARSET;
1364#endif // !__WXMICROWIN__
1365
1366 case wxFONTENCODING_CP437:
1367 return OEM_CHARSET;
1368
1369 default:
1370 // no way to translate this encoding into a Windows charset
1371 return -1;
1372 }
1373}
1374
1375// we have 2 versions of wxCharsetToCodepage(): the old one which directly
1376// looks up the vlaues in the registry and the new one which is more
1377// politically correct and has more chances to work on other Windows versions
1378// as well but the old version is still needed for !wxUSE_FONTMAP case
1379#if wxUSE_FONTMAP
1380
1381#include "wx/fontmap.h"
1382
1383extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding)
1384{
1385 // There don't seem to be symbolic names for
1386 // these under Windows so I just copied the
1387 // values from MSDN.
1388
1389 unsigned int ret;
1390
1391 switch (encoding)
1392 {
1393 case wxFONTENCODING_ISO8859_1: ret = 28591; break;
1394 case wxFONTENCODING_ISO8859_2: ret = 28592; break;
1395 case wxFONTENCODING_ISO8859_3: ret = 28593; break;
1396 case wxFONTENCODING_ISO8859_4: ret = 28594; break;
1397 case wxFONTENCODING_ISO8859_5: ret = 28595; break;
1398 case wxFONTENCODING_ISO8859_6: ret = 28596; break;
1399 case wxFONTENCODING_ISO8859_7: ret = 28597; break;
1400 case wxFONTENCODING_ISO8859_8: ret = 28598; break;
1401 case wxFONTENCODING_ISO8859_9: ret = 28599; break;
1402 case wxFONTENCODING_ISO8859_10: ret = 28600; break;
1403 case wxFONTENCODING_ISO8859_11: ret = 28601; break;
1404 // case wxFONTENCODING_ISO8859_12, // doesn't exist currently, but put it
1405 case wxFONTENCODING_ISO8859_13: ret = 28603; break;
1406 case wxFONTENCODING_ISO8859_14: ret = 28604; break;
1407 case wxFONTENCODING_ISO8859_15: ret = 28605; break;
1408 case wxFONTENCODING_KOI8: ret = 20866; break;
1409 case wxFONTENCODING_KOI8_U: ret = 21866; break;
1410 case wxFONTENCODING_CP437: ret = 437; break;
1411 case wxFONTENCODING_CP850: ret = 850; break;
1412 case wxFONTENCODING_CP852: ret = 852; break;
1413 case wxFONTENCODING_CP855: ret = 855; break;
1414 case wxFONTENCODING_CP866: ret = 866; break;
1415 case wxFONTENCODING_CP874: ret = 874; break;
1416 case wxFONTENCODING_CP932: ret = 932; break;
1417 case wxFONTENCODING_CP936: ret = 936; break;
1418 case wxFONTENCODING_CP949: ret = 949; break;
1419 case wxFONTENCODING_CP950: ret = 950; break;
1420 case wxFONTENCODING_CP1250: ret = 1250; break;
1421 case wxFONTENCODING_CP1251: ret = 1251; break;
1422 case wxFONTENCODING_CP1252: ret = 1252; break;
1423 case wxFONTENCODING_CP1253: ret = 1253; break;
1424 case wxFONTENCODING_CP1254: ret = 1254; break;
1425 case wxFONTENCODING_CP1255: ret = 1255; break;
1426 case wxFONTENCODING_CP1256: ret = 1256; break;
1427 case wxFONTENCODING_CP1257: ret = 1257; break;
1428 case wxFONTENCODING_EUC_JP: ret = 20932; break;
1429 case wxFONTENCODING_MACROMAN: ret = 10000; break;
1430 case wxFONTENCODING_MACJAPANESE: ret = 10001; break;
1431 case wxFONTENCODING_MACCHINESETRAD: ret = 10002; break;
1432 case wxFONTENCODING_MACKOREAN: ret = 10003; break;
1433 case wxFONTENCODING_MACARABIC: ret = 10004; break;
1434 case wxFONTENCODING_MACHEBREW: ret = 10005; break;
1435 case wxFONTENCODING_MACGREEK: ret = 10006; break;
1436 case wxFONTENCODING_MACCYRILLIC: ret = 10007; break;
1437 case wxFONTENCODING_MACTHAI: ret = 10021; break;
1438 case wxFONTENCODING_MACCHINESESIMP: ret = 10008; break;
1439 case wxFONTENCODING_MACCENTRALEUR: ret = 10029; break;
1440 case wxFONTENCODING_MACCROATIAN: ret = 10082; break;
1441 case wxFONTENCODING_MACICELANDIC: ret = 10079; break;
1442 case wxFONTENCODING_MACROMANIAN: ret = 10009; break;
1443 case wxFONTENCODING_UTF7: ret = 65000; break;
1444 case wxFONTENCODING_UTF8: ret = 65001; break;
1445 default: return -1;
1446 }
1447
1448 if (::IsValidCodePage(ret) == 0)
1449 return -1;
1450
1451 CPINFO info;
1452 if (::GetCPInfo(ret, &info) == 0)
1453 return -1;
1454
1455 return (long) ret;
1456}
1457
1458extern long wxCharsetToCodepage(const wxChar *name)
1459{
1460 // first get the font encoding for this charset
1461 if ( !name )
1462 return -1;
1463
1464 wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false);
1465 if ( enc == wxFONTENCODING_SYSTEM )
1466 return -1;
1467
1468 // the use the helper function
1469 return wxEncodingToCodepage(enc);
1470}
1471
1472#else // !wxUSE_FONTMAP
1473
1474#include "wx/msw/registry.h"
1475
1476// this should work if Internet Exploiter is installed
1477extern long wxCharsetToCodepage(const wxChar *name)
1478{
1479 if (!name)
1480 return GetACP();
1481
1482 long CP = -1;
1483
1484 wxString path(wxT("MIME\\Database\\Charset\\"));
1485 wxString cn(name);
1486
1487 // follow the alias loop
1488 for ( ;; )
1489 {
1490 wxRegKey key(wxRegKey::HKCR, path + cn);
1491
1492 if (!key.Exists())
1493 break;
1494
1495 // two cases: either there's an AliasForCharset string,
1496 // or there are Codepage and InternetEncoding dwords.
1497 // The InternetEncoding gives us the actual encoding,
1498 // the Codepage just says which Windows character set to
1499 // use when displaying the data.
1500 if (key.HasValue(wxT("InternetEncoding")) &&
1501 key.QueryValue(wxT("InternetEncoding"), &CP))
1502 break;
1503
1504 // no encoding, see if it's an alias
1505 if (!key.HasValue(wxT("AliasForCharset")) ||
1506 !key.QueryValue(wxT("AliasForCharset"), cn))
1507 break;
1508 }
1509
1510 return CP;
1511}
1512
1513#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
1514
1515/*
1516 Creates a hidden window with supplied window proc registering the class for
1517 it if necesssary (i.e. the first time only). Caller is responsible for
1518 destroying the window and unregistering the class (note that this must be
1519 done because wxWidgets may be used as a DLL and so may be loaded/unloaded
1520 multiple times into/from the same process so we cna't rely on automatic
1521 Windows class unregistration).
1522
1523 pclassname is a pointer to a caller stored classname, which must initially be
1524 NULL. classname is the desired wndclass classname. If function successfully
1525 registers the class, pclassname will be set to classname.
1526 */
1527extern "C" WXDLLIMPEXP_BASE HWND
1528wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc)
1529{
1530 wxCHECK_MSG( classname && pclassname && wndproc, NULL,
1531 _T("NULL parameter in wxCreateHiddenWindow") );
1532
1533 // register the class fi we need to first
1534 if ( *pclassname == NULL )
1535 {
1536 WNDCLASS wndclass;
1537 wxZeroMemory(wndclass);
1538
1539 wndclass.lpfnWndProc = wndproc;
1540 wndclass.hInstance = wxGetInstance();
1541 wndclass.lpszClassName = classname;
1542
1543 if ( !::RegisterClass(&wndclass) )
1544 {
1545 wxLogLastError(wxT("RegisterClass() in wxCreateHiddenWindow"));
1546
1547 return NULL;
1548 }
1549
1550 *pclassname = classname;
1551 }
1552
1553 // next create the window
1554 HWND hwnd = ::CreateWindow
1555 (
1556 *pclassname,
1557 NULL,
1558 0, 0, 0, 0,
1559 0,
1560 (HWND) NULL,
1561 (HMENU)NULL,
1562 wxGetInstance(),
1563 (LPVOID) NULL
1564 );
1565
1566 if ( !hwnd )
1567 {
1568 wxLogLastError(wxT("CreateWindow() in wxCreateHiddenWindow"));
1569 }
1570
1571 return hwnd;
1572}
1573