Windows2003-3790/multimedia/directx/dinput/dx7/dll/diutil.c
2020-09-30 16:53:55 +02:00

1043 lines
28 KiB
C

/*****************************************************************************
*
* DIUtil.c
*
* Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
*
* Abstract:
*
* Misc helper functions.
*
* Contents:
*
*
*
*****************************************************************************/
#include "dinputpr.h"
/*****************************************************************************
*
* The sqiffle for this file.
*
*****************************************************************************/
#define sqfl sqflUtil
#ifdef IDirectInputDevice2Vtbl
/*****************************************************************************
*
* @doc INTERNAL
*
* @func LPCTSTR | _ParseHex |
*
* Parse a hex string encoding cb bytes (at most 4), then expect
* the tchDelim to appear afterwards. If tchDelim is 0, then no
* delimiter is expected.
*
* Store the result into the indicated LPBYTE (using only the
* size requested), updating it, and return a pointer to the
* next unparsed character, or 0 on error.
*
* If the incoming pointer is also 0, then return 0 immediately.
*
* @parm IN LPCTSTR | ptsz |
*
* The string to parse.
*
* @parm IN OUT LPBYTE * | ppb |
*
* Pointer to the address of the destination buffer.
*
* @parm IN int | cb |
*
* The size in bytes of the buffer.
*
* @parm IN TCHAR | tchDelim |
*
* The delimiter charater to end the sequence or zero if none is
* expected.
*
* @returns
*
* Returns a pointer to the next unparsed character, or 0 on error.
*
* @comm
* Stolen from TweakUI.
*
* Prefix takes a strong dislike to this function, reporting that
* all callers could use uninitialized memory when the function
* succeeds.
* The problem appears to be that Prefix is unable to determine that
* if the source string can successfully be read, the destination is
* always completely filled (the whole passed destination size) with
* the binary value of the source string. Since all callers always
* pass the size of the variable to which the destination buffer
* pointer points, the memory is always completely initialized but
* it seems reasonable that Prefix would raise a warning.
*
*****************************************************************************/
LPCTSTR INTERNAL
_ParseHex(LPCTSTR ptsz, LPBYTE *ppb, int cb, TCHAR tchDelim)
{
if(ptsz)
{
int i = cb * 2;
DWORD dwParse = 0;
do
{
DWORD uch;
uch = (TBYTE)*ptsz - TEXT('0');
if(uch < 10)
{ /* a decimal digit */
} else
{
uch = (*ptsz | 0x20) - TEXT('a');
if(uch < 6)
{ /* a hex digit */
uch += 10;
} else
{
return 0; /* Parse error */
}
}
dwParse = (dwParse << 4) + uch;
ptsz++;
} while(--i);
if(tchDelim && *ptsz++ != tchDelim) return 0; /* Parse error */
for(i = 0; i < cb; i++)
{
(*ppb)[i] = ((LPBYTE)&dwParse)[i];
}
*ppb += cb;
}
return ptsz;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func BOOL | ParseGUID |
*
* Take a string and convert it into a GUID, return success/failure.
*
* @parm OUT LPGUID | lpGUID |
*
* Receives the parsed GUID on success.
*
* @parm IN LPCTSTR | ptsz |
*
* The string to parse. The format is
*
* { <lt>dword<gt> - <lt>word<gt> - <lt>word<gt>
* - <lt>byte<gt> <lt>byte<gt>
* - <lt>byte<gt> <lt>byte<gt> <lt>byte<gt>
* <lt>byte<gt> <lt>byte<gt> <lt>byte<gt> }
*
* @returns
*
* Returns zero if <p ptszGUID> is not a valid GUID.
*
*
* @comm
*
* Stolen from TweakUI.
*
*****************************************************************************/
BOOL EXTERNAL
ParseGUID(LPGUID pguid, LPCTSTR ptsz)
{
if(lstrlen(ptsz) == ctchGuid - 1 && *ptsz == TEXT('{'))
{
ptsz++;
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 4, TEXT('-'));
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 2, TEXT('-'));
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('-'));
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, 0 );
ptsz = _ParseHex(ptsz, (LPBYTE *)&pguid, 1, TEXT('}'));
return (BOOL)(UINT_PTR)ptsz;
} else
{
return 0;
}
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func BOOL | ParseVIDPID |
*
* Take a string formatted as VID_%04&PID_%04.
*
* @parm OUT PUSHORT | puVID |
*
* Receives the parsed VID.
*
* @parm OUT PUSHORT | puPID |
*
* Receives the parsed PID.
*
* @parm IN LPCTSTR | ptsz |
*
*
* @returns
*
* Returns zero on failure.
*
*
* @comm
*
* Stolen from TweakUI.
*
*****************************************************************************/
// VID _ XXXX & PID _ YYYY
#define ctchVIDPID ( 3 + 1 + 4 + 1 + 3 + 1 + 4 )
#define VID_ TEXT("VID_")
#define VID_offset (3+1)
#define PID_ TEXT("&PID_")
#define PID_offset (3+1+4+1+3+1)
BOOL EXTERNAL
ParseVIDPID(PUSHORT puVID, PUSHORT puPID , LPCWSTR pwsz)
{
LPCTSTR ptsz;
#ifndef UNICODE
TCHAR tsz[MAX_JOYSTRING];
UToT( tsz, cA(tsz), pwsz );
ptsz = tsz;
#else
ptsz = pwsz;
#endif
if( _ParseHex(ptsz+VID_offset, (LPBYTE *)&puVID, 2, TEXT('&')) &&
_ParseHex(ptsz+PID_offset, (LPBYTE *)&puPID, 2, 0) )
{
return TRUE;
}
return FALSE;
}
#endif
#if DIRECTINPUT_VERSION > 0x0300
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | NameFromGUID |
*
* Convert a GUID into an ASCII string that will be used
* to name it in the global namespace.
*
* We use the name "DirectInput.{guid}".
*
* Names are used in the following places:
*
* <c g_hmtxGlobal> names a mutex based on
* <c IID_IDirectInputW> to gate access to the
* shared memory block used to manage exclusive access.
*
* <c g_psop> names a shared memory block based on
* <c IID_IDirectInputDeviceW> to record information
* about exclusive access.
*
* <c g_hmtxJoy> names a mutex based on
* <c IID_IDirectInputDevice2A> to gate access to the
* shared memory block used to track joystick effects.
*
* @parm LPTSTR | ptszBuf |
*
* Output buffer to receive the converted name. It must
* be <c ctchNameGuid> characters in size.
*
* @parm PCGUID | pguid |
*
* The GUID to convert.
*
*
*****************************************************************************/
#pragma BEGIN_CONST_DATA
/* Note: If you change this string, you need to change ctchNameGuid to match */
TCHAR c_tszNameFormat[] =
TEXT("DirectInput.{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}");
#pragma END_CONST_DATA
void EXTERNAL
NameFromGUID(LPTSTR ptszBuf, PCGUID pguid)
{
int ctch;
ctch = wsprintf(ptszBuf, c_tszNameFormat,
pguid->Data1, pguid->Data2, pguid->Data3,
pguid->Data4[0], pguid->Data4[1],
pguid->Data4[2], pguid->Data4[3],
pguid->Data4[4], pguid->Data4[5],
pguid->Data4[6], pguid->Data4[7]);
AssertF(ctch == ctchNameGuid - 1);
}
#endif
/*****************************************************************************
*
* @doc INTERNAL
*
* @func PV | pvFindResource |
*
* Handy wrapper that finds and loads a resource.
*
* @parm IN HINSTANCE | hinst |
*
* Module instance handle.
*
* @parm DWORD | id |
*
* Resource identifier.
*
* @parm LPCTSTR | rt |
*
* Resource type.
*
* @returns
*
* Pointer to resource, or 0.
*
*****************************************************************************/
PV EXTERNAL
pvFindResource(HINSTANCE hinst, DWORD id, LPCTSTR rt)
{
HANDLE hrsrc;
PV pv;
hrsrc = FindResource(hinst, (LPTSTR)(LONG_PTR)id, rt);
if(hrsrc)
{
pv = LoadResource(hinst, hrsrc);
} else
{
pv = 0;
}
return pv;
}
#ifndef UNICODE
/*****************************************************************************
*
* @doc INTERNAL
*
* @func UINT | LoadStringW |
*
* Implementation of LoadStringW for platforms on which Unicode is
* not supported. Does exactly what LoadStringW would've done
* if it existed.
*
* @parm IN HINSTANCE | hinst |
*
* Module instance handle.
*
* @parm UINT | ids |
*
* String id number.
*
* @parm LPWSTR | pwsz |
*
* UNICODE output buffer.
*
* @parm UINT | cwch |
*
* Size of UNICODE output buffer.
*
* @returns
*
* Number of characters copied, not including terminating null.
*
* @comm
*
* Since the string is stored in the resource as UNICODE,
* we just pull it out ourselves. If we go through
* <f LoadStringA>, we may end up losing characters due
* to character set translation.
*
*****************************************************************************/
int EXTERNAL
LoadStringW(HINSTANCE hinst, UINT ids, LPWSTR pwsz, int cwch)
{
PWCHAR pwch;
AssertF(cwch);
ScrambleBuf(pwsz, cbCwch(cwch));
/*
* String tables are broken up into "bundles" of 16 strings each.
*/
pwch = pvFindResource(hinst, 1 + ids / 16, RT_STRING);
if(pwch)
{
/*
* Now skip over the strings in the resource until we
* hit the one we want. Each entry is a counted string,
* just like Pascal.
*/
for(ids %= 16; ids; ids--)
{
pwch += *pwch + 1;
}
cwch = min(*pwch, cwch - 1);
memcpy(pwsz, pwch+1, cbCwch(cwch)); /* Copy the goo */
} else
{
cwch = 0;
}
pwsz[cwch] = TEXT('\0'); /* Terminate the string */
return cwch;
}
#endif
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | GetNthString |
*
* Generate a generic numbered object name.
*
* @parm LPWSTR | pwsz |
*
* Output buffer of <c MAX_PATH> characters.
*
* @parm UINT | ids |
*
* String containing number template.
*
* @parm UINT | ui |
*
* Button number.
*
*****************************************************************************/
void EXTERNAL
GetNthString(LPWSTR pwsz, UINT ids, UINT ui)
{
TCHAR tsz[256];
#ifndef UNICODE
TCHAR tszOut[MAX_PATH];
#endif
LoadString(g_hinst, ids, tsz, cA(tsz));
#ifdef UNICODE
wsprintfW(pwsz, tsz, ui);
#else
wsprintf(tszOut, tsz, ui);
TToU(pwsz, MAX_PATH, tszOut);
#endif
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | hresRunControlPanel |
*
* Run the control panel with the specified applet.
*
* @parm LPCTSTR | ptszApplet |
*
* Applet name.
*
* @returns
*
* <c S_OK> if we started the applet.
*
*****************************************************************************/
#pragma BEGIN_CONST_DATA
TCHAR c_tszControlExeS[] = TEXT("control.exe %s");
#pragma END_CONST_DATA
HRESULT EXTERNAL
hresRunControlPanel(LPCTSTR ptszCpl)
{
HRESULT hres;
STARTUPINFO si;
PROCESS_INFORMATION pi;
TCHAR tsz[MAX_PATH];
EnterProc(hresRunControlPanel, (_ "s", ptszCpl));
ZeroX(si);
si.cb = cbX(si);
wsprintf(tsz, c_tszControlExeS, ptszCpl);
if(CreateProcess(0, tsz, 0, 0, 0, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
hres = S_OK;
} else
{
hres = hresLe(GetLastError());
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | DeviceInfoWToA |
*
;begin_dx3
* Convert a <t DIDEVICEINSTANCEW> to a <t DIDEVICEINSTANCEA>.
;end_dx3
;begin_dx5
* Convert a <t DIDEVICEINSTANCEW> to a <t DIDEVICEINSTANCE_DX3A>
* or a <t DIDEVICEINSTANCE_DX5A>.
;end_dx5
*
* @parm LPDIDIDEVICEINSTANCEA | pdiA |
*
* Destination.
*
* @parm LPCDIDIDEVICEINSTANCEW | pdiW |
*
* Source.
*
*****************************************************************************/
void EXTERNAL
DeviceInfoWToA(LPDIDEVICEINSTANCEA pdiA, LPCDIDEVICEINSTANCEW pdiW)
{
EnterProc(DeviceInfoWToA, (_ "pp", pdiA, pdiW));
AssertF(pdiW->dwSize == sizeof(DIDEVICEINSTANCEW));
#if DIRECTINPUT_VERSION <= 0x0400
pdiA->dwSize = sizeof(*pdiA);
#else
AssertF(IsValidSizeDIDEVICEINSTANCEA(pdiA->dwSize));
#endif
pdiA->guidInstance = pdiW->guidInstance;
pdiA->guidProduct = pdiW->guidProduct;
pdiA->dwDevType = pdiW->dwDevType;
UToA(pdiA->tszInstanceName, cA(pdiA->tszInstanceName), pdiW->tszInstanceName);
UToA(pdiA->tszProductName, cA(pdiA->tszProductName), pdiW->tszProductName);
#if DIRECTINPUT_VERSION > 0x0400
if(pdiA->dwSize >= cbX(DIDEVICEINSTANCE_DX5A))
{
pdiA->guidFFDriver = pdiW->guidFFDriver;
pdiA->wUsage = pdiW->wUsage;
pdiA->wUsagePage = pdiW->wUsagePage;
}
#endif
ExitProc();
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | ObjectInfoWToA |
*
#ifdef HAVE_DIDEVICEOBJECTINSTANCE_DX5
* Convert a <t DIDEVICEOBJECTINSTANCEW>
* to a <t DIDEVICEOBJECTINSTANCE_DX3A>
* or a <t DIDEVICEOBJECTINSTANCE_DX5A>.
#else
* Convert a <t DIDEVICEOBJECTINSTANCEW>
* to a <t DIDEVICEOBJECTINSTANCEA>.
#endif
*
* @parm LPDIDIDEVICEOBJECTINSTANCEA | pdoiA |
*
* Destination.
*
* @parm LPCDIDIDEVICEOBJECTINSTANCEW | pdoiW |
*
* Source.
*
*****************************************************************************/
void EXTERNAL
ObjectInfoWToA(LPDIDEVICEOBJECTINSTANCEA pdoiA,
LPCDIDEVICEOBJECTINSTANCEW pdoiW)
{
EnterProc(ObjectInfoWToA, (_ "pp", pdoiA, pdoiW));
AssertF(pdoiW->dwSize == sizeof(DIDEVICEOBJECTINSTANCEW));
#ifdef HAVE_DIDEVICEOBJECTINSTANCE_DX5
AssertF(IsValidSizeDIDEVICEOBJECTINSTANCEA(pdoiA->dwSize));
#else
pdoiA->dwSize = sizeof(*pdoiA);
#endif
pdoiA->guidType = pdoiW->guidType;
pdoiA->dwOfs = pdoiW->dwOfs;
pdoiA->dwType = pdoiW->dwType;
pdoiA->dwFlags = pdoiW->dwFlags;
UToA(pdoiA->tszName, cA(pdoiA->tszName), pdoiW->tszName);
#ifdef HAVE_DIDEVICEOBJECTINSTANCE_DX5
if(pdoiA->dwSize >= cbX(DIDEVICEOBJECTINSTANCE_DX5A))
{
pdoiA->dwFFMaxForce = pdoiW->dwFFMaxForce;
pdoiA->dwFFForceResolution = pdoiW->dwFFForceResolution;
pdoiA->wCollectionNumber = pdoiW->wCollectionNumber;
pdoiA->wDesignatorIndex = pdoiW->wDesignatorIndex;
pdoiA->wUsagePage = pdoiW->wUsagePage;
pdoiA->wUsage = pdoiW->wUsage;
pdoiA->dwDimension = pdoiW->dwDimension;
pdoiA->wExponent = pdoiW->wExponent;
pdoiA->wReportId = pdoiW->wReportId;
}
#endif
ExitProc();
}
#ifdef IDirectInputDevice2Vtbl
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | EffectInfoWToA |
*
* Convert a <t DIEFFECTINFOW> to a <t DIEFFECTINFOA>
*
* @parm LPDIEFFECTINFOA | pdeiA |
*
* Destination.
*
* @parm LPCDIEFFECTINFOW | pdeiW |
*
* Source.
*
*****************************************************************************/
void EXTERNAL
EffectInfoWToA(LPDIEFFECTINFOA pdeiA, LPCDIEFFECTINFOW pdeiW)
{
EnterProc(EffectInfoWToA, (_ "pp", pdeiA, pdeiW));
AssertF(pdeiW->dwSize == sizeof(DIEFFECTINFOW));
AssertF(pdeiA->dwSize == cbX(*pdeiA));
pdeiA->guid = pdeiW->guid;
pdeiA->dwEffType = pdeiW->dwEffType;
pdeiA->dwStaticParams = pdeiW->dwStaticParams;
pdeiA->dwDynamicParams = pdeiW->dwDynamicParams;
UToA(pdeiA->tszName, cA(pdeiA->tszName), pdeiW->tszName);
ExitProc();
}
#endif
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | hresValidInstanceVer |
*
* Check the <t HINSTANCE> and version number received from
* an application.
*
* @parm HINSTANCE | hinst |
*
* Purported module instance handle.
*
* @parm DWORD | dwVersion |
*
* Version the application is asking for.
*
*****************************************************************************/
HRESULT EXTERNAL
hresValidInstanceVer_(HINSTANCE hinst, DWORD dwVersion, LPCSTR s_szProc)
{
HRESULT hres;
TCHAR tszScratch[4];
EnterProcS(hresValidInstanceVer, (_ "xxs", hinst, dwVersion, s_szProc));
/*
* You would think that passing a zero-sized buffer to
* GetModuleFileName would return the necessary buffer size.
*
* You would be right. Except that the Win95 validation layer
* doesn't realize that this was a valid scenario, so the call
* fails in the validation layer and never reached Kernel.
*
* So we read it into a small scratch buffer. The scratch buffer
* must be at least 2 characters; if we passed only 1, then
* GetModuleFileName won't be able to write any characters and
* will return 0.
*
* Now it turns out that there's a bug in NT where, if you
* pass a buffer size of 4, but the actual name is longer than
* 4, it writes 4 characters, PLUS A NULL TERMINATOR, thereby
* smashing your stack and making you fault randomly.
*
* I spent two hours trying to figure that out.
*
* Therefore, you must pass one *less* than the buffer size
* to GetModuleFileName, because it will overwrite your buffer
* by one.
*/
/*
* For compatibility reasons, DirectInput 3.0 clients must be
* allowed to pass hinst == 0. (It was a loophole in the original
* DX3 implementation.)
*/
if(hinst == 0 ?
dwVersion == 0x0300 :
GetModuleFileName(hinst, tszScratch, cA(tszScratch) - 1))
{
/*
* We need to permit the following DirectX versions:
*
* 0x0300 - DX3 golden
* 0x0500 - DX5 golden
* 0x050A - DX5a Win98 golden
* 0x05B2 - NT 5 beta 2 (also the CPL and WinMM)
* 0x0602 - Win98 OSR1 internal first version
* 0x061A - DX6.1a Win98 OSR1
* 0x0700 - DX7 Win2000 golden
*/
if(dwVersion == 0x0300 ||
dwVersion == 0x0500 ||
dwVersion == 0x050A ||
dwVersion == 0x05B2 ||
dwVersion == 0x0602 ||
dwVersion == 0x061A ||
dwVersion == 0x0700
)
{
hres = S_OK;
} else if ( dwVersion == 0 ) {
RPF("%s: DinputInput object has not been initialized, or the version is given as 0.",
s_szProc);
hres = DIERR_NOTINITIALIZED;
} else if(dwVersion < DIRECTINPUT_VERSION)
{
RPF("%s: Incorrect dwVersion(0x%x); program was written with beta SDK. This version 0x%x",
s_szProc, dwVersion, DIRECTINPUT_VERSION);
hres = DIERR_BETADIRECTINPUTVERSION;
} else
{
RPF("%s: Incorrect dwVersion(0x%x); program needs newer version of dinput. This version 0x%x",
s_szProc, dwVersion, DIRECTINPUT_VERSION);
hres = DIERR_OLDDIRECTINPUTVERSION;
}
} else
{
RPF("%s: Invalid HINSTANCE", s_szProc);
hres = E_INVALIDARG;
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | DupEventHandle |
*
* Duplicate an event handle intra-process-ly. If the incoming
* handle is NULL, then so is the output handle (and the call
* succeeds).
*
* @parm HANDLE | h |
*
* Source handle.
*
* @parm LPHANDLE | phOut |
*
* Receives output handle.
*
*****************************************************************************/
HRESULT EXTERNAL
DupEventHandle(HANDLE h, LPHANDLE phOut)
{
HRESULT hres;
EnterProc(DupEventHandle, (_ "p", h));
if(h)
{
HANDLE hProcessMe = GetCurrentProcess();
if(DuplicateHandle(hProcessMe, h, hProcessMe, phOut,
EVENT_MODIFY_STATE, 0, 0))
{
hres = S_OK;
} else
{
hres = hresLe(GetLastError());
}
} else
{
*phOut = h;
hres = S_OK;
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func DWORD | GetWindowPid |
*
* Simple wrapper that returns the PID of a window.
*
* Here is also where we do goofy hacks for DOS boxes
* on Win95.
*
* @parm HWND | hwnd |
*
* Window handle.
*
* @returns
*
* PID or 0.
*
*****************************************************************************/
DWORD EXTERNAL
GetWindowPid(HWND hwnd)
{
DWORD pid;
if(IsWindow(hwnd) &&
GetWindowThreadProcessId(hwnd, &pid) )
{
if( !fWinnt )
/*
* The Winoldap console window belongs to another
* process but Win95 lies and says that it belongs
* to you but it doesn't.
*/
if ( GetProp(hwnd, TEXT("flWinOldAp")) != 0 )
pid = 0;
} else
{
pid = 0;
}
return pid;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func HRESULT | hresDupPtszPptsz |
*
* OLEish version of strdup.
*
* @parm LPCTSTR | ptszSrc |
*
* Source string being duplicated.
*
* @parm LPTSTR * | pptszDst |
*
* Receives the duplicated string.
*
* @returns
*
* <c S_OK> or an error code.
*
*****************************************************************************/
HRESULT EXTERNAL
hresDupPtszPptsz(LPCTSTR ptszSrc, LPTSTR *pptszDst)
{
HRESULT hres;
hres = AllocCbPpv(cbCtch(lstrlen(ptszSrc) + 1), pptszDst);
if(SUCCEEDED(hres))
{
lstrcpy(*pptszDst, ptszSrc);
hres = S_OK;
}
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func BOOL | fInitializeCriticalSection |
*
* Initialize the give critical section, returning 0 if an exception
* is thrown, else 0.
*
* @parm LPCRITICAL_SECTION | pCritSec |
*
* Pointer to an uninitialized critical section.
*
*****************************************************************************/
BOOL EXTERNAL
fInitializeCriticalSection(LPCRITICAL_SECTION pCritSec)
{
BOOL fres = 1;
EnterProc(fInitializeCriticalSection, (_ "" ));
AssertF( pCritSec );
__try
{
InitializeCriticalSection( pCritSec );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
fres = 0;
}
ExitProcF( fres );
return fres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | DiCharUpperW |
*
* This function converts a wide-character string or a single wide-character
* to uppercase. Since Win9x doesn't implement CharUpperW, we have to implement
* ourselves.
*
* @parm LPWSTR | pwsz |
*
* The string to be converted
*
* @returns
*
* void
*
*****************************************************************************/
void EXTERNAL
DiCharUpperW(LPWSTR pwsz)
{
int idx;
int iLen = lstrlenW(pwsz);
#define DIFF (L'a' - L'A')
for( idx=0; idx<iLen; idx++ )
{
if( (pwsz[idx] >= L'a') && (pwsz[idx] <= L'z') ){
pwsz[idx] -= DIFF;
}
}
#undef DIFF
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func DWORD | DIGetOSVersion |
*
* Return the OS version on which DInput8.dll is running.
*
* @returns
*
* WIN95_OS, WIN98_OS, WINME_OS, WINNT_OS, WINWH_OS, or WIN_UNKNOWN_OS.
*
*****************************************************************************/
DWORD DIGetOSVersion()
{
OSVERSIONINFO osVerInfo;
DWORD dwVer;
if( GetVersion() < 0x80000000 ) {
dwVer = WINNT_OS;
} else {
dwVer = WIN95_OS; //assume Windows 95 for safe
}
osVerInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
// If GetVersionEx is supported, then get more details.
if( GetVersionEx( &osVerInfo ) )
{
// Win2K
if( osVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
{
// Whistler: Major = 5 & Build # > 2195
if( osVerInfo.dwMajorVersion == 5 && osVerInfo.dwBuildNumber > 2195 )
{
dwVer = WINWH_OS;
} else {
dwVer = WINNT_OS;
}
}
// Win9X
else
{
if( (HIBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 4) )
{
// WinMe: Major = 4, Minor = 90
if( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) == 90) )
{
dwVer = WINME_OS;
} else if ( (LOBYTE(HIWORD(osVerInfo.dwBuildNumber)) > 0) ) {
dwVer = WIN98_OS;
} else {
dwVer = WIN95_OS;
}
}
}
}
return dwVer;
}