# system detect fixes
simplify detect code by adding support for WMI (the "proper" way to do things) wutsname: fix incorrect reporting of windows version ps/Util: add note on exception that is raised on Wow64 (Windows bug) This was SVN commit r5213.
This commit is contained in:
parent
153c9edfe9
commit
805736cb8f
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
111
source/lib/sysdep/win/wmi.cpp
Normal file
111
source/lib/sysdep/win/wmi.cpp
Normal file
@ -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 <wbemidl.h>
|
||||
|
||||
#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;
|
||||
}
|
29
source/lib/sysdep/win/wmi.h
Normal file
29
source/lib/sysdep/win/wmi.h
Normal file
@ -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 <comdef.h> // VARIANT
|
||||
typedef std::map<std::wstring, VARIANT> 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
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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');
|
||||
|
@ -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();
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user