hdirect-0.21.0: comlib/ComPrimSrc.c
/* #define DEBUG */
/* If you don't want the 'stack' allocator, comment this out */
/* #define USESTACK */
#ifndef COM
#define COM
#endif
/* define the DLL export macro */
#if defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__MINGW32__)
#define DLLEXPORT(res) __declspec(dllexport) res
#else
/* redef this default for your system */
#define DLLEXPORT(res) extern res
#endif
#ifdef COM
#define COBJMACROS
#define CINTERFACE
#endif
#include <stdio.h>
#ifdef _MSC_VER
#include <windows.h>
#else
#include <stdlib.h>
#include "comPrim.h"
#include "PointerSrc.h"
#endif
#define MAXSZ 255
const IID IID_NULL = {0x00000000L, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
#ifndef _MSC_VER
const IID IID_IUnknown = {0x00000000L, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
const IID IID_IClassFactory = {0x00000001L, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
#endif
DLLEXPORT(char*) hresultString( HRESULT hr )
{
static char msgbuf[256];
int len;
sprintf( msgbuf, "(0x%lx) ", hr );
len = strlen(msgbuf);
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
msgbuf + len,
256,
NULL
);
return msgbuf;
}
HRESULT primStringToGUID( WCHAR* guidStr, GUID* guid )
{
if (guid) return CLSIDFromString( guidStr, guid );
else return E_OUTOFMEMORY;
}
HRESULT primGUIDToString( CLSID* guid, WCHAR** guidStr )
{
CLSID* rclsid;
HRESULT hr;
rclsid = (CLSID*)guid;
if (!rclsid) rclsid = (CLSID*)&IID_NULL;
if (guidStr) {
hr = StringFromCLSID( rclsid, guidStr );
} else {
hr = E_POINTER;
}
return hr;
}
HRESULT primProgIDFromCLSID( const CLSID* clsid, WCHAR** clsidStr )
{
if (!clsid) clsid = &IID_NULL;
if (clsidStr) return ProgIDFromCLSID( clsid, clsidStr );
else return E_POINTER;
}
/*-----------------------------------------------------------
-- Com library calls
-----------------------------------------------------------*/
static int com_already_initialized = 0;
static int com_already_uninitialized = 0;
HRESULT comInitialize(void)
{
if (!com_already_initialized) {
com_already_initialized = 1;
return OleInitialize(NULL);
} else {
return S_OK;
}
}
void shutdown__()
{
OleUninitialize();
com_already_initialized = 0;
com_already_uninitialized = 0;
}
void comUnInitialize(void)
{
if (!com_already_uninitialized) {
com_already_uninitialized=1;
atexit(shutdown__);
}
}
/*-----------------------------------------------------------
-- Object Creation
-----------------------------------------------------------*/
/* CLSIDFromProgID is a bit too naive, so I wrote it myself */
HRESULT primCLSIDFromProgID( const char* progid, CLSID* clsid )
{
HRESULT hr;
char name[MAXSZ];
DWORD namesz = MAXSZ;
BYTE value[MAXSZ];
DWORD valuesz = MAXSZ;
WCHAR clsidName[MAXSZ];
DWORD type = REG_SZ;
HKEY key = 0;
HKEY subkey = 0;
if (!clsid) return E_POINTER;
if (!progid) return E_POINTER;
hr = HRESULT_FROM_WIN32(RegOpenKeyExA( HKEY_CLASSES_ROOT, progid, 0, KEY_READ, &key ));
if (FAILED(hr)) return CO_E_CLASSSTRING;
hr = HRESULT_FROM_WIN32(RegOpenKeyExA( key, "CurVer", 0, KEY_READ, &subkey ));
if (SUCCEEDED(hr))
{
hr = HRESULT_FROM_WIN32(RegEnumValueA( subkey, 0, name, &namesz, NULL, &type, value, &valuesz));
RegCloseKey( key );
RegCloseKey( subkey );
if (FAILED(hr)) return hr;
hr = HRESULT_FROM_WIN32(RegOpenKeyExA( HKEY_CLASSES_ROOT, (char*)value, 0, KEY_QUERY_VALUE, &key ));
if (FAILED(hr)) return CO_E_CLASSSTRING;
namesz = MAXSZ;
valuesz = MAXSZ;
}
hr = HRESULT_FROM_WIN32(RegOpenKeyExA( key, "CLSID", 0, KEY_READ, &subkey ));
if (FAILED(hr)) { RegCloseKey( key ); return CO_E_CLSREG_INCONSISTENT; };
hr = HRESULT_FROM_WIN32(RegEnumValueA( subkey, 0, name, &namesz, NULL, &type,value,&valuesz));
RegCloseKey( subkey );
RegCloseKey( key );
if (FAILED(hr)) return hr;
mbstowcs( clsidName, (char*)value, MAXSZ );
hr = CLSIDFromString( clsidName, clsid );
return hr;
}
/* Newer COM libraries supply the functionality of
bindObject() via CoGetObject(), but to avoid depending
on that being around, we stick with our own implementation.
*/
HRESULT bindObject( const WCHAR* name, IID* iid, void** unk )
{
HRESULT hr;
IBindCtx *bc;
IMoniker *mk;
ULONG count;
if (!unk) return E_POINTER;
else *unk = NULL;
if (!iid) return E_POINTER;
bc = NULL;
mk = NULL;
hr = CreateBindCtx(0, &bc);
if (FAILED(hr)) return hr;
hr = MkParseDisplayName(bc, name, &count, &mk);
if (FAILED(hr)) { IUnknown_Release(bc); return hr; }
hr = IMoniker_BindToObject( mk, bc, NULL, iid, unk );
IUnknown_Release(mk);
IUnknown_Release(bc);
return hr;
}
typedef HRESULT (__stdcall * qi_methPtrTy)(void*,void*,void**);
HRESULT primQI ( /*[in]*/void* methPtr
, /*[in]*/void* iptr
, /*[in]*/void* riid
, /*[in]*/void** ppv
)
{
return ((qi_methPtrTy)methPtr)(iptr,riid,ppv);
}
typedef unsigned int (__stdcall * addRef_methPtrTy)(void*);
unsigned int
primAddRef ( /*[in]*/void* methPtr
, /*[in]*/void* iptr
)
{
return ((addRef_methPtrTy)methPtr)(iptr);
}
typedef unsigned int (__stdcall * release_methPtrTy)(void*);
unsigned int
primRelease ( /*[in]*/void* methPtr
, /*[in]*/void* iptr
)
{
return ((release_methPtrTy)methPtr)(iptr);
}
typedef unsigned int (__stdcall * enumNext_methPtrTy)(void* iptr, unsigned int celt, void* ptr, void* po);
HRESULT
primEnumNext(void* methPtr, void* iptr, unsigned int celt, void* ptr, void* po)
{
return ((enumNext_methPtrTy)methPtr)(iptr,celt,ptr,po);
}
typedef unsigned int (__stdcall * enumSkip_methPtrTy)(void* iptr, unsigned int celt);
HRESULT
primEnumSkip(void* methPtr, void* iptr, unsigned int celt)
{
return ((enumSkip_methPtrTy)methPtr)(iptr,celt);
}
typedef unsigned int (__stdcall * enumReset_methPtrTy)(void* iptr);
HRESULT
primEnumReset(void* methPtr, void* iptr)
{
return ((enumReset_methPtrTy)methPtr)(iptr);
}
typedef unsigned int (__stdcall * enumClone_methPtrTy)(void* iptr,void* ppv);
HRESULT
primEnumClone(void* methPtr, void* iptr, void* ppv)
{
return ((enumClone_methPtrTy)methPtr)(iptr,ppv);
}
typedef unsigned int (__stdcall * persistLoad_methPtrTy)(void* iptr,void* pszFileName,unsigned int dwMode);
HRESULT
primPersistLoad(void* methPtr, void* iptr, void* pszFileName, unsigned int dwMode)
{
return ((persistLoad_methPtrTy)methPtr)(iptr,pszFileName,dwMode);
}
HRESULT primGetActiveObject( CLSID* clsid, IUnknown** unk )
{
if (!unk) return E_POINTER;
else *unk = NULL;
return GetActiveObject( clsid, NULL, unk );
}
HRESULT primLoadRegTypeLib
( GUID* rguid
, short wMaj
, short wMin
, LCID lcid
, void** ppv
)
{
HRESULT hr;
hr = LoadRegTypeLib(rguid, wMaj, wMin, GetUserDefaultLCID(), (IUnknown**)ppv);
return hr;
}
void messageBox (char* str, char* t, unsigned long x)
{
MessageBox ( NULL, str, t, x);
return;
}
IID* primNullIID () { return (IID*)(&IID_NULL); }
DWORD
lOCALE_USER_DEFAULT()
{
return(GetUserDefaultLCID());
}
BOOL primComEqual( IUnknown* unk1, IUnknown* unk2 )
{
IUnknown* obj1;
IUnknown* obj2;
BOOL res;
HRESULT hr;
if (!unk1) return (unk2 == NULL);
if (!unk2) return FALSE;
hr = IUnknown_QueryInterface( unk1, &IID_IUnknown, (void**)&obj1 );
if (FAILED(hr)) return FALSE;
hr = IUnknown_QueryInterface( unk2, &IID_IUnknown, (void**)&obj2 );
if (FAILED(hr)) {IUnknown_Release(obj1); return FALSE; }
res = (obj1 == obj2);
IUnknown_Release(obj1);
IUnknown_Release(obj2);
return res;
}
HRESULT
primCopyGUID (GUID* g1, GUID* g2)
{
if (g2 == NULL || g1 == NULL) {
return E_FAIL;
} else {
memcpy(g2,g1,sizeof(GUID));
return S_OK;
}
}
HRESULT
primNewGUID (GUID* g1)
{
if (g1 == NULL) {
return E_FAIL;
} else {
return CoCreateGuid(g1);
}
}
/*
*
* CreateTypeLib() stub.
*
*/
HRESULT primCreateTypeLib ( int i, LPOLESTR fname, void** ppv )
{
/* Not much point really of defining this stub, since
* should really be using the FFI, but a little bit
* easier to debug this way until we know everything's reaonable
* stable.
*/
/* Unfortunately, the cygwin/mingw liboleaut32.a import library doesn't have an entry
* for _CreateTypeLib@12, so you either have to generate your own version of it (which
* I did), or fall back on CreateTypeLib().
*/
#ifdef _MSC
return ( CreateTypeLib2(1/*SYS_WIN32*/, fname, ppv) );
#else
return ( CreateTypeLib(1/*SYS_WIN32*/, fname, ppv) );
#endif
}
BSTR primQueryPathOfRegTypeLib ( GUID* rguid
, unsigned short maj
, unsigned short min
)
{
BSTR bs;
HRESULT hr;
bs = SysAllocStringByteLen (NULL, 255);
hr = QueryPathOfRegTypeLib ( rguid, maj, min, GetUserDefaultLCID(), &bs);
if (FAILED(hr)) {
SysFreeString(bs);
return NULL;
}
return bs;
}
#define MAX_LEN_MOD_FNAME 2048
char*
getModuleFileName ( HANDLE hMod)
{
char* buf = malloc(sizeof(char) * MAX_LEN_MOD_FNAME);
DWORD len;
len = GetModuleFileNameA(hMod, buf, MAX_LEN_MOD_FNAME);
return buf;
}
/*-----------------------------------------------------------
-- Message pumping utils
-----------------------------------------------------------*/
void messagePump()
{
MSG msg;
while ( GetMessage(&msg, 0, 0, 0) ) {
DispatchMessage(&msg);
}
}
HANDLE
mkEvent()
{
return CreateEvent(NULL, FALSE, FALSE, NULL);
}
void
waitForEvent (HANDLE h)
{
HANDLE ha = h;
DWORD dwR;
MSG msg;
while(1) {
dwR = MsgWaitForMultipleObjects(1, &ha, FALSE, INFINITE, QS_ALLEVENTS);
if (dwR == WAIT_OBJECT_0) {
break;
} else {
while (PeekMessage(&msg,NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
void
signalEvent(HANDLE h)
{
SetEvent(h);
}
/* Add a WM_QUIT to the STA thread's message queue, causing the
above pump to shutdown.
*/
void postQuitMsg()
{
PostMessage(NULL, WM_QUIT, 0, 0);
}
/*-----------------------------------------------------------
-- BSTR <--> String operations:
-----------------------------------------------------------*/
HRESULT
stringToBSTR( /*[in,ptr]*/const char* pstrz
, /*[out]*/ BSTR* pbstr
)
{
int i;
if (!pbstr) {
return E_FAIL;
} else {
*pbstr = NULL;
}
if (!pstrz) {
return S_OK;
}
i = MultiByteToWideChar(CP_ACP, 0, pstrz, -1, NULL, 0);
if ( i < 0 ) {
return E_FAIL;
}
/* i is the length of the string *including* the null-terminator
* (which we don't want in the BSTR). So the length of the BSTR is
* i-1.
*/
*pbstr = SysAllocStringLen(NULL,i-1);
if (*pbstr != NULL) {
MultiByteToWideChar(CP_ACP, 0, pstrz, -1, *pbstr, i-1);
return S_OK;
} else {
return E_FAIL;
}
}
int
bstrLen( /*[in]*/ BSTR bstr )
{
if (!bstr) {
return 0;
}
// return wcstombs( NULL, bstr, SysStringLen(bstr)+1);
return WideCharToMultiByte ( CP_ACP, 0, bstr, SysStringLen(bstr)
, NULL, 0, NULL, NULL);
}
HRESULT
bstrToStringLen ( BSTR bstr
, int len
, char* p
)
{
int i;
if (!p) {
return E_FAIL;
} else {
*p = '\0';
}
if (!bstr) {
return E_FAIL;
}
// i = wcstombs(p,bstr,len+1);
i = WideCharToMultiByte ( CP_ACP, 0, bstr, SysStringLen(bstr)
, p, len, NULL, NULL);
if ( i == 0 ) {
return E_FAIL;
} else {
p[i]= '\0';
return S_OK;
}
}
/*
* Wrapper for the interesting bits of GetVersionEx()
*/
void
primGetVersionInfo
( /*[out]*/unsigned long* maj
, /*[out]*/unsigned long* min
, /*[out]*/unsigned long* pid
)
{
OSVERSIONINFO oe;
BOOL b;
oe.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
b = GetVersionEx(&oe);
#ifdef DEBUG
if (!b) {
fprintf(stderr, "GetVersionEx failed\n");
exit(1);
}
#endif
/* Assume everything went well */
*maj = oe.dwMajorVersion;
*min = oe.dwMinorVersion;
*pid = oe.dwPlatformId;
return;
}
/*
* IUnknown finaliser called by GC when ForeignObjs holding them
* are finalised.
*/
void
releaseIUnknown__(void* ip)
{
DWORD d;
#ifdef DEBUG
fprintf(stderr, "Releasing COM i-pointer 0x%p\n", ip); fflush(stderr);
#endif
if (ip) {
d = IUnknown_Release((IUnknown*)ip);
#ifdef DEBUG
fprintf(stderr, "Released COM i-pointer 0x%p %d\n", ip, d); fflush(stderr);
#endif
}
}
void*
addrOfReleaseIUnknown()
{
/* Strictly speaking, converting a function pointer to a void*
is not guaranteed to be information preserving in ANSI C.
*/
return (void*)&releaseIUnknown__;
}