+ else
+ strDir = szHome;
+
+ // add a trailing slash if needed
+ if ( strDir.Last() != wxT('/') )
+ 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;
+ #endif
+ #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;
+
+// old w32api don't have ULARGE_INTEGER
+#if defined(__WIN32__) && \
+ (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION( 0, 3 ))
+ // GetDiskFreeSpaceEx() is not available under original Win95, check for
+ // it
+ typedef BOOL (WINAPI *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;
+ }
+
+ // ULARGE_INTEGER is a union of a 64 bit value and a struct containing
+ // two 32 bit fields which may be or may be not named - try to make it
+ // compile in all cases
+#if defined(__BORLANDC__) && !defined(_ANONYMOUS_STRUCT)
+ #define UL(ul) ul.u
+#else // anon union
+ #define UL(ul) ul
+#endif
+ if ( pTotal )
+ {
+ *pTotal = wxLongLong(UL(bytesTotal).HighPart, UL(bytesTotal).LowPart);
+ }
+
+ if ( pFree )
+ {
+ *pFree = wxLongLong(UL(bytesFree).HighPart, UL(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)¶ms) )
+ {
+ // 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