/* #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 #ifdef _MSC_VER #include #else #include "PointerSrc.h" #include "comPrim.h" #include #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(), (ITypeLib **)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, (ICreateTypeLib **)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 = 0; 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__; }