Files
wxWidgets/src/msw/utils.cpp
Ron Lee 3a922bb4bd More build system polishing.. mostly. Some stuff ported over from
recent changes to the 2.2 branch.

Rationalised the autoconf scripts again, removed lots of stuff that
shouldn't be there anymore and pounded the rest into an even tighter
furball. (There's more work to be done here, but we're getting there..)

Implemented the library naming scheme outlined in tn0012.txt -- introduced
'toolchain' and 'widget set' into the autoconf scripts, obsoleted the
top level wx/setup.h and much of the mess associated with it.

More changes for cross compiling and 2.3 debs.

s/burnt_name/soname/g ; s/CC/CXX/g ; s/CCC/CC/g ;  Just because it's Right.
(Thanks Vadim for already doing *FLAGS..)

Fixed libfl Makefile to actually work.

Removed *_DEPS from tmake templates, in every case they can be determined
from the relevant *_OBJS

Added BASE_MSW_OBJS, a couple of missing #includes, some missing files to
the 'dist' targets, and fixed some compile warnings.

Changed setup.py to use wx-config --gl-libs instead of hard coded constants.

 Modified Files:
 	Makefile.in configure configure.in setup.h.in wx-config.in
 	wxBase.spec wxGTK.spec wxMotif.spec
 	contrib/include/wx/applet/window.h contrib/src/Makefile.in
 	contrib/src/applet/appletwindow.cpp contrib/src/fl/Makefile.in
 	debian/changelog debian/control.in debian/libwxbase-dbg.dirs
 	debian/libwxbase-dbg.links debian/libwxbase-dbg.postinst
 	debian/libwxbase-dbg.prerm debian/libwxbase-dev.dirs
 	debian/libwxbase-dev.files debian/libwxbase-dev.links
 	debian/libwxbase-dev.postinst debian/libwxbase-dev.prerm
 	debian/libwxgtk-dbg.dirs debian/libwxgtk-dbg.links
 	debian/libwxgtk-dbg.postinst debian/libwxgtk-dbg.prerm
 	debian/libwxgtk-dev.dirs debian/libwxgtk-dev.files
 	debian/libwxgtk-dev.links debian/libwxgtk-dev.postinst
 	debian/libwxgtk-dev.prerm debian/rules
 	distrib/msw/tmake/base.t distrib/msw/tmake/gtk.t
 	distrib/msw/tmake/mgl.t distrib/msw/tmake/motif.t
 	distrib/msw/tmake/msw.t distrib/msw/tmake/os2.t
 	distrib/msw/tmake/univ.t docs/motif/install.txt
 	include/wx/msw/private.h include/wx/os2/SETUP.H
 	include/wx/os2/SETUP0.H samples/ipc/Makefile.in
 	samples/sockets/Makefile.in src/files.lst src/make.env.in
 	src/makelib.env.in src/makeprog.env.in src/common/strconv.cpp
 	src/gtk/files.lst src/mgl/files.lst src/motif/files.lst
 	src/msw/files.lst src/msw/gsocket.c src/msw/gsockmsw.c
 	src/msw/toplevel.cpp src/msw/utils.cpp src/os2/files.lst
 	src/univ/files.lst wxPython/setup.py
 Added Files:
 	debian/libwxbase-msw-dev.dirs debian/libwxbase-msw-dev.links
 	debian/libwxbase-msw-dev.postinst
 	debian/libwxbase-msw-dev.prerm debian/libwxmsw-dev.dirs
 	debian/libwxmsw-dev.links debian/libwxmsw-dev.postinst
 	debian/libwxmsw-dev.prerm debian/wxwin-doc.doc-base
 	debian/wxwin-headers-msw.dirs
 Removed Files:
 	debian/wxwin-doc.doc-base.in include/wx/setup.h


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11713 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2001-09-28 07:00:13 +00:00

1721 lines
45 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: msw/utils.cpp
// Purpose: Various utilities
// Author: Julian Smart
// Modified by:
// Created: 04/01/98
// RCS-ID: $Id$
// Copyright: (c) Julian Smart and Markus Holzem
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
// #pragma implementation "utils.h" // Note: this is done in utilscmn.cpp now.
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/utils.h"
#include "wx/app.h"
#include "wx/intl.h"
#include "wx/log.h"
#if wxUSE_GUI
#include "wx/cursor.h"
#endif
#endif //WX_PRECOMP
// In some mingws there is a missing extern "C" int the winsock header,
// so we put it here just to be safe. Note that this must appear _before_
// #include "wx/msw/private.h" which itself includes <windows.h>, as this
// one in turn includes <winsock.h> unless we define WIN32_LEAN_AND_MEAN.
//
#if defined(__WIN32__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__) && ! (defined(__GNUWIN32__) && !defined(__MINGW32__))
extern "C" {
#include <winsock.h> // we use socket functions in wxGetFullHostName()
}
#endif
#include "wx/msw/private.h" // includes <windows.h>
#include "wx/timer.h"
#if !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__)
#include <direct.h>
#ifndef __MWERKS__
#include <dos.h>
#endif
#endif //GNUWIN32
#if defined(__GNUWIN32__) && !defined(__TWIN32__)
#include <sys/unistd.h>
#include <sys/stat.h>
#endif //GNUWIN32
#ifdef __BORLANDC__ // Please someone tell me which version of Borland needs
// this (3.1 I believe) and how to test for it.
// If this works for Borland 4.0 as well, then no worries.
#include <dir.h>
#endif
// VZ: there is some code using NetXXX() functions to get the full user name:
// I don't think it's a good idea because they don't work under Win95 and
// seem to return the same as wxGetUserId() under NT. If you really want
// to use them, just #define USE_NET_API
#undef USE_NET_API
#ifdef USE_NET_API
#include <lm.h>
#endif // USE_NET_API
#if defined(__WIN32__) && !defined(__WXWINE__) && !defined(__WXMICROWIN__)
#include <io.h>
#ifndef __GNUWIN32__
#include <shellapi.h>
#endif
#endif
#ifndef __WATCOMC__
#if !(defined(_MSC_VER) && (_MSC_VER > 800))
#include <errno.h>
#endif
#endif
//// BEGIN for console support: VC++ only
#ifdef __VISUALC__
#include "wx/msw/msvcrt.h"
#include <fcntl.h>
#include "wx/ioswrap.h"
#include "wx/ioswrap.h"
/* Need to undef new if including crtdbg.h */
# ifdef new
# undef new
# endif
#ifndef __WIN16__
# include <crtdbg.h>
#endif
# if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS && wxUSE_DEBUG_NEW_ALWAYS
# define new new(__TFILE__,__LINE__)
# endif
#endif
// __VISUALC__
/// END for console support
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// In the WIN.INI file
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
#ifndef __WXMICROWIN__
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// get host name and related
// ----------------------------------------------------------------------------
// Get hostname only (without domain name)
bool wxGetHostName(wxChar *buf, int maxSize)
{
#if defined(__WIN32__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__)
DWORD nSize = maxSize;
if ( !::GetComputerName(buf, &nSize) )
{
wxLogLastError(wxT("GetComputerName"));
return FALSE;
}
return TRUE;
#else
wxChar *sysname;
const wxChar *default_host = wxT("noname");
if ((sysname = wxGetenv(wxT("SYSTEM_NAME"))) == NULL) {
GetProfileString(WX_SECTION, eHOSTNAME, default_host, buf, maxSize - 1);
} else
wxStrncpy(buf, sysname, maxSize - 1);
buf[maxSize] = wxT('\0');
return *buf ? TRUE : FALSE;
#endif
}
// get full hostname (with domain name if possible)
bool wxGetFullHostName(wxChar *buf, int maxSize)
{
#if defined(__WIN32__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__) && ! (defined(__GNUWIN32__) && !defined(__MINGW32__))
// TODO should use GetComputerNameEx() when available
WSADATA wsa;
if ( WSAStartup(MAKEWORD(1, 1), &wsa) == 0 )
{
wxString host;
char bufA[256];
if ( gethostname(bufA, WXSIZEOF(bufA)) == 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);
if ( pHostEnt )
{
// Windows will use DNS internally now
pHostEnt = gethostbyaddr(pHostEnt->h_addr, 4, PF_INET);
}
if ( pHostEnt )
{
host = pHostEnt->h_name;
}
}
}
WSACleanup();
if ( !!host )
{
wxStrncpy(buf, host, maxSize);
return TRUE;
}
}
#endif // Win32
return wxGetHostName(buf, maxSize);
}
// Get user ID e.g. jacs
bool wxGetUserId(wxChar *buf, int maxSize)
{
#if defined(__WIN32__) && !defined(__win32s__) && !defined(__TWIN32__) && !defined(__WXMICROWIN__)
DWORD nSize = maxSize;
if ( ::GetUserName(buf, &nSize) == 0 )
{
// actually, it does happen on Win9x if the user didn't log on
DWORD res = ::GetEnvironmentVariable(wxT("username"), buf, maxSize);
if ( res == 0 )
{
// not found
return FALSE;
}
}
return TRUE;
#else // Win16 or Win32s
wxChar *user;
const wxChar *default_id = wxT("anonymous");
// Can't assume we have NIS (PC-NFS) or some other ID daemon
// So we ...
if ( (user = wxGetenv(wxT("USER"))) == NULL &&
(user = wxGetenv(wxT("LOGNAME"))) == NULL )
{
// Use wxWindows configuration data (comming soon)
GetProfileString(WX_SECTION, eUSERID, default_id, buf, maxSize - 1);
}
else
{
wxStrncpy(buf, user, maxSize - 1);
}
return *buf ? TRUE : FALSE;
#endif
}
// Get user name e.g. Julian Smart
bool wxGetUserName(wxChar *buf, int maxSize)
{
#if wxUSE_PENWINDOWS && !defined(__WATCOMC__) && !defined(__GNUWIN32__)
extern HANDLE g_hPenWin; // PenWindows Running?
if (g_hPenWin)
{
// PenWindows Does have a user concept!
// Get the current owner of the recognizer
GetPrivateProfileString("Current", "User", default_name, wxBuffer, maxSize - 1, "PENWIN.INI");
strncpy(buf, wxBuffer, maxSize - 1);
}
else
#endif
{
#ifdef USE_NET_API
CHAR szUserName[256];
if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) )
return FALSE;
// TODO how to get the domain name?
CHAR *szDomain = "";
// the code is based on the MSDN example (also see KB article Q119670)
WCHAR wszUserName[256]; // Unicode user name
WCHAR wszDomain[256];
LPBYTE ComputerName;
USER_INFO_2 *ui2; // User structure
// Convert ANSI user name and domain to Unicode
MultiByteToWideChar( CP_ACP, 0, szUserName, strlen(szUserName)+1,
wszUserName, WXSIZEOF(wszUserName) );
MultiByteToWideChar( CP_ACP, 0, szDomain, strlen(szDomain)+1,
wszDomain, WXSIZEOF(wszDomain) );
// Get the computer name of a DC for the domain.
if ( NetGetDCName( NULL, wszDomain, &ComputerName ) != NERR_Success )
{
wxLogError(wxT("Can not find domain controller"));
goto error;
}
// Look up the user on the DC
NET_API_STATUS status = NetUserGetInfo( (LPWSTR)ComputerName,
(LPWSTR)&wszUserName,
2, // level - we want USER_INFO_2
(LPBYTE *) &ui2 );
switch ( status )
{
case NERR_Success:
// ok
break;
case NERR_InvalidComputer:
wxLogError(wxT("Invalid domain controller name."));
goto error;
case NERR_UserNotFound:
wxLogError(wxT("Invalid user name '%s'."), szUserName);
goto error;
default:
wxLogSysError(wxT("Can't get information about user"));
goto error;
}
// Convert the Unicode full name to ANSI
WideCharToMultiByte( CP_ACP, 0, ui2->usri2_full_name, -1,
buf, maxSize, NULL, NULL );
return TRUE;
error:
wxLogError(wxT("Couldn't look up full user name."));
return FALSE;
#else // !USE_NET_API
// Could use NIS, MS-Mail or other site specific programs
// Use wxWindows configuration data
bool ok = GetProfileString(WX_SECTION, eUSERNAME, wxT(""), buf, maxSize - 1) != 0;
if ( !ok )
{
ok = wxGetUserId(buf, maxSize);
}
if ( !ok )
{
wxStrncpy(buf, wxT("Unknown User"), maxSize);
}
#endif // Win32/16
}
return TRUE;
}
const wxChar* wxGetHomeDir(wxString *pstr)
{
wxString& strDir = *pstr;
#if defined(__UNIX__) && !defined(__TWIN32__)
const wxChar *szHome = wxGetenv("HOME");
if ( szHome == NULL ) {
// we're homeless...
wxLogWarning(_("can't find user's HOME, using current directory."));
strDir = wxT(".");
}
else
strDir = szHome;
// add a trailing slash if needed
if ( strDir.Last() != wxT('/') )
strDir << wxT('/');
#else // Windows
#ifdef __WIN32__
const wxChar *szHome = wxGetenv(wxT("HOMEDRIVE"));
if ( szHome != NULL )
strDir << szHome;
szHome = wxGetenv(wxT("HOMEPATH"));
if ( szHome != NULL ) {
strDir << szHome;
// the idea is that under NT these variables have default values
// of "%systemdrive%:" and "\\". As we don't want to create our
// config files in the root directory of the system drive, we will
// create it in our program's dir. However, if the user took care
// 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 )
return strDir.c_str();
}
#else // Win16
// Win16 has no idea about home, so use the working directory instead
#endif // WIN16/32
// 260 was taken from windef.h
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
wxString strPath;
::GetModuleFileName(::GetModuleHandle(NULL),
strPath.GetWriteBuf(MAX_PATH), MAX_PATH);
strPath.UngetWriteBuf();
// extract the dir name
wxSplitPath(strPath, &strDir, NULL, NULL);
#endif // UNIX/Win
return strDir.c_str();
}
wxChar *wxGetUserHome(const wxString& WXUNUSED(user))
{
// VZ: the old code here never worked for user != "" anyhow! Moreover, it
// returned sometimes a malloc()'d pointer, sometimes a pointer to a
// static buffer and sometimes I don't even know what.
static wxString s_home;
return (wxChar *)wxGetHomeDir(&s_home);
}
bool wxDirExists(const wxString& dir)
{
#ifdef __WXMICROWIN__
return wxPathExist(dir);
#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
}
bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree)
{
if ( path.empty() )
return FALSE;
#ifdef __WIN32__
// GetDiskFreeSpaceEx() is not available under original Win95, check for
// it
typedef BOOL (*GetDiskFreeSpaceEx_t)(LPCTSTR,
PULARGE_INTEGER,
PULARGE_INTEGER,
PULARGE_INTEGER);
GetDiskFreeSpaceEx_t
pGetDiskFreeSpaceEx = (GetDiskFreeSpaceEx_t)::GetProcAddress
(
::GetModuleHandle(_T("kernel32.dll")),
#if wxUSE_UNICODE
"GetDiskFreeSpaceExW"
#else
"GetDiskFreeSpaceExA"
#endif
);
if ( pGetDiskFreeSpaceEx )
{
ULARGE_INTEGER bytesFree, bytesTotal;
// may pass the path as is, GetDiskFreeSpaceEx() is smart enough
if ( !pGetDiskFreeSpaceEx(path,
&bytesFree,
&bytesTotal,
NULL) )
{
wxLogLastError(_T("GetDiskFreeSpaceEx"));
return FALSE;
}
if ( pTotal )
{
*pTotal = wxLongLong(bytesTotal.HighPart, bytesTotal.LowPart);
}
if ( pFree )
{
*pFree = wxLongLong(bytesFree.HighPart, bytesFree.LowPart);
}
}
else
#endif // Win32
{
// there's a problem with drives larger than 2GB, GetDiskFreeSpaceEx()
// should be used instead - but if it's not available, fall back on
// GetDiskFreeSpace() nevertheless...
DWORD lSectorsPerCluster,
lBytesPerSector,
lNumberOfFreeClusters,
lTotalNumberOfClusters;
// FIXME: this is wrong, we should extract the root drive from path
// instead, but this is the job for wxFileName...
if ( !::GetDiskFreeSpace(path,
&lSectorsPerCluster,
&lBytesPerSector,
&lNumberOfFreeClusters,
&lTotalNumberOfClusters) )
{
wxLogLastError(_T("GetDiskFreeSpace"));
return FALSE;
}
wxLongLong lBytesPerCluster = lSectorsPerCluster;
lBytesPerCluster *= lBytesPerSector;
if ( pTotal )
{
*pTotal = lBytesPerCluster;
*pTotal *= lTotalNumberOfClusters;
}
if ( pFree )
{
*pFree = lBytesPerCluster;
*pFree *= lNumberOfFreeClusters;
}
}
return TRUE;
}
// ----------------------------------------------------------------------------
// env vars
// ----------------------------------------------------------------------------
bool wxGetEnv(const wxString& var, wxString *value)
{
#ifdef __WIN16__
const wxChar* ret = wxGetenv(var);
if (ret)
{
*value = ret;
return TRUE;
}
else
return FALSE;
#else
// 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;
}
if ( value )
{
(void)::GetEnvironmentVariable(var, value->GetWriteBuf(dwRet), dwRet);
value->UngetWriteBuf();
}
return TRUE;
#endif
}
bool wxSetEnv(const wxString& var, const wxChar *value)
{
// some compilers have putenv() or _putenv() or _wputenv() but it's better
// to always use Win32 function directly instead of dealing with them
#if defined(__WIN32__)
if ( !::SetEnvironmentVariable(var, value) )
{
wxLogLastError(_T("SetEnvironmentVariable"));
return FALSE;
}
return TRUE;
#else // no way to set env vars
return FALSE;
#endif
}
// ----------------------------------------------------------------------------
// process management
// ----------------------------------------------------------------------------
#ifdef __WIN32__
// structure used to pass parameters from wxKill() to wxEnumFindByPidProc()
struct wxFindByPidParams
{
wxFindByPidParams() { hwnd = 0; pid = 0; }
// the HWND used to return the result
HWND hwnd;
// the PID we're looking from
DWORD pid;
};
// wxKill helper: EnumWindows() callback which is used to find the first (top
// level) window belonging to the given process
BOOL CALLBACK wxEnumFindByPidProc(HWND hwnd, LPARAM lParam)
{
DWORD pid;
(void)::GetWindowThreadProcessId(hwnd, &pid);
wxFindByPidParams *params = (wxFindByPidParams *)lParam;
if ( pid == params->pid )
{
// remember the window we found
params->hwnd = hwnd;
// return FALSE to stop the enumeration
return FALSE;
}
// continue enumeration
return TRUE;
}
#endif // __WIN32__
int wxKill(long pid, wxSignal sig, wxKillError *krc)
{
#ifdef __WIN32__
// get the process handle to operate on
HANDLE hProcess = ::OpenProcess(SYNCHRONIZE |
PROCESS_TERMINATE |
PROCESS_QUERY_INFORMATION,
FALSE, // not inheritable
(DWORD)pid);
if ( hProcess == NULL )
{
if ( krc )
{
if ( ::GetLastError() == ERROR_ACCESS_DENIED )
{
*krc = wxKILL_ACCESS_DENIED;
}
else
{
*krc = wxKILL_NO_PROCESS;
}
}
return -1;
}
bool ok = TRUE;
switch ( sig )
{
case wxSIGKILL:
// kill the process forcefully returning -1 as error code
if ( !::TerminateProcess(hProcess, (UINT)-1) )
{
wxLogSysError(_("Failed to kill process %d"), pid);
if ( krc )
{
// this is not supposed to happen if we could open the
// process
*krc = wxKILL_ERROR;
}
ok = FALSE;
}
break;
case wxSIGNONE:
// do nothing, we just want to test for process existence
break;
default:
// any other signal means "terminate"
{
wxFindByPidParams params;
params.pid = (DWORD)pid;
// EnumWindows() has nice semantics: it returns 0 if it found
// something or if an error occured and non zero if it
// enumerated all the window
if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)&params) )
{
// did we find any window?
if ( params.hwnd )
{
// tell the app to close
//
// NB: this is the harshest way, the app won't have
// opportunity to save any files, for example, but
// this is probably what we want here. If not we
// can also use SendMesageTimeout(WM_CLOSE)
if ( !::PostMessage(params.hwnd, WM_QUIT, 0, 0) )
{
wxLogLastError(_T("PostMessage(WM_QUIT)"));
}
}
else // it was an error then
{
wxLogLastError(_T("EnumWindows"));
ok = FALSE;
}
}
else // no windows for this PID
{
if ( krc )
{
*krc = wxKILL_ERROR;
}
ok = FALSE;
}
}
}
// the return code
DWORD rc;
if ( ok )
{
// as we wait for a short time, we can use just WaitForSingleObject()
// and not MsgWaitForMultipleObjects()
switch ( ::WaitForSingleObject(hProcess, 500 /* msec */) )
{
case WAIT_OBJECT_0:
// process terminated
if ( !::GetExitCodeProcess(hProcess, &rc) )
{
wxLogLastError(_T("GetExitCodeProcess"));
}
break;
default:
wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") );
// fall through
case WAIT_FAILED:
wxLogLastError(_T("WaitForSingleObject"));
// fall through
case WAIT_TIMEOUT:
if ( krc )
{
*krc = wxKILL_ERROR;
}
rc = STILL_ACTIVE;
break;
}
}
else // !ok
{
// just to suppress the warnings about uninitialized variable
rc = 0;
}
::CloseHandle(hProcess);
// the return code is the same as from Unix kill(): 0 if killed
// successfully or -1 on error
if ( sig == wxSIGNONE )
{
if ( ok && rc == STILL_ACTIVE )
{
// there is such process => success
return 0;
}
}
else // not SIGNONE
{
if ( ok && rc != STILL_ACTIVE )
{
// killed => success
return 0;
}
}
#else // Win15
wxFAIL_MSG( _T("not implemented") );
#endif // Win32/Win16
// error
return -1;
}
// Execute a program in an Interactive Shell
bool wxShell(const wxString& command)
{
wxChar *shell = wxGetenv(wxT("COMSPEC"));
if ( !shell )
shell = wxT("\\COMMAND.COM");
wxString cmd;
if ( !command )
{
// just the shell
cmd = shell;
}
else
{
// pass the command to execute to the command processor
cmd.Printf(wxT("%s /c %s"), shell, command.c_str());
}
return wxExecute(cmd, TRUE /* sync */) != 0;
}
// ----------------------------------------------------------------------------
// misc
// ----------------------------------------------------------------------------
// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
long wxGetFreeMemory()
{
#if defined(__WIN32__) && !defined(__BORLANDC__) && !defined(__TWIN32__)
MEMORYSTATUS memStatus;
memStatus.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus(&memStatus);
return memStatus.dwAvailPhys;
#else
return (long)GetFreeSpace(0);
#endif
}
// Emit a beeeeeep
void wxBell()
{
::MessageBeep((UINT)-1); // default sound
}
wxString wxGetOsDescription()
{
#ifdef __WIN32__
wxString str;
OSVERSIONINFO info;
wxZeroMemory(info);
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if ( ::GetVersionEx(&info) )
{
switch ( info.dwPlatformId )
{
case VER_PLATFORM_WIN32s:
str = _("Win32s on Windows 3.1");
break;
case VER_PLATFORM_WIN32_WINDOWS:
str.Printf(_("Windows 9%c"),
info.dwMinorVersion == 0 ? _T('5') : _T('8'));
if ( !wxIsEmpty(info.szCSDVersion) )
{
str << _T(" (") << info.szCSDVersion << _T(')');
}
break;
case VER_PLATFORM_WIN32_NT:
str.Printf(_T("Windows NT %lu.%lu (build %lu"),
info.dwMajorVersion,
info.dwMinorVersion,
info.dwBuildNumber);
if ( !wxIsEmpty(info.szCSDVersion) )
{
str << _T(", ") << info.szCSDVersion;
}
str << _T(')');
break;
}
}
else
{
wxFAIL_MSG( _T("GetVersionEx() failed") ); // should never happen
}
return str;
#else // Win16
return _("Windows 3.1");
#endif // Win32/16
}
int wxGetOsVersion(int *majorVsn, int *minorVsn)
{
#if defined(__WIN32__) && !defined(__SC__)
OSVERSIONINFO info;
wxZeroMemory(info);
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if ( ::GetVersionEx(&info) )
{
if (majorVsn)
*majorVsn = info.dwMajorVersion;
if (minorVsn)
*minorVsn = info.dwMinorVersion;
switch ( info.dwPlatformId )
{
case VER_PLATFORM_WIN32s:
return wxWIN32S;
case VER_PLATFORM_WIN32_WINDOWS:
return wxWIN95;
case VER_PLATFORM_WIN32_NT:
return wxWINDOWS_NT;
}
}
return wxWINDOWS; // error if we get here, return generic value
#else // Win16
int retValue = wxWINDOWS;
#ifdef __WINDOWS_386__
retValue = wxWIN386;
#else
#if !defined(__WATCOMC__) && !defined(GNUWIN32) && wxUSE_PENWINDOWS
extern HANDLE g_hPenWin;
retValue = g_hPenWin ? wxPENWINDOWS : wxWINDOWS;
#endif
#endif
if (majorVsn)
*majorVsn = 3;
if (minorVsn)
*minorVsn = 1;
return retValue;
#endif
}
// ----------------------------------------------------------------------------
// sleep functions
// ----------------------------------------------------------------------------
#if wxUSE_GUI
#if wxUSE_TIMER
// Sleep for nSecs seconds. Attempt a Windows implementation using timers.
static bool gs_inTimer = FALSE;
class wxSleepTimer : public wxTimer
{
public:
virtual void Notify()
{
gs_inTimer = FALSE;
Stop();
}
};
static wxTimer *wxTheSleepTimer = NULL;
void wxUsleep(unsigned long milliseconds)
{
#ifdef __WIN32__
::Sleep(milliseconds);
#else // !Win32
if (gs_inTimer)
return;
wxTheSleepTimer = new wxSleepTimer;
gs_inTimer = TRUE;
wxTheSleepTimer->Start(milliseconds);
while (gs_inTimer)
{
if (wxTheApp->Pending())
wxTheApp->Dispatch();
}
delete wxTheSleepTimer;
wxTheSleepTimer = NULL;
#endif // Win32/!Win32
}
void wxSleep(int nSecs)
{
if (gs_inTimer)
return;
wxTheSleepTimer = new wxSleepTimer;
gs_inTimer = TRUE;
wxTheSleepTimer->Start(nSecs*1000);
while (gs_inTimer)
{
if (wxTheApp->Pending())
wxTheApp->Dispatch();
}
delete wxTheSleepTimer;
wxTheSleepTimer = NULL;
}
// Consume all events until no more left
void wxFlushEvents()
{
// wxYield();
}
#endif // wxUSE_TIMER
#elif defined(__WIN32__) // wxUSE_GUI
void wxUsleep(unsigned long milliseconds)
{
::Sleep(milliseconds);
}
void wxSleep(int nSecs)
{
wxUsleep(1000*nSecs);
}
#endif // wxUSE_GUI/!wxUSE_GUI
#endif
// __WXMICROWIN__
// ----------------------------------------------------------------------------
// deprecated (in favour of wxLog) log functions
// ----------------------------------------------------------------------------
#if wxUSE_GUI
// Output a debug mess., in a system dependent fashion.
#ifndef __WXMICROWIN__
void wxDebugMsg(const wxChar *fmt ...)
{
va_list ap;
static wxChar buffer[512];
if (!wxTheApp->GetWantDebugOutput())
return ;
va_start(ap, fmt);
wvsprintf(buffer,fmt,ap) ;
OutputDebugString((LPCTSTR)buffer) ;
va_end(ap);
}
// Non-fatal error: pop up message box and (possibly) continue
void wxError(const wxString& msg, const wxString& title)
{
wxSprintf(wxBuffer, wxT("%s\nContinue?"), WXSTRINGCAST msg);
if (MessageBox(NULL, (LPCTSTR)wxBuffer, (LPCTSTR)WXSTRINGCAST title,
MB_ICONSTOP | MB_YESNO) == IDNO)
wxExit();
}
// Fatal error: pop up message box and abort
void wxFatalError(const wxString& msg, const wxString& title)
{
wxSprintf(wxBuffer, wxT("%s: %s"), WXSTRINGCAST title, WXSTRINGCAST msg);
FatalAppExit(0, (LPCTSTR)wxBuffer);
}
#endif // __WXMICROWIN__
// ----------------------------------------------------------------------------
// functions to work with .INI files
// ----------------------------------------------------------------------------
// Reading and writing resources (eg WIN.INI, .Xdefaults)
#if wxUSE_RESOURCES
bool wxWriteResource(const wxString& section, const wxString& entry, const wxString& value, const wxString& file)
{
if (file != wxT(""))
// Don't know what the correct cast should be, but it doesn't
// compile in BC++/16-bit without this cast.
#if !defined(__WIN32__)
return (WritePrivateProfileString((const char*) section, (const char*) entry, (const char*) value, (const char*) file) != 0);
#else
return (WritePrivateProfileString((LPCTSTR)WXSTRINGCAST section, (LPCTSTR)WXSTRINGCAST entry, (LPCTSTR)value, (LPCTSTR)WXSTRINGCAST file) != 0);
#endif
else
return (WriteProfileString((LPCTSTR)WXSTRINGCAST section, (LPCTSTR)WXSTRINGCAST entry, (LPCTSTR)WXSTRINGCAST value) != 0);
}
bool wxWriteResource(const wxString& section, const wxString& entry, float value, const wxString& file)
{
wxString buf;
buf.Printf(wxT("%.4f"), value);
return wxWriteResource(section, entry, buf, file);
}
bool wxWriteResource(const wxString& section, const wxString& entry, long value, const wxString& file)
{
wxString buf;
buf.Printf(wxT("%ld"), value);
return wxWriteResource(section, entry, buf, file);
}
bool wxWriteResource(const wxString& section, const wxString& entry, int value, const wxString& file)
{
wxString buf;
buf.Printf(wxT("%d"), value);
return wxWriteResource(section, entry, buf, file);
}
bool wxGetResource(const wxString& section, const wxString& entry, wxChar **value, const wxString& file)
{
static const wxChar defunkt[] = wxT("$$default");
if (file != wxT(""))
{
int n = GetPrivateProfileString((LPCTSTR)WXSTRINGCAST section, (LPCTSTR)WXSTRINGCAST entry, (LPCTSTR)defunkt,
(LPTSTR)wxBuffer, 1000, (LPCTSTR)WXSTRINGCAST file);
if (n == 0 || wxStrcmp(wxBuffer, defunkt) == 0)
return FALSE;
}
else
{
int n = GetProfileString((LPCTSTR)WXSTRINGCAST section, (LPCTSTR)WXSTRINGCAST entry, (LPCTSTR)defunkt,
(LPTSTR)wxBuffer, 1000);
if (n == 0 || wxStrcmp(wxBuffer, defunkt) == 0)
return FALSE;
}
if (*value) delete[] (*value);
*value = copystring(wxBuffer);
return TRUE;
}
bool wxGetResource(const wxString& section, const wxString& entry, float *value, const wxString& file)
{
wxChar *s = NULL;
bool succ = wxGetResource(section, entry, (wxChar **)&s, file);
if (succ)
{
*value = (float)wxStrtod(s, NULL);
delete[] s;
return TRUE;
}
else return FALSE;
}
bool wxGetResource(const wxString& section, const wxString& entry, long *value, const wxString& file)
{
wxChar *s = NULL;
bool succ = wxGetResource(section, entry, (wxChar **)&s, file);
if (succ)
{
*value = wxStrtol(s, NULL, 10);
delete[] s;
return TRUE;
}
else return FALSE;
}
bool wxGetResource(const wxString& section, const wxString& entry, int *value, const wxString& file)
{
wxChar *s = NULL;
bool succ = wxGetResource(section, entry, (wxChar **)&s, file);
if (succ)
{
*value = (int)wxStrtol(s, NULL, 10);
delete[] s;
return TRUE;
}
else return FALSE;
}
#endif // wxUSE_RESOURCES
// ---------------------------------------------------------------------------
// helper functions for showing a "busy" cursor
// ---------------------------------------------------------------------------
static HCURSOR gs_wxBusyCursor = 0; // new, busy cursor
static HCURSOR gs_wxBusyCursorOld = 0; // old cursor
static int gs_wxBusyCursorCount = 0;
extern HCURSOR wxGetCurrentBusyCursor()
{
return gs_wxBusyCursor;
}
// Set the cursor to the busy cursor for all windows
void wxBeginBusyCursor(wxCursor *cursor)
{
if ( gs_wxBusyCursorCount++ == 0 )
{
gs_wxBusyCursor = (HCURSOR)cursor->GetHCURSOR();
#ifndef __WXMICROWIN__
gs_wxBusyCursorOld = ::SetCursor(gs_wxBusyCursor);
#endif
}
//else: nothing to do, already set
}
// Restore cursor to normal
void wxEndBusyCursor()
{
wxCHECK_RET( gs_wxBusyCursorCount > 0,
wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
if ( --gs_wxBusyCursorCount == 0 )
{
#ifndef __WXMICROWIN__
::SetCursor(gs_wxBusyCursorOld);
#endif
gs_wxBusyCursorOld = 0;
}
}
// TRUE if we're between the above two calls
bool wxIsBusy()
{
return (gs_wxBusyCursorCount > 0);
}
// Check whether this window wants to process messages, e.g. Stop button
// in long calculations.
bool wxCheckForInterrupt(wxWindow *wnd)
{
wxCHECK( wnd, FALSE );
MSG msg;
while ( ::PeekMessage(&msg, GetHwndOf(wnd), 0, 0, PM_REMOVE) )
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
return TRUE;
}
// MSW only: get user-defined resource from the .res file.
// Returns NULL or newly-allocated memory, so use delete[] to clean up.
#ifndef __WXMICROWIN__
wxChar *wxLoadUserResource(const wxString& resourceName, const wxString& resourceType)
{
HRSRC hResource = ::FindResource(wxGetInstance(), resourceName, resourceType);
if ( hResource == 0 )
return NULL;
HGLOBAL hData = ::LoadResource(wxGetInstance(), hResource);
if ( hData == 0 )
return NULL;
wxChar *theText = (wxChar *)::LockResource(hData);
if ( !theText )
return NULL;
// Not all compilers put a zero at the end of the resource (e.g. BC++ doesn't).
// so we need to find the length of the resource.
int len = ::SizeofResource(wxGetInstance(), hResource);
wxChar *s = new wxChar[len+1];
wxStrncpy(s,theText,len);
s[len]=0;
// wxChar *s = copystring(theText);
// Obsolete in WIN32
#ifndef __WIN32__
UnlockResource(hData);
#endif
// No need??
// GlobalFree(hData);
return s;
}
#endif
// ----------------------------------------------------------------------------
// get display info
// ----------------------------------------------------------------------------
// See also the wxGetMousePosition in window.cpp
// Deprecated: use wxPoint wxGetMousePosition() instead
void wxGetMousePosition( int* x, int* y )
{
POINT pt;
GetCursorPos( & pt );
if ( x ) *x = pt.x;
if ( y ) *y = pt.y;
};
// Return TRUE if we have a colour display
bool wxColourDisplay()
{
#ifdef __WXMICROWIN__
// MICROWIN_TODO
return TRUE;
#else
// this function is called from wxDC ctor so it is called a *lot* of times
// hence we optimize it a bit but doign the check only once
//
// this should be MT safe as only the GUI thread (holding the GUI mutex)
// can call us
static int s_isColour = -1;
if ( s_isColour == -1 )
{
ScreenHDC dc;
int noCols = ::GetDeviceCaps(dc, NUMCOLORS);
s_isColour = (noCols == -1) || (noCols > 2);
}
return s_isColour != 0;
#endif
}
// Returns depth of screen
int wxDisplayDepth()
{
ScreenHDC dc;
return GetDeviceCaps(dc, PLANES) * GetDeviceCaps(dc, BITSPIXEL);
}
// Get size of display
void wxDisplaySize(int *width, int *height)
{
#ifdef __WXMICROWIN__
RECT rect;
HWND hWnd = GetDesktopWindow();
::GetWindowRect(hWnd, & rect);
*width = rect.right - rect.left;
*height = rect.bottom - rect.top;
#else
ScreenHDC dc;
if ( width ) *width = GetDeviceCaps(dc, HORZRES);
if ( height ) *height = GetDeviceCaps(dc, VERTRES);
#endif
}
void wxDisplaySizeMM(int *width, int *height)
{
#ifdef __WXMICROWIN__
// MICROWIN_TODO
*width = 0; * height = 0;
#else
ScreenHDC dc;
if ( width ) *width = GetDeviceCaps(dc, HORZSIZE);
if ( height ) *height = GetDeviceCaps(dc, VERTSIZE);
#endif
}
void wxClientDisplayRect(int *x, int *y, int *width, int *height)
{
#if defined(__WIN16__) || defined(__WXMICROWIN__)
*x = 0; *y = 0;
wxDisplaySize(width, height);
#else
// Determine the desktop dimensions minus the taskbar and any other
// special decorations...
RECT r;
SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
if (x) *x = r.left;
if (y) *y = r.top;
if (width) *width = r.right - r.left;
if (height) *height = r.bottom - r.top;
#endif
}
// ---------------------------------------------------------------------------
// window information functions
// ---------------------------------------------------------------------------
wxString WXDLLEXPORT wxGetWindowText(WXHWND hWnd)
{
wxString str;
int len = GetWindowTextLength((HWND)hWnd) + 1;
GetWindowText((HWND)hWnd, str.GetWriteBuf(len), len);
str.UngetWriteBuf();
return str;
}
wxString WXDLLEXPORT wxGetWindowClass(WXHWND hWnd)
{
#ifdef __WXMICROWIN__
// MICROWIN_TODO
return wxEmptyString;
#else
wxString str;
int len = 256; // some starting value
for ( ;; )
{
// as we've #undefined GetClassName we must now manually choose the
// right function to call
int count =
#ifndef __WIN32__
GetClassName
#else // Win32
#ifdef UNICODE
GetClassNameW
#else // !Unicode
#ifdef __TWIN32__
GetClassName
#else // !Twin32
GetClassNameA
#endif // Twin32/!Twin32
#endif // Unicode/ANSI
#endif // Win16/32
((HWND)hWnd, str.GetWriteBuf(len), len);
str.UngetWriteBuf();
if ( count == len )
{
// the class name might have been truncated, retry with larger
// buffer
len *= 2;
}
else
{
break;
}
}
return str;
#endif
}
WXWORD WXDLLEXPORT wxGetWindowId(WXHWND hWnd)
{
#ifndef __WIN32__
return (WXWORD)GetWindowWord((HWND)hWnd, GWW_ID);
#else // Win32
return (WXWORD)GetWindowLong((HWND)hWnd, GWL_ID);
#endif // Win16/32
}
#endif // wxUSE_GUI
#if wxUSE_GUI
// ----------------------------------------------------------------------------
// Metafile helpers
// ----------------------------------------------------------------------------
extern void PixelToHIMETRIC(LONG *x, LONG *y)
{
ScreenHDC hdcRef;
int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
*x *= (iWidthMM * 100);
*x /= iWidthPels;
*y *= (iHeightMM * 100);
*y /= iHeightPels;
}
extern void HIMETRICToPixel(LONG *x, LONG *y)
{
ScreenHDC hdcRef;
int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE),
iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE),
iWidthPels = GetDeviceCaps(hdcRef, HORZRES),
iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
*x *= iWidthPels;
*x /= (iWidthMM * 100);
*y *= iHeightPels;
*y /= (iHeightMM * 100);
}
#endif // wxUSE_GUI
#if 0
//------------------------------------------------------------------------
// wild character routines
//------------------------------------------------------------------------
bool wxIsWild( const wxString& pattern )
{
wxString tmp = pattern;
char *pat = WXSTRINGCAST(tmp);
while (*pat) {
switch (*pat++) {
case '?': case '*': case '[': case '{':
return TRUE;
case '\\':
if (!*pat++)
return FALSE;
}
}
return FALSE;
};
bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special )
{
wxString tmp1 = pat;
char *pattern = WXSTRINGCAST(tmp1);
wxString tmp2 = text;
char *str = WXSTRINGCAST(tmp2);
char c;
char *cp;
bool done = FALSE, ret_code, ok;
// Below is for vi fans
const char OB = '{', CB = '}';
// dot_special means '.' only matches '.'
if (dot_special && *str == '.' && *pattern != *str)
return FALSE;
while ((*pattern != '\0') && (!done)
&& (((*str=='\0')&&((*pattern==OB)||(*pattern=='*')))||(*str!='\0'))) {
switch (*pattern) {
case '\\':
pattern++;
if (*pattern != '\0')
pattern++;
break;
case '*':
pattern++;
ret_code = FALSE;
while ((*str!='\0')
&& (!(ret_code=wxMatchWild(pattern, str++, FALSE))))
/*loop*/;
if (ret_code) {
while (*str != '\0')
str++;
while (*pattern != '\0')
pattern++;
}
break;
case '[':
pattern++;
repeat:
if ((*pattern == '\0') || (*pattern == ']')) {
done = TRUE;
break;
}
if (*pattern == '\\') {
pattern++;
if (*pattern == '\0') {
done = TRUE;
break;
}
}
if (*(pattern + 1) == '-') {
c = *pattern;
pattern += 2;
if (*pattern == ']') {
done = TRUE;
break;
}
if (*pattern == '\\') {
pattern++;
if (*pattern == '\0') {
done = TRUE;
break;
}
}
if ((*str < c) || (*str > *pattern)) {
pattern++;
goto repeat;
}
} else if (*pattern != *str) {
pattern++;
goto repeat;
}
pattern++;
while ((*pattern != ']') && (*pattern != '\0')) {
if ((*pattern == '\\') && (*(pattern + 1) != '\0'))
pattern++;
pattern++;
}
if (*pattern != '\0') {
pattern++, str++;
}
break;
case '?':
pattern++;
str++;
break;
case OB:
pattern++;
while ((*pattern != CB) && (*pattern != '\0')) {
cp = str;
ok = TRUE;
while (ok && (*cp != '\0') && (*pattern != '\0')
&& (*pattern != ',') && (*pattern != CB)) {
if (*pattern == '\\')
pattern++;
ok = (*pattern++ == *cp++);
}
if (*pattern == '\0') {
ok = FALSE;
done = TRUE;
break;
} else if (ok) {
str = cp;
while ((*pattern != CB) && (*pattern != '\0')) {
if (*++pattern == '\\') {
if (*++pattern == CB)
pattern++;
}
}
} else {
while (*pattern!=CB && *pattern!=',' && *pattern!='\0') {
if (*++pattern == '\\') {
if (*++pattern == CB || *pattern == ',')
pattern++;
}
}
}
if (*pattern != '\0')
pattern++;
}
break;
default:
if (*str == *pattern) {
str++, pattern++;
} else {
done = TRUE;
}
}
}
while (*pattern == '*')
pattern++;
return ((*str == '\0') && (*pattern == '\0'));
};
#endif // 0
#if 0
// maximum mumber of lines the output console should have
static const WORD MAX_CONSOLE_LINES = 500;
BOOL WINAPI MyConsoleHandler( DWORD dwCtrlType ) { // control signal type
FreeConsole();
return TRUE;
}
void wxRedirectIOToConsole()
{
int hConHandle;
long lStdHandle;
CONSOLE_SCREEN_BUFFER_INFO coninfo;
FILE *fp;
// allocate a console for this app
AllocConsole();
// set the screen buffer to be big enough to let us scroll text
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
&coninfo);
coninfo.dwSize.Y = MAX_CONSOLE_LINES;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
coninfo.dwSize);
// redirect unbuffered STDOUT to the console
lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
if(hConHandle <= 0) return;
fp = _fdopen( hConHandle, "w" );
*stdout = *fp;
setvbuf( stdout, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console
lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
if(hConHandle <= 0) return;
fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf( stdin, NULL, _IONBF, 0 );
// redirect unbuffered STDERR to the console
lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
if(hConHandle <= 0) return;
fp = _fdopen( hConHandle, "w" );
*stderr = *fp;
setvbuf( stderr, NULL, _IONBF, 0 );
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
// point to console as well
ios::sync_with_stdio();
SetConsoleCtrlHandler(MyConsoleHandler, TRUE);
}
#else
// Not supported
void wxRedirectIOToConsole()
{
}
#endif
#ifdef __WXMICROWIN__
int wxGetOsVersion(int *majorVsn, int *minorVsn)
{
// MICROWIN_TODO
if (majorVsn) *majorVsn = 0;
if (minorVsn) *minorVsn = 0;
return wxUNIX;
}
#endif