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