X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f6afe7fdf1de812bbc656a1ef832088e56412ae3..74a8f67d96591cec101def2a7d47c64072aff7fd:/src/msw/utils.cpp diff --git a/src/msw/utils.cpp b/src/msw/utils.cpp index 5e295b5a8e..f208feb48f 100644 --- a/src/msw/utils.cpp +++ b/src/msw/utils.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: msw/utils.cpp +// Name: src/msw/utils.cpp // Purpose: Various utilities // Author: Julian Smart // Modified by: @@ -31,14 +31,17 @@ #include "wx/log.h" #endif //WX_PRECOMP +#include "wx/msw/registry.h" #include "wx/apptrait.h" #include "wx/dynlib.h" #include "wx/dynload.h" +#include "wx/scopeguard.h" +#include "wx/filename.h" #include "wx/confbase.h" // for wxExpandEnvVars() #include "wx/msw/private.h" // includes -#include "wx/msw/missing.h" // CHARSET_HANGUL +#include "wx/msw/missing.h" // for CHARSET_HANGUL #if defined(__CYGWIN__) //CYGWIN gives annoying warning about runtime stuff if we don't do this @@ -53,9 +56,7 @@ #include #endif -#include "wx/timer.h" - -#if !defined(__GNUWIN32__) && !defined(__SALFORDC__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) +#if !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) #include #ifndef __MWERKS__ @@ -66,7 +67,9 @@ #if defined(__CYGWIN__) #include #include - #include // for cygwin_conv_to_full_win32_path() + #include // for cygwin_conv_path() + // and cygwin_conv_to_full_win32_path() + #include #endif //GNUWIN32 #ifdef __BORLANDC__ // Please someone tell me which version of Borland needs @@ -109,8 +112,15 @@ // ---------------------------------------------------------------------------- // In the WIN.INI file +#if (!defined(USE_NET_API) && !defined(__WXWINCE__)) || defined(__WXMICROWIN__) static const wxChar WX_SECTION[] = wxT("wxWindows"); +#endif + +#if (!defined(USE_NET_API) && !defined(__WXWINCE__)) static const wxChar eUSERNAME[] = wxT("UserName"); +#endif + +WXDLLIMPEXP_DATA_BASE(const wxChar *) wxUserResourceStr = wxT("TEXT"); // ============================================================================ // implementation @@ -124,11 +134,16 @@ static const wxChar eUSERNAME[] = wxT("UserName"); bool wxGetHostName(wxChar *buf, int maxSize) { #if defined(__WXWINCE__) - // TODO-CE - wxUnusedVar(buf); - wxUnusedVar(maxSize); - return false; -#elif defined(__WIN32__) && !defined(__WXMICROWIN__) + // GetComputerName() is not supported but the name seems to be stored in + // this location in the registry, at least for PPC2003 and WM5 + wxString hostName; + wxRegKey regKey(wxRegKey::HKLM, wxT("Ident")); + if ( !regKey.HasValue(wxT("Name")) || + !regKey.QueryValue(wxT("Name"), hostName) ) + return false; + + wxStrlcpy(buf, hostName.wx_str(), maxSize); +#else // !__WXWINCE__ DWORD nSize = maxSize; if ( !::GetComputerName(buf, &nSize) ) { @@ -136,25 +151,15 @@ bool wxGetHostName(wxChar *buf, int maxSize) return false; } +#endif // __WXWINCE__/!__WXWINCE__ 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( __WXMICROWIN__) && wxUSE_DYNAMIC_LOADER && wxUSE_SOCKETS +#if !defined( __WXMICROWIN__) && wxUSE_DYNLIB_CLASS && wxUSE_SOCKETS // TODO should use GetComputerNameEx() when available // we don't want to always link with Winsock DLL as we might not use it at @@ -162,7 +167,7 @@ bool wxGetFullHostName(wxChar *buf, int maxSize) // missing, we handle this) wxLogNull noLog; - wxDynamicLibrary dllWinsock(_T("ws2_32.dll"), wxDL_VERBATIM); + wxDynamicLibrary dllWinsock(wxT("ws2_32.dll"), wxDL_VERBATIM); if ( dllWinsock.IsLoaded() ) { typedef int (PASCAL *WSAStartup_t)(WORD, WSADATA *); @@ -173,7 +178,7 @@ bool wxGetFullHostName(wxChar *buf, int maxSize) #define LOAD_WINSOCK_FUNC(func) \ func ## _t \ - pfn ## func = (func ## _t)dllWinsock.GetSymbol(_T(#func)) + pfn ## func = (func ## _t)dllWinsock.GetSymbol(wxT(#func)) LOAD_WINSOCK_FUNC(WSAStartup); @@ -224,7 +229,7 @@ bool wxGetFullHostName(wxChar *buf, int maxSize) if ( !host.empty() ) { - wxStrncpy(buf, host, maxSize); + wxStrlcpy(buf, host.c_str(), maxSize); return true; } @@ -236,14 +241,13 @@ bool wxGetFullHostName(wxChar *buf, int maxSize) } // Get user ID e.g. jacs -bool wxGetUserId(wxChar *buf, int maxSize) +bool wxGetUserId(wxChar *WXUNUSED_IN_WINCE(buf), + int WXUNUSED_IN_WINCE(maxSize)) { #if defined(__WXWINCE__) // TODO-CE - wxUnusedVar(buf); - wxUnusedVar(maxSize); return false; -#elif defined(__WIN32__) && !defined(__WXMICROWIN__) +#else DWORD nSize = maxSize; if ( ::GetUserName(buf, &nSize) == 0 ) { @@ -257,35 +261,24 @@ bool wxGetUserId(wxChar *buf, int maxSize) } return true; -#else // __WXMICROWIN__ - 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 wxWidgets 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 defined(__WXWINCE__) - // TODO-CE - wxUnusedVar(buf); - wxUnusedVar(maxSize); - return false; + wxCHECK_MSG( buf && ( maxSize > 0 ), false, + wxT("empty buffer in wxGetUserName") ); +#if defined(__WXWINCE__) && wxUSE_REGKEY + wxLogNull noLog; + wxRegKey key(wxRegKey::HKCU, wxT("ControlPanel\\Owner")); + if(!key.Open(wxRegKey::Read)) + return false; + wxString name; + if(!key.QueryValue(wxT("Owner"),name)) + return false; + wxStrlcpy(buf, name.c_str(), maxSize); + return true; #elif defined(USE_NET_API) CHAR szUserName[256]; if ( !wxGetUserId(szUserName, WXSIZEOF(szUserName)) ) @@ -310,7 +303,7 @@ bool wxGetUserName(wxChar *buf, int maxSize) // Get the computer name of a DC for the domain. if ( NetGetDCName( NULL, wszDomain, &ComputerName ) != NERR_Success ) { - wxLogError(wxT("Can not find domain controller")); + wxLogError(wxT("Cannot find domain controller")); goto error; } @@ -363,7 +356,7 @@ error: if ( !ok ) { - wxStrncpy(buf, wxT("Unknown User"), maxSize); + wxStrlcpy(buf, wxT("Unknown User"), maxSize); } return true; @@ -375,8 +368,8 @@ const wxChar* wxGetHomeDir(wxString *pstr) wxString& strDir = *pstr; // first branch is for Cygwin -#if defined(__UNIX__) - const wxChar *szHome = wxGetenv("HOME"); +#if defined(__UNIX__) && !defined(__WINE__) + const wxChar *szHome = wxGetenv(wxT("HOME")); if ( szHome == NULL ) { // we're homeless... wxLogWarning(_("can't find user's HOME, using current directory.")); @@ -392,7 +385,11 @@ const wxChar* wxGetHomeDir(wxString *pstr) #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); + #if CYGWIN_VERSION_DLL_MAJOR >= 1007 + cygwin_conv_path(CCP_POSIX_TO_WIN_W, strDir, windowsPath, MAX_PATH); + #else + cygwin_conv_to_full_win32_path(strDir, windowsPath); + #endif strDir = windowsPath; #endif #elif defined(__WXWINCE__) @@ -449,30 +446,29 @@ const wxChar* wxGetHomeDir(wxString *pstr) else // fall back to the program directory { // extract the directory component of the program file name - wxSplitPath(wxGetFullModuleName(), &strDir, NULL, NULL); + wxFileName::SplitPath(wxGetFullModuleName(), &strDir, NULL, NULL); } #endif // UNIX/Win return strDir.c_str(); } -wxChar *wxGetUserHome(const wxString& WXUNUSED(user)) +wxString wxGetUserHome(const wxString& 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; + wxString home; + + if ( user.empty() || user == wxGetUserId() ) + wxGetHomeDir(&home); - return (wxChar *)wxGetHomeDir(&s_home); + return home; } -bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree) +bool wxGetDiskSpace(const wxString& WXUNUSED_IN_WINCE(path), + wxDiskspaceSize_t *WXUNUSED_IN_WINCE(pTotal), + wxDiskspaceSize_t *WXUNUSED_IN_WINCE(pFree)) { #ifdef __WXWINCE__ // TODO-CE - wxUnusedVar(path); - wxUnusedVar(pTotal); - wxUnusedVar(pFree); return false; #else if ( path.empty() ) @@ -491,7 +487,7 @@ bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree) GetDiskFreeSpaceEx_t pGetDiskFreeSpaceEx = (GetDiskFreeSpaceEx_t)::GetProcAddress ( - ::GetModuleHandle(_T("kernel32.dll")), + ::GetModuleHandle(wxT("kernel32.dll")), #if wxUSE_UNICODE "GetDiskFreeSpaceExW" #else @@ -504,12 +500,12 @@ bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree) ULARGE_INTEGER bytesFree, bytesTotal; // may pass the path as is, GetDiskFreeSpaceEx() is smart enough - if ( !pGetDiskFreeSpaceEx(path, + if ( !pGetDiskFreeSpaceEx(path.t_str(), &bytesFree, &bytesTotal, NULL) ) { - wxLogLastError(_T("GetDiskFreeSpaceEx")); + wxLogLastError(wxT("GetDiskFreeSpaceEx")); return false; } @@ -524,12 +520,20 @@ bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree) #endif if ( pTotal ) { - *pTotal = wxLongLong(UL(bytesTotal).HighPart, UL(bytesTotal).LowPart); +#if wxUSE_LONGLONG + *pTotal = wxDiskspaceSize_t(UL(bytesTotal).HighPart, UL(bytesTotal).LowPart); +#else + *pTotal = wxDiskspaceSize_t(UL(bytesTotal).LowPart); +#endif } if ( pFree ) { +#if wxUSE_LONGLONG *pFree = wxLongLong(UL(bytesFree).HighPart, UL(bytesFree).LowPart); +#else + *pFree = wxDiskspaceSize_t(UL(bytesFree).LowPart); +#endif } } else @@ -546,18 +550,18 @@ bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree) // FIXME: this is wrong, we should extract the root drive from path // instead, but this is the job for wxFileName... - if ( !::GetDiskFreeSpace(path, + if ( !::GetDiskFreeSpace(path.t_str(), &lSectorsPerCluster, &lBytesPerSector, &lNumberOfFreeClusters, &lTotalNumberOfClusters) ) { - wxLogLastError(_T("GetDiskFreeSpace")); + wxLogLastError(wxT("GetDiskFreeSpace")); return false; } - wxLongLong lBytesPerCluster = lSectorsPerCluster; + wxDiskspaceSize_t lBytesPerCluster = (wxDiskspaceSize_t) lSectorsPerCluster; lBytesPerCluster *= lBytesPerSector; if ( pTotal ) @@ -582,16 +586,15 @@ bool wxGetDiskSpace(const wxString& path, wxLongLong *pTotal, wxLongLong *pFree) // env vars // ---------------------------------------------------------------------------- -bool wxGetEnv(const wxString& var, wxString *value) +bool wxGetEnv(const wxString& WXUNUSED_IN_WINCE(var), + wxString *WXUNUSED_IN_WINCE(value)) { #ifdef __WXWINCE__ // no environment variables under CE - wxUnusedVar(var); - wxUnusedVar(value); return false; #else // Win32 // first get the size of the buffer - DWORD dwRet = ::GetEnvironmentVariable(var, NULL, 0); + DWORD dwRet = ::GetEnvironmentVariable(var.t_str(), NULL, 0); if ( !dwRet ) { // this means that there is no such variable @@ -600,7 +603,8 @@ bool wxGetEnv(const wxString& var, wxString *value) if ( value ) { - (void)::GetEnvironmentVariable(var, wxStringBuffer(*value, dwRet), + (void)::GetEnvironmentVariable(var.t_str(), + wxStringBuffer(*value, dwRet), dwRet); } @@ -608,25 +612,53 @@ bool wxGetEnv(const wxString& var, wxString *value) #endif // WinCE/32 } -bool wxSetEnv(const wxString& var, const wxChar *value) +bool wxDoSetEnv(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__) && !defined(__WXWINCE__) - if ( !::SetEnvironmentVariable(var, value) ) +#ifdef __WXWINCE__ + // no environment variables under CE + wxUnusedVar(var); + wxUnusedVar(value); + return false; +#else // !__WXWINCE__ + // update the CRT environment if possible as people expect getenv() to also + // work and it is not affected by Win32 SetEnvironmentVariable() call (OTOH + // the CRT does use Win32 call to update the process environment block so + // there is no need to call it) + // + // TODO: add checks for the other compilers (and update wxSetEnv() + // documentation in interface/wx/utils.h accordingly) +#if defined(__VISUALC__) || defined(__MINGW32__) + // notice that Microsoft _putenv() has different semantics from POSIX + // function with almost the same name: in particular it makes a copy of the + // string instead of using it as part of environment so we can safely call + // it here without going through all the troubles with wxSetEnvModule as in + // src/unix/utilsunx.cpp + wxString envstr = var; + envstr += '='; + if ( value ) + envstr += value; + _tputenv(envstr.t_str()); +#else // other compiler + if ( !::SetEnvironmentVariable(var.t_str(), value) ) { - wxLogLastError(_T("SetEnvironmentVariable")); + wxLogLastError(wxT("SetEnvironmentVariable")); return false; } +#endif // compiler return true; -#else // no way to set env vars - // no environment variables under CE - wxUnusedVar(var); - wxUnusedVar(value); - return false; -#endif +#endif // __WXWINCE__/!__WXWINCE__ +} + +bool wxSetEnv(const wxString& variable, const wxString& value) +{ + return wxDoSetEnv(variable, value.t_str()); +} + +bool wxUnsetEnv(const wxString& variable) +{ + return wxDoSetEnv(variable, NULL); } // ---------------------------------------------------------------------------- @@ -644,7 +676,7 @@ struct wxFindByPidParams // the PID we're looking from DWORD pid; - DECLARE_NO_COPY_CLASS(wxFindByPidParams) + wxDECLARE_NO_COPY_CLASS(wxFindByPidParams); }; // wxKill helper: EnumWindows() callback which is used to find the first (top @@ -676,28 +708,34 @@ int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags) wxKillAllChildren(pid, sig, krc); // get the process handle to operate on - HANDLE hProcess = ::OpenProcess(SYNCHRONIZE | - PROCESS_TERMINATE | - PROCESS_QUERY_INFORMATION, - FALSE, // not inheritable - (DWORD)pid); + DWORD dwAccess = PROCESS_QUERY_INFORMATION | SYNCHRONIZE; + if ( sig == wxSIGKILL ) + dwAccess |= PROCESS_TERMINATE; + + HANDLE hProcess = ::OpenProcess(dwAccess, FALSE, (DWORD)pid); if ( hProcess == NULL ) { if ( krc ) { - if ( ::GetLastError() == ERROR_ACCESS_DENIED ) - { - *krc = wxKILL_ACCESS_DENIED; - } - else - { - *krc = wxKILL_NO_PROCESS; - } + // recognize wxKILL_ACCESS_DENIED as special because this doesn't + // mean that the process doesn't exist and this is important for + // wxProcess::Exists() + *krc = ::GetLastError() == ERROR_ACCESS_DENIED + ? wxKILL_ACCESS_DENIED + : wxKILL_NO_PROCESS; } return -1; } + wxON_BLOCK_EXIT1(::CloseHandle, hProcess); + + // Default timeout for waiting for the process termination after killing + // it. It should be long enough to allow the process to terminate even on a + // busy system but short enough to avoid blocking the main thread for too + // long. + DWORD waitTimeout = 500; // ms + bool ok = true; switch ( sig ) { @@ -719,7 +757,13 @@ int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags) break; case wxSIGNONE: - // do nothing, we just want to test for process existence + // Opening the process handle may succeed for a process even if it + // doesn't run any more (typically because open handles to it still + // exist elsewhere, possibly in this process itself if we're + // killing a child process) so we still need check if it hasn't + // terminated yet but, unlike when killing it, we don't need to + // wait for any time at all. + waitTimeout = 0; break; default: @@ -729,7 +773,7 @@ int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags) 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 + // something or if an error occurred and non zero if it // enumerated all the window if ( !::EnumWindows(wxEnumFindByPidProc, (LPARAM)¶ms) ) { @@ -738,18 +782,18 @@ int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags) { // tell the app to close // - // NB: this is the harshest way, the app won't have + // NB: this is the harshest way, the app won't have an // 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)")); + wxLogLastError(wxT("PostMessage(WM_QUIT)")); } } else // it was an error then { - wxLogLastError(_T("EnumWindows")); + wxLogLastError(wxT("EnumWindows")); ok = false; } @@ -757,9 +801,7 @@ int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags) else // no windows for this PID { if ( krc ) - { *krc = wxKILL_ERROR; - } ok = false; } @@ -767,71 +809,64 @@ int wxKill(long pid, wxSignal sig, wxKillError *krc, int flags) } // 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 */) ) + switch ( ::WaitForSingleObject(hProcess, waitTimeout) ) { case WAIT_OBJECT_0: - // process terminated - if ( !::GetExitCodeProcess(hProcess, &rc) ) + // Process terminated: normally this indicates that we + // successfully killed it but when testing for the process + // existence, this means failure. + if ( sig == wxSIGNONE ) { - wxLogLastError(_T("GetExitCodeProcess")); + if ( krc ) + *krc = wxKILL_NO_PROCESS; + + ok = false; } break; default: - wxFAIL_MSG( _T("unexpected WaitForSingleObject() return") ); + wxFAIL_MSG( wxT("unexpected WaitForSingleObject() return") ); // fall through case WAIT_FAILED: - wxLogLastError(_T("WaitForSingleObject")); + wxLogLastError(wxT("WaitForSingleObject")); // fall through case WAIT_TIMEOUT: - if ( krc ) + // Process didn't terminate: normally this is a failure but not + // when we're just testing for its existence. + if ( sig != wxSIGNONE ) { - *krc = wxKILL_ERROR; - } + if ( krc ) + *krc = wxKILL_ERROR; - rc = STILL_ACTIVE; + ok = false; + } 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 - // - // be careful to interpret rc correctly: for wxSIGNONE we return success if - // the process exists, for all the other sig values -- if it doesn't - if ( ok && - ((sig == wxSIGNONE) == (rc == STILL_ACTIVE)) ) - { - if ( krc ) - { - *krc = wxKILL_OK; - } + if ( !ok ) + return -1; - return 0; - } + if ( krc ) + *krc = wxKILL_OK; - // error - return -1; + return 0; } -HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ; -BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ; -BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ; +typedef HANDLE (WINAPI *CreateToolhelp32Snapshot_t)(DWORD,DWORD); +typedef BOOL (WINAPI *Process32_t)(HANDLE,LPPROCESSENTRY32); + +CreateToolhelp32Snapshot_t lpfCreateToolhelp32Snapshot; +Process32_t lpfProcess32First, lpfProcess32Next; static void InitToolHelp32() { @@ -846,9 +881,9 @@ static void InitToolHelp32() lpfProcess32First = NULL; lpfProcess32Next = NULL; - HINSTANCE hInstLib = LoadLibrary( wxT("Kernel32.DLL") ) ; - if( hInstLib == NULL ) - return ; +#if wxUSE_DYNLIB_CLASS + + wxDynamicLibrary dllKernel(wxT("kernel32.dll"), wxDL_VERBATIM); // Get procedure addresses. // We are linking to these functions of Kernel32 @@ -856,37 +891,16 @@ static void InitToolHelp32() // 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 - ) ; + lpfCreateToolhelp32Snapshot = + (CreateToolhelp32Snapshot_t)dllKernel.RawGetSymbol(wxT("CreateToolhelp32Snapshot")); - lpfProcess32First= - (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32)) - GetProcAddress( hInstLib, -#ifdef __WXWINCE__ - wxT("Process32First") -#else - "Process32First" -#endif - ) ; + lpfProcess32First = + (Process32_t)dllKernel.RawGetSymbol(wxT("Process32First")); - lpfProcess32Next= - (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32)) - GetProcAddress( hInstLib, -#ifdef __WXWINCE__ - wxT("Process32Next") -#else - "Process32Next" -#endif - ) ; + lpfProcess32Next = + (Process32_t)dllKernel.RawGetSymbol(wxT("Process32Next")); - FreeLibrary( hInstLib ) ; +#endif // wxUSE_DYNLIB_CLASS } // By John Skiff @@ -963,16 +977,15 @@ bool wxShell(const wxString& command) } // Shutdown or reboot the PC -bool wxShutdown(wxShutdownFlags wFlags) +bool wxShutdown(int WXUNUSED_IN_WINCE(flags)) { #ifdef __WXWINCE__ // TODO-CE - wxUnusedVar(wFlags); return false; #elif defined(__WIN32__) bool bOK = true; - if ( wxGetOsVersion(NULL, NULL) == wxWINDOWS_NT ) // if is NT or 2K + if ( wxGetOsVersion(NULL, NULL) == wxOS_WINDOWS_NT ) // if is NT or 2K { // Get a token for this process. HANDLE hToken; @@ -984,56 +997,59 @@ bool wxShutdown(wxShutdownFlags wFlags) TOKEN_PRIVILEGES tkp; // Get the LUID for the shutdown privilege. - ::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, - &tkp.Privileges[0].Luid); + bOK = ::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, + &tkp.Privileges[0].Luid) != 0; - tkp.PrivilegeCount = 1; // one privilege to set - tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if ( bOK ) + { + tkp.PrivilegeCount = 1; // one privilege to set + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + // Get the shutdown privilege for this process. + ::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, + (PTOKEN_PRIVILEGES)NULL, 0); - // Get the shutdown privilege for this process. - ::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, - (PTOKEN_PRIVILEGES)NULL, 0); + // Cannot test the return value of AdjustTokenPrivileges. + bOK = ::GetLastError() == ERROR_SUCCESS; + } - // Cannot test the return value of AdjustTokenPrivileges. - bOK = ::GetLastError() == ERROR_SUCCESS; + ::CloseHandle(hToken); } } if ( bOK ) { - UINT flags = EWX_SHUTDOWN | EWX_FORCE; - switch ( wFlags ) + UINT wFlags = 0; + if ( flags & wxSHUTDOWN_FORCE ) + { + wFlags = EWX_FORCE; + flags &= ~wxSHUTDOWN_FORCE; + } + + switch ( flags ) { case wxSHUTDOWN_POWEROFF: - flags |= EWX_POWEROFF; + wFlags |= EWX_POWEROFF; break; case wxSHUTDOWN_REBOOT: - flags |= EWX_REBOOT; + wFlags |= EWX_REBOOT; + break; + + case wxSHUTDOWN_LOGOFF: + wFlags |= EWX_LOGOFF; break; default: - wxFAIL_MSG( _T("unknown wxShutdown() flag") ); + wxFAIL_MSG( wxT("unknown wxShutdown() flag") ); return false; } - bOK = ::ExitWindowsEx(flags, 0) != 0; + bOK = ::ExitWindowsEx(wFlags, 0) != 0; } return bOK; -#endif // Win32/16 -} - -wxPowerType wxGetPowerType() -{ - // TODO - return wxPOWER_UNKNOWN; -} - -wxBatteryState wxGetBatteryState() -{ - // TODO - return wxBATTERY_UNKNOWN_STATE; +#endif // WinCE/!WinCE } // ---------------------------------------------------------------------------- @@ -1045,9 +1061,9 @@ wxMemorySize wxGetFreeMemory() { #if defined(__WIN64__) MEMORYSTATUSEX memStatex; - statex.dwLength = sizeof (statex); - ::GlobalMemoryStatusEx (&statex); - return (wxMemorySize)memStatus.ullAvailPhys; + memStatex.dwLength = sizeof (memStatex); + ::GlobalMemoryStatusEx (&memStatex); + return (wxMemorySize)memStatex.ullAvailPhys; #else /* if defined(__WIN32__) */ MEMORYSTATUS memStatus; memStatus.dwLength = sizeof(MEMORYSTATUS); @@ -1069,23 +1085,125 @@ void wxBell() bool wxIsDebuggerRunning() { +#if wxUSE_DYNLIB_CLASS // IsDebuggerPresent() is not available under Win95, so load it dynamically - wxDynamicLibrary dll(_T("kernel32.dll"), wxDL_VERBATIM); + wxDynamicLibrary dll(wxT("kernel32.dll"), wxDL_VERBATIM); typedef BOOL (WINAPI *IsDebuggerPresent_t)(); - if ( !dll.HasSymbol(_T("IsDebuggerPresent")) ) + if ( !dll.HasSymbol(wxT("IsDebuggerPresent")) ) { // no way to know, assume no return false; } - return (*(IsDebuggerPresent_t)dll.GetSymbol(_T("IsDebuggerPresent")))() != 0; + return (*(IsDebuggerPresent_t)dll.GetSymbol(wxT("IsDebuggerPresent")))() != 0; +#else + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// working with MSW resources +// ---------------------------------------------------------------------------- + +bool +wxLoadUserResource(const void **outData, + size_t *outLen, + const wxString& resourceName, + const wxString& resourceType, + WXHINSTANCE instance) +{ + wxCHECK_MSG( outData && outLen, false, "output pointers can't be NULL" ); + + HRSRC hResource = ::FindResource(instance, + resourceName.wx_str(), + resourceType.wx_str()); + if ( !hResource ) + return false; + + HGLOBAL hData = ::LoadResource(instance, hResource); + if ( !hData ) + { + wxLogSysError(_("Failed to load resource \"%s\"."), resourceName); + return false; + } + + *outData = ::LockResource(hData); + if ( !*outData ) + { + wxLogSysError(_("Failed to lock resource \"%s\"."), resourceName); + return false; + } + + *outLen = ::SizeofResource(instance, hResource); + + // Notice that we do not need to call neither UnlockResource() (which is + // obsolete in Win32) nor GlobalFree() (resources are freed on process + // termination only) + + return true; +} + +char * +wxLoadUserResource(const wxString& resourceName, + const wxString& resourceType, + int* pLen, + WXHINSTANCE instance) +{ + const void *data; + size_t len; + if ( !wxLoadUserResource(&data, &len, resourceName, resourceType, instance) ) + return NULL; + + char *s = new char[len + 1]; + memcpy(s, data, len); + s[len] = '\0'; // NUL-terminate in case the resource itself wasn't + + if (pLen) + *pLen = len; + + return s; } // ---------------------------------------------------------------------------- // OS version // ---------------------------------------------------------------------------- +// check if we're running under a server or workstation Windows system: it +// returns true or false with obvious meaning as well as -1 if the system type +// couldn't be determined +// +// this function is currently private but we may want to expose it later if +// it's really useful +namespace +{ + +int wxIsWindowsServer() +{ +#ifdef VER_NT_WORKSTATION + OSVERSIONINFOEX info; + wxZeroMemory(info); + + info.dwOSVersionInfoSize = sizeof(info); + if ( ::GetVersionEx(reinterpret_cast(&info)) ) + { + switch ( info.wProductType ) + { + case VER_NT_WORKSTATION: + return false; + + case VER_NT_SERVER: + case VER_NT_DOMAIN_CONTROLLER: + return true; + } + } +#endif // VER_NT_WORKSTATION + + return -1; +} + +} // anonymous namespace + wxString wxGetOsDescription() { wxString str; @@ -1098,6 +1216,13 @@ wxString wxGetOsDescription() { switch ( info.dwPlatformId ) { +#ifdef VER_PLATFORM_WIN32_CE + case VER_PLATFORM_WIN32_CE: + str.Printf(_("Windows CE (%d.%d)"), + info.dwMajorVersion, + info.dwMinorVersion); + break; +#endif case VER_PLATFORM_WIN32s: str = _("Win32s on Windows 3.1"); break; @@ -1138,107 +1263,227 @@ wxString wxGetOsDescription() } if ( !wxIsEmpty(info.szCSDVersion) ) { - str << _T(" (") << info.szCSDVersion << _T(')'); + str << wxT(" (") << info.szCSDVersion << wxT(')'); } break; case VER_PLATFORM_WIN32_NT: - if ( info.dwMajorVersion == 5 ) + switch ( info.dwMajorVersion ) { - 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; - } + case 5: + switch ( info.dwMinorVersion ) + { + case 0: + str = _("Windows 2000"); + break; + + case 2: + // we can't distinguish between XP 64 and 2003 + // as they both are 5.2, so examine the product + // type to resolve this ambiguity + if ( wxIsWindowsServer() == 1 ) + { + str = _("Windows Server 2003"); + break; + } + //else: must be XP, fall through + + case 1: + str = _("Windows XP"); + break; + } + break; + + case 6: + switch ( info.dwMinorVersion ) + { + case 0: + str = wxIsWindowsServer() == 1 + ? _("Windows Server 2008") + : _("Windows Vista"); + break; + + case 1: + str = wxIsWindowsServer() == 1 + ? _("Windows Server 2008 R2") + : _("Windows 7"); + break; + } + break; } - if ( wxIsEmpty(str) ) + + if ( str.empty() ) { - str.Printf(_("Windows NT %lu.%lu (build %lu"), - info.dwMajorVersion, - info.dwMinorVersion, - info.dwBuildNumber); + str.Printf(_("Windows NT %lu.%lu"), + info.dwMajorVersion, + info.dwMinorVersion); } + + str << wxT(" (") + << wxString::Format(_("build %lu"), info.dwBuildNumber); if ( !wxIsEmpty(info.szCSDVersion) ) { - str << _T(", ") << info.szCSDVersion; + str << wxT(", ") << info.szCSDVersion; } - str << _T(')'); + str << wxT(')'); + + if ( wxIsPlatform64Bit() ) + str << _(", 64-bit edition"); break; } } else { - wxFAIL_MSG( _T("GetVersionEx() failed") ); // should never happen + wxFAIL_MSG( wxT("GetVersionEx() failed") ); // should never happen } return str; } -wxToolkitInfo& wxAppTraits::GetToolkitInfo() +bool wxIsPlatform64Bit() { - // cache the version info, it's not going to change - // - // NB: this is MT-safe, we may use these static vars from different threads - // but as they always have the same value it doesn't matter - static int s_ver = -1, - s_major = -1, - s_minor = -1; +#if defined(_WIN64) + return true; // 64-bit programs run only on Win64 +#elif wxUSE_DYNLIB_CLASS // Win32 + // 32-bit programs run on both 32-bit and 64-bit Windows so check + typedef BOOL (WINAPI *IsWow64Process_t)(HANDLE, BOOL *); + + wxDynamicLibrary dllKernel32(wxT("kernel32.dll")); + IsWow64Process_t pfnIsWow64Process = + (IsWow64Process_t)dllKernel32.RawGetSymbol(wxT("IsWow64Process")); + + BOOL wow64 = FALSE; + if ( pfnIsWow64Process ) + { + pfnIsWow64Process(::GetCurrentProcess(), &wow64); + } + //else: running under a system without Win64 support - if ( s_ver == -1 ) + return wow64 != FALSE; +#else + return false; +#endif // Win64/Win32 +} + +wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin) +{ + static struct + { + // this may be false, true or -1 if we tried to initialize but failed + int initialized; + + wxOperatingSystemId os; + + int verMaj, + verMin; + } s_version; + + // query the OS info only once as it's not supposed to change + if ( !s_version.initialized ) { OSVERSIONINFO info; wxZeroMemory(info); - - s_ver = wxWINDOWS; - info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + info.dwOSVersionInfoSize = sizeof(info); if ( ::GetVersionEx(&info) ) { - s_major = info.dwMajorVersion; - s_minor = info.dwMinorVersion; + s_version.initialized = true; -#ifdef __SMARTPHONE__ - s_ver = wxWINDOWS_SMARTPHONE; -#elif defined(__POCKETPC__) - s_ver = wxWINDOWS_POCKETPC; -#else +#if defined(__WXWINCE__) + s_version.os = wxOS_WINDOWS_CE; +#elif defined(__WXMICROWIN__) + s_version.os = wxOS_WINDOWS_MICRO; +#else // "normal" desktop Windows system, use run-time detection switch ( info.dwPlatformId ) { - case VER_PLATFORM_WIN32s: - s_ver = wxWIN32S; + case VER_PLATFORM_WIN32_NT: + s_version.os = wxOS_WINDOWS_NT; break; case VER_PLATFORM_WIN32_WINDOWS: - s_ver = wxWIN95; + s_version.os = wxOS_WINDOWS_9X; break; + } +#endif // Windows versions - case VER_PLATFORM_WIN32_NT: - s_ver = wxWINDOWS_NT; + s_version.verMaj = info.dwMajorVersion; + s_version.verMin = info.dwMinorVersion; + } + else // GetVersionEx() failed + { + s_version.initialized = -1; + } + } + + if ( s_version.initialized == 1 ) + { + if ( verMaj ) + *verMaj = s_version.verMaj; + if ( verMin ) + *verMin = s_version.verMin; + } + + // this works even if we were not initialized successfully as the initial + // values of this field is 0 which is wxOS_UNKNOWN and exactly what we need + return s_version.os; +} + +wxWinVersion wxGetWinVersion() +{ + int verMaj, + verMin; + switch ( wxGetOsVersion(&verMaj, &verMin) ) + { + case wxOS_WINDOWS_9X: + if ( verMaj == 4 ) + { + switch ( verMin ) + { + case 0: + return wxWinVersion_95; + + case 10: + return wxWinVersion_98; + + case 90: + return wxWinVersion_ME; + } + } + break; + + case wxOS_WINDOWS_NT: + switch ( verMaj ) + { + case 3: + return wxWinVersion_NT3; + + case 4: + return wxWinVersion_NT4; + + case 5: + switch ( verMin ) + { + case 0: + return wxWinVersion_2000; + + case 1: + return wxWinVersion_XP; + + case 2: + return wxWinVersion_2003; + } break; -#ifdef __WXWINCE__ - case VER_PLATFORM_WIN32_CE: - s_ver = wxWINDOWS_CE; -#endif + + case 6: + return wxWinVersion_NT6; } -#endif - } + break; + + default: + // Do nothing just to silence GCC warning + break; } - static wxToolkitInfo info; - info.versionMajor = s_major; - info.versionMinor = s_minor; - info.os = s_ver; - info.name = _T("wxBase"); - return info; + return wxWinVersion_Unknown; } // ---------------------------------------------------------------------------- @@ -1286,8 +1531,10 @@ extern WXDLLIMPEXP_BASE long wxEncodingToCharset(wxFontEncoding encoding) case wxFONTENCODING_CP936: return GB2312_CHARSET; +#ifndef __WXWINCE__ case wxFONTENCODING_CP949: return HANGUL_CHARSET; +#endif case wxFONTENCODING_CP950: return CHINESEBIG5_CHARSET; @@ -1355,13 +1602,15 @@ extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding) case wxFONTENCODING_ISO8859_8: ret = 28598; break; case wxFONTENCODING_ISO8859_9: ret = 28599; break; case wxFONTENCODING_ISO8859_10: ret = 28600; break; - case wxFONTENCODING_ISO8859_11: ret = 28601; break; + case wxFONTENCODING_ISO8859_11: ret = 874; break; // case wxFONTENCODING_ISO8859_12, // doesn't exist currently, but put it case wxFONTENCODING_ISO8859_13: ret = 28603; break; - case wxFONTENCODING_ISO8859_14: ret = 28604; break; + // case wxFONTENCODING_ISO8859_14: ret = 28604; break; // no correspondence on Windows case wxFONTENCODING_ISO8859_15: ret = 28605; break; + case wxFONTENCODING_KOI8: ret = 20866; break; case wxFONTENCODING_KOI8_U: ret = 21866; break; + case wxFONTENCODING_CP437: ret = 437; break; case wxFONTENCODING_CP850: ret = 850; break; case wxFONTENCODING_CP852: ret = 852; break; @@ -1380,7 +1629,9 @@ extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding) case wxFONTENCODING_CP1255: ret = 1255; break; case wxFONTENCODING_CP1256: ret = 1256; break; case wxFONTENCODING_CP1257: ret = 1257; break; - case wxFONTENCODING_EUC_JP: ret = 51932; break; + + case wxFONTENCODING_EUC_JP: ret = 20932; break; + case wxFONTENCODING_MACROMAN: ret = 10000; break; case wxFONTENCODING_MACJAPANESE: ret = 10001; break; case wxFONTENCODING_MACCHINESETRAD: ret = 10002; break; @@ -1395,8 +1646,12 @@ extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding) case wxFONTENCODING_MACCROATIAN: ret = 10082; break; case wxFONTENCODING_MACICELANDIC: ret = 10079; break; case wxFONTENCODING_MACROMANIAN: ret = 10009; break; + + case wxFONTENCODING_ISO2022_JP: ret = 50222; break; + case wxFONTENCODING_UTF7: ret = 65000; break; case wxFONTENCODING_UTF8: ret = 65001; break; + default: return -1; } @@ -1410,7 +1665,7 @@ extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding) return (long) ret; } -extern long wxCharsetToCodepage(const wxChar *name) +extern long wxCharsetToCodepage(const char *name) { // first get the font encoding for this charset if ( !name ) @@ -1429,13 +1684,14 @@ extern long wxCharsetToCodepage(const wxChar *name) #include "wx/msw/registry.h" // this should work if Internet Exploiter is installed -extern long wxCharsetToCodepage(const wxChar *name) +extern long wxCharsetToCodepage(const char *name) { if (!name) return GetACP(); long CP = -1; +#if wxUSE_REGKEY wxString path(wxT("MIME\\Database\\Charset\\")); wxString cn(name); @@ -1461,6 +1717,7 @@ extern long wxCharsetToCodepage(const wxChar *name) !key.QueryValue(wxT("AliasForCharset"), cn)) break; } +#endif // wxUSE_REGKEY return CP; } @@ -1476,14 +1733,14 @@ extern long wxCharsetToCodepage(const wxChar *name) 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 + NULL. classname is the desired wndclass classname. If function successfully 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") ); + wxT("NULL parameter in wxCreateHiddenWindow") ); // register the class fi we need to first if ( *pclassname == NULL ) @@ -1525,4 +1782,3 @@ wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc) return hwnd; } -