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