#endif //WX_PRECOMP
#include "wx/apptrait.h"
+#include "wx/dynload.h"
+
+#include "wx/confbase.h" // for wxExpandEnvVars()
#include "wx/msw/private.h" // includes <windows.h>
#include "wx/msw/missing.h" // CHARSET_HANGUL
-#if defined(__GNUWIN32_OLD__) || defined(__WXWINCE__)
+#if defined(__GNUWIN32_OLD__) || defined(__WXWINCE__) \
+ || defined(__CYGWIN32__)
// apparently we need to include winsock.h to get WSADATA and other stuff
// used in wxGetFullHostName() with the old mingw32 versions
#include <winsock.h>
#endif
#endif
+// For wxKillAllChildren
+#include <tlhelp32.h>
+
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
static const wxChar WX_SECTION[] = wxT("wxWindows");
static const wxChar eUSERNAME[] = wxT("UserName");
-// these are only used under Win16
-#if !defined(__WIN32__) && !defined(__WXMICROWIN__)
-static const wxChar eHOSTNAME[] = wxT("HostName");
-static const wxChar eUSERID[] = wxT("UserId");
-#endif // !Win32
-
// ============================================================================
// implementation
// ============================================================================
bool wxGetHostName(wxChar *buf, int maxSize)
{
#if defined(__WXWINCE__)
- return FALSE;
+ return false;
#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
DWORD nSize = maxSize;
if ( !::GetComputerName(buf, &nSize) )
{
wxLogLastError(wxT("GetComputerName"));
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
#else
wxChar *sysname;
const wxChar *default_host = wxT("noname");
} else
wxStrncpy(buf, sysname, maxSize - 1);
buf[maxSize] = wxT('\0');
- return *buf ? TRUE : FALSE;
+ return *buf ? true : false;
#endif
}
// get full hostname (with domain name if possible)
bool wxGetFullHostName(wxChar *buf, int maxSize)
{
-#if defined(__WIN32__) && !defined(__WXMICROWIN__) && ! (defined(__GNUWIN32__) && !defined(__MINGW32__))
+#if !defined( __WXMICROWIN__) && wxUSE_DYNAMIC_LOADER
// TODO should use GetComputerNameEx() when available
- // the idea is that if someone had set wxUSE_SOCKETS to 0 the code
- // shouldn't use winsock.dll (a.k.a. ws2_32.dll) at all so only use this
- // code if we link with it anyhow
-#if wxUSE_SOCKETS
- WSADATA wsa;
- if ( WSAStartup(MAKEWORD(1, 1), &wsa) == 0 )
+ // we don't want to always link with Winsock DLL as we might not use it at
+ // all, so load it dynamically here if needed (and don't complain if it is
+ // missing, we handle this)
+ wxLogNull noLog;
+
+ wxDynamicLibrary dllWinsock(_T("ws2_32.dll"), wxDL_VERBATIM);
+ if ( dllWinsock.IsLoaded() )
{
- wxString host;
- char bufA[256];
- if ( gethostname(bufA, WXSIZEOF(bufA)) == 0 )
+ typedef int (PASCAL *WSAStartup_t)(WORD, WSADATA *);
+ typedef int (PASCAL *gethostname_t)(char *, int);
+ typedef hostent* (PASCAL *gethostbyname_t)(const char *);
+ typedef hostent* (PASCAL *gethostbyaddr_t)(const char *, int , int);
+ typedef int (PASCAL *WSACleanup_t)(void);
+
+ #define LOAD_WINSOCK_FUNC(func) \
+ func ## _t \
+ pfn ## func = (func ## _t)dllWinsock.GetSymbol(_T(#func))
+
+ LOAD_WINSOCK_FUNC(WSAStartup);
+
+ WSADATA wsa;
+ if ( pfnWSAStartup && pfnWSAStartup(MAKEWORD(1, 1), &wsa) == 0 )
{
- // gethostname() won't usually include the DNS domain name, for
- // this we need to work a bit more
- if ( !strchr(bufA, '.') )
- {
- struct hostent *pHostEnt = gethostbyname(bufA);
+ LOAD_WINSOCK_FUNC(gethostname);
- if ( pHostEnt )
+ wxString host;
+ if ( pfngethostname )
+ {
+ char bufA[256];
+ if ( pfngethostname(bufA, WXSIZEOF(bufA)) == 0 )
{
- // Windows will use DNS internally now
- pHostEnt = gethostbyaddr(pHostEnt->h_addr, 4, AF_INET);
- }
+ // gethostname() won't usually include the DNS domain name,
+ // for this we need to work a bit more
+ if ( !strchr(bufA, '.') )
+ {
+ LOAD_WINSOCK_FUNC(gethostbyname);
- if ( pHostEnt )
- {
- host = wxString::FromAscii(pHostEnt->h_name);
+ struct hostent *pHostEnt = pfngethostbyname
+ ? pfngethostbyname(bufA)
+ : NULL;
+
+ if ( pHostEnt )
+ {
+ // Windows will use DNS internally now
+ LOAD_WINSOCK_FUNC(gethostbyaddr);
+
+ pHostEnt = pfngethostbyaddr
+ ? pfngethostbyaddr(pHostEnt->h_addr,
+ 4, AF_INET)
+ : NULL;
+ }
+
+ if ( pHostEnt )
+ {
+ host = wxString::FromAscii(pHostEnt->h_name);
+ }
+ }
}
}
- }
- WSACleanup();
+ LOAD_WINSOCK_FUNC(WSACleanup);
+ if ( pfnWSACleanup )
+ pfnWSACleanup();
- if ( !host.empty() )
- {
- wxStrncpy(buf, host, maxSize);
- return TRUE;
+ if ( !host.empty() )
+ {
+ wxStrncpy(buf, host, maxSize);
+
+ return true;
+ }
}
}
-
-#endif // wxUSE_SOCKETS
-
-#endif // Win32
+#endif // !__WXMICROWIN__
return wxGetHostName(buf, maxSize);
}
bool wxGetUserId(wxChar *buf, int maxSize)
{
#if defined(__WXWINCE__)
- return FALSE;
-#elif defined(__WIN32__) && !defined(__win32s__) && !defined(__WXMICROWIN__)
+ return false;
+#elif defined(__WIN32__) && !defined(__WXMICROWIN__)
DWORD nSize = maxSize;
if ( ::GetUserName(buf, &nSize) == 0 )
{
if ( res == 0 )
{
// not found
- return FALSE;
+ return false;
}
}
- return TRUE;
-#else // Win16 or Win32s
+ return true;
+#else // __WXMICROWIN__
wxChar *user;
const wxChar *default_id = wxT("anonymous");
if ( (user = wxGetenv(wxT("USER"))) == NULL &&
(user = wxGetenv(wxT("LOGNAME"))) == NULL )
{
- // Use wxWindows configuration data (comming soon)
+ // Use wxWidgets configuration data (comming soon)
GetProfileString(WX_SECTION, eUSERID, default_id, buf, maxSize - 1);
}
else
wxStrncpy(buf, user, maxSize - 1);
}
- return *buf ? TRUE : FALSE;
+ return *buf ? true : false;
#endif
}
bool wxGetUserName(wxChar *buf, int maxSize)
{
#if defined(__WXWINCE__)
- return FALSE;
+ return false;
#elif defined(USE_NET_API)
CHAR szUserName[256];
if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) )
- return FALSE;
+ return false;
// TODO how to get the domain name?
CHAR *szDomain = "";
WideCharToMultiByte( CP_ACP, 0, ui2->usri2_full_name, -1,
buf, maxSize, NULL, NULL );
- return TRUE;
+ return true;
error:
wxLogError(wxT("Couldn't look up full user name."));
- return FALSE;
+ return false;
#else // !USE_NET_API
// Could use NIS, MS-Mail or other site specific programs
- // Use wxWindows configuration data
+ // Use wxWidgets configuration data
bool ok = GetProfileString(WX_SECTION, eUSERNAME, wxEmptyString, buf, maxSize - 1) != 0;
if ( !ok )
{
}
#endif // Win32/16
- return TRUE;
+ return true;
}
const wxChar* wxGetHomeDir(wxString *pstr)
{
- wxString& strDir = *pstr;
+ wxString& strDir = *pstr;
+ // first branch is for Cygwin
#if defined(__UNIX__)
const wxChar *szHome = wxGetenv("HOME");
if ( szHome == NULL ) {
strDir << wxT('/');
#ifdef __CYGWIN__
- // Cygwin returns unix type path but that does not work well
- static wxChar windowsPath[MAX_PATH];
- cygwin_conv_to_full_win32_path(strDir, windowsPath);
- strDir = windowsPath;
+ // Cygwin returns unix type path but that does not work well
+ static wxChar windowsPath[MAX_PATH];
+ cygwin_conv_to_full_win32_path(strDir, windowsPath);
+ strDir = windowsPath;
#endif
#elif defined(__WXWINCE__)
// Nothing
#else
- #ifdef __WIN32__
- strDir.clear();
+ strDir.clear();
- // If we have a valid HOME directory, as is used on many machines that
- // have unix utilities on them, we should use that.
- const wxChar *szHome = wxGetenv(wxT("HOME"));
+ // If we have a valid HOME directory, as is used on many machines that
+ // have unix utilities on them, we should use that.
+ const wxChar *szHome = wxGetenv(wxT("HOME"));
- if ( szHome != NULL )
- {
+ if ( szHome != NULL )
+ {
strDir = szHome;
- }
- else // no HOME, try HOMEDRIVE/PATH
- {
- szHome = wxGetenv(wxT("HOMEDRIVE"));
- if ( szHome != NULL )
+ }
+ else // no HOME, try HOMEDRIVE/PATH
+ {
+ szHome = wxGetenv(wxT("HOMEDRIVE"));
+ if ( szHome != NULL )
strDir << szHome;
- szHome = wxGetenv(wxT("HOMEPATH"));
+ szHome = wxGetenv(wxT("HOMEPATH"));
- if ( szHome != NULL )
- {
+ if ( szHome != NULL )
+ {
strDir << szHome;
// the idea is that under NT these variables have default values
// to set HOMEPATH to something other than "\\", we suppose that he
// knows what he is doing and use the supplied value.
if ( wxStrcmp(szHome, wxT("\\")) == 0 )
- strDir.clear();
- }
- }
+ strDir.clear();
+ }
+ }
- if ( strDir.empty() )
- {
- // If we have a valid USERPROFILE directory, as is the case in
- // Windows NT, 2000 and XP, we should use that as our home directory.
- szHome = wxGetenv(wxT("USERPROFILE"));
+ if ( strDir.empty() )
+ {
+ // If we have a valid USERPROFILE directory, as is the case in
+ // Windows NT, 2000 and XP, we should use that as our home directory.
+ szHome = wxGetenv(wxT("USERPROFILE"));
- if ( szHome != NULL )
+ if ( szHome != NULL )
strDir = szHome;
- }
-
- if ( !strDir.empty() )
- {
- return strDir.c_str();
- }
- //else: fall back to the prograrm directory
- #else // Win16
- // Win16 has no idea about home, so use the executable directory instead
- #endif // WIN16/32
-
- // 260 was taken from windef.h
- #ifndef MAX_PATH
- #define MAX_PATH 260
- #endif
-
- wxString strPath;
- ::GetModuleFileName(::GetModuleHandle(NULL),
- wxStringBuffer(strPath, MAX_PATH), MAX_PATH);
-
- // extract the dir name
- wxSplitPath(strPath, &strDir, NULL, NULL);
+ }
+ if ( !strDir.empty() )
+ {
+ // sometimes the value of HOME may be "%USERPROFILE%", so reexpand the
+ // value once again, it shouldn't hurt anyhow
+ strDir = wxExpandEnvVars(strDir);
+ }
+ else // fall back to the program directory
+ {
+ // extract the directory component of the program file name
+ wxSplitPath(wxGetFullModuleName(), &strDir, NULL, NULL);
+ }
#endif // UNIX/Win
- return strDir.c_str();
+ return strDir.c_str();
}
wxChar *wxGetUserHome(const wxString& WXUNUSED(user))
#elif defined(__WIN32__)
DWORD attribs = GetFileAttributes(dir);
return ((attribs != (DWORD)-1) && (attribs & FILE_ATTRIBUTE_DIRECTORY));
-#else // Win16
- #ifdef __BORLANDC__
- struct ffblk fileInfo;
- #else
- struct find_t fileInfo;
- #endif
- // In Borland findfirst has a different argument
- // ordering from _dos_findfirst. But _dos_findfirst
- // _should_ be ok in both MS and Borland... why not?
- #ifdef __BORLANDC__
- return (findfirst(dir, &fileInfo, _A_SUBDIR) == 0 &&
- (fileInfo.ff_attrib & _A_SUBDIR) != 0);
- #else
- return (_dos_findfirst(dir, _A_SUBDIR, &fileInfo) == 0) &&
- ((fileInfo.attrib & _A_SUBDIR) != 0);
- #endif
-#endif // Win32/16
+#endif // Win32/__WXMICROWIN__
}
bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
{
#ifdef __WXWINCE__
- return FALSE;
+ return false;
#else
if ( path.empty() )
- return FALSE;
+ return false;
// old w32api don't have ULARGE_INTEGER
#if defined(__WIN32__) && \
{
wxLogLastError(_T("GetDiskFreeSpaceEx"));
- return FALSE;
+ return false;
}
// ULARGE_INTEGER is a union of a 64 bit value and a struct containing
{
wxLogLastError(_T("GetDiskFreeSpace"));
- return FALSE;
+ return false;
}
wxLongLong lBytesPerCluster = lSectorsPerCluster;
}
}
- return TRUE;
+ return true;
#endif
// __WXWINCE__
}
bool wxGetEnv(const wxString& var, wxString *value)
{
#ifdef __WXWINCE__
- return FALSE;
-#elif defined(__WIN16__)
- const wxChar* ret = wxGetenv(var);
- if ( !ret )
- return FALSE;
-
- if ( value )
- {
- *value = ret;
- }
-
- return TRUE;
+ return false;
#else // Win32
// first get the size of the buffer
DWORD dwRet = ::GetEnvironmentVariable(var, NULL, 0);
if ( !dwRet )
{
// this means that there is no such variable
- return FALSE;
+ return false;
}
if ( value )
dwRet);
}
- return TRUE;
-#endif // Win16/32
+ return true;
+#endif // WinCE/32
}
bool wxSetEnv(const wxString& var, const wxChar *value)
{
wxLogLastError(_T("SetEnvironmentVariable"));
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
#else // no way to set env vars
- return FALSE;
+ return false;
#endif
}
return TRUE;
}
-int wxKill(long pid, wxSignal sig, wxKillError *krc)
+int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc);
+
+int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags)
{
+ if (flags & wxKILL_CHILDREN)
+ wxKillAllChildren(pid, sig, krc);
+
// get the process handle to operate on
HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
PROCESS_TERMINATE |
return -1;
}
- bool ok = TRUE;
+ bool ok = true;
switch ( sig )
{
case wxSIGKILL:
*krc = wxKILL_ERROR;
}
- ok = FALSE;
+ ok = false;
}
break;
{
wxLogLastError(_T("EnumWindows"));
- ok = FALSE;
+ ok = false;
}
}
else // no windows for this PID
*krc = wxKILL_ERROR;
}
- ok = FALSE;
+ ok = false;
}
}
}
return -1;
}
+HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ;
+BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ;
+BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ;
+
+static void InitToolHelp32()
+{
+ static bool s_initToolHelpDone = false;
+
+ if (s_initToolHelpDone)
+ return;
+
+ s_initToolHelpDone = true;
+
+ lpfCreateToolhelp32Snapshot = NULL;
+ lpfProcess32First = NULL;
+ lpfProcess32Next = NULL;
+
+ HINSTANCE hInstLib = LoadLibrary( wxT("Kernel32.DLL") ) ;
+ if( hInstLib == NULL )
+ return ;
+
+ // Get procedure addresses.
+ // We are linking to these functions of Kernel32
+ // explicitly, because otherwise a module using
+ // this code would fail to load under Windows NT,
+ // which does not have the Toolhelp32
+ // functions in the Kernel 32.
+ lpfCreateToolhelp32Snapshot=
+ (HANDLE(WINAPI *)(DWORD,DWORD))
+ GetProcAddress( hInstLib,
+#ifdef __WXWINCE__
+ wxT("CreateToolhelp32Snapshot")
+#else
+ "CreateToolhelp32Snapshot"
+#endif
+ ) ;
+
+ lpfProcess32First=
+ (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
+ GetProcAddress( hInstLib,
+#ifdef __WXWINCE__
+ wxT("Process32First")
+#else
+ "Process32First"
+#endif
+ ) ;
+
+ lpfProcess32Next=
+ (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
+ GetProcAddress( hInstLib,
+#ifdef __WXWINCE__
+ wxT("Process32Next")
+#else
+ "Process32Next"
+#endif
+ ) ;
+
+ FreeLibrary( hInstLib ) ;
+}
+
+// By John Skiff
+int wxKillAllChildren(long pid, wxSignal sig, wxKillError *krc)
+{
+ InitToolHelp32();
+
+ if (krc)
+ *krc = wxKILL_OK;
+
+ // If not implemented for this platform (e.g. NT 4.0), silently ignore
+ if (!lpfCreateToolhelp32Snapshot || !lpfProcess32First || !lpfProcess32Next)
+ return 0;
+
+ // Take a snapshot of all processes in the system.
+ HANDLE hProcessSnap = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hProcessSnap == INVALID_HANDLE_VALUE) {
+ if (krc)
+ *krc = wxKILL_ERROR;
+ return -1;
+ }
+
+ //Fill in the size of the structure before using it.
+ PROCESSENTRY32 pe = {0};
+ pe.dwSize = sizeof(PROCESSENTRY32);
+
+ // Walk the snapshot of the processes, and for each process,
+ // kill it if its parent is pid.
+ if (!lpfProcess32First(hProcessSnap, &pe)) {
+ // Can't get first process.
+ if (krc)
+ *krc = wxKILL_ERROR;
+ CloseHandle (hProcessSnap);
+ return -1;
+ }
+
+ do {
+ if (pe.th32ParentProcessID == (DWORD) pid) {
+ if (wxKill(pe.th32ProcessID, sig, krc))
+ return -1;
+ }
+ } while (lpfProcess32Next (hProcessSnap, &pe));
+
+
+ return 0;
+}
+
// Execute a program in an Interactive Shell
bool wxShell(const wxString& command)
{
+ wxString cmd;
+
#ifdef __WXWINCE__
- return FALSE;
+ cmd = command;
#else
wxChar *shell = wxGetenv(wxT("COMSPEC"));
if ( !shell )
shell = (wxChar*) wxT("\\COMMAND.COM");
- wxString cmd;
if ( !command )
{
// just the shell
// pass the command to execute to the command processor
cmd.Printf(wxT("%s /c %s"), shell, command.c_str());
}
+#endif
return wxExecute(cmd, wxEXEC_SYNC) == 0;
-#endif
}
// Shutdown or reboot the PC
bool wxShutdown(wxShutdownFlags wFlags)
{
#ifdef __WXWINCE__
- return FALSE;
+ return false;
#elif defined(__WIN32__)
- bool bOK = TRUE;
+ bool bOK = true;
if ( wxGetOsVersion(NULL, NULL) == wxWINDOWS_NT ) // if is NT or 2K
{
default:
wxFAIL_MSG( _T("unknown wxShutdown() flag") );
- return FALSE;
+ return false;
}
- bOK = ::ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE | EWX_REBOOT, 0) != 0;
+ bOK = ::ExitWindowsEx(flags, 0) != 0;
}
return bOK;
-#else // Win16
- return FALSE;
#endif // Win32/16
}
unsigned long wxGetProcessId()
{
-#ifdef __WIN32__
return ::GetCurrentProcessId();
-#else
- return 0;
-#endif
}
// Emit a beeeeeep
wxString wxGetOsDescription()
{
-#ifdef __WIN32__
wxString str;
OSVERSIONINFO info;
break;
case VER_PLATFORM_WIN32_WINDOWS:
- str.Printf(_("Windows 9%c"),
- info.dwMinorVersion == 0 ? _T('5') : _T('8'));
+ switch (info.dwMinorVersion)
+ {
+ case 0:
+ if ( info.szCSDVersion[1] == 'B' ||
+ info.szCSDVersion[1] == 'C' )
+ {
+ str = _("Windows 95 OSR2");
+ }
+ else
+ {
+ str = _("Windows 95");
+ }
+ break;
+ case 10:
+ if ( info.szCSDVersion[1] == 'B' ||
+ info.szCSDVersion[1] == 'C' )
+ {
+ str = _("Windows 98 SE");
+ }
+ else
+ {
+ str = _("Windows 98");
+ }
+ break;
+ case 90:
+ str = _("Windows ME");
+ break;
+ default:
+ str.Printf(_("Windows 9x (%d.%d)"),
+ info.dwMajorVersion,
+ info.dwMinorVersion);
+ break;
+ }
if ( !wxIsEmpty(info.szCSDVersion) )
{
str << _T(" (") << info.szCSDVersion << _T(')');
break;
case VER_PLATFORM_WIN32_NT:
- str.Printf(_T("Windows NT %lu.%lu (build %lu"),
+ if ( info.dwMajorVersion == 5 )
+ {
+ switch ( info.dwMinorVersion )
+ {
+ case 0:
+ str.Printf(_("Windows 2000 (build %lu"),
+ info.dwBuildNumber);
+ break;
+ case 1:
+ str.Printf(_("Windows XP (build %lu"),
+ info.dwBuildNumber);
+ break;
+ case 2:
+ str.Printf(_("Windows Server 2003 (build %lu"),
+ info.dwBuildNumber);
+ break;
+ }
+ }
+ if ( wxIsEmpty(str) )
+ {
+ str.Printf(_("Windows NT %lu.%lu (build %lu"),
info.dwMajorVersion,
info.dwMinorVersion,
info.dwBuildNumber);
+ }
if ( !wxIsEmpty(info.szCSDVersion) )
{
str << _T(", ") << info.szCSDVersion;
}
return str;
-#else // Win16
- return _("Windows 3.1");
-#endif // Win32/16
}
-int wxAppTraits::GetOSVersion(int *verMaj, int *verMin)
+wxToolkitInfo& wxAppTraits::GetToolkitInfo()
{
// cache the version info, it's not going to change
//
case VER_PLATFORM_WIN32_CE:
s_ver = wxWINDOWS_CE;
break;
-#endif
+#endif
}
}
}
- if ( verMaj )
- *verMaj = s_major;
- if ( verMin )
- *verMin = s_minor;
-
- return s_ver;
+ static wxToolkitInfo info;
+ info.versionMajor = s_major;
+ info.versionMinor = s_minor;
+ info.os = s_ver;
+ info.name = _T("wxBase");
+ return info;
}
// ----------------------------------------------------------------------------
// sleep functions
// ----------------------------------------------------------------------------
-void wxUsleep(unsigned long milliseconds)
+void wxMilliSleep(unsigned long milliseconds)
{
::Sleep(milliseconds);
}
+void wxMicroSleep(unsigned long microseconds)
+{
+ wxMilliSleep(microseconds/1000);
+}
+
void wxSleep(int nSecs)
{
- wxUsleep(1000*nSecs);
+ wxMilliSleep(1000*nSecs);
}
// ----------------------------------------------------------------------------
if ( !name )
return -1;
- wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(name, FALSE);
+ wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(name, false);
if ( enc == wxFONTENCODING_SYSTEM )
return -1;
#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
+/*
+ Creates a hidden window with supplied window proc registering the class for
+ it if necesssary (i.e. the first time only). Caller is responsible for
+ destroying the window and unregistering the class (note that this must be
+ done because wxWidgets may be used as a DLL and so may be loaded/unloaded
+ multiple times into/from the same process so we cna't rely on automatic
+ Windows class unregistration).
+
+ pclassname is a pointer to a caller stored classname, which must initially be
+ NULL. classname is the desired wndclass classname. If function succesfully
+ registers the class, pclassname will be set to classname.
+ */
+extern "C" WXDLLIMPEXP_BASE HWND
+wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc)
+{
+ wxCHECK_MSG( classname && pclassname && wndproc, NULL,
+ _T("NULL parameter in wxCreateHiddenWindow") );
+
+ // register the class fi we need to first
+ if ( *pclassname == NULL )
+ {
+ WNDCLASS wndclass;
+ wxZeroMemory(wndclass);
+
+ wndclass.lpfnWndProc = wndproc;
+ wndclass.hInstance = wxGetInstance();
+ wndclass.lpszClassName = classname;
+
+ if ( !::RegisterClass(&wndclass) )
+ {
+ wxLogLastError(wxT("RegisterClass() in wxCreateHiddenWindow"));
+
+ return NULL;
+ }
+
+ *pclassname = classname;
+ }
+
+ // next create the window
+ HWND hwnd = ::CreateWindow
+ (
+ *pclassname,
+ NULL,
+ 0, 0, 0, 0,
+ 0,
+ (HWND) NULL,
+ (HMENU)NULL,
+ wxGetInstance(),
+ (LPVOID) NULL
+ );
+
+ if ( !hwnd )
+ {
+ wxLogLastError(wxT("CreateWindow() in wxCreateHiddenWindow"));
+ }
+
+ return hwnd;
+}
+