# 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:
janwas 2007-06-24 13:24:40 +00:00
parent 153c9edfe9
commit 805736cb8f
8 changed files with 187 additions and 79 deletions

View File

@ -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;
}

View 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;
}

View 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

View File

@ -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;
}

View File

@ -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);

View File

@ -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');

View File

@ -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();

View File

@ -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;