# vista compat (fixes wsnd issue) and improvements

lib: move IsSimilarMagnitude and downcasters here from single modules
where they're used
acpi: simplify by only using v1.0 or 2.0 tables
snd: add note on why OpenAL can't be used
mahaf: change prefix
wcpu: cache results, reinstate wcpu_ClockFrequency
win: add winreg.h for registry functions
wsnd: only do the DSound thing on non-vista (and delay-load to avoid
overhead)
wutil: add code to correctly detect windows version

This was SVN commit r5090.
This commit is contained in:
janwas 2007-05-26 15:34:10 +00:00
parent ceee6e00bd
commit 452d67f0b7
14 changed files with 240 additions and 245 deletions

View File

@ -32,10 +32,6 @@ u16 subusw(u16 x, u16 y)
}
//-----------------------------------------------------------------------------
// rand
//-----------------------------------------------------------------------------
// type conversion

View File

@ -170,7 +170,7 @@ STMT(\
**/
#define SAFE_FREE(p)\
STMT(\
free(p); /* if p == 0, free is a no-op */ \
free((void*)p); /* if p == 0, free is a no-op */ \
(p) = 0;\
)
@ -206,6 +206,14 @@ inline bool feqf(float f1, float f2, float epsilon = 0.001f)
return fabsf(f1 - f2) < epsilon;
}
inline bool IsSimilarMagnitude(double d1, double d2, const double relativeErrorTolerance = 0.05)
{
const double relativeError = fabs(d1/d2 - 1.0);
if(relativeError > relativeErrorTolerance)
return false;
return true;
}
//-----------------------------------------------------------------------------
// type conversion
@ -222,6 +230,32 @@ extern u16 u32_lo(u32 x); /// return lower 16-bits
extern u64 u64_from_u32(u32 hi, u32 lo); /// assemble u64 from u32
extern u32 u32_from_u16(u16 hi, u16 lo); /// assemble u32 from u16
// safe downcasters: cast from any integral type to u32 or u16;
// issues warning if larger than would fit in the target type.
//
// these are generally useful but included here (instead of e.g. lib.h) for
// several reasons:
// - including implementation in lib.h doesn't work because the definition
// of debug_assert in turn requires lib.h's STMT.
// - separate compilation of templates via export isn't supported by
// most compilers.
template<typename T> u32 u32_from_larger(T x)
{
const u32 max = std::numeric_limits<u32>::max();
if((u64)x > (u64)max)
throw std::out_of_range("u32_from_larger");
return (u32)(x & max);
}
template<typename T> u16 u16_from_larger(T x)
{
const u16 max = std::numeric_limits<u16>::max();
if((u64)x > (u64)max)
throw std::out_of_range("u16_from_larger");
return (u16)(x & max);
}
/// convert double to u8; verifies number is in range.
extern u8 u8_from_double(double in);
/// convert double to u16; verifies number is in range.

View File

@ -22,31 +22,6 @@
#include "file_internal.h"
// safe downcasters: cast from any integral type to u32 or u16;
// issues warning if larger than would fit in the target type.
//
// these are generally useful but included here (instead of e.g. lib.h) for
// several reasons:
// - including implementation in lib.h doesn't work because the definition
// of debug_assert in turn requires lib.h's STMT.
// - separate compilation of templates via export isn't supported by
// most compilers.
template<typename T> u32 u32_from_larger(T x)
{
const u32 max = std::numeric_limits<u32>::max();
debug_assert((u64)x <= (u64)max);
return (u32)(x & max);
}
template<typename T> u16 u16_from_larger(T x)
{
const u16 max = std::numeric_limits<u16>::max();
debug_assert((u64)x <= (u64)max);
return (u16)(x & max);
}
//-----------------------------------------------------------------------------
// timestamp conversion: DOS FAT <-> Unix time_t
//-----------------------------------------------------------------------------

View File

@ -29,7 +29,7 @@ static const AcpiTable* AllocateCopyOfTable(u64 physicalAddress)
{
// 4 KiB ought to be enough; if not, the table will be re-mapped.
const size_t initialSize = 4*KiB;
const AcpiTable* mappedTable = (const AcpiTable*)MapPhysicalMemory(physicalAddress, initialSize);
const AcpiTable* mappedTable = (const AcpiTable*)mahaf_MapPhysicalMemory(physicalAddress, initialSize);
if(!mappedTable)
return 0;
const size_t size = mappedTable->size;
@ -37,8 +37,8 @@ static const AcpiTable* AllocateCopyOfTable(u64 physicalAddress)
if(size > initialSize)
{
// re-map with correct size
UnmapPhysicalMemory((void*)mappedTable);
mappedTable = (const AcpiTable*)MapPhysicalMemory(physicalAddress, size);
mahaf_UnmapPhysicalMemory((void*)mappedTable);
mappedTable = (const AcpiTable*)mahaf_MapPhysicalMemory(physicalAddress, size);
if(!mappedTable)
return 0;
}
@ -47,7 +47,7 @@ static const AcpiTable* AllocateCopyOfTable(u64 physicalAddress)
if(table)
cpu_memcpy(table, mappedTable, size);
UnmapPhysicalMemory((void*)mappedTable);
mahaf_UnmapPhysicalMemory((void*)mappedTable);
return table;
}
@ -86,14 +86,10 @@ static bool VerifyTable(const AcpiTable* table, const char* signature = 0)
//-----------------------------------------------------------------------------
// get pointer to (eXtended) Root System Descriptor Table
// Root System Descriptor Pointer
//-----------------------------------------------------------------------------
// Root System Descriptor Pointer
static const size_t RSDP_ALIGNMENT = 16;
struct RSDPv1
struct RSDP
{
char signature[8]; // "RSD PTR "
u8 checksum; // sum of this struct = 0
@ -102,20 +98,7 @@ struct RSDPv1
u32 rsdtPhysicalAddress;
};
struct RSDPv2Additions
{
u32 size; // of entire table (including V1)
u64 xsdtPhysicalAddress64;
u8 extendedChecksum; // sum of entire table (including V1) = 0
char reserved[3]; // must be 0
};
struct RSDP
{
RSDPv1 v1;
RSDPv2Additions v2;
};
static const size_t RSDP_ALIGNMENT = 16;
static const RSDP* LocateRsdp(const u8* buf, size_t numBytes)
{
@ -124,10 +107,10 @@ static const RSDP* LocateRsdp(const u8* buf, size_t numBytes)
{
const RSDP* rsdp = (const RSDP*)p;
if(memcmp(rsdp->v1.signature, "RSD PTR ", 8) != 0)
if(memcmp(rsdp->signature, "RSD PTR ", 8) != 0)
continue;
if(ComputeChecksum(p, 20) != 0)
if(ComputeChecksum(p, sizeof(RSDP)) != 0)
continue;
return rsdp;
@ -139,13 +122,13 @@ static const RSDP* LocateRsdp(const u8* buf, size_t numBytes)
static bool LocateAndRetrieveRsdp(uintptr_t physicalAddress, size_t numBytes, RSDP& rsdp)
{
void* virtualAddress = MapPhysicalMemory(physicalAddress, numBytes);
void* virtualAddress = mahaf_MapPhysicalMemory(physicalAddress, numBytes);
const RSDP* prsdp = LocateRsdp((const u8*)virtualAddress, numBytes);
if(prsdp)
rsdp = *prsdp; // stash in output parameter before unmapping
UnmapPhysicalMemory(virtualAddress);
mahaf_UnmapPhysicalMemory(virtualAddress);
return (prsdp != 0);
}
@ -159,7 +142,7 @@ static uintptr_t LocateEbdaPhysicalAddress()
u16 ebdaSegment;
// ...
};
const BiosDataArea* bda = (const BiosDataArea*)MapPhysicalMemory(0x400, 0x100);
const BiosDataArea* bda = (const BiosDataArea*)mahaf_MapPhysicalMemory(0x400, 0x100);
if(!bda)
return 0;
const uintptr_t ebdaPhysicalAddress = ((uintptr_t)bda->ebdaSegment) * 16;
@ -183,22 +166,7 @@ static bool RetrieveRsdp(RSDP& rsdp)
}
static bool VerifyRsdp(const RSDP& rsdp)
{
if(ComputeChecksum(&rsdp.v1, sizeof(rsdp.v1)) != 0)
return false;
if(rsdp.v1.revision >= 2)
{
if(ComputeChecksum(&rsdp, rsdp.v2.size) != 0)
return false;
if(rsdp.v2.size < sizeof(RSDP))
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Root System Descriptor Table
struct RSDT
@ -207,107 +175,63 @@ struct RSDT
u32 tables[1];
};
// eXtended root System Descriptor Table (same thing, just 64-bit pointers)
struct XSDT
{
AcpiTable header;
u64 tables[1];
};
// caller is responsible for verifying the table is valid and must
// free() the returned pointer.
static const XSDT* AllocateCopyOfXsdt()
{
RSDP rsdp;
if(!RetrieveRsdp(rsdp))
return 0;
if(!VerifyRsdp(rsdp))
return 0;
// callers should only have to deal with XSDTs, not the obsolete RSDTs.
// ACPI 2.0+, already have XSDT (note: caller must verify+free it)
if(rsdp.v1.revision >= 2)
return (const XSDT*)AllocateCopyOfTable(rsdp.v2.xsdtPhysicalAddress64);
// ACPI 1.0 - convert RSDT to XSDT (32->64 bit pointers)
const RSDT* rsdt = (const RSDT*)AllocateCopyOfTable(rsdp.v1.rsdtPhysicalAddress);
if(!rsdt)
return 0;
if(!VerifyTable((const AcpiTable*)rsdt, "RSDT"))
{
free((void*)rsdt);
return 0;
}
const size_t numTables = (rsdt->header.size - sizeof(AcpiTable)) / sizeof(u32);
const size_t xsdtSize = sizeof(AcpiTable) + numTables * sizeof(u64);
XSDT* xsdt = (XSDT*)malloc(xsdtSize);
if(xsdt)
{
xsdt->header = rsdt->header;
cpu_memcpy(xsdt->header.signature, "XSDT", 4);
xsdt->header.size = (u32)xsdtSize;
for(size_t i = 0; i < numTables; i++)
xsdt->tables[i] = (u64)rsdt->tables[i];
xsdt->header.checksum = -ComputeChecksum(xsdt, xsdtSize);
}
free((void*)rsdt);
return xsdt;
}
//-----------------------------------------------------------------------------
typedef std::map<u32, const AcpiTable*> Tables;
static Tables tables;
// avoid std::map et al. because we are called before _cinit
static const AcpiTable** tables;
static size_t numTables;
static bool LatchAllTables()
{
const XSDT* xsdt = AllocateCopyOfXsdt();
if(!xsdt)
RSDP rsdp;
if(!RetrieveRsdp(rsdp))
return false;
if(!VerifyTable((const AcpiTable*)xsdt, "XSDT"))
const RSDT* rsdt = (const RSDT*)AllocateCopyOfTable(rsdp.rsdtPhysicalAddress);
if(!rsdt)
return false;
if(!VerifyTable((const AcpiTable*)rsdt, "RSDT"))
{
free((void*)xsdt);
free((void*)rsdt);
return false;
}
const size_t numTables = (xsdt->header.size - sizeof(AcpiTable)) / sizeof(u64);
numTables = (rsdt->header.size - sizeof(AcpiTable)) / sizeof(rsdt->tables[0]);
tables = new const AcpiTable*[numTables];
for(size_t i = 0; i < numTables; i++)
{
const AcpiTable* table = AllocateCopyOfTable(xsdt->tables[i]);
const AcpiTable* table = AllocateCopyOfTable(rsdt->tables[i]);
if(!table)
continue;
if(!VerifyTable(table))
debug_warn("invalid ACPI table");
const u32 signature32 = *(u32*)table->signature;
tables[signature32] = table;
// table is now owned by tables and released via FreeAllTables.
tables[i] = table; // transfers ownership
}
free((void*)xsdt);
free((void*)rsdt);
return true;
}
static void FreeAllTables()
{
for(Tables::iterator it(tables.begin()); it != tables.end(); ++it)
for(size_t i = 0; i < numTables; i++)
{
std::pair<u32, const AcpiTable*> item = *it;
free((void*)item.second);
SAFE_FREE(tables[i]);
}
delete[] tables;
}
const AcpiTable* acpiGetTable(const char* signature)
const AcpiTable* acpi_GetTable(const char* signature)
{
const u32 signature32 = *(u32*)signature;
const AcpiTable* table = tables[signature32];
return table;
// (typically only a few tables, linear search is OK)
for(size_t i = 0; i < numTables; i++)
{
const AcpiTable* table = tables[i];
if(strncmp(table->signature, signature, 4) == 0)
return table;
}
return 0;
}
@ -315,24 +239,24 @@ const AcpiTable* acpiGetTable(const char* signature)
static ModuleInitState initState;
bool acpiInit()
bool acpi_Init()
{
if(!ModuleShouldInitialize(&initState))
return true;
if(!MahafInit())
if(!mahaf_Init())
return false;
LatchAllTables();
return true;
}
void acpiShutdown()
void acpi_Shutdown()
{
if(!ModuleShouldShutdown(&initState))
return;
FreeAllTables();
MahafShutdown();
mahaf_Shutdown();
}

View File

@ -48,9 +48,9 @@ struct AcpiGenericAddress
#pragma pack(pop)
extern bool acpiInit();
extern void acpiShutdown();
extern bool acpi_Init();
extern void acpi_Shutdown();
extern const AcpiTable* acpiGetTable(const char* signature);
extern const AcpiTable* acpi_GetTable(const char* signature);
#endif // #ifndef INCLUDED_ACPI

View File

@ -17,12 +17,14 @@ char snd_drv_ver[SND_DRV_VER_LEN];
void snd_detect()
{
// note: OpenAL alGetString is worthless: it only returns
// OpenAL API version and renderer (e.g. "Software").
#if OS_WIN
extern LibError win_get_snd_info();
win_get_snd_info();
#else
// At least reset the values for unhandled platforms. Should perhaps do
// something like storing the OpenAL version or similar.
// At least reset the values for unhandled platforms.
debug_assert(SND_CARD_LEN >= 8 && SND_DRV_VER_LEN >= 8); // protect strcpy
SAFE_STRCPY(snd_card, "Unknown");
SAFE_STRCPY(snd_drv_ver, "Unknown");

View File

@ -45,21 +45,21 @@ static u32 ReadPort(u16 port, u8 numBytes)
return value;
}
u8 ReadPort8(u16 port)
u8 mahaf_ReadPort8(u16 port)
{
const u32 value = ReadPort(port, 1);
debug_assert(value <= 0xFF);
return (u8)(value & 0xFF);
}
u16 ReadPort16(u16 port)
u16 mahaf_ReadPort16(u16 port)
{
const u32 value = ReadPort(port, 2);
debug_assert(value <= 0xFFFF);
return (u16)(value & 0xFFFF);
}
u32 ReadPort32(u16 port)
u32 mahaf_ReadPort32(u16 port)
{
const u32 value = ReadPort(port, 4);
return value;
@ -80,23 +80,23 @@ static void WritePort(u16 port, u32 value, u8 numBytes)
WARN_WIN32_ERR;
}
void WritePort8(u16 port, u8 value)
void mahaf_WritePort8(u16 port, u8 value)
{
WritePort(port, (u32)value, 1);
}
void WritePort16(u16 port, u16 value)
void mahaf_WritePort16(u16 port, u16 value)
{
WritePort(port, (u32)value, 2);
}
void WritePort32(u16 port, u32 value)
void mahaf_WritePort32(u16 port, u32 value)
{
WritePort(port, value, 4);
}
void* MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes)
void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes)
{
AkenMapIn in;
in.physicalAddress = (DWORD64)physicalAddress;
@ -118,7 +118,7 @@ void* MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes)
}
void UnmapPhysicalMemory(void* virtualAddress)
void mahaf_UnmapPhysicalMemory(void* virtualAddress)
{
AkenUnmapIn in;
in.virtualAddress = (DWORD64)virtualAddress;
@ -237,7 +237,7 @@ create:
static ModuleInitState initState;
bool MahafInit()
bool mahaf_Init()
{
if(!ModuleShouldInitialize(&initState))
return true;
@ -257,7 +257,7 @@ bool MahafInit()
}
void MahafShutdown()
void mahaf_Shutdown()
{
if(!ModuleShouldShutdown(&initState))
return;

View File

@ -14,17 +14,17 @@
#ifndef INCLUDED_MAHAF
#define INCLUDED_MAHAF
extern bool MahafInit();
extern void MahafShutdown();
extern bool mahaf_Init();
extern void mahaf_Shutdown();
extern u8 ReadPort8 (u16 port);
extern u16 ReadPort16(u16 port);
extern u32 ReadPort32(u16 port);
extern void WritePort8 (u16 port, u8 value);
extern void WritePort16(u16 port, u16 value);
extern void WritePort32(u16 port, u32 value);
extern u8 mahaf_ReadPort8 (u16 port);
extern u16 mahaf_ReadPort16(u16 port);
extern u32 mahaf_ReadPort32(u16 port);
extern void mahaf_WritePort8 (u16 port, u8 value);
extern void mahaf_WritePort16(u16 port, u16 value);
extern void mahaf_WritePort32(u16 port, u32 value);
extern void* MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes);
extern void UnmapPhysicalMemory(void* virtualAddress);
extern void* mahaf_MapPhysicalMemory(uintptr_t physicalAddress, size_t numBytes);
extern void mahaf_UnmapPhysicalMemory(void* virtualAddress);
#endif // INCLUDED_MAHAF

View File

@ -20,21 +20,60 @@
// WinAPI only supports max. 32 CPUs anyway (due to DWORD bitfields).
static const uint MAX_CPUS = 32;
// note: the below routines should cache their results to simplify things
// for callers. however, we don't want to set the variables during init
// because that would create init order dependencies (if other modules
// use this from e.g. their PreLibcInit). hence, each routine must check
// if they've been called for the first time.
/// get number of CPUs (can't fail)
uint wcpu_NumProcessors()
{
static uint numProcessors = 0;
if(numProcessors)
return numProcessors;
SYSTEM_INFO si;
GetSystemInfo(&si);
const uint num_processors = (uint)si.dwNumberOfProcessors;
return num_processors;
numProcessors = (uint)si.dwNumberOfProcessors;
return numProcessors;
}
double wcpu_ClockFrequency()
{
static double clockFrequency = -1.0;
if(clockFrequency > 0.0)
return clockFrequency;
// read CPU frequency from registry
HKEY hKey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
DWORD freqMhz;
DWORD size = sizeof(freqMhz);
if(RegQueryValueEx(hKey, "~MHz", 0, 0, (LPBYTE)&freqMhz, &size) == STATUS_SUCCESS)
clockFrequency = freqMhz * 1e6;
else
debug_assert(0);
RegCloseKey(hKey);
}
else
debug_assert(0);
return clockFrequency;
}
int wcpu_IsThrottlingPossible()
{
static int isThrottlingPossible = -1;
if(isThrottlingPossible != -1)
return isThrottlingPossible;
WIN_SAVE_LAST_ERROR;
int is_throttling_possible = -1;
// CallNtPowerInformation
// (manual import because it's not supported on Win95)
@ -50,7 +89,7 @@ int wcpu_IsThrottlingPossible()
if(pCNPI(SystemPowerCapabilities, 0,0, &spc,sizeof(spc)) == STATUS_SUCCESS)
{
if(!spc.ProcessorThrottle || !spc.ThermalControl)
is_throttling_possible = 0;
isThrottlingPossible = 0;
}
// probably speedstep if cooling mode active.
@ -59,7 +98,7 @@ int wcpu_IsThrottlingPossible()
if(pCNPI(SystemPowerInformation, 0,0, &spi,sizeof(spi)) == STATUS_SUCCESS)
{
if(spi.CoolingMode != PO_TZ_INVALID_MODE)
is_throttling_possible = 1;
isThrottlingPossible = 1;
}
// definitely speedstep if any throttle is less than 100%.
@ -71,7 +110,7 @@ int wcpu_IsThrottlingPossible()
{
if(p->MhzLimit != p->MaxMhz || p->CurrentMhz != p->MaxMhz)
{
is_throttling_possible = 1;
isThrottlingPossible = 1;
break;
}
}
@ -81,7 +120,7 @@ int wcpu_IsThrottlingPossible()
// CallNtPowerInformation not available, or none of the above apply:
// don't know yet (for certain, at least).
if(is_throttling_possible == -1)
if(isThrottlingPossible == -1)
{
// check if running on a laptop
HW_PROFILE_INFO hi;
@ -93,13 +132,13 @@ int wcpu_IsThrottlingPossible()
// we'll guess SpeedStep is active if on a laptop.
// ia32 code will get a second crack at it.
is_throttling_possible = (is_laptop)? 1 : 0;
isThrottlingPossible = (is_laptop)? 1 : 0;
}
WIN_RESTORE_LAST_ERROR;
debug_assert(is_throttling_possible == 0 || is_throttling_possible == 1);
return is_throttling_possible;
debug_assert(isThrottlingPossible == 0 || isThrottlingPossible == 1);
return isThrottlingPossible;
}
@ -155,6 +194,7 @@ LibError wcpu_CallByEachCPU(CpuCallback cb, void* param)
//
//////////////////////////////////////////////////////////////////////////////
#if 0
// we need a means of measuring performance, since it is hard to predict and
// depends on many factors. to cover a wider range of configurations, this
@ -371,3 +411,4 @@ probably hard; a start would be just the function in which the address is, then
*/
#endif

View File

@ -14,8 +14,8 @@
#include "lib/sysdep/cpu.h"
extern uint wcpu_NumProcessors();
extern int wcpu_IsThrottlingPossible();
extern double wcpu_ClockFrequency();
extern int wcpu_IsThrottlingPossible();
extern LibError wcpu_CallByEachCPU(CpuCallback cb, void* param);
#endif // #ifndef INCLUDED_WCPU

View File

@ -70,9 +70,10 @@
#define NOPROFILER // Profiler interface.
#define NODEFERWINDOWPOS // DeferWindowPos routines
#define NOMCX // Modem Configuration Extensions
#include <windows.h>
#include <winreg.h>
//-----------------------------------------------------------------------------
// fixes for VC6 platform SDK

View File

@ -23,41 +23,6 @@
#include "wutil.h"
// DirectSound header
// HACK: workaround for "subwtype.h not found" errors on VC6/7 hybrid.
// (subwtype.h <- d3dtypes.h <- dsound.h)
// since we're only using one DS function (DirectSoundEnumerate),
// we forward-declare it rather than fix/mess with the system headers.
#if 0
// mmsystem.h is necessary for dsound.h; we cut out unnecessary junk
# define MMNODRV // Installable driver support
# define MMNOSOUND // Sound support
//# define MMNOWAVE // Waveform support
# define MMNOMIDI // MIDI support
# define MMNOAUX // Auxiliary audio support
# define MMNOMIXER // Mixer support
# define MMNOTIMER // Timer support
# define MMNOJOY // Joystick support
# define MMNOMCI // MCI support
# define MMNOMMIO // Multimedia file I/O support
# define MMNOMMSYSTEM // General MMSYSTEM functions
# include <MMSystem.h>
# define DIRECTSOUND_VERSION 0x0500
# include <dsound.h>
#else
# define DS_OK 0
typedef BOOL (CALLBACK* LPDSENUMCALLBACKA)(void*, const char*, const char*, void*);
EXTERN_C __declspec(dllimport) HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA, void*);
#endif
#if MSC_VERSION
#pragma comment(lib, "dsound.lib")
#endif
// note: OpenAL alGetString is worthless: it only returns OpenAL API version
// and renderer (e.g. "Software").
// indicate if this directory entry is an OpenAL DLL.
// (matches "*oal.dll" and "*OpenAL*", as with OpenAL router's search)
static LibError IsOpenAlDll(const DirEnt* ent)
@ -120,50 +85,64 @@ static LibError add_oal_dlls_in_dir(const char* dir, StringSet* dlls)
}
// DS3D driver path; filled by ds_enum, used by win_get_snd_info.
// side effect: remains zeroed if there's no sound card installed.
static char ds_drv_path[MAX_PATH+1];
//-----------------------------------------------------------------------------
// DirectSound driver version
// we've seen audio problems caused by buggy DirectSound drivers (because
// OpenAL can use them in its implementation), so their version should be
// 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
// the version info for that bogus driver path, we'll skip this code there.
// (delay-loading dsound.dll eliminates any overhead)
static char directSoundDriverPath[MAX_PATH+1];
// store sound card name and path to DirectSound driver.
// called for each DirectSound driver, but aborts after first valid driver.
static BOOL CALLBACK ds_enum(void* guid, const char* description,
static BOOL CALLBACK DirectSoundCallback(void* guid, const char* UNUSED(description),
const char* module, void* UNUSED(ctx))
{
// skip first dummy entry (description == "Primary Sound Driver")
if(guid == NULL)
return TRUE; // continue calling
strcpy_s(snd_card, SND_CARD_LEN, description);
// note: $system\\drivers is not in LoadLibrary's search list,
// so we have to give the full pathname.
snprintf(ds_drv_path, ARRAY_SIZE(ds_drv_path), "%s\\drivers\\%s", win_sys_dir, module);
snprintf(directSoundDriverPath, ARRAY_SIZE(directSoundDriverPath), "%s\\drivers\\%s", win_sys_dir, module);
// we assume the first "driver name" (sound card) is the one we want;
// stick with that and stop calling.
return FALSE;
}
static const char* GetDirectSoundDriverPath()
{
#define DS_OK 0
typedef BOOL (CALLBACK* LPDSENUMCALLBACKA)(void*, const char*, const char*, void*);
HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA, void*);
HMODULE hDsoundDll = LoadLibrary("dsound.dll");
*(void**)&pDirectSoundEnumerateA = GetProcAddress(hDsoundDll, "DirectSoundEnumerateA");
if(pDirectSoundEnumerateA)
{
if(DirectSoundEnumerateA(DirectSoundCallback, (void*)0) != DS_OK)
debug_warn("DirectSoundEnumerate failed");
}
FreeLibrary(hDsoundDll);
return directSoundDriverPath;
}
//-----------------------------------------------------------------------------
LibError win_get_snd_info()
{
// get sound card name and DS driver path.
if(DirectSoundEnumerateA((LPDSENUMCALLBACKA)ds_enum, (void*)0) != DS_OK)
debug_warn("DirectSoundEnumerate failed");
// there are apparently no sound card/drivers installed; so indicate.
// (the code below would fail and not produce reasonable output)
if(ds_drv_path[0] == '\0')
{
strcpy_s(snd_card, SND_CARD_LEN, "(none)");
strcpy_s(snd_drv_ver, SND_DRV_VER_LEN, "(none)");
return INFO::OK;
}
// find all DLLs related to OpenAL, retrieve their versions,
// and store in snd_drv_ver string.
dll_list_init(snd_drv_ver, SND_DRV_VER_LEN);
(void)dll_list_add(ds_drv_path);
if(!wutil_IsVista())
(void)dll_list_add(GetDirectSoundDriverPath());
StringSet dlls; // ensures uniqueness
(void)add_oal_dlls_in_dir(win_exe_dir, &dlls);
(void)add_oal_dlls_in_dir(win_sys_dir, &dlls);

View File

@ -226,6 +226,39 @@ static void EnableLowFragmentationHeap()
}
//-----------------------------------------------------------------------------
// version
static char versionString[20];
static void DetectWindowsVersion()
{
// note: don't use GetVersion[Ex] because it gives the version of the
// emulated OS when running an app with compatibility shims enabled.
HKEY hKey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
{
DWORD size = ARRAY_SIZE(versionString);
(void)RegQueryValueEx(hKey, "CurrentVersion", 0, 0, (LPBYTE)versionString, &size);
RegCloseKey(hKey);
}
else
debug_assert(0);
}
const char* wutil_WindowsVersionString()
{
debug_assert(versionString[0] != '\0');
return versionString;
}
bool wutil_IsVista()
{
debug_assert(versionString[0] != '\0');
return (versionString[0] >= '6');
}
//-----------------------------------------------------------------------------
// Wow64
@ -304,6 +337,8 @@ static LibError wutil_PreLibcInit()
GetDirectories();
DetectWindowsVersion();
ImportWow64Functions();
DetectWow64();

View File

@ -94,6 +94,14 @@ extern char win_sys_dir[MAX_PATH+1];
extern char win_exe_dir[MAX_PATH+1];
//
// version
//
extern const char* wutil_WindowsVersionString();
extern bool wutil_IsVista();
//
// Wow64
//