home *** CD-ROM | disk | FTP | other *** search
- #include "common.hpp"
-
-
- /*****************************************************************************
- *
- * privcom.c
- *
- * Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
- *
- * Abstract:
- *
- * Functions that sort-of duplicate what OLE does.
- *
- * Adapted from dinput\dx8\dll\dioledup.c
- *
- *****************************************************************************/
-
-
- typedef LPUNKNOWN PUNK;
- typedef LPVOID PV, *PPV;
- typedef CONST VOID *PCV;
- typedef REFIID RIID;
- typedef CONST GUID *PCGUID;
-
- /*
- * Convert an object (X) to a count of bytes (cb).
- */
- #define cbX(X) sizeof(X)
-
- /*
- * Convert an array name (A) to a generic count (c).
- */
- #define cA(a) (cbX(a)/cbX(a[0]))
-
- /*
- * Convert a count of X's (cx) into a count of bytes
- * and vice versa.
- */
- #define cbCxX(cx, X) ((cx) * cbX(X))
- #define cxCbX(cb, X) ((cb) / cbX(X))
-
- /*
- * Convert a count of chars (cch), tchars (ctch), wchars (cwch),
- * or dwords (cdw) into a count of bytes, and vice versa.
- */
- #define cbCch(cch) cbCxX( cch, CHAR)
- #define cbCwch(cwch) cbCxX(cwch, WCHAR)
- #define cbCtch(ctch) cbCxX(ctch, TCHAR)
- #define cbCdw(cdw) cbCxX( cdw, DWORD)
-
- #define cchCb(cb) cxCbX(cb, CHAR)
- #define cwchCb(cb) cxCbX(cb, WCHAR)
- #define ctchCb(cb) cxCbX(cb, TCHAR)
- #define cdwCb(cb) cxCbX(cb, DWORD)
-
- // yay
- #define ctchGuid (1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
-
- /*****************************************************************************
- *
- * _ParseHex
- *
- * Parse a hex string encoding cb bytes (at most 4), then
- * expect the tchDelim to appear afterwards. If chDelim 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.
- *
- *****************************************************************************/
-
- LPCTSTR
- _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
- 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 LONG | RegQueryString |
- *
- * Wrapper for <f RegQueryValueEx> that reads a
- * string value from the registry. An annoying quirk
- * is that on Windows NT, the returned string might
- * not end in a null terminator, so we might need to add
- * one manually.
- *
- * @parm IN HKEY | hk |
- *
- * Parent registry key.
- *
- * @parm LPCTSTR | ptszValue |
- *
- * Value name.
- *
- * @parm LPTSTR | ptsz |
- *
- * Output buffer.
- *
- * @parm DWORD | ctchBuf |
- *
- * Size of output buffer.
- *
- * @returns
- *
- * Registry error code.
- *
- *****************************************************************************/
-
- LONG
- RegQueryString(HKEY hk, LPCTSTR ptszValue, LPTSTR ptszBuf, DWORD ctchBuf)
- {
- LONG lRc;
- DWORD reg;
-
- #ifdef UNICODE
- DWORD cb;
-
- /*
- * NT quirk: Non-null terminated strings can exist.
- */
- cb = cbCtch(ctchBuf);
- lRc = RegQueryValueEx(hk, ptszValue, 0, ®, (LPBYTE)(PV)ptszBuf, &cb);
- if(lRc == ERROR_SUCCESS)
- {
- if(reg == REG_SZ)
- {
- /*
- * Check the last character. If it is not NULL, then
- * append a NULL if there is room.
- */
- DWORD ctch = ctchCb(cb);
- if(ctch == 0)
- {
- ptszBuf[ctch] = TEXT('\0');
- } else if(ptszBuf[ctch-1] != TEXT('\0'))
- {
- if(ctch < ctchBuf)
- {
- ptszBuf[ctch] = TEXT('\0');
- } else
- {
- lRc = ERROR_MORE_DATA;
- }
- }
- } else
- {
- lRc = ERROR_INVALID_DATA;
- }
- }
-
-
- #else
-
- /*
- * This code is executed only on Win95, so we don't have to worry
- * about the NT quirk.
- */
-
- lRc = RegQueryValueEx(hk, ptszValue, 0, ®, (LPBYTE)(PV)ptszBuf, &ctchBuf);
-
- if(lRc == ERROR_SUCCESS && reg != REG_SZ)
- {
- lRc = ERROR_INVALID_DATA;
- }
-
-
- #endif
-
- return lRc;
- }
-
- /*****************************************************************************
- *
- * @doc INTERNAL
- *
- * @func HRESULT | _CreateInstance |
- *
- * Worker function for <f DICoCreateInstance>.
- *
- * @parm REFCLSID | rclsid |
- *
- * The <t CLSID> to create.
- *
- * @parm LPCTSTR | ptszDll |
- *
- * The name of the DLL to load.
- *
- * @parm LPUNKNOWN | punkOuter |
- *
- * Controlling unknown for aggregation.
- *
- * @parm RIID | riid |
- *
- * Interface to obtain.
- *
- * @parm PPV | ppvOut |
- *
- * Receives a pointer to the created object if successful.
- *
- * @parm HINSTANCE * | phinst |
- *
- * Receives the instance handle of the in-proc DLL that was
- * loaded. <f FreeLibrary> this DLL when you are finished
- * with the object.
- *
- * Note that since we don't implement a binder, this means
- * that you cannot give the returned pointer away to anybody
- * you don't control; otherwise, you won't know when to
- * free the DLL.
- *
- * @returns
- *
- * Standard OLE status code.
- *
- *****************************************************************************/
-
- HRESULT
- _CreateInprocObject(BOOL bInstance, REFCLSID rclsid, LPCTSTR ptszDll, LPUNKNOWN punkOuter,
- REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
- {
- HRESULT hres;
- HINSTANCE hinst;
-
- hinst = LoadLibrary(ptszDll);
- if (hinst) {
- LPFNGETCLASSOBJECT DllGetClassObject;
-
- DllGetClassObject = (LPFNGETCLASSOBJECT)
- GetProcAddress(hinst, "DllGetClassObject");
-
- if (DllGetClassObject) {
- IClassFactory *pcf;
-
- if (bInstance)
- hres = DllGetClassObject(rclsid, IID_IClassFactory, (LPVOID *)&pcf);
- else
- {
- hres = DllGetClassObject(rclsid, riid, ppvOut);
- if (FAILED(hres))
- *ppvOut = NULL;
- }
- if (SUCCEEDED(hres) && bInstance) {
- hres = pcf->CreateInstance(punkOuter, riid, ppvOut);
- pcf->Release();
-
- /*
- * People forget to adhere to
- * the OLE spec, which requires that *ppvOut be
- * set to zero on failure.
- */
- if (FAILED(hres)) {
- /* if (*ppvOut) {
- RPF("ERROR! CoCreateInstance: %s forgot to zero "
- "out *ppvOut on failure path", ptszDll);
- }*/
- *ppvOut = 0;
- }
-
- }
- } else {
- /*
- * DLL does not export GetClassObject.
- */
- hres = REGDB_E_CLASSNOTREG;
- }
-
- if (SUCCEEDED(hres)) {
- *phinst = hinst;
- } else {
- FreeLibrary(hinst);
- }
- } else {
- /*
- * DLL does not exist.
- */
- hres = REGDB_E_CLASSNOTREG;
- }
-
- return hres;
- }
-
-
- /*****************************************************************************
- *
- * @doc INTERNAL
- *
- * @func HRESULT | DICoCreateInstance |
- *
- * Private version of CoCreateInstance that doesn't use OLE.
- *
- * @parm LPTSTR | ptszClsid |
- *
- * The string version of the <t CLSID> to create.
- *
- * @parm LPUNKNOWN | punkOuter |
- *
- * Controlling unknown for aggregation.
- *
- * @parm RIID | riid |
- *
- * Interface to obtain.
- *
- * @parm PPV | ppvOut |
- *
- * Receives a pointer to the created object if successful.
- *
- * @parm HINSTANCE * | phinst |
- *
- * Receives the instance handle of the in-proc DLL that was
- * loaded. <f FreeLibrary> this DLL when you are finished
- * with the object.
- *
- * Note that since we don't implement a binder, this means
- * that you cannot give the returned pointer away to anybody
- * you don't control; otherwise, you won't know when to
- * free the DLL.
- *
- * @returns
- *
- * Standard OLE status code.
- *
- *****************************************************************************/
-
- STDMETHODIMP
- CreateInprocObject(BOOL bInstance, LPCTSTR ptszClsid, LPUNKNOWN punkOuter,
- REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
- {
- HRESULT hres;
- CLSID clsid;
-
- *ppvOut = 0;
- *phinst = 0;
-
- if (ParseGUID(&clsid, ptszClsid)) {
- HKEY hk;
- LONG lRc;
- TCHAR tszKey[ctchGuid + 40]; /* 40 is more than enough */
-
- /*
- * Look up the CLSID in HKEY_CLASSES_ROOT.
- */
- wsprintf(tszKey, TEXT("CLSID\\%s\\InProcServer32"), ptszClsid);
-
- lRc = RegOpenKeyEx(HKEY_CLASSES_ROOT, tszKey, 0,
- KEY_QUERY_VALUE, &hk);
- if (lRc == ERROR_SUCCESS) {
- TCHAR tszDll[MAX_PATH];
- DWORD cb;
-
- cb = cbX(tszDll);
- lRc = RegQueryValue(hk, 0, tszDll, (PLONG)&cb);
-
- if (lRc == ERROR_SUCCESS) {
- TCHAR tszModel[20]; /* more than enough */
-
- lRc = RegQueryString(hk, TEXT("ThreadingModel"),
- tszModel, cA(tszModel));
- if (lRc == ERROR_SUCCESS &&
- ((lstrcmpi(tszModel, TEXT("Both"))==0x0) ||
- (lstrcmpi(tszModel, TEXT("Free"))==0x0))) {
-
- hres = _CreateInprocObject(bInstance, clsid, tszDll, punkOuter,
- riid, ppvOut, phinst);
-
- } else {
- /*
- * No threading model or bad threading model.
- */
- hres = REGDB_E_CLASSNOTREG;
- }
- } else {
- /*
- * No InprocServer32.
- */
- hres = REGDB_E_CLASSNOTREG;
- }
-
- RegCloseKey(hk);
-
- } else {
- /*
- * CLSID not registered.
- */
- hres = REGDB_E_CLASSNOTREG;
- }
- } else {
- /*
- * Invalid CLSID string.
- */
- hres = REGDB_E_CLASSNOTREG;
- }
-
- return hres;
- }
-
-
- HRESULT
- PrivCreateInstance(REFCLSID ptszClsid, LPUNKNOWN punkOuter, DWORD dwClsContext,
- REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
- {
- if (dwClsContext != CLSCTX_INPROC_SERVER || phinst == NULL)
- return E_INVALIDARG;
-
- return CreateInprocObject(TRUE, GUIDSTR(ptszClsid), punkOuter, riid, ppvOut, phinst);
- }
-
- HRESULT
- PrivGetClassObject(REFCLSID ptszClsid, DWORD dwClsContext, LPVOID pReserved,
- REFIID riid, LPVOID *ppvOut, HINSTANCE *phinst)
- {
- if (dwClsContext != CLSCTX_INPROC_SERVER || pReserved != NULL || phinst == NULL)
- return E_INVALIDARG;
-
- return CreateInprocObject(FALSE, GUIDSTR(ptszClsid), NULL, riid, ppvOut, phinst);
- }
-