diff --git a/source/lib/sysdep/win/wgfx.cpp b/source/lib/sysdep/win/wgfx.cpp index b4499e1511..67156f706d 100644 --- a/source/lib/sysdep/win/wgfx.cpp +++ b/source/lib/sysdep/win/wgfx.cpp @@ -13,6 +13,7 @@ #include "wdll_ver.h" #include "win.h" +#include "wmi.h" #if MSC_VERSION #pragma comment(lib, "advapi32.lib") // registry @@ -63,57 +64,12 @@ LibError gfx_get_monitor_size(int& width_mm, int& height_mm) //----------------------------------------------------------------------------- -// EnumDisplayDevices is not available on Win95 or NT. -// try to import it manually here; return -1 if not available. -static BOOL (WINAPI *pEnumDisplayDevicesA)(LPCSTR, DWORD, LPDISPLAY_DEVICEA, DWORD); -static LibError import_EnumDisplayDevices() -{ - if(!pEnumDisplayDevicesA) - { - static HMODULE hUser32Dll = LoadLibrary("user32.dll"); - *(void**)&pEnumDisplayDevicesA = GetProcAddress(hUser32Dll, "EnumDisplayDevicesA"); - - // do not free the DLL reference! if this happens to be the first - // use of user32 (possible if it's delay-loaded or otherwise unused), - // it would actually be unloaded. that apparently breaks the - // Windows cursor. - // unfortunately there's no way to get at the reference count, - // so this resource leak is unavoidable. - } - - return pEnumDisplayDevicesA? INFO::OK : ERR::FAIL; -} - - static LibError win_get_gfx_card() { - // make sure EnumDisplayDevices is available (as pEnumDisplayDevicesA) - if(import_EnumDisplayDevices() >= 0) - { - // loop through all display adapters and put the primary device's - // identifier in gfx_card. - // (we don't bother returning a list of all of them because it's - // likely to be redundant, e.g. "Radeon" and "Radeon Secondary"; - // we're only interested in the 'main' card anyway) - DISPLAY_DEVICEA dd = { sizeof(DISPLAY_DEVICEA) }; - for(DWORD dev_num = 0; ; dev_num++) - { - if(!pEnumDisplayDevicesA(0, dev_num, &dd, 0)) - break; - - // ignore mirror pseudo-devices (installed e.g. by NetMeeting) - if(dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) - continue; - - if(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) - { - strcpy_s(gfx_card, ARRAY_SIZE(gfx_card), (const char*)dd.DeviceString); - return INFO::OK; - } - } - } - - WARN_RETURN(ERR::FAIL); + WmiMap wmiMap; + RETURN_ERR(wmi_GetClass("Win32_VideoController", wmiMap)); + sprintf_s(gfx_card, GFX_CARD_LEN, "%ls", wmiMap[L"Caption"].bstrVal); + return INFO::OK; } diff --git a/source/lib/sysdep/win/wmi.cpp b/source/lib/sysdep/win/wmi.cpp new file mode 100644 index 0000000000..db72804caf --- /dev/null +++ b/source/lib/sysdep/win/wmi.cpp @@ -0,0 +1,111 @@ +/** + * ========================================================================= + * File : wmi.cpp + * Project : 0 A.D. + * Description : wrapper for Windows Management Instrumentation + * ========================================================================= + */ + +// license: GPL; see lib/license.txt + +#include "precompiled.h" +#include "wmi.h" + +#include + +#include "winit.h" + +#pragma comment(lib, "wbemuuid.lib") + +WINIT_REGISTER_EARLY_INIT(wmi_Init); +WINIT_REGISTER_EARLY_SHUTDOWN(wmi_Shutdown); + + +static IWbemLocator* pLoc; +static IWbemServices* pSvc; + +static LibError wmi_Init() +{ + HRESULT hr; + + // initializing with COINIT_MULTITHREADED causes the (unchanged) value of + // pSvc to be invalid by the time wmi_Shutdown is reached. the cause is + // unclear (maybe another DLL already doing CoUninitialize?), but using + // single-threaded apartment mode (the default) avoids it. + hr = CoInitialize(0); + if(FAILED(hr)) + WARN_RETURN(ERR::_1); + + hr = CoInitializeSecurity(0, -1, 0, 0, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE, 0); + if(FAILED(hr)) + WARN_RETURN(ERR::_2); + + hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**)&pLoc); + if(FAILED(hr)) + WARN_RETURN(ERR::_3); + + hr = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), 0, 0, 0, 0, 0, 0, &pSvc); + if(FAILED(hr)) + WARN_RETURN(ERR::_4); + + hr = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 0, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, 0, EOAC_NONE); + if(FAILED(hr)) + WARN_RETURN(ERR::_5); + + return INFO::OK; +} + + +static LibError wmi_Shutdown() +{ + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + + return INFO::OK; +} + + +LibError wmi_GetClass(const char* className, WmiMap& wmiMap) +{ + HRESULT hr; + + IEnumWbemClassObject* pEnum = 0; + char query[200]; + sprintf_s(query, ARRAY_SIZE(query), "SELECT * FROM %s", className); + hr = pSvc->ExecQuery(L"WQL", _bstr_t(query), WBEM_FLAG_FORWARD_ONLY|WBEM_FLAG_RETURN_IMMEDIATELY, 0, &pEnum); + if(FAILED(hr)) + WARN_RETURN(ERR::FAIL); + debug_assert(pEnum); + + for(;;) + { + IWbemClassObject* pObj = 0; + ULONG numReturned = 0; + hr = pEnum->Next(WBEM_INFINITE, 1, &pObj, &numReturned); + if(FAILED(hr)) + WARN_RETURN(ERR::FAIL); + if(numReturned == 0) + break; + debug_assert(pEnum); + + pObj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY); + for(;;) + { + BSTR name; + VARIANT value; + VariantInit(&value); + if(pObj->Next(0, &name, &value, 0, 0) != WBEM_S_NO_ERROR) + { + SysFreeString(name); + break; + } + wmiMap[name] = value; + SysFreeString(name); + } + pObj->Release(); + } + pEnum->Release(); + + return INFO::OK; +} diff --git a/source/lib/sysdep/win/wmi.h b/source/lib/sysdep/win/wmi.h new file mode 100644 index 0000000000..21f05e3d06 --- /dev/null +++ b/source/lib/sysdep/win/wmi.h @@ -0,0 +1,29 @@ +/** + * ========================================================================= + * File : wmi.h + * Project : 0 A.D. + * Description : wrapper for Windows Management Instrumentation + * ========================================================================= + */ + +// license: GPL; see lib/license.txt + +#ifndef INCLUDED_WMI +#define INCLUDED_WMI + +// note: we expose the VARIANT value as returned by WMI. this allows other +// modules to use the values they want directly, rather than forcing +// everything to be converted to/parsed from strings. it does drag in +// OLE headers, but this module is entirely Windows-specific anyway. +#define _WIN32_DCOM +#include "win.h" +#include // VARIANT +typedef std::map WmiMap; + +/** + * return a map of name/value pairs of the WMI class members. + * @return LibError + **/ +extern LibError wmi_GetClass(const char* className, WmiMap& wmiMap); + +#endif // #ifndef INCLUDED_WMI diff --git a/source/lib/sysdep/win/wposix/wutsname.cpp b/source/lib/sysdep/win/wposix/wutsname.cpp index 18a1422dab..6f8bc00876 100644 --- a/source/lib/sysdep/win/wposix/wutsname.cpp +++ b/source/lib/sysdep/win/wposix/wutsname.cpp @@ -1,8 +1,11 @@ #include "precompiled.h" #include "wutsname.h" +#include "../wutil.h" + #include "wposix_internal.h" + int uname(struct utsname* un) { static OSVERSIONINFO vi; @@ -10,41 +13,16 @@ int uname(struct utsname* un) GetVersionEx(&vi); // OS implementation name - const char* family = "??"; - int ver = (vi.dwMajorVersion << 8) | vi.dwMinorVersion; - if(vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) - family = (ver == 0x045a)? "ME" : "9x"; - if(vi.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - if(ver == 0x0500) - family = "2k"; - else if(ver == 0x0501) - family = "XP"; - else - family = "NT"; - } - sprintf(un->sysname, "Win%s", family); + strcpy_s(un->sysname, ARRAY_SIZE(un->sysname), wutil_WindowsFamily()); // release info const char* vs = vi.szCSDVersion; int sp; if(sscanf(vs, "Service Pack %d", &sp) == 1) sprintf(un->release, "SP %d", sp); - else - { - const char* release = ""; - if(vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) - { - if(!strcmp(vs, " C")) - release = "OSR2"; - else if(!strcmp(vs, " A")) - release = "SE"; - } - strcpy(un->release, release); // safe - } // version - sprintf(un->version, "%lu.%02lu.%lu", vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber & 0xFFFF); + sprintf(un->version, "%s.%lu", wutil_WindowsVersionString(), vi.dwBuildNumber & 0xFFFF); // node name DWORD buf_size = sizeof(un->nodename); @@ -60,9 +38,9 @@ int uname(struct utsname* un) static SYSTEM_INFO si; GetSystemInfo(&si); if(si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) - strcpy(un->machine, "AMD64"); // safe + strcpy_s(un->machine, ARRAY_SIZE(un->machine), "AMD64"); else - strcpy(un->machine, "IA-32"); // safe + strcpy_s(un->machine, ARRAY_SIZE(un->machine), "IA-32"); return 0; } diff --git a/source/lib/sysdep/win/wsnd.cpp b/source/lib/sysdep/win/wsnd.cpp index 6a58c7f166..2cacba01fc 100644 --- a/source/lib/sysdep/win/wsnd.cpp +++ b/source/lib/sysdep/win/wsnd.cpp @@ -21,6 +21,7 @@ #include "wdll_ver.h" #include "win.h" #include "wutil.h" +#include "wmi.h" // indicate if this directory entry is an OpenAL DLL. @@ -93,7 +94,7 @@ static LibError add_oal_dlls_in_dir(const char* dir, StringSet* dlls) // retrieved as well. the only way I know of is to enumerate all DS devices. // // unfortunately this fails with Vista's DS emulation - it returns some -// GUID crap as the module name. to avoid crashing when attempting to get +// GUID crap as the module name. to avoidc crashing when attempting to get // the version info for that bogus driver path, we'll skip this code there. // (delay-loading dsound.dll eliminates any overhead) @@ -138,6 +139,10 @@ static const char* GetDirectSoundDriverPath() LibError win_get_snd_info() { + WmiMap wmiMap; + if(wmi_GetClass("Win32_SoundDevice", wmiMap) == INFO::OK) + sprintf_s(snd_card, SND_CARD_LEN, "%ls", wmiMap[L"ProductName"].bstrVal); + // find all DLLs related to OpenAL, retrieve their versions, // and store in snd_drv_ver string. wdll_ver_list_init(snd_drv_ver, SND_DRV_VER_LEN); diff --git a/source/lib/sysdep/win/wutil.cpp b/source/lib/sysdep/win/wutil.cpp index 88923b67fe..4f8f073cf3 100644 --- a/source/lib/sysdep/win/wutil.cpp +++ b/source/lib/sysdep/win/wutil.cpp @@ -22,6 +22,7 @@ WINIT_REGISTER_EARLY_INIT(wutil_Init); WINIT_REGISTER_LATE_SHUTDOWN(wutil_Shutdown); + //----------------------------------------------------------------------------- // safe allocator @@ -253,6 +254,26 @@ static void DetectWindowsVersion() debug_assert(0); } + +const char* wutil_WindowsFamily() +{ + debug_assert(windowsVersion != 0); + switch(windowsVersion) + { + case WUTIL_VERSION_2K: + return "Win2k"; + case WUTIL_VERSION_XP: + return "WinXP"; + case WUTIL_VERSION_XP64: + return "WinXP64"; + case WUTIL_VERSION_VISTA: + return "Vista"; + default: + return "Windows"; + } +} + + const char* wutil_WindowsVersionString() { debug_assert(windowsVersionString[0] != '\0'); diff --git a/source/lib/sysdep/win/wutil.h b/source/lib/sysdep/win/wutil.h index 33e53571b1..8d6b2388d8 100644 --- a/source/lib/sysdep/win/wutil.h +++ b/source/lib/sysdep/win/wutil.h @@ -101,9 +101,16 @@ extern char win_exe_dir[MAX_PATH+1]; extern const char* wutil_WindowsVersionString(); // (same format as WINVER) +const uint WUTIL_VERSION_2K = 0x0500; const uint WUTIL_VERSION_XP = 0x0501; +const uint WUTIL_VERSION_XP64 = 0x0502; const uint WUTIL_VERSION_VISTA = 0x0600; +/** + * @return short textual representation of the appropriate WUTIL_VERSION + **/ +extern const char* wutil_WindowsFamily(); + extern uint wutil_WindowsVersion(); diff --git a/source/ps/Util.cpp b/source/ps/Util.cpp index e30a25365f..ad83cd47e6 100644 --- a/source/ps/Util.cpp +++ b/source/ps/Util.cpp @@ -112,6 +112,7 @@ void WriteSystemInfo() fprintf(f, "Network Name : %s", hostname); { + // ignore exception here - see https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=114032 hostent* host = gethostbyname(hostname); if(!host) goto no_ip;