NT4/private/ole32/com/class/compapi.cxx
2020-09-30 17:12:29 +02:00

2543 lines
72 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1993.
//
// File: compapi.cxx
//
// Contents: API for the compobj dll
//
// Classes:
//
// Functions:
//
// History: 31-Dec-93 ErikGav Chicago port
// 28-Mar-94 BruceMa CLSID_NULL undoes TreatAs emulation
// 20-Apr-94 Rickhi CClassExtMap, commenting, cleanup
// 03-May-94 BruceMa Corrected IsOle1Class w/ OLE 2.01
// 04-May-94 BruceMa Conformed CoTreatAsClass to 16-bit OLE
// 12-Dec-94 BruceMa Support CoGetClassPattern on Chicago
// 03-Jan-95 BruceMa Support Chicago style pattern matching
// on NT if CoInitialize has not been
// called
// 28-Aug-95 MurthyS StringFromGUID2 and StringFromGUID2A
// no longer use sprintf or wsprintf
// 07-Sep-95 MurthyS Only do validation in API rtns with
// work done by worker routines. Commonly
// used (internally) worker routines moved
// to common\ccompapi.cxx
// 04-Feb-96 BruceMa Add per-user registry support
//
//----------------------------------------------------------------------------
#include <ole2int.h>
#include "ole1guid.h"
#ifndef _CHICAGO_
#include <shrtbl.hxx> // CDllShrdTbl
#endif // !_CHICAGO_
#include "pattbl.hxx" // CChicoPatternTable
#include <dbgpopup.hxx>
#include <tracelog.hxx>
// forward references
INTERNAL wCoMarshalHresult(IStream FAR* pstm, HRESULT hresult);
INTERNAL wCoUnmarshalHresult(IStream FAR* pstm, HRESULT FAR * phresult);
#ifndef _CHICAGO_
CDllShrdTbl *GetSharedTbl(void);
#endif
INTERNAL wRegGetClassPattern(HANDLE hfile, CLSID *pclsid);
//+-------------------------------------------------------------------------
//
// Function: wCoMarshalHresult (internal)
//
// Synopsis: writes an hresult into the stream
//
// Arguments: [pStm] - the stream to write into
// [hresult] - the hresult to write
//
// Returns: results from the write
//
//--------------------------------------------------------------------------
inline INTERNAL wCoMarshalHresult(IStream FAR* pstm, HRESULT hresult)
{
return pstm->Write(&hresult,sizeof(hresult),NULL);
}
//+-------------------------------------------------------------------------
//
// Function: wCoUnMarshalHresult (internal)
//
// Synopsis: reads an hresult from the stream
//
// Arguments: [pStm] - the stream to write into
// [hresult] - the hresult to write
//
// Returns: results from the write
//
//--------------------------------------------------------------------------
inline INTERNAL wCoUnmarshalHresult(IStream FAR* pstm, HRESULT FAR * phresult)
{
SCODE sc;
HRESULT hresult = pstm->Read(&sc,sizeof(sc),NULL);
CairoleAssert((hresult == NOERROR)
&& "CoUnmarshalHresult: Stream read error");
if (hresult == NOERROR)
{
*phresult = sc;
}
return hresult;
}
//+-------------------------------------------------------------------------
//
// Function: wCoGetCallerTID (internal)
//
// Synopsis: gets the TID of the ORPC client that called us.
//
// Arguments: [pTIDCaller] - where to put the result.
//
//--------------------------------------------------------------------------
inline HRESULT wCoGetCallerTID(DWORD *pTIDCaller)
{
HRESULT hr;
COleTls tls(hr);
if (SUCCEEDED(hr))
{
*pTIDCaller = tls->dwTIDCaller;
return (tls->dwFlags & OLETLS_LOCALTID) ? S_OK : S_FALSE;
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: wCoGetCurrentLogicalThreadId (internal)
//
// Synopsis: Gets the current logical thread id that this physical
// thread is operating under. The current physical thread
// takes on the logical tid of any client application that
// makes an Rpc call into this app. The function is exported
// so that the tools infrastructure (conformance suite, logger,
// etc) can use it.
//
// Arguments: [pguid] - where to return the logical thread id
//
// Returns: [S_OK] - got the logical thread id
// [E_OUTOFMEMORY] - cant allocate resources
//
//--------------------------------------------------------------------------
inline INTERNAL wCoGetCurrentLogicalThreadId(GUID *pguid)
{
GUID *pguidTmp = TLSGetLogicalThread();
if (pguidTmp != NULL)
{
*pguid = *pguidTmp;
return S_OK;
}
return E_OUTOFMEMORY;
}
NAME_SEG(CompApi)
ASSERTDATA
#ifndef _CHICAGO_
// global shared memory table object
extern CDllShrdTbl *g_pShrdTbl;
#else // _CHICAGO_
// Chicago does not use the shared memory caches that NT does.
// Also, NT is permitted to use the Chicago style pattern table
// if CoInitialize has not been called
CChicoPatternTbl *g_pPatTbl = NULL;
#endif // _CHICAGO_
// defined in com\inc\psctbl.cxx
extern WCHAR wszProxyStubClsid[]; // L"\\ProxyStubClsid32"
extern WCHAR wszProxyStubClsid16[]; // L"\\ProxyStubClsid"
//
// string constants used throughout this file
//
WCHAR wszCairoRoot[] = L"";
WCHAR wszInterfaceKey[] = L"Interface\\";
ULONG ulInterfaceKeyLen = ((sizeof(wszInterfaceKey)/sizeof(WCHAR))-1);
WCHAR wszTreatAs[] = L"TreatAs";
WCHAR wszAutoTreatAs[] = L"AutoTreatAs";
WCHAR wszIID[] = L"IID";
ULONG ulIIDKeyLen = ((sizeof(wszIID)/sizeof(WCHAR))-1);
extern WCHAR wszOle1Class[]; // defined in common\ccompapi.cxx
// Constant for inprocess marshaling - this s/b big enough to cover most
// cases since reallocations just waste time.
#define EST_INPROC_MARSHAL_SIZE 256
//+-------------------------------------------------------------------------
//
// Function: CoMarshalHresult (public)
//
// Synopsis: writes an hresult into the stream
//
// Arguments: [pStm] - the stream to write into
// [hresult] - the hresult to write
//
// Returns: results from the write
//
//--------------------------------------------------------------------------
STDAPI CoMarshalHresult(IStream FAR* pstm, HRESULT hresult)
{
OLETRACEIN((API_CoMarshalHresult, PARAMFMT("pstm= %p, hresult= %x"), pstm, hresult));
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)&pstm);
HRESULT hr;
if (IsValidInterface(pstm))
{
hr = wCoMarshalHresult(pstm, hresult);
}
else
{
hr = E_INVALIDARG;
}
OLETRACEOUT((API_CoMarshalHresult, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CoUnMarshalHresult (public)
//
// Synopsis: reads an hresult from the stream
//
// Arguments: [pStm] - the stream to write into
// [hresult] - the hresult to write
//
// Returns: results from the write
//
//--------------------------------------------------------------------------
STDAPI CoUnmarshalHresult(IStream FAR* pstm, HRESULT FAR * phresult)
{
HRESULT hr;
OLETRACEIN((API_CoUnmarshalHresult, PARAMFMT("pstm= %p, phresult= %p"), pstm, phresult));
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStream,(IUnknown **)&pstm);
if (IsValidInterface(pstm) &&
IsValidPtrOut(phresult, sizeof(*phresult)))
{
hr = wCoUnmarshalHresult(pstm, phresult);
}
else
{
hr = E_INVALIDARG;
}
OLETRACEOUT((API_CoUnmarshalHresult, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CoGetCallerTID (exported, but not in header files)
//
// Synopsis: gets the TID of the current calling application
//
// Arguments: [pTIDCaller] - where to return the caller TID
//
// Returns: [S_TRUE] - caller TID set, caller in SAME process
// [S_FALSE] = caller TID set, caller in different process
// [E_OUTOFMEMORY] - caller TID not set
//
//--------------------------------------------------------------------------
STDAPI CoGetCallerTID(DWORD *pTIDCaller)
{
OLETRACEIN((API_CoGetCallerTID, PARAMFMT("pTIDCaller= %p"), pTIDCaller));
HRESULT hr;
if (IsValidPtrOut(pTIDCaller, sizeof(*pTIDCaller)))
{
hr = wCoGetCallerTID(pTIDCaller);
}
else
{
hr = E_INVALIDARG;
}
OLETRACEOUT((API_CoGetCallerTID, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CoGetCurrentLogicalThreadId (exported, but not in header files)
//
// Synopsis: Gets the current logical thread id that this physical
// thread is operating under. The current physical thread
// takes on the logical tid of any client application that
// makes an Rpc call into this app. The function is exported
// so that the tools infrastructure (conformance suite, logger,
// etc) can use it.
//
// Arguments: [pguid] - where to return the logica thread id
//
// Returns: [S_OK] - got the logical thread id
// [E_OUTOFMEMORY] - cant allocate resources
//
//--------------------------------------------------------------------------
STDAPI CoGetCurrentLogicalThreadId(GUID *pguid)
{
OLETRACEIN((API_CoGetCurrentLogicalThreadId, PARAMFMT("pguid= %p"), pguid));
HRESULT hr;
if (IsValidPtrOut(pguid, sizeof(*pguid)))
{
hr = wCoGetCurrentLogicalThreadId(pguid);
}
else
{
hr = E_INVALIDARG;
}
OLETRACEOUT((API_CoGetCurrentLogicalThreadId, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: StringFromGUID2 (public)
//
// Synopsis: converts GUID into {...} form without leading identifier;
//
// Arguments: [rguid] - the guid to convert
// [lpszy] - buffer to hold the results
// [cbMax] - sizeof the buffer
//
// Returns: amount of data copied to lpsz if successful
// 0 if buffer too small.
//
//--------------------------------------------------------------------------
STDAPI_(int) StringFromGUID2(REFGUID rguid, LPWSTR lpsz, int cbMax)
{
OLETRACECMNIN((API_StringFromGUID2, PARAMFMT("rguid= %I, lpsz= %p, cbMax= %d"),
&rguid, lpsz, cbMax));
int iRet = 0;
if ((&rguid != NULL) &&
IsValidPtrIn(&rguid, sizeof(rguid)) &&
IsValidPtrOut(lpsz, cbMax))
{
if (cbMax >= GUIDSTR_MAX)
{
iRet = wStringFromGUID2(rguid, lpsz, cbMax);
}
}
OLETRACECMNOUTEX((API_StringFromGUID2, RETURNFMT("%d"), iRet));
return iRet;
}
//+-------------------------------------------------------------------------
//
// Function: GUIDFromString (private)
//
// Synopsis: parse above format; always writes over *pguid.
//
// Arguments: [lpsz] - the guid string to convert
// [pguid] - guid to return
//
// Returns: TRUE if successful
//
//--------------------------------------------------------------------------
STDAPI_(BOOL) GUIDFromString(LPCWSTR lpsz, LPGUID pguid)
{
if ((lpsz != NULL) &&
IsValidPtrIn(lpsz, GUIDSTR_MAX) &&
IsValidPtrOut(pguid, sizeof(*pguid)))
{
if (lstrlenW(lpsz) < (GUIDSTR_MAX - 1))
return(FALSE);
return(wGUIDFromString(lpsz, pguid));
}
return(FALSE);
}
//+-------------------------------------------------------------------------
//
// Function: StringFromCLSID (public)
//
// Synopsis: converts GUID into {...} form.
//
// Arguments: [rclsid] - the guid to convert
// [lplpsz] - ptr to buffer for results
//
// Returns: NOERROR
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
STDAPI StringFromCLSID(REFCLSID rclsid, LPWSTR FAR* lplpsz)
{
OLETRACEIN((API_StringFromCLSID, PARAMFMT("rclsid= %I, lplpsz= %p"), &rclsid, lplpsz));
HRESULT hr;
if ((&rclsid != NULL) &&
IsValidPtrIn(&rclsid, sizeof(rclsid)) &&
IsValidPtrOut(lplpsz, sizeof(*lplpsz)))
{
hr = wStringFromCLSID(rclsid, lplpsz);
}
else
{
hr = E_INVALIDARG;
}
OLETRACEOUT((API_StringFromCLSID, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CLSIDFromString (public)
//
// Synopsis: converts string {...} form int guid
//
// Arguments: [lpsz] - ptr to buffer for results
// [lpclsid] - the guid to convert
//
// Returns: NOERROR
// CO_E_CLASSSTRING
//
//--------------------------------------------------------------------------
STDAPI CLSIDFromString(LPWSTR lpsz, LPCLSID lpclsid)
{
HRESULT hr;
OLETRACEIN((API_CLSIDFromString, PARAMFMT("lpsz= %ws, lpclsid= %p"),
lpsz, lpclsid));
// Note: Should be doing IsValidPtrIn(lpsz, CLSIDSTR_MAX) but can't because
// what comes in might be a ProgId.
if (IsValidPtrIn(lpsz, 1) &&
IsValidPtrOut(lpclsid, sizeof(*lpclsid)))
{
hr = wCLSIDFromString(lpsz, lpclsid);
}
else
{
hr = E_INVALIDARG;
}
OLETRACEOUT((API_CLSIDFromString, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CLSIDFromOle1Class (public)
//
// Synopsis: translate Ole1Class into clsid
//
// Arguments: [lpsz] - ptr to buffer for results
// [lpclsid] - the guid to convert
//
// Returns: NOERROR
// E_INVALIDARG
// CO_E_CLASSSTRING (not ole1 class)
// REGDB_E_WRITEREGDB
//
//--------------------------------------------------------------------------
STDAPI CLSIDFromOle1Class(LPCWSTR lpsz, LPCLSID lpclsid, BOOL fForceAssign)
{
if ((lpsz != NULL) &&
IsValidPtrIn(lpsz,1) &&
IsValidPtrOut(lpclsid, sizeof(*lpclsid)))
{
if (lpsz[0] == 0)
{
// NOTE - This check wasn't in shipped versions of this
// code. In prior versions the empty string would be passed
// down into the guts of the 1.0 CLSID support and would
// fail there with CO_E_CLASSSTRING. That code path depended
// on an assert being broken to function properly. With that
// assert fixed, this new check is required.
*lpclsid = CLSID_NULL;
return CO_E_CLASSSTRING;
}
return(wCLSIDFromOle1Class(lpsz, lpclsid, fForceAssign));
}
return(E_INVALIDARG);
}
//+---------------------------------------------------------------------------
//
// Function: Ole1ClassFromCLSID2
//
// Synopsis: translate CLSID into Ole1Class
// REVIEW: might want to have CLSIDFromOle1Class instead of having
// CLSIDFromString do the work.
//
// Arguments: [rclsid] --
// [lpsz] --
// [cbMax] --
//
// Returns:
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI_(int) Ole1ClassFromCLSID2(REFCLSID rclsid, LPWSTR lpsz, int cbMax)
{
if ((&rclsid != NULL) &&
IsValidPtrIn(&rclsid, sizeof(rclsid)) &&
IsValidPtrOut(lpsz, cbMax))
{
return(wOle1ClassFromCLSID2(rclsid, lpsz, cbMax));
}
return(E_INVALIDARG);
}
//+-------------------------------------------------------------------------
//
// Function: StringFromIID (public)
//
// Synopsis: converts GUID into {...} form.
//
// Arguments: [rclsid] - the guid to convert
// [lplpsz] - ptr to buffer for results
//
// Returns: NOERROR
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
STDAPI StringFromIID(REFIID rclsid, LPWSTR FAR* lplpsz)
{
OLETRACEIN((API_StringFromIID, PARAMFMT("rclsid= %I, lplpsz= %p"), &rclsid, lplpsz));
HRESULT hr = NOERROR;
if ((&rclsid != NULL) &&
IsValidPtrIn(&rclsid, sizeof(rclsid)) &&
IsValidPtrOut(lplpsz, sizeof(*lplpsz)))
{
hr = wStringFromIID(rclsid, lplpsz);
}
else
{
hr = E_INVALIDARG;
}
OLETRACEOUT((API_StringFromIID, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: IIDFromString (public)
//
// Synopsis: converts string {...} form int guid
//
// Arguments: [lpsz] - ptr to buffer for results
// [lpiid] - the guid to convert
//
// Returns: NOERROR
// CO_E_CLASSSTRING
//
//--------------------------------------------------------------------------
STDAPI IIDFromString(LPWSTR lpsz, LPIID lpiid)
{
OLETRACEIN((API_IIDFromString, PARAMFMT("lpsz= %ws, lpiid= %p"), lpsz, lpiid));
HRESULT hr = E_INVALIDARG;
if (IsValidPtrIn(lpsz, IIDSTR_MAX) &&
IsValidPtrOut(lpiid, sizeof(*lpiid)))
{
if ((lpsz == NULL) ||
(lstrlenW(lpsz) == (IIDSTR_MAX - 1)))
{
hr = wIIDFromString(lpsz, lpiid);
}
}
OLETRACEOUT((API_IIDFromString, hr));
return hr;
}
#ifndef DCOM
//+-------------------------------------------------------------------------
//
// Function: CoGetPSClsid (public)
//
// Synopsis: returns the proxystub clsid associated with the specified
// interface IID.
//
// Arguments: [riid] - the interface iid to lookup
// [lpclsid] - where to return the clsid
//
// Returns: S_OK if successfull
// REGDB_E_IIDNOTREG if interface is not registered.
// REGDB_E_READREGDB if any other error
//
// Algorithm: First it looks in the shared memory table for the specified
// IID. If the entry is not found and the table is FULL, it
// will look in the registry itself. I expect this latter case
// to be very rare.
//
// History: 07-Apr-94 Rickhi rewrite
//
//--------------------------------------------------------------------------
STDAPI CoGetPSClsid(REFIID riid, LPCLSID lpclsid)
{
if ((&riid != NULL) &&
IsValidPtrIn(&riid, sizeof(riid)) &&
IsValidPtrOut(lpclsid, sizeof(*lpclsid)))
{
return(wCoGetPSClsid(riid, lpclsid));
}
return(E_INVALIDARG);
}
#endif
//+-------------------------------------------------------------------------
//
// Function: CoIsOle1Class (public)
//
// Synopsis: reads the Ole1Class entry in the registry for the given clsid
//
// Arguments: [rclsid] - the classid to look up
//
// Returns: TRUE if Ole1Class
// FALSE otherwise
//
//--------------------------------------------------------------------------
STDAPI_(BOOL) CoIsOle1Class(REFCLSID rclsid)
{
if ((&rclsid != NULL) &&
IsValidPtrIn(&rclsid, sizeof(rclsid)))
{
return(wCoIsOle1Class(rclsid));
}
return(FALSE);
}
//+-------------------------------------------------------------------------
//
// Function: ProgIDFromCLSID (public)
//
// Synopsis: convert clsid into progid
//
// Arguments: [rclsid] - the classid to look up
// [pszProgID] - returned progid
//
// Returns: E_INVALIDARG, E_OUTOFMEMORY,
// REGDB_CLASSNOTREG, REGDB_E_READREGDB
//
//--------------------------------------------------------------------------
STDAPI ProgIDFromCLSID(REFCLSID rclsid, LPWSTR FAR* ppszProgID)
{
if ((&rclsid != NULL) &&
IsValidPtrIn(&rclsid, sizeof(rclsid)) &&
IsValidPtrOut(ppszProgID, sizeof(*ppszProgID)))
{
return(wkProgIDFromCLSID(rclsid, ppszProgID));
}
return(E_INVALIDARG);
}
//+-------------------------------------------------------------------------
//
// Function: CLSIDFromProgID (public)
//
// Synopsis: convert progid into clsid
//
// Arguments: [pszProgID] - the progid to convert
// [pclsid] - the returned classid
//
// Returns: E_INVALIDARG, CO_E_CLASSSTRING (not ole1 class)
// REGDB_E_WRITEREGDB
//
//--------------------------------------------------------------------------
STDAPI CLSIDFromProgID(LPCWSTR pszProgID, LPCLSID pclsid)
{
return CLSIDFromOle1Class(pszProgID, pclsid);
}
//+-------------------------------------------------------------------------
//
// Function: CoOpenClassKey (public)
//
// Synopsis: opens a registry key for specified class
//
// Arguments: [rclsid] - the classid to look up
// [pszProgID] - returned progid
//
// Returns: REGDB_CLASSNOTREG, REGDB_E_READREGDB
//
//--------------------------------------------------------------------------
STDAPI CoOpenClassKey(REFCLSID clsid, HKEY FAR* lphkeyClsid)
{
if ((&clsid != NULL) &&
IsValidPtrIn(&clsid, sizeof(clsid)) &&
IsValidPtrOut(lphkeyClsid, sizeof(*lphkeyClsid)))
{
return(wCoOpenClassKey(clsid, lphkeyClsid));
}
return(E_INVALIDARG);
}
//+-------------------------------------------------------------------------
//
// Function: CoGetTreatAsClass (public)
//
// Synopsis: get current treat as class if any
//
// Arguments: [clsidOld] - the classid to look up
// [pclsidNew] - returned classid
//
// Returns: S_OK when there is a TreatAs entry.
// S_FALSE when there is no TreatAs entry.
// REGDB_E_READREGDB or same as CLSIDFromString
//
//--------------------------------------------------------------------------
STDAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID lpClsidNew)
{
if ((&clsidOld != NULL) &&
IsValidPtrIn(&clsidOld, sizeof(clsidOld)) &&
IsValidPtrOut(lpClsidNew, sizeof(*lpClsidNew)))
{
return(wCoGetTreatAsClass(clsidOld, lpClsidNew));
}
return(E_INVALIDARG);
}
//+-------------------------------------------------------------------------
//
// Function: CoTreatAsClass (public)
//
// Synopsis: set current treat as class if any
//
// Arguments: [clsidOld] - the old classid to look up
// [clsidNew] - the new classid
//
// Returns: S_OK if successful
// REGDB_E_CLASSNOTREG, REGDB_E_READREGDB, REGDB_E_WRITEREGDB
//
//--------------------------------------------------------------------------
STDAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
{
if ((&clsidOld != NULL) &&
(&clsidNew != NULL) &&
IsValidPtrIn(&clsidOld, sizeof(clsidOld)) &&
IsValidPtrIn(&clsidNew, sizeof(clsidNew)))
{
return(wCoTreatAsClass(clsidOld, clsidNew));
}
return(E_INVALIDARG);
}
//+-------------------------------------------------------------------------
//
// Function: CoCreateInstance (public)
//
// Synopsis: helper function to create instance in given context
//
// Arguments: [rclsid] - the class of object to create
// [pUnkOuter] - the controlling unknown (for aggregation)
// [dwContext] - class context
// [riid] - interface id
// [ppv] - pointer for returned object
//
// Returns: REGDB_E_CLASSNOTREG, REGDB_E_READREGDB, REGDB_E_WRITEREGDB
//
//--------------------------------------------------------------------------
STDAPI CoCreateInstance(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwContext,
REFIID riid,
LPVOID FAR* ppv)
{
if ((&rclsid != NULL) &&
IsValidPtrIn(&rclsid, sizeof(rclsid)) &&
((!pUnkOuter) || IsValidInterface(pUnkOuter)) &&
(&riid != NULL) &&
IsValidPtrIn(&riid, sizeof(riid)) &&
IsValidPtrOut(ppv, sizeof(*ppv)))
{
return(wCoCreateInstance(rclsid, pUnkOuter, dwContext, riid, ppv));
}
return(E_INVALIDARG);
}
//+-------------------------------------------------------------------------
//
// Function: CoMarshalInterThreadInterfaceInStream, public
//
// Synopsis: helper function to a marshaled buffer to be passed
// between threads.
//
// Arguments: [riid] - interface id
// [pUnk] - ptr to interface we want to marshal
// [ppStm] - stream we want to give back to caller
//
// Returns: NOERROR - Stream returned
// E_INVALIDARG - Input parameters are invalid
// E_OUTOFMEMORY - memory stream could not be created.
//
// Algorithm: Validate pointers. Create a stream and finally marshal
// the input interface into the stream.
//
// History: 03-Nov-94 Ricksa Created
//
//--------------------------------------------------------------------------
HRESULT CoMarshalInterThreadInterfaceInStream(
REFIID riid,
LPUNKNOWN pUnk,
LPSTREAM *ppStm)
{
HRESULT hr = E_INVALIDARG;
LPSTREAM pStm = NULL;
// Validate parameters
if ((&riid != NULL)
&& IsValidPtrIn(&riid, sizeof(riid))
&& IsValidInterface(pUnk)
&& IsValidPtrOut(ppStm, sizeof(*ppStm)))
{
return(wCoMarshalInterThreadInterfaceInStream(riid, pUnk, ppStm));
}
return(E_INVALIDARG);
}
//+-------------------------------------------------------------------------
//
// Function: CoGetInterfaceAndReleaseStream, public
//
// Synopsis: Helper to unmarshal object from stream for inter-thread pass
//
// Arguments: [riid] - interface id
// [pStm] - stream we want to give back to caller
// [ppv] - pointer for returned object
//
// Returns: NOERROR - Unmarshaled object returned
// E_OUTOFMEMORY - out of memory
//
// Algorithm: Validate the input parameters. Unmarshal the stream and
// finally release the stream pointer.
//
// History: 03-Nov-94 Ricksa Created
//
// Notes: This always releases the input stream if stream is valid.
//
//--------------------------------------------------------------------------
HRESULT CoGetInterfaceAndReleaseStream(
LPSTREAM pstm,
REFIID riid,
LPVOID *ppv)
{
// Validate parameters.
if (IsValidInterface(pstm) &&
(&riid != NULL) &&
IsValidPtrIn(&riid, sizeof(riid)) &&
IsValidPtrOut(ppv, sizeof(*ppv)))
{
return(wCoGetInterfaceAndReleaseStream(pstm, riid, ppv));
}
return(E_INVALIDARG);
}
// The real working section...worker routines. Assume parameter
// validation has already been done and therefore can be used
// internally by COM, STG, SCM etc
WCHAR wszOle1Class[] = L"Ole1Class";
WCHAR wszProgID[] = L"ProgID";
WCHAR wszClassKey[] = L"CLSID\\";
#define ulClassKeyLen ((sizeof(wszClassKey)/sizeof(WCHAR))-1)
//+-------------------------------------------------------------------------
//
// Function: wIsInternalProxyStubIID (internal)
//
// Synopsis: returns the proxystub clsid associated with the specified
// interface IID.
//
// Arguments: [riid] - the interface iid to lookup
// [lpclsid] - where to return the clsid
//
// Returns: S_OK if successfull
// E_OUTOFMEMORY if interface is not an internal one.
//
// Algorithm: See if it is one of the standard format internal IIDs.
// If it is not one of the Automation ones, return our internal
// proxy clsid
//
// History: 15-Feb-95 GregJen create
//
//--------------------------------------------------------------------------
INTERNAL wIsInternalProxyStubIID(REFIID riid, LPCLSID lpclsid)
{
DWORD *ptr = (DWORD *) lpclsid;
HRESULT hr = E_OUTOFMEMORY;
if (*(ptr+1) == 0x00000000 && // all internal iid's have these
*(ptr+2) == 0x000000C0 && // common values
*(ptr+3) == 0x46000000)
{
// make sure it is not an automation iid
if ( *ptr < 0x00020400 )
{
memcpy( lpclsid, &CLSID_PSOlePrx32, sizeof(CLSID));
hr = S_OK;
}
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: wCoTreatAsClass (internal)
//
// Synopsis: set current treat as class if any
//
// Arguments: [clsidOld] - the old classid to look up
// [clsidNew] - the new classid
//
// Returns: S_OK if successful
// REGDB_E_CLASSNOTREG, REGDB_E_READREGDB, REGDB_E_WRITEREGDB
//
//--------------------------------------------------------------------------
INTERNAL wCoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
{
TRACECALL(TRACE_REGISTRY, "wCoTreatAsClass");
HRESULT hresult = S_OK;
HKEY hkeyClsid = NULL;
WCHAR szClsid[VALUE_LEN];
LONG cb = sizeof(szClsid);
CLSID clsidNewTmp;
// The class had better be registered
hresult = wCoOpenClassKey (clsidOld, &hkeyClsid);
if (hresult != S_OK)
{
return hresult;
}
// Save the new clsid because it's a const and we may write into it
clsidNewTmp = clsidNew;
// Convert the new CLSID to a string
Verify(StringFromCLSID2(clsidNew, szClsid, sizeof(szClsid)) != 0);
// If the new CLSID equals the old CLSID, then convert AutoTreatAs, if
// any, to TreatAs.
if (IsEqualCLSID(clsidOld, clsidNew))
{
if (RegQueryValue(hkeyClsid, wszAutoTreatAs, szClsid, &cb) ==
ERROR_SUCCESS)
{
if (wCLSIDFromString(szClsid, &clsidNewTmp) != S_OK)
{
return REGDB_E_INVALIDVALUE;
}
}
// If no AutoTreatAs, remove any TreatAs
else
{
clsidNewTmp = CLSID_NULL;
}
}
// Make sure the new CLSID is not an OLE 1 class
if (CoIsOle1Class(clsidNew))
{
return E_INVALIDARG;
}
// If the new CLSID is CLSID_NULL, then undo the emulation
if (IsEqualCLSID(clsidNewTmp, CLSID_NULL))
{
LONG err = RegDeleteKey(hkeyClsid, wszTreatAs);
if (err != ERROR_SUCCESS)
{
hresult = REGDB_E_WRITEREGDB;
}
else
{
hresult = S_OK;
}
Verify (ERROR_SUCCESS == RegCloseKey(hkeyClsid));
return hresult;
}
if (RegSetValue(hkeyClsid, wszTreatAs, REG_SZ, (LPWSTR) szClsid,
lstrlenW(szClsid)) != ERROR_SUCCESS)
{
hresult = REGDB_E_WRITEREGDB;
}
Verify (ERROR_SUCCESS == RegCloseKey(hkeyClsid));
return hresult;
}
//+-------------------------------------------------------------------------
//
// Function: wCLSIDFromString (internal)
//
// Synopsis: converts string {...} form int guid
//
// Arguments: [lpsz] - ptr to buffer for results
// [lpclsid] - the guid to convert
//
// Returns: NOERROR
// CO_E_CLASSSTRING
//
//--------------------------------------------------------------------------
INTERNAL wCLSIDFromString(LPWSTR lpsz, LPCLSID lpclsid)
{
if (lpsz == NULL)
{
*lpclsid = CLSID_NULL;
return NOERROR;
}
if (*lpsz == 0)
{
return(CO_E_CLASSSTRING);
}
if (lpsz[0] != '{')
{
return wCLSIDFromOle1Class(lpsz, lpclsid);
}
return wGUIDFromString(lpsz,lpclsid)
? NOERROR : CO_E_CLASSSTRING;
}
// translate CLSID into Ole1Class
// REVIEW: might want to have CLSIDFromOle1Class instead of having
// CLSIDFromString do the work.
INTERNAL_(int) wOle1ClassFromCLSID2(REFCLSID rclsid, LPWSTR lpsz, int cbMax)
{
if (wRegQueryClassValue(rclsid, wszOle1Class, lpsz, cbMax) != ERROR_SUCCESS)
{
// Use lookup table
return Ole10_StringFromCLSID (rclsid, lpsz, cbMax) == NOERROR
? lstrlenW (lpsz) : 0;
}
return lstrlenW(lpsz);
}
//+-------------------------------------------------------------------------
//
// Function: wCLSIDFromOle1Class (internal)
//
// Synopsis: translate Ole1Class into clsid
//
// Arguments: [lpsz] - ptr to buffer for results
// [lpclsid] - the guid to convert
//
// Returns: NOERROR
// E_INVALIDARG
// CO_E_CLASSSTRING (not ole1 class)
// REGDB_E_WRITEREGDB
//
//--------------------------------------------------------------------------
INTERNAL wCLSIDFromOle1Class(LPCWSTR lpsz, LPCLSID lpclsid, BOOL fForceAssign)
{
// lookup lpsz\\clsid and call CLSIDFromString on the result;
// in a pathalogical case, this could infinitely recurse.
WCHAR sz[256];
LONG cbValue = sizeof(sz);
if (lpsz == NULL)
{
return(E_INVALIDARG);
}
if (*lpsz == 0)
{
return(CO_E_CLASSSTRING);
}
lstrcpyW(sz, lpsz);
lstrcatW(sz, L"\\Clsid");
if (RegQueryValue(HKEY_CLASSES_ROOT, sz, sz, &cbValue) == ERROR_SUCCESS)
{
return wCLSIDFromString(sz, lpclsid);
}
// Use lookup table or hash string to create CLSID
return Ole10_CLSIDFromString (lpsz, lpclsid, fForceAssign);
}
//+-------------------------------------------------------------------------
//
// Function: wCoGetTreatAsClass (internal)
//
// Synopsis: get current treat as class if any
//
// Arguments: [clsidOld] - the classid to look up
// [pclsidNew] - returned classid
//
// Returns: S_OK when there is a TreatAs entry.
// S_FALSE when there is no TreatAs entry.
// REGDB_E_READREGDB or same as CLSIDFromString
//
//--------------------------------------------------------------------------
INTERNAL wCoGetTreatAsClass(REFCLSID clsidOld, LPCLSID lpClsidNew)
{
TRACECALL(TRACE_REGISTRY, "wCoGetTreatAsClass");
// lookup HKEY_CLASSES_ROOT\CLSID\{rclsid}\TreatAs
HRESULT hresult;
HKEY hkeyClsid = NULL;
WCHAR szClsid[VALUE_LEN];
LONG cb = sizeof(szClsid);
VDATEPTROUT (lpClsidNew, CLSID);
hresult = wCoOpenClassKey (clsidOld, &hkeyClsid);
if (hresult != NOERROR)
{
// same as no TreatAs case below
*lpClsidNew = clsidOld;
return S_FALSE;
}
CairoleDebugOut((DEB_REG, "RegQueryValue(%ws)\n", wszTreatAs));
// Fetch the TreatAs class from the registry
if (RegQueryValue(hkeyClsid, wszTreatAs, szClsid, &cb) == ERROR_SUCCESS)
{
hresult = wCLSIDFromString(szClsid, lpClsidNew);
}
// There is no TreatAs
else
{
*lpClsidNew = clsidOld;
hresult = S_FALSE;
}
Verify (ERROR_SUCCESS==RegCloseKey(hkeyClsid));
return hresult;
}
//+-------------------------------------------------------------------------
//
// Function: wRegQueryPSClsid (private)
//
// Synopsis: reads the proxystub clsid entry out of the registry.
//
// Arguments: [riid] - the interface iid to lookup
// [lpclsid] - where to return the clsid
//
// Returns: S_OK if successfull
// REGDB_E_IIDNOTREG if interface is not registered.
// REGDB_E_READREGDB if any other error
//
// Notes: this is an internal function used only if the requested IID
// entry is not in the shared memory table and the table is full.
//
// History: 07-Apr-94 Rickhi extracted from original source
// 04-Feb-96 BruceMa Per-user registry support
//
//--------------------------------------------------------------------------
INTERNAL wRegQueryPSClsid(REFIID riid, LPCLSID lpclsid)
{
// lookup HKEY_CLASSES_ROOT\Interface\{iid}\ProxyStubClsid
WCHAR szKey[KEY_LEN];
WCHAR szValue[VALUE_LEN];
ULONG cbValue = sizeof(szValue);
HKEY hIf;
DWORD dwType;
lstrcpyW(szKey, wszInterfaceKey);
// translate riid into string
int cbIid = StringFromIID2(riid, &szKey[ulInterfaceKeyLen],
sizeof(szKey)-ulInterfaceKeyLen);
CairoleAssert((cbIid != 0) && "wRegQueryPSClsid");
lstrcpyW(&szKey[ulInterfaceKeyLen+cbIid-1], wszProxyStubClsid);
CairoleDebugOut((DEB_REG, "RegOpenKeyEx(%ws)\n", szKey));
#ifdef DCOM
CDllShrdTbl *pShrdTbl = GetSharedTbl();
if (pShrdTbl == NULL)
{
return REGDB_E_IIDNOTREG;
}
#endif
int err = RegOpenKeyEx(HKEY_CLASSES_ROOT, szKey, NULL, KEY_READ, &hIf);
if (err == ERROR_SUCCESS)
{
// The unnamed value is the clsid for this iid
RegQueryValueEx(hIf, NULL, NULL, &dwType, (BYTE *) szValue,
&cbValue);
RegCloseKey(hIf);
return wCLSIDFromString(szValue, lpclsid);
}
else
{
// If the key is missing, check to see if it is IDispatch
//
// There wasn't a ProxyStubClsid32 for this interface.
// Because many applications install with interfaces
// that are variations on IDispatch, we are going to check
// to see if there is a ProxyStubClsid. If there is, and its
// class is that of IDispatch, then the OLE Automation DLL is
// the correct one to use. In that particular case, we will
// pretend that ProxyStubClsid32 existed, and that it is
// for IDispatch.
lstrcpyW(&szKey[ulInterfaceKeyLen+cbIid-1], wszProxyStubClsid16);
if(RegQueryValue(HKEY_CLASSES_ROOT, szKey, szValue, (LONG*)&cbValue) == ERROR_SUCCESS)
{
CLSID clsid;
if((wCLSIDFromString(szValue,&clsid) == NOERROR) &&
memcmp(&CLSID_PSDispatch,&clsid,sizeof(clsid)) == 0)
{
CairoleDebugOut((DEB_WARN,
"Substituting IDispatch based on ProxyStubClsid\n"));
memcpy(lpclsid,&CLSID_PSDispatch,sizeof(CLSID));
return(NOERROR);
}
}
}
CairoleDebugOut((DEB_WARN, "Missing 'ProxyStubClsid32' registry entry for interface.\n"));
return REGDB_E_IIDNOTREG;
}
#ifndef _CHICAGO_
//+-------------------------------------------------------------------------
//
// Function: GetSharedTbl (internal)
//
// Synopsis: returns ptr to the shared memory cache. Creates it if needed.
//
// History: 25-Oct-95 Rickhi Created
//
//+-------------------------------------------------------------------------
CDllShrdTbl *GetSharedTbl(void)
{
if (g_pShrdTbl == NULL)
{
// since two threads could call this simultaneously, we take
// a lock around it and check the ptr value again.
COleStaticLock lck(gmxsOleMisc);
if (g_pShrdTbl == NULL)
{
// intialize the shared memory tables. we allocate the
// CDllShrdTbl instead of using a static object because
// its constructor opens a mutex, and we dont want that
// open unless CoInitialize is called.
HRESULT hr = E_OUTOFMEMORY;
g_pShrdTbl = new CDllShrdTbl(hr);
if (FAILED(hr))
{
// something failed in ctor, delete the table & set ptr to NULL
delete g_pShrdTbl;
g_pShrdTbl = NULL;
}
}
}
return g_pShrdTbl;
}
#endif
//+-------------------------------------------------------------------------
//
// Function: wCoGetPSClsid (internal)
//
// Synopsis: returns the proxystub clsid associated with the specified
// interface IID.
//
// Arguments: [riid] - the interface iid to lookup
// [lpclsid] - where to return the clsid
//
// Returns: S_OK if successfull
// REGDB_E_IIDNOTREG if interface is not registered.
// REGDB_E_READREGDB if any other error
//
// Algorithm: First it looks in the shared memory table for the specified
// IID. If the entry is not found and the table is FULL, it
// will look in the registry itself. I expect this latter case
// to be very rare.
//
// History: 07-Apr-94 Rickhi rewrite
//
//--------------------------------------------------------------------------
INTERNAL wCoGetPSClsid(REFIID riid, LPCLSID lpclsid)
{
TRACECALL(TRACE_REGISTRY, "wCoGetPSClsid");
HRESULT hr = E_OUTOFMEMORY;
#ifndef _CHICAGO_
CDllShrdTbl *pShrdTbl = GetSharedTbl();
if (pShrdTbl)
{
// look for the entry in the shared memory tables.
hr = pShrdTbl->FindPSClsid(riid, lpclsid);
}
#endif
if (hr == E_OUTOFMEMORY || hr == REGDB_E_IIDNOTREG)
{
// there is no cache, look in the registry directly. this error
// is distinguished from the entry not existing in the cache.
hr = wRegQueryPSClsid(riid, lpclsid);
}
#if DBG==1
#ifndef _CHICAGO_
// in debug mode, verify that the cache is consistent with the
// registry value.
if (hr == S_OK)
{
GUID clsidReg;
wRegQueryPSClsid(riid, &clsidReg);
if (memcmp(lpclsid, &clsidReg, sizeof(GUID)) &&
memcmp(lpclsid,&CLSID_PSDispatch,sizeof(GUID)))
Win4Assert(!"Cached IID value not equal to Registry value!");
}
#endif
#endif
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: wCoGetClassExt (internal)
//
// Synopsis: returns the clsid for files with the specified file extension
//
// Arguments: [pszExt] - the file extension to look up
// [pclsid] - where to return the clsid
//
// Returns: S_OK if successfull
// REGDB_E_CLASSNOTREG if extension is not registered.
// REGDB_E_READREGDB if any other error
//
// History: 07-Apr-94 Rickhi added caching
//
//--------------------------------------------------------------------------
INTERNAL wCoGetClassExt(LPCWSTR pwszExt, LPCLSID pclsid)
{
TRACECALL(TRACE_REGISTRY, "wCoGetClassExt");
HRESULT hr = MK_E_INVALIDEXTENSION;
#ifndef _CHICAGO_
//
// we first look in the cache.
//
if (g_cProcessInits > 0)
{
CDllShrdTbl *pShrdTbl = GetSharedTbl();
if (pShrdTbl)
{
hr = g_pShrdTbl->FindClassExt(pwszExt, pclsid);
}
}
if (hr != NOERROR)
#endif
{
//
// Not in cache. Try it manually in case a registry update was
// missed, or in the event that it is a new OLE 1.0 registration.
// New OLE 1.0 registrations are handled specially in ole1guid.cxx
//
hr = wRegGetClassExt(pwszExt, pclsid);
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: wRegGetClassExt (private)
//
// Synopsis: returns the clsid for files with the specified file extension
//
// Arguments: [pszExt] - the file extension to look up
// [pclsid] - where to return the clsid
//
// Returns: S_OK if successfull
// REGDB_E_CLASSNOTREG if extension is not registered.
// REGDB_E_READREGDB if any other error
//
// Notes:
//
// History: 07-Apr-94 Rickhi added caching
// 04-Feb-96 BruceMa Per-user registry support
//
//--------------------------------------------------------------------------
INTERNAL wRegGetClassExt(LPCWSTR lpszExt, LPCLSID pclsid)
{
TRACECALL(TRACE_REGISTRY, "wRegGetClassExt");
HKEY hExt;
int err;
WCHAR szKey[KEY_LEN];
WCHAR szValue[VALUE_LEN];
LONG cbValue = sizeof(szValue);
DWORD dwType;
// Formulate the key
lstrcpyW(szKey, wszCairoRoot);
lstrcatW(szKey, lpszExt);
CairoleDebugOut((DEB_REG, "RegOpenKeyEx(%ws)\n", szKey));
// Open the key
if ((err = RegOpenKeyEx(HKEY_CLASSES_ROOT, lpszExt, NULL, KEY_READ,
&hExt))
!= ERROR_SUCCESS)
{
return REGDB_E_CLASSNOTREG;
}
// The ProgId is this key's unnamed value
if ((err = RegQueryValueEx(hExt, NULL, NULL, &dwType, (BYTE *) szValue,
(ULONG *) &cbValue))
!= ERROR_SUCCESS)
{
RegCloseKey(hExt);
return REGDB_E_CLASSNOTREG;
}
#ifdef DCOM
CDllShrdTbl *pShrdTbl = GetSharedTbl();
if (pShrdTbl == NULL)
{
RegCloseKey(hExt);
return REGDB_E_CLASSNOTREG;
}
#endif
// Translate string into pclsid
RegCloseKey(hExt);
return wCLSIDFromProgID (szValue, pclsid); // normal case
}
#ifdef _CHICAGO_
HANDLE g_hRegPatTblEvent = NULL;
#endif
//+-------------------------------------------------------------------------
//
// Function: wCoGetClassPattern (internal)
//
// Synopsis: attempts to determine the class of a file by looking
// at byte patterns in the file.
//
// Arguments: [hfile] - handle of file to look at
// [pclsid] - the class of object to create
//
// Returns: S_OK - a pattern match was found, pclisd contains the clsid
// MK_E_CANTOPENFILE - cant open the file.
// REGDB_E_CLASSNOTREG - no pattern match was made
//
//--------------------------------------------------------------------------
INTERNAL wCoGetClassPattern(HANDLE hfile, CLSID *pclsid)
{
TRACECALL(TRACE_REGISTRY, "wCoGetClassPattern");
HRESULT hr = REGDB_E_CLASSNOTREG;
#ifndef _CHICAGO_
CDllShrdTbl *pShrdTbl = GetSharedTbl();
if (pShrdTbl)
{
if (SUCCEEDED(pShrdTbl->FindPattern(hfile, pclsid)))
{
return S_OK;
}
#ifdef REVISIT_PERSONAL_CLASSES_FOR_NT50
// NT 5.0
// If PersonalClasses is turned on then search the registry
// if (pShrdTbl->GetPersonalClasses())
// return wRegGetClassPattern(hfile, pclsid);
#endif
}
return hr;
#else // !_CHICAGO_
// Check whether our pattern table has been initialized
if(g_pPatTbl == NULL)
{
// Create an event we'll use to signal when the registry
// has changed.
if (g_hRegPatTblEvent == NULL)
{
g_hRegPatTblEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
}
// Force the event so we can initialize the pattern cache
SetEvent(g_hRegPatTblEvent);
}
// If the registry has changed since we were here last then reload
// the pattern table
DWORD dwState = WaitForSingleObject(g_hRegPatTblEvent, 0);
if (dwState == WAIT_OBJECT_0)
{
// Remove any previous pattern cache
delete g_pPatTbl;
// Reload the cache
g_pPatTbl = new CChicoPatternTbl(hr);
if (FAILED(hr))
{
return hr;
}
}
// Check the file for registered patterns
hr = g_pPatTbl->FindPattern(hfile, pclsid);
return hr;
#endif // _CHICAGO_
}
#ifndef _CHICAGO_
// BUGBUG: BruceMa 05-Feb-96. The following code duplicates code in
// com\inc\shrtbls.cxx and com\inc\pattbl.cxx. These two versions need to
// be coalesced by making a utility class. I don't have time to do this
// now because dcom beta is breathing down my neck!
//+-------------------------------------------------------------------------
//
// Function: IsValidPattern
//
// Synopsis: Determines if the pattern entry read from the registry is of
// a valid format. See ParseEntry for the format.
//
// Arguments: [psz] - pattern buffer
// [cb] - size of buffer read
//
// Returns: TRUE if pattern is valid, FALSE otherwise
//
//--------------------------------------------------------------------------
BOOL IsValidPattern(LPWSTR psz, LONG cb)
{
// We must find exactly 3 commas before the end of the string
// in order for the entry to be of a parseable format.
ULONG cCommas = 0;
LPWSTR pszEnd = psz + (cb / sizeof(WCHAR));
while (psz < pszEnd && *psz)
{
if (*psz == ',')
cCommas++;
psz++;
}
return (cCommas == 3) ? TRUE : FALSE;
}
//+-------------------------------------------------------------------------
//
// Functon: SkipToNext
//
// Synopsis: Skips missing entries in the list and whitespaces
//
// Arguments: [sz] - ptr to string
//
// Returns: ptr to next entry in the list
//
//--------------------------------------------------------------------------
LPWSTR SkipToNext(LPWSTR sz)
{
while (*sz && *sz != ',')
{
sz++;
}
Assert(*sz == ',');
sz++;
while (*sz)
{
USHORT CharType[1];
GetStringTypeW (CT_CTYPE1, sz, 1, CharType);
if ((CharType[0] & C1_SPACE) == 0)
{
break;
}
sz++;
}
return sz;
}
//+-------------------------------------------------------------------------
//
// Function: ToHex
//
// Synopsis: Converts two characters to a hex byte
//
// Arguments: [psz] - ptr to string
//
// Returns: The value of the string in hex
//
//--------------------------------------------------------------------------
BYTE ToHex(LPWSTR psz)
{
BYTE bMask = 0xFF;
USHORT CharTypes[2];
GetStringTypeW (CT_CTYPE1, psz, 2, CharTypes);
if (CharTypes[0] & C1_XDIGIT)
{
bMask = CharTypes[0] & C1_DIGIT ? *psz - '0' : (BYTE)CharUpperW((LPWSTR)*psz) - 'A' + 10;
psz++;
if (CharTypes[1] & C1_XDIGIT)
{
bMask *= 16;
bMask += CharTypes[1] & C1_DIGIT ? *psz - '0' : (BYTE)CharUpperW((LPWSTR)*psz) - 'A' + 10;
psz++;
}
}
return bMask;
}
//+-------------------------------------------------------------------------
//
// Function: ParsePattern (internal)
//
// Synopsis: Parse a FileType class pattern
//
// Arguments: [psz] - The pattern as read from the registry
// [cb] - Length of pattern in bytes
// [pEntry] - Where to store the parwsed pattern
// [rclsid] - The associated clsid
//
// Returns: TRUE if pattern parsed successfully
// FALSE otherwise
//
// History: 05-Feb-96 BruceMa Created
//
//--------------------------------------------------------------------------
BOOL ParsePattern(LPWSTR psz,
LONG cb,
SPatternEntry *pEntry,
REFCLSID rclsid)
{
// Validate the pattern before we attempt to parse it, simplifies
// error handling in the rest of the routine.
if (!IsValidPattern(psz, cb))
{
return FALSE;
}
// Copy in the clsid
memcpy(&pEntry->clsid, &rclsid, sizeof(CLSID));
// Get the file offset
pEntry->lFileOffset = wcstol(psz, NULL, 0);
psz = SkipToNext(psz);
// Get the byte count
pEntry->ulCb = wcstol(psz, NULL, 0);
Assert(pEntry->ulCb > 0);
// Get the mask ptrs
LPWSTR pszMask = SkipToNext(psz);
BYTE *pbMask = pEntry->abData;
// Get the pattern ptrs
LPWSTR pszPattern = SkipToNext(pszMask);
BYTE *pbPattern = pbMask + pEntry->ulCb;
// Convert and copy the mask & pattern bytes into the pEntry
for (ULONG ulCb = pEntry->ulCb; ulCb > 0; ulCb--)
{
if (*pszMask == ',')
{
// Missing mask means use 0xff
*pbMask = 0xff;
}
else
{
// Convert the mask string to a byte
*pbMask = ToHex(pszMask);
pszMask += 2;
}
pbMask++;
// Convert the pattern string to a byte
*pbPattern = ToHex(pszPattern);
pbPattern++;
pszPattern += 2;
}
// Compute this entry size, rounded to 8 byte alignment.
// Note: the struct has 4 bytes in abData, so the sizeof
// returns 4 more than we need.
pEntry->ulEntryLen = ((sizeof(SPatternEntry) - 4 +
(2 * pEntry->ulCb) + 7) & 0xfff8);
return TRUE;
}
//+-------------------------------------------------------------------------
//
// Function: Matches
//
// Synopsis: Checks if the bytes in the buffer match the given pattern
//
// Arguments: [pFileBuf] - Buffer containing the file data
// [pPattern] - Pattern to match
//
// Returns: TRUE if found, FALSE otherwise.
//
//--------------------------------------------------------------------------
BOOL Matches(BYTE *pFileBuf, SPatternEntry *pPattern)
{
// The pattern bytes follow the mask bytes. They are the same size.
BYTE *pbMask = pPattern->abData;
BYTE *pbPattern = pbMask + pPattern->ulCb;
for (ULONG iCtr = 0; iCtr < pPattern->ulCb; iCtr++)
{
if ((BYTE)(*(pFileBuf + iCtr) & *pbMask) != *pbPattern)
{
return FALSE;
}
// update the mask & pattern bytes
pbMask++;
pbPattern++;
}
return TRUE;
}
//+-------------------------------------------------------------------------
//
// Function: SearchForPattern
//
// Synopsis: Searches in the file for a given pattern
//
// Arguments: [hFile] - Handle to the file to look in
// [pPattern] - The pattern to search for
//
// Returns: TRUE if pattern found, FALSE otherwise.
//
//--------------------------------------------------------------------------
BOOL SearchForPattern(HANDLE hFile, SPatternEntry *pPattern)
{
LONG lLastOffset = 0;
ULONG ulLastCb = 0;
BYTE bStackBuf[256];
BYTE *pBuf;
// Allocate a file read buffer
pBuf = (BYTE *) PrivMemAlloc(1024);
if (pBuf == NULL)
{
return FALSE;
}
// Now grovel through the file looking for a pattern match
BOOL fLook = TRUE;
if (pPattern->lFileOffset != lLastOffset ||
pPattern->ulCb > ulLastCb)
{
// Must read part of the file
DWORD cbRead = 0;
DWORD dwMethod;
LONG cbMove;
if (pPattern->lFileOffset < 0)
{
cbMove = -1;
dwMethod = FILE_END;
}
else
{
cbMove = 0;
dwMethod = FILE_BEGIN;
}
fLook = FALSE; // assume failure
if (SetFilePointer(hFile, pPattern->lFileOffset, &cbMove, dwMethod)
!= 0xffffffff)
{
if (ReadFile(hFile, pBuf, pPattern->ulCb, &cbRead, NULL))
{
fLook = TRUE;
}
}
}
// Free the file read buffer
PrivMemFree(pBuf);
// Compare
return fLook && Matches(pBuf, pPattern);
}
//+-------------------------------------------------------------------------
//
// Function: wRegGetClassPattern (internal)
//
// Synopsis: Attempts to determine the clsid of a file based on file
// patterns
//
// Arguments: [hfile] - handle of file to look at
// [pclsid] - where to store the determined clsid
//
// Returns: S_OK - a pattern match was found, pclisd contains the clsid
// REGDB_E_CLASSNOTREG - no pattern match was made
//
// Notes: This is called only if the file patterns for the given clsid
// could not be found in the shared memory pattern cache.
//
// History: 04-Feb-96 BruceMa Created
//
//--------------------------------------------------------------------------
INTERNAL wRegGetClassPattern(HANDLE hFile, CLSID *pclsid)
{
HRESULT hr = REGDB_E_CLASSNOTREG;
HKEY hkFileType;
SPatternEntry *pPattern;
#ifdef DCOM
CDllShrdTbl *pShrdTbl = GetSharedTbl();
// Check that we can access the shared table
if (pShrdTbl == NULL)
{
return hr;
}
#endif
// Allocate storage to hold a class pattern
pPattern = (SPatternEntry *) PrivMemAlloc(sizeof(SPatternEntry) + 128);
if (pPattern == NULL)
{
return E_OUTOFMEMORY;
}
// Open the class pattern entries
if (RegOpenKey(HKEY_CLASSES_ROOT, L"FileType", &hkFileType)
== ERROR_SUCCESS)
{
// Enumerate the clsid's under this key
WCHAR szBuf[40];
DWORD iClsid = 0;
while (RegEnumKey(hkFileType, iClsid, szBuf, sizeof(szBuf))
== ERROR_SUCCESS)
{
// Ensure this is a valid clsid
WCHAR szTemp[MAX_PATH];
LONG cbTemp = sizeof(szTemp);
WCHAR szClsid[80];
lstrcpyW(szClsid, L"Clsid\\");
lstrcatW(szClsid, szBuf);
if (RegQueryValue(HKEY_CLASSES_ROOT, szClsid, szTemp, &cbTemp)
== ERROR_SUCCESS)
{
// Clsid exists, open the key and enumerate the entries.
HKEY hkClsid;
CLSID clsid;
BOOL fValid;
// Fetch asociated file patterns only if CLSID is valid
if (GUIDFromString(szBuf, &clsid) &&
RegOpenKey(hkFileType, szBuf, &hkClsid) == ERROR_SUCCESS)
{
// Enumerate the patterns under this clsid
WCHAR szNum[10];
DWORD iPattern = 0;
while (RegEnumKey(hkClsid, iPattern, szNum, sizeof(szNum))
== ERROR_SUCCESS)
{
// Read the registry value and parse the string to
// create a class pattern
WCHAR szPattern[512];
LONG cb = sizeof(szPattern);
if (RegQueryValue(hkClsid, szNum, szPattern, &cb) ==
ERROR_SUCCESS)
{
// Parse this entry
if (ParsePattern(szPattern, cb, pPattern, clsid))
{
// Check the file for this pattern
if (SearchForPattern(hFile, pPattern))
{
memcpy(pclsid, &clsid, sizeof(CLSID));
RegCloseKey(hkClsid);
RegCloseKey(hkFileType);
return S_OK;
}
}
}
++iPattern;
}
RegCloseKey(hkClsid);
}
}
++iClsid;
}
RegCloseKey(hkFileType);
}
PrivMemFree(pPattern);
return hr;
}
#endif // !_CHICAGO_
//+-------------------------------------------------------------------------
//
// Function: wCoCreateInstance (internal)
//
// Synopsis: helper function to create instance in given context
//
// Arguments: [rclsid] - the class of object to create
// [pUnkOuter] - the controlling unknown (for aggregation)
// [dwContext] - class context
// [riid] - interface id
// [ppv] - pointer for returned object
//
// Returns: REGDB_E_CLASSNOTREG, REGDB_E_READREGDB, REGDB_E_WRITEREGDB
//
//--------------------------------------------------------------------------
INTERNAL wCoCreateInstance(
REFCLSID rclsid,
LPUNKNOWN pUnkOuter,
DWORD dwContext,
REFIID riid,
LPVOID FAR* ppv)
{
TRACECALL(TRACE_ACTIVATION, "wCoCreateInstance");
#ifdef DCOM
MULTI_QI OneQI;
HRESULT hr;
OneQI.pItf = NULL;
OneQI.pIID = &riid;
hr = CoCreateInstanceEx( rclsid, pUnkOuter, dwContext, NULL, 1, &OneQI );
*ppv = OneQI.pItf;
return hr;
#else
IClassFactory FAR* pCF = NULL;
*ppv = NULL;
HRESULT hr = IOldCoGetClassObject(rclsid, dwContext, NULL,
IID_IClassFactory, (void FAR* FAR*)&pCF);
if (SUCCEEDED(hr))
{
hr = pCF->CreateInstance(pUnkOuter, riid, ppv);
pCF->Release();
}
return hr;
#endif
}
//+-------------------------------------------------------------------------
//
// Function: wCoMarshalInterThreadInterfaceInStream, (internal)
//
// Synopsis: helper function to a marshaled buffer to be passed
// between threads.
//
// Arguments: [riid] - interface id
// [pUnk] - ptr to interface we want to marshal
// [ppStm] - stream we want to give back to caller
//
// Returns: NOERROR - Stream returned
// E_INVALIDARG - Input parameters are invalid
// E_OUTOFMEMORY - memory stream could not be created.
//
// Algorithm: Create a stream and finally marshal
// the input interface into the stream.
//
// History: 03-Nov-94 Ricksa Created
//
//--------------------------------------------------------------------------
INTERNAL_(HRESULT) wCoMarshalInterThreadInterfaceInStream(
REFIID riid,
LPUNKNOWN pUnk,
LPSTREAM *ppStm)
{
HRESULT hr;
LPSTREAM pStm = NULL;
// Assume error
hr = E_OUTOFMEMORY;
// Create a stream
pStm = CreateMemStm(EST_INPROC_MARSHAL_SIZE, NULL);
if (pStm != NULL)
{
// Marshal the interface into the stream
hr = CoMarshalInterface(pStm, riid, pUnk, MSHCTX_INPROC, NULL,
MSHLFLAGS_NORMAL);
}
if (SUCCEEDED(hr))
{
// Reset the stream to the begining
LARGE_INTEGER li;
LISet32(li, 0);
pStm->Seek(li, STREAM_SEEK_SET, NULL);
// Set the return value
*ppStm = pStm;
}
else
{
// Cleanup if failure
if (pStm != NULL)
{
pStm->Release();
}
*ppStm = NULL;
}
// Assert
// Return the result
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: wCoGetInterfaceAndReleaseStream, (internal)
//
// Synopsis: Helper to unmarshal object from stream for inter-thread pass
//
// Arguments: [riid] - interface id
// [pStm] - stream we want to give back to caller
// [ppv] - pointer for returned object
//
// Returns: NOERROR - Unmarshaled object returned
// E_OUTOFMEMORY - out of memory
//
// Algorithm: Unmarshal the stream and
// finally release the stream pointer.
//
// History: 03-Nov-94 Ricksa Created
//
// Notes: This always releases the input stream if stream is valid.
//
//--------------------------------------------------------------------------
INTERNAL_(HRESULT) wCoGetInterfaceAndReleaseStream(
LPSTREAM pstm,
REFIID riid,
LPVOID *ppv)
{
HRESULT hr;
// Unmarshal the interface
hr = CoUnmarshalInterface(pstm, riid, ppv);
// Release the stream since that is the way the function is defined.
pstm->Release();
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: HexStringToDword (private)
//
// Synopsis: scan lpsz for a number of hex digits (at most 8); update lpsz
// return value in Value; check for chDelim;
//
// Arguments: [lpsz] - the hex string to convert
// [Value] - the returned value
// [cDigits] - count of digits
//
// Returns: TRUE for success
//
//--------------------------------------------------------------------------
static BOOL HexStringToDword(LPCWSTR FAR& lpsz, DWORD FAR& Value,
int cDigits, WCHAR chDelim)
{
int Count;
Value = 0;
for (Count = 0; Count < cDigits; Count++, lpsz++)
{
if (*lpsz >= '0' && *lpsz <= '9')
Value = (Value << 4) + *lpsz - '0';
else if (*lpsz >= 'A' && *lpsz <= 'F')
Value = (Value << 4) + *lpsz - 'A' + 10;
else if (*lpsz >= 'a' && *lpsz <= 'f')
Value = (Value << 4) + *lpsz - 'a' + 10;
else
return(FALSE);
}
if (chDelim != 0)
return *lpsz++ == chDelim;
else
return TRUE;
}
//+-------------------------------------------------------------------------
//
// Function: wUUIDFromString (internal)
//
// Synopsis: Parse UUID such as 00000000-0000-0000-0000-000000000000
//
// Arguments: [lpsz] - Supplies the UUID string to convert
// [pguid] - Returns the GUID.
//
// Returns: TRUE if successful
//
//--------------------------------------------------------------------------
INTERNAL_(BOOL) wUUIDFromString(LPCWSTR lpsz, LPGUID pguid)
{
DWORD dw;
if (!HexStringToDword(lpsz, pguid->Data1, sizeof(DWORD)*2, '-'))
return FALSE;
if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-'))
return FALSE;
pguid->Data2 = (WORD)dw;
if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-'))
return FALSE;
pguid->Data3 = (WORD)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[0] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, '-'))
return FALSE;
pguid->Data4[1] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[2] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[3] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[4] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[5] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[6] = (BYTE)dw;
if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0))
return FALSE;
pguid->Data4[7] = (BYTE)dw;
return TRUE;
}
//+-------------------------------------------------------------------------
//
// Function: wGUIDFromString (internal)
//
// Synopsis: Parse GUID such as {00000000-0000-0000-0000-000000000000}
//
// Arguments: [lpsz] - the guid string to convert
// [pguid] - guid to return
//
// Returns: TRUE if successful
//
//--------------------------------------------------------------------------
INTERNAL_(BOOL) wGUIDFromString(LPCWSTR lpsz, LPGUID pguid)
{
DWORD dw;
if (*lpsz++ != '{' )
return FALSE;
if(wUUIDFromString(lpsz, pguid) != TRUE)
return FALSE;
lpsz +=36;
if (*lpsz++ != '}' )
return FALSE;
if (*lpsz != '\0') // check for zero terminated string - test bug #18307
{
return FALSE;
}
return TRUE;
}
//+-------------------------------------------------------------------------
//
// Function: wStringFromCLSID (internal)
//
// Synopsis: converts GUID into {...} form.
//
// Arguments: [rclsid] - the guid to convert
// [lplpsz] - ptr to buffer for results
//
// Returns: NOERROR
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
INTERNAL wStringFromCLSID(REFCLSID rclsid, LPWSTR FAR* lplpsz)
{
WCHAR sz[CLSIDSTR_MAX];
Verify(StringFromCLSID2(rclsid, sz, CLSIDSTR_MAX) != 0);
*lplpsz = UtDupString(sz);
return *lplpsz != NULL ? NOERROR : E_OUTOFMEMORY;
}
//+-------------------------------------------------------------------------
//
// Function: wStringFromIID (internal)
//
// Synopsis: converts GUID into {...} form.
//
// Arguments: [rclsid] - the guid to convert
// [lplpsz] - ptr to buffer for results
//
// Returns: NOERROR
// E_OUTOFMEMORY
//
//--------------------------------------------------------------------------
INTERNAL wStringFromIID(REFIID rclsid, LPWSTR FAR* lplpsz)
{
WCHAR sz[IIDSTR_MAX];
*lplpsz = NULL;
if (StringFromIID2(rclsid, sz, IIDSTR_MAX) != 0)
{
*lplpsz = UtDupString(sz);
}
return *lplpsz != NULL ? NOERROR : E_OUTOFMEMORY;
}
//+-------------------------------------------------------------------------
//
// Function: wIIDFromString (internal)
//
// Synopsis: converts string {...} form int guid
//
// Arguments: [lpsz] - ptr to buffer for results
// [lpiid] - the guid to convert
//
// Returns: NOERROR
// CO_E_CLASSSTRING
//
//--------------------------------------------------------------------------
INTERNAL wIIDFromString(LPWSTR lpsz, LPIID lpiid)
{
if (lpsz == NULL)
{
*lpiid = IID_NULL;
return NOERROR;
}
return wGUIDFromString(lpsz, lpiid)
? NOERROR : CO_E_IIDSTRING;
}
//+-------------------------------------------------------------------------
//
// Function: wCoIsOle1Class (internal)
//
// Synopsis: reads the Ole1Class entry in the registry for the given clsid
//
// Arguments: [rclsid] - the classid to look up
//
// Returns: TRUE if Ole1Class
// FALSE otherwise
//
//--------------------------------------------------------------------------
INTERNAL_(BOOL) wCoIsOle1Class(REFCLSID rclsid)
{
TRACECALL(TRACE_REGISTRY, "wCoIsOle1Class");
CairoleDebugOut((DEB_REG, "wCoIsOle1Class called.\n"));
// since we now have guid, Ole1Class = would indicate OLE 1.0 nature.
// lookup HKEY_CLASSES_ROOT\{rclsid}\Ole1Class
WCHAR szValue[VALUE_LEN];
if (wRegQueryClassValue(rclsid, wszOle1Class, szValue, sizeof(szValue)) != ERROR_SUCCESS)
{
return FALSE;
}
else
{
WORD hiWord = HIWORD(rclsid.Data1);
return hiWord == 3 || hiWord == 4;
}
}
//+-------------------------------------------------------------------------
//
// Function: wkProgIDFromCLSID (internal)
// (wProgIDFromCLSID name is already in use)
//
// Synopsis: convert clsid into progid
//
// Arguments: [rclsid] - the classid to look up
// [pszProgID] - returned progid
//
// Returns: E_INVALIDARG, E_OUTOFMEMORY,
// REGDB_CLASSNOTREG, REGDB_E_READREGDB
//
//--------------------------------------------------------------------------
INTERNAL wkProgIDFromCLSID(REFCLSID rclsid, LPWSTR FAR* ppszProgID)
{
TRACECALL(TRACE_REGISTRY, "wkProgIDFromCLSID");
WCHAR szProgID[KEY_LEN];
*ppszProgID = NULL;
switch (wRegQueryClassValue (rclsid, wszProgID, szProgID, sizeof(szProgID)))
{
case ERROR_SUCCESS:
*ppszProgID = UtDupString (szProgID);
return (*ppszProgID != NULL) ? NOERROR : E_OUTOFMEMORY;
// win32 will return file not found instead of bad key
case ERROR_FILE_NOT_FOUND:
case ERROR_BADKEY:
return REGDB_E_CLASSNOTREG;
default:
return REGDB_E_READREGDB;
}
}
//+-------------------------------------------------------------------------
//
// Function: wRegQueryClassValue (Internal)
//
// Synopsis: reads the specified subkey of the specified clsid
//
// Arguments: [rclsid] - the classid to look up
// [lpszSubKey] - subkey to read
// [lpszValue] - buffer to hold returned value
// [cbMax] - sizeof the buffer
//
// Returns: REGDB_E_CLASSNOTREG, REGDB_E_READREGDB
//
//--------------------------------------------------------------------------
INTERNAL_(LONG) wRegQueryClassValue(REFCLSID rclsid, LPCWSTR lpszSubKey,
LPWSTR lpszValue, int cbMax)
{
WCHAR szKey[KEY_LEN];
int cbClsid;
LONG cbValue = cbMax;
lstrcpyW(szKey, wszClassKey);
// translate rclsid into string
cbClsid = StringFromCLSID2(rclsid, &szKey[ulClassKeyLen],
sizeof(szKey)-ulClassKeyLen);
CairoleAssert((cbClsid != 0) && "wRegQueryClassValue");
szKey[ulClassKeyLen+cbClsid-1] = L'\\';
lstrcpyW(&szKey[ulClassKeyLen+cbClsid], lpszSubKey);
CairoleDebugOut((DEB_REG, "ReqQueryValue(%ws)\n", szKey));
return RegQueryValue(HKEY_CLASSES_ROOT, szKey, lpszValue, &cbValue);
}
//+-------------------------------------------------------------------------
//
// Function: wCoOpenClassKey (internal)
//
// Synopsis: opens a registry key for specified class
//
// Arguments: [rclsid] - the classid to look up
// [pszProgID] - returned progid
//
// Returns: REGDB_CLASSNOTREG, REGDB_E_READREGDB
//
//--------------------------------------------------------------------------
INTERNAL wCoOpenClassKey(REFCLSID clsid, HKEY FAR* lphkeyClsid)
{
TRACECALL(TRACE_REGISTRY, "wCoOpenClassKey");
if (IsEqualCLSID(clsid, CLSID_NULL))
return REGDB_E_CLASSNOTREG;
WCHAR szKey[KEY_LEN];
lstrcpyW (szKey, wszClassKey);
Verify (StringFromCLSID2 (clsid, szKey+ulClassKeyLen,
sizeof(szKey)-ulClassKeyLen) != 0);
switch (RegOpenKey(HKEY_CLASSES_ROOT, szKey, lphkeyClsid))
{
case ERROR_SUCCESS:
return NOERROR;
// win32 will return file not found instead of bad key
case ERROR_FILE_NOT_FOUND:
case ERROR_BADKEY:
return REGDB_E_CLASSNOTREG;
default:
return REGDB_E_READREGDB;
}
}