|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: oregfmt.cpp
//
// Contents: Enumerator implementation for the regdb formatetc's
//
// Classes: CEnumFmt
// CEnumFmt10
//
// Functions: OleRegEnumFormatEtc
//
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH add Dump methods to CEnumFmt, CEnumFmt10
// and add APIs DumpCEnumFmt, DumpCEnumFmt10
// DumpFMT, DumpFMTCache
// 25-Jan-94 alexgo first pass at converting to Cairo-style
// memory allocations.
// 11-Jan-94 alexgo added VDATEHEAP macros to every function
// 31-Dec-93 erikgav chicago port
// 01-Dec-93 alexgo 32bit port
// 12-Nov-92 jasonful author
//
//--------------------------------------------------------------------------
#include <le2int.h>
#pragma SEG(oregfmt)
#include <reterr.h>
#include "oleregpv.h"
#include <ctype.h>
#include <string.h>
#ifdef _DEBUG
#include <dbgdump.h>
#endif // _DEBUG
ASSERTDATA
#define MAX_STR 256
#define UtRemoveRightmostBit(x) ((x)&((x)-1))
#define UtRightmostBit(x) ((x)^UtRemoveRightmostBit(x))
#define UtIsSingleBit(x) ((x) && (0==UtRemoveRightmostBit(x)))
// reg db key
static const LPCOLESTR DATA_FORMATS = OLESTR("DataFormats\\GetSet");
static INTERNAL CreateEnumFormatEtc10 (REFCLSID clsid, DWORD dwDirection, LPENUMFORMATETC FAR* ppenum);
typedef struct FARSTRUCT { FORMATETC fmt; DWORD dwAspects; // aspects not yet returned
BOOL fUseMe; // is the cache valid?
} FMTCACHE;
//+-------------------------------------------------------------------------
//
// Class: CEnumFmt
//
// Purpose: FORMATETC enumerator for regdb formats
//
// Interface: IEnumFORMATETC
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
class FAR CEnumFmt : public IEnumFORMATETC, public CPrivAlloc { public: // *** IUnknown methods ***
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG,AddRef) (THIS); STDMETHOD_(ULONG,Release) (THIS);
// *** IEnumFORMATETC methods ***
STDMETHOD(Next) (THIS_ ULONG celt, FORMATETC FAR * rgelt, ULONG FAR* pceltFetched) ; STDMETHOD(Skip) (THIS_ ULONG celt) ; STDMETHOD(Reset) (THIS) ; STDMETHOD(Clone) (THIS_ LPENUMFORMATETC FAR* ppenum) ;
CEnumFmt (LPOLESTR szClsid, DWORD dwDirection, DWORD iKey=0); STDMETHOD(OpenHKey) (HKEY FAR*);
#ifdef _DEBUG
HRESULT Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel); #endif // _DEBUG
ULONG m_cRef; LPOLESTR m_szClsid; DWORD m_dwDirection; DWORD m_iKey ; // index of current key in reg db
// We cannot keep an hkey open because Clone (or trying to use any 2
// independent enumerators) would fail.
FMTCACHE m_cache; };
// For OLE 1.0
typedef struct { CLIPFORMAT cf; DWORD dw; // DATADIR_GET/SET
} FMT;
#ifdef _DEBUG
// for use in CEnumFmt[10] Dump methods
char *DumpFMT(FMT *pFMT, ULONG ulFlag, int nIndentLevel); char *DumpFMTCACHE(FMTCACHE *pFMTC, ULONG ulFlag, int nIndentLevel); #endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Class: CEnumFmt10 : CEnumFmt
//
// Purpose: Enumerates OLE1.0 formats
//
// Interface: IEnumFORMATETC
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
class FAR CEnumFmt10 : public CEnumFmt { public: STDMETHOD(Next) (THIS_ ULONG celt, FORMATETC FAR * rgelt, ULONG FAR* pceltFetched) ; STDMETHOD(Skip) (THIS_ ULONG celt) ; STDMETHOD(Clone) (THIS_ LPENUMFORMATETC FAR* ppenum) ; STDMETHOD_(ULONG,Release) (THIS) ; CEnumFmt10 (LPOLESTR szClsid, DWORD dwDirection, DWORD iKey=0);
STDMETHOD(InitFromRegDb) (HKEY); STDMETHOD(InitFromScratch) (void);
#ifdef _DEBUG
HRESULT Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel); #endif // _DEBUG
FMT FAR* m_rgFmt; size_t m_cFmt; // number of Fmts in m_rgFmt
};
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::CEnumFmt
//
// Synopsis: Constructor for the formatetc enumerator
//
// Effects:
//
// Arguments: [szClsid] -- the class id to look for
// [dwDirection] -- (either SET or GET)
// [iKey] -- index into the regdb (which formatetc)
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_ctor)
CEnumFmt::CEnumFmt (LPOLESTR szClsid, DWORD dwDirection, DWORD iKey) { VDATEHEAP();
m_cRef = 1; m_szClsid = szClsid; m_iKey = iKey; m_dwDirection = dwDirection; m_cache.fUseMe = FALSE; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt10::CEnumFmt10
//
// Synopsis: Constructor for the 1.0 formatetc enumerator
//
// Effects:
//
// Arguments: [szClsid] -- the class id to look for
// [dwDirection] -- (either SET or GET)
// [iKey] -- index into the regdb (which formatetc)
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt10_ctor)
CEnumFmt10::CEnumFmt10 (LPOLESTR szClsid, DWORD dwDirection, DWORD iKey) : CEnumFmt (szClsid, dwDirection, iKey) { VDATEHEAP();
m_rgFmt = NULL; }
//+-------------------------------------------------------------------------
//
// Function: CreateEnumFormatEtc (static)
//
// Synopsis: Creates a 2.0 formatetc enumerator object
//
// Effects:
//
// Arguments: [clsid] -- the class ID to look for
// [dwDirection] -- the formatetc direction (SET or GET)
// [ppenum] -- where to put the enumerator
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Algorithm: Checks to make sure that the data exists in the reg db
// and then allocates an enumerator object
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CreateEnumFormatEtc)
static INTERNAL CreateEnumFormatEtc (REFCLSID clsid, DWORD dwDirection, LPENUMFORMATETC FAR* ppenum) { VDATEHEAP();
OLECHAR szKey[MAX_STR]; LPOLESTR szClsid = NULL; HKEY hkey = NULL; HKEY hkeyFmts = NULL;
RetErr (StringFromCLSID (clsid, &szClsid)); _xstrcpy (szKey, szClsidRoot); _xstrcat (szKey, szClsid); if (ERROR_SUCCESS != OpenClassesRootKey (szKey, &hkey)) { PubMemFree(szClsid); return ReportResult(0, REGDB_E_CLASSNOTREG, 0, 0); }
if (ERROR_SUCCESS != RegOpenKeyEx (hkey, (LPOLESTR) DATA_FORMATS, 0, KEY_READ, &hkeyFmts)) { CLOSE (hkey); PubMemFree(szClsid); return ReportResult(0, REGDB_E_KEYMISSING, 0, 0); } CLOSE (hkeyFmts); CLOSE (hkey); *ppenum = new FAR CEnumFmt (szClsid, dwDirection); // hook the new interface
CALLHOOKOBJECTCREATE(S_OK,CLSID_NULL,IID_IEnumFORMATETC, (IUnknown **)ppenum); // do not delete szClsid. Will be deleted on Release
return *ppenum ? NOERROR : ResultFromScode (E_OUTOFMEMORY); }
//+-------------------------------------------------------------------------
//
// Function: OleRegEnumFormatEtc
//
// Synopsis: Creates a reg db formatetc enumerator
//
// Effects:
//
// Arguments: [clsid] -- the class ID we're interested in
// [dwDirection] -- either GET or SET (for the formatetc and
// IDataObject->[Get|Set]Data)
// [ppenum] -- where to put the enumerator
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Algorithm: Creates either an OLE2 enumerator or an OLE1 enumerator
//
// History: dd-mmm-yy Author Comment
// 29-Nov-93 ChrisWe allow more than one DATADIR_* flag at a
// time
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(OleRegEnumFormatEtc)
STDAPI OleRegEnumFormatEtc (REFCLSID clsid, DWORD dwDirection, LPENUMFORMATETC FAR* ppenum) { OLETRACEIN((API_OleRegEnumFormatEtc, PARAMFMT("clsid= %I, dwDirection= %x, ppenum= %p"), &clsid, dwDirection, ppenum));
VDATEHEAP();
HRESULT hr;
VDATEPTROUT_LABEL(ppenum, LPENUMFORMATETC, errRtn, hr); *ppenum = NULL;
// check that dwDirection only has valid values
if (dwDirection & ~(DATADIR_GET | DATADIR_SET)) { hr = ResultFromScode(E_INVALIDARG); goto errRtn; }
if (CoIsOle1Class (clsid)) { hr = CreateEnumFormatEtc10 (clsid, dwDirection, ppenum); } else { hr = CreateEnumFormatEtc (clsid, dwDirection, ppenum); }
errRtn: OLETRACEOUT((API_OleRegEnumFormatEtc, hr));
return hr; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::OpenHKey
//
// Synopsis: Opens a the regdb and returns a handle to the formatetc's
//
// Effects:
//
// Arguments: [phkey] -- where to put the regdb handle
//
// Requires:
//
// Returns: NOERROR, REGDB_E_KEYMISSING
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_OpenHKey)
STDMETHODIMP CEnumFmt::OpenHKey (HKEY FAR* phkey) { VDATEHEAP();
VDATEPTRIN (phkey, HKEY); OLECHAR szBuf [MAX_STR];
_xstrcpy (szBuf, szClsidRoot); _xstrcat (szBuf, m_szClsid); _xstrcat (szBuf, OLESTR("\\")); _xstrcat (szBuf, DATA_FORMATS); return ERROR_SUCCESS==OpenClassesRootKey (szBuf, phkey) ? NOERROR : ResultFromScode(REGDB_E_KEYMISSING); }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::Reset
//
// Synopsis: Resets the enumerator
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: NOERROR
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFormatEtc
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_Reset)
STDMETHODIMP CEnumFmt::Reset (void) { VDATEHEAP();
m_iKey = 0; return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::Skip
//
// Synopsis: Skips the next [c] formatetc's
//
// Effects:
//
// Arguments: [c] -- number of formatetc's to skip
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFormatEtc
//
// Algorithm: just calls Next [c] times :)
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_Skip)
STDMETHODIMP CEnumFmt::Skip (ULONG c) { VDATEHEAP();
ULONG i=0; FORMATETC formatetc; HRESULT hresult = NOERROR;
while (i++ < c) { // There will not be a target device to free
ErrRtnH (Next (1, &formatetc, NULL)); }
errRtn: return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::Next
//
// Synopsis: Gets the next formatetc from teh regdb
//
// Effects:
//
// Arguments: [cfmt] -- the number of formatetc's to return
// [rgfmt] -- where to put the formatetc's
// [pcfmtFetched] -- where to put how many formatetc's were
// actually fetched
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFORMATETC
//
// Algorithm: In the reg db, apps may compactly specify that a formatetc
// applies to multiple aspects by simply using the numeric
// value of the aspects or'ed together. Since our enumerator
// should give one formatetc *per* aspect, if multiple aspects
// are specified, then we cache the formatetc and use it the
// next time a formatetc is requested (via next or [cfmt] > 1)
// That's what the m_cache stuff is all about.
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_Next)
STDMETHODIMP CEnumFmt::Next (ULONG cfmt, FORMATETC FAR * rgfmt, ULONG FAR* pcfmtFetched) { VDATEHEAP();
OLECHAR szBuf [MAX_STR]; OLECHAR szKey [80]; DWORD dwAspects; LPOLESTR psz; LONG cb = 0; HKEY hkey = NULL; ULONG ifmt = 0; // number successfully fetched so far
LPOLESTR szFmt = NULL; LPOLESTR szAspects = NULL; LPOLESTR szMedia = NULL; LPOLESTR szDirection = NULL; HRESULT hresult = NOERROR;
RetErr (OpenHKey (&hkey));
while (ifmt < cfmt) { // use the cached value (multiple aspects specified for the
// formatetc.
if (m_cache.fUseMe) { rgfmt[ifmt] = m_cache.fmt; rgfmt[ifmt].dwAspect = UtRightmostBit ( m_cache.dwAspects); m_cache.dwAspects = UtRemoveRightmostBit ( m_cache.dwAspects); if (0==m_cache.dwAspects) m_cache.fUseMe = FALSE; ifmt++; } else { wsprintf (szKey, OLESTR("%d"), m_iKey++); cb = MAX_STR; if (ERROR_SUCCESS == RegQueryValue (hkey, szKey, szBuf, &cb)) { rgfmt[ifmt].ptd = NULL; rgfmt[ifmt].lindex = DEF_LINDEX;
psz = szBuf; ErrZS(*psz, REGDB_E_INVALIDVALUE);
szFmt = psz;
while (*psz && *psz != DELIM[0]) psz++; ErrZS(*psz, REGDB_E_INVALIDVALUE); *psz++ = OLESTR('\0');
szAspects = psz;
while (*psz && *psz != DELIM[0]) psz++; ErrZS(*psz, REGDB_E_INVALIDVALUE); *psz++ = OLESTR('\0');
szMedia = psz;
while (*psz && *psz != DELIM[0]) psz++; ErrZS(*psz, REGDB_E_INVALIDVALUE); *psz++ = OLESTR('\0');
szDirection = psz;
// Format
rgfmt [ifmt].cfFormat = _xisdigit (szFmt[0]) ? (CLIPFORMAT) Atol (szFmt) : (CLIPFORMAT) RegisterClipboardFormat (szFmt); // Aspect
dwAspects = Atol (szAspects); ErrZS (dwAspects, REGDB_E_INVALIDVALUE); if (UtIsSingleBit (dwAspects)) { rgfmt[ifmt].dwAspect = Atol(szAspects); } else { rgfmt[ifmt].dwAspect = UtRightmostBit(dwAspects); m_cache.fmt = rgfmt[ifmt]; m_cache.dwAspects = UtRemoveRightmostBit( dwAspects) & 0xf; if (m_cache.dwAspects != 0) { m_cache.fUseMe = TRUE; } } // Media
rgfmt[ifmt].tymed = Atol (szMedia); if (m_cache.fUseMe) { m_cache.fmt.tymed = rgfmt[ifmt].tymed; } // Direction
if ( (Atol (szDirection) & m_dwDirection) == m_dwDirection) { // This format supports the direction
// we are interested in
ifmt++; } else { m_cache.fUseMe = FALSE; } } else { break; // no more entries
} }// else
}// while
if (pcfmtFetched) { *pcfmtFetched = ifmt; } errRtn: CLOSE (hkey);
if (NOERROR==hresult) { return ifmt==cfmt ? NOERROR : ResultFromScode (S_FALSE); } else { if (pcfmtFetched) { *pcfmtFetched = 0; }
m_cache.fUseMe = FALSE; return hresult; } }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::Clone
//
// Synopsis: clones the enumerator
//
// Effects:
//
// Arguments: [ppenum] -- where to put the cloned enumerator
//
// Requires:
//
// Returns: NOERROR, E_OUTOFMEMORY
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFORMATETC
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_Clone)
STDMETHODIMP CEnumFmt::Clone (LPENUMFORMATETC FAR* ppenum) { VDATEHEAP();
VDATEPTRIN (ppenum, LPENUMFORMATETC); *ppenum = new FAR CEnumFmt (UtDupString(m_szClsid), m_dwDirection, m_iKey); return *ppenum ? NOERROR : ResultFromScode (E_OUTOFMEMORY); }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::QueryInterface
//
// Synopsis: returns supported interfaces
//
// Effects:
//
// Arguments: [iid] -- the requested interface ID
// [ppv] -- where to put the interface pointer
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFormatEtc
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_QueryInterface)
STDMETHODIMP CEnumFmt::QueryInterface(REFIID iid, LPVOID FAR* ppv) { VDATEHEAP();
M_PROLOG(this); if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IEnumFORMATETC)) { *ppv = this; AddRef(); return NOERROR; } else { *ppv = NULL; return ResultFromScode (E_NOINTERFACE); } }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::AddRef
//
// Synopsis: Increments the reference count
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: ULONG -- the new reference count
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFORMATETC
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_AddRef)
STDMETHODIMP_(ULONG) CEnumFmt::AddRef(void) { VDATEHEAP();
M_PROLOG(this); return ++m_cRef; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::Release
//
// Synopsis: decrements the reference count
//
// Effects: may delete this object
//
// Arguments: void
//
// Requires:
//
// Returns: ULONG -- the new reference count
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFORMATETC
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt_Release)
STDMETHODIMP_(ULONG) CEnumFmt::Release(void) { VDATEHEAP();
M_PROLOG(this); if (--m_cRef == 0) { PubMemFree(m_szClsid); delete this; return 0; } return m_cRef; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt::Dump, public (_DEBUG only)
//
// Synopsis: return a string containing the contents of the data members
//
// Effects:
//
// Arguments: [ppszDump] - an out pointer to a null terminated character array
// [ulFlag] - flag determining prefix of all newlines of the
// out character array (default is 0 - no prefix)
// [nIndentLevel] - will add a indent prefix after the other prefix
// for ALL newlines (including those with no prefix)
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies: [ppszDump] - argument
//
// Derivation:
//
// Algorithm: use dbgstream to create a string containing information on the
// content of data structures
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
HRESULT CEnumFmt::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel) { int i; char *pszPrefix; char *pszFMTCACHE; dbgstream dstrPrefix; dbgstream dstrDump;
// determine prefix of newlines
if ( ulFlag & DEB_VERBOSE ) { dstrPrefix << this << " _VB "; }
// determine indentation prefix for all newlines
for (i = 0; i < nIndentLevel; i++) { dstrPrefix << DUMPTAB; }
pszPrefix = dstrPrefix.str();
// put data members in stream
dstrDump << pszPrefix << "No. of References = " << m_cRef << endl;
dstrDump << pszPrefix << "CLSID string = " << m_szClsid << endl;
dstrDump << pszPrefix << "Direction = " << m_dwDirection<< endl;
dstrDump << pszPrefix << "Current Key Index = " << m_iKey << endl;
pszFMTCACHE = DumpFMTCACHE(&m_cache, ulFlag, nIndentLevel + 1); dstrDump << pszPrefix << "FMTCACHE: " << endl; dstrDump << pszFMTCACHE; CoTaskMemFree(pszFMTCACHE);
// cleanup and provide pointer to character array
*ppszDump = dstrDump.str();
if (*ppszDump == NULL) { *ppszDump = UtDupStringA(szDumpErrorMessage); }
CoTaskMemFree(pszPrefix);
return NOERROR; }
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DumpCEnumFmt, public (_DEBUG only)
//
// Synopsis: calls the CEnumFmt::Dump method, takes care of errors and
// returns the zero terminated string
//
// Effects:
//
// Arguments: [pEF] - pointer to CEnumFmt
// [ulFlag] - flag determining prefix of all newlines of the
// out character array (default is 0 - no prefix)
// [nIndentLevel] - will add a indent prefix after the other prefix
// for ALL newlines (including those with no prefix)
//
// Requires:
//
// Returns: character array of structure dump or error (null terminated)
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
char *DumpCEnumFmt(CEnumFmt *pEF, ULONG ulFlag, int nIndentLevel) { HRESULT hresult; char *pszDump;
if (pEF == NULL) { return UtDupStringA(szDumpBadPtr); }
hresult = pEF->Dump(&pszDump, ulFlag, nIndentLevel);
if (hresult != NOERROR) { CoTaskMemFree(pszDump);
return DumpHRESULT(hresult); }
return pszDump; }
#endif // _DEBUG
/////////////////////////////////////////
// OLE 1.0 stuff
//+-------------------------------------------------------------------------
//
// Function: CreateEnumFormatEtc10
//
// Synopsis: Creates a 1.0 format enumerator
//
// Effects:
//
// Arguments: [clsid] -- the class id we're interested in
// [dwDirection] -- either GET or SET
// [ppenum] -- where to put the enumerator
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Algorithm: checks to see if the info's in the reg db, then creates
// and initializes a 1.0 enumerator object. (note that there
// does not *have* to be any info in the regdb, we can
// InitFromScratch)
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CreateEnumFormatEtc10)
static INTERNAL CreateEnumFormatEtc10 (REFCLSID clsid, DWORD dwDirection, LPENUMFORMATETC FAR* ppenum) { VDATEHEAP();
LPOLESTR szClsid = NULL; HKEY hkey = NULL; HKEY hkeyFmts = NULL; HRESULT hresult = NOERROR; BOOL fInReg; CEnumFmt10 FAR* penum; VDATEPTROUT (ppenum, LPENUMFORMATETC); *ppenum = NULL;
RetErr (ProgIDFromCLSID (clsid, &szClsid)); if (ERROR_SUCCESS != OpenClassesRootKey (szClsid, &hkey)) { PubMemFree(szClsid); return ReportResult(0, REGDB_E_CLASSNOTREG, 0, 0); }
// Does this server have "Request/SetDataFormats" keys?
fInReg = (ERROR_SUCCESS == RegOpenKeyEx (hkey, OLESTR("Protocol\\StdFileEditing\\RequestDataFormats"), 0, KEY_READ, &hkeyFmts)); CLOSE(hkeyFmts);
penum = new FAR CEnumFmt10 (szClsid, dwDirection); if (NULL==penum) { ErrRtnH (ResultFromScode (E_OUTOFMEMORY)); }
if (fInReg) { penum->InitFromRegDb (hkey); } else { penum->InitFromScratch (); }
errRtn: CLOSE (hkey); if (hresult == NOERROR) { *ppenum = penum; CALLHOOKOBJECTCREATE(S_OK,CLSID_NULL,IID_IEnumFORMATETC, (IUnknown **)ppenum); } else { PubMemFree(szClsid); // If no error, szClsid will be deleted on Release
} return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt10::Next
//
// Synopsis: Gets the next 1.0 format
//
// Effects:
//
// Arguments: [cfmt] -- the number of formatetc's to get
// [rgfmt] -- where to put the formatetc's
// [pcfmtFetched] -- where to put the num of formatetc's fetched
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFORMATETC
//
// Algorithm: Ole1.0 formats are retrieved when the enumerator object
// is created, so we just return ones from our internal array
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt10_Next)
STDMETHODIMP CEnumFmt10::Next (ULONG cfmt, FORMATETC FAR * rgfmt, ULONG FAR* pcfmtFetched) { VDATEHEAP();
ULONG ifmt = 0; // number successfully fetched so far
while (ifmt < cfmt && m_rgFmt != NULL && m_rgFmt[m_iKey].cf != 0) { if ( (m_rgFmt[m_iKey].dw & m_dwDirection) == m_dwDirection) { // This format supports the direction we are
// interested in
rgfmt [ifmt].cfFormat = m_rgFmt[m_iKey].cf; rgfmt [ifmt].ptd = NULL; rgfmt [ifmt].lindex = DEF_LINDEX; rgfmt [ifmt].tymed = UtFormatToTymed(m_rgFmt[m_iKey].cf); rgfmt [ifmt].dwAspect = DVASPECT_CONTENT; ifmt++; } m_iKey++; } if (pcfmtFetched) *pcfmtFetched = ifmt; return ifmt==cfmt ? NOERROR : ResultFromScode (S_FALSE); }
//+-------------------------------------------------------------------------
//
// Function: Index (static)
//
// Synopsis: finds the index of the given clipformat in the format
// array
//
// Effects:
//
// Arguments: [rgFmt] -- the clipformat array
// [cf] -- the clipformat to look for
// [iMax] -- size of the array
// [pi] -- where to put the index
//
// Requires:
//
// Returns: TRUE if found, FALSE otherwise
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(Index)
static INTERNAL_(BOOL) Index (FMT FAR * rgFmt, CLIPFORMAT cf, // format to search for
size_t iMax, // size of array
size_t FAR* pi) // out parm, index of found format
{ VDATEHEAP();
for (size_t i=0; i< iMax; i++) { if (rgFmt[i].cf==cf) { *pi = i; return TRUE; } } return FALSE; }
//+-------------------------------------------------------------------------
//
// Function: String2Clipformat (static)
//
// Synopsis: Converts a string to a clipboard format number (and then
// registers the format)
//
// Effects:
//
// Arguments: [sz] -- the string to convert
//
// Requires:
//
// Returns: CLIPFORMAT
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(String2Clipformat)
static INTERNAL_(CLIPFORMAT) String2Clipformat (LPOLESTR sz) { VDATEHEAP();
if (_xstrlen(sz) >= 3 && 0==memcmp (sz, OLESTR("CF_"), 3*sizeof(sz[0]))) { #define macro(cf) if (0==_xstricmp (sz, OLESTR(#cf))) return cf
macro (CF_TEXT); macro (CF_BITMAP); macro (CF_METAFILEPICT); macro (CF_SYLK); macro (CF_DIF); macro (CF_TIFF); macro (CF_OEMTEXT); macro (CF_DIB); macro (CF_PALETTE); macro (CF_PENDATA); macro (CF_RIFF); macro (CF_WAVE); macro (CF_OWNERDISPLAY); macro (CF_DSPTEXT); macro (CF_DSPBITMAP); macro (CF_DSPMETAFILEPICT); #undef macro
} return (CLIPFORMAT) RegisterClipboardFormat (sz); }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt10::InitFromRegDb (internal)
//
// Synopsis: Initializes the 1.0 enumerator from the reg db (loads
// all the available formats)
//
// Effects:
//
// Arguments: [hkey] -- handle to the regdb
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
// Original comment:
//
// Fill m_rgFmt with FMTs which map clipformats to Get/Set flags
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt10_InitFromRegDb)
STDMETHODIMP CEnumFmt10::InitFromRegDb (HKEY hkey) // CLSID key
{ VDATEHEAP();
LPOLESTR pch; LPOLESTR szReq = (LPOLESTR)PubMemAlloc(512 * sizeof(OLECHAR)); LPOLESTR szSet = (LPOLESTR)PubMemAlloc(512 * sizeof(OLECHAR)); LPOLESTR szFmt; BOOL bMore; size_t cFmts = 0; size_t iFmt = 0; size_t iFmtPrev; CLIPFORMAT cf; LONG cb; HRESULT hresult = NOERROR;
if( !szReq ) { // assumes delete 0 works (if szSet == 0)
PubMemFree(szSet); return ResultFromScode (E_OUTOFMEMORY); } if( !szSet ) { PubMemFree(szReq); return ResultFromScode (E_OUTOFMEMORY); } cb = 512; if (ERROR_SUCCESS == RegQueryValue (hkey, OLESTR("Protocol\\StdFileEditing\\RequestDataFormats"), szReq, &cb)) { cFmts = 1; // no commas means one format
for (pch = szReq; *pch; pch++) { if (*pch==OLESTR(',')) cFmts++; } }
// the size of szSet
cb = 512; if (ERROR_SUCCESS == RegQueryValue (hkey, OLESTR("Protocol\\StdFileEditing\\SetDataFormats"), szSet, &cb)) { cFmts++; // no commas means one format
for (pch = szSet; *pch; pch++) { if (*pch==OLESTR(',')) cFmts++; } }
if (cFmts==0) { Assert(0); ErrRtnH (ReportResult(0, REGDB_E_KEYMISSING, 0, 0)); }
m_rgFmt = (FMT FAR *)PrivMemAlloc(sizeof(FMT)*(cFmts+1)); if (m_rgFmt==NULL) { ErrRtnH (ResultFromScode (E_OUTOFMEMORY)); }
pch = szReq; bMore = (*pch != 0); while (bMore) { while (*pch == OLESTR(' ')) pch++; szFmt = pch; while (*pch && *pch != DELIM[0]) pch++; if (*pch == 0) bMore = FALSE; *pch++ = OLESTR('\0'); m_rgFmt[iFmt].cf = String2Clipformat(szFmt); m_rgFmt[iFmt++].dw = DATADIR_GET; }
pch = szSet; bMore = (*pch != 0); while (bMore) { while (*pch == OLESTR(' ')) pch++; szFmt = pch; while (*pch && *pch != DELIM[0]) pch++; if (*pch == 0) bMore = FALSE; *pch++ = OLESTR('\0'); cf = String2Clipformat(szFmt); if (Index (m_rgFmt, cf, iFmt, &iFmtPrev)) { // This format can also be gotten
m_rgFmt[iFmtPrev].dw |= DATADIR_SET; } else { m_rgFmt[iFmt].cf = cf; m_rgFmt[iFmt++].dw = DATADIR_SET; } }
// Terminator
m_rgFmt[iFmt].cf = 0; m_cFmt = iFmt;
errRtn: PubMemFree(szReq); PubMemFree(szSet); return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt10::InitFromScratch
//
// Synopsis: Initialize the enumerated formats for a 1.0 server that
// does not specify any Request/SetData formats.
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: HRESULT (NOERROR, E_OUTOFMEMORY)
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm: sets up Metafiles and "Native" formats
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
// The spec says that what EnumFormatEtc returns is not a
// guarantee of support.
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt10_InitFromScratch)
STDMETHODIMP CEnumFmt10::InitFromScratch (void) { VDATEHEAP();
m_rgFmt = (FMT FAR *)PrivMemAlloc(10 * sizeof(FMT)); if( !m_rgFmt ) { return ResultFromScode (E_OUTOFMEMORY); } m_rgFmt[0].cf = CF_METAFILEPICT; m_rgFmt[0].dw = DATADIR_GET; m_rgFmt[1].cf = (CLIPFORMAT) RegisterClipboardFormat (OLESTR("Native")); m_rgFmt[1].dw = DATADIR_GET | DATADIR_SET; m_rgFmt[2].cf = 0; // Terminator
m_cFmt = 2; return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt10::Skip
//
// Synopsis: skips to over [c] formats
//
// Effects:
//
// Arguments: [c] -- the number of formats to skip
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFORMATETC
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes: This is re-implemented so we get the right implementation
// of Next (because C++ is evil OOP).
// REVIEW32: we can probably get rid of this by clever use
// of virtual (but must make sure the vtables don't get hosed).
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt10_Skip)
STDMETHODIMP CEnumFmt10::Skip (ULONG c) { VDATEHEAP();
ULONG i=0; FORMATETC formatetc; HRESULT hresult = NOERROR;
while (i++ < c) { // There will not be a target device to free
ErrRtnH (Next (1, &formatetc, NULL)); }
errRtn: return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt10::Clone
//
// Synopsis: duplicates the 1.0 format enumerator
//
// Effects:
//
// Arguments: [ppenum] -- where to put the cloned enumerator
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFORMATETC
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port, fixed memory leak
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt10_Clone)
STDMETHODIMP CEnumFmt10::Clone (LPENUMFORMATETC FAR* ppenum) { VDATEHEAP();
VDATEPTROUT (ppenum, LPENUMFORMATETC); CEnumFmt10 FAR* penum; penum = new FAR CEnumFmt10 (UtDupString(m_szClsid), m_dwDirection, m_iKey); if (NULL==penum) { return ResultFromScode (E_OUTOFMEMORY); } penum->m_cFmt = m_cFmt; penum->m_rgFmt = (FMT FAR *)PrivMemAlloc((m_cFmt+1) * sizeof(FMT)); if (NULL==penum->m_rgFmt) { delete penum; return ResultFromScode (E_OUTOFMEMORY); } _xmemcpy (penum->m_rgFmt, m_rgFmt, (m_cFmt+1)*sizeof(FMT)); Assert (penum->m_rgFmt[penum->m_cFmt].cf==0); *ppenum = penum; return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt10::Release
//
// Synopsis: decrements the reference count
//
// Effects: may delete the object
//
// Arguments: void
//
// Requires:
//
// Returns: ULONG -- the new reference count
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumFORMATETC
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumFmt10_Release)
STDMETHODIMP_(ULONG) CEnumFmt10::Release(void) { VDATEHEAP();
M_PROLOG(this); if (--m_cRef == 0) { PubMemFree(m_szClsid); PrivMemFree(m_rgFmt); delete this; return 0; } return m_cRef; }
//+-------------------------------------------------------------------------
//
// Member: CEnumFmt10::Dump, public (_DEBUG only)
//
// Synopsis: return a string containing the contents of the data members
//
// Effects:
//
// Arguments: [ppszDump] - an out pointer to a null terminated character array
// [ulFlag] - flag determining prefix of all newlines of the
// out character array (default is 0 - no prefix)
// [nIndentLevel] - will add a indent prefix after the other prefix
// for ALL newlines (including those with no prefix)
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies: [ppszDump] - argument
//
// Derivation:
//
// Algorithm: use dbgstream to create a string containing information on the
// content of data structures
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
HRESULT CEnumFmt10::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel) { int i; unsigned int ui; char *pszPrefix; char *pszCEnumFmt; char *pszFMT; dbgstream dstrPrefix; dbgstream dstrDump;
// determine prefix of newlines
if ( ulFlag & DEB_VERBOSE ) { dstrPrefix << this << " _VB "; }
// determine indentation prefix for all newlines
for (i = 0; i < nIndentLevel; i++) { dstrPrefix << DUMPTAB; }
pszPrefix = dstrPrefix.str();
// put data members in stream
pszCEnumFmt = DumpCEnumFmt((CEnumFmt *)this, ulFlag, nIndentLevel + 1); dstrDump << pszPrefix << "CEnumFmt: " << endl; dstrDump << pszCEnumFmt; CoTaskMemFree(pszCEnumFmt);
dstrDump << pszPrefix << "No. in FMT array = " << (UINT) m_cFmt << endl;
for (ui = 0; ui < m_cFmt; ui++) { pszFMT = DumpFMT(&m_rgFmt[ui], ulFlag, nIndentLevel + 1); dstrDump << pszPrefix << "FMT [" << ui << "]: " << endl; dstrDump << pszFMT; CoTaskMemFree(pszFMT); }
// cleanup and provide pointer to character array
*ppszDump = dstrDump.str();
if (*ppszDump == NULL) { *ppszDump = UtDupStringA(szDumpErrorMessage); }
CoTaskMemFree(pszPrefix);
return NOERROR; }
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DumpCEnumFmt10, public (_DEBUG only)
//
// Synopsis: calls the CEnunFmt10::Dump method, takes care of errors and
// returns the zero terminated string
//
// Effects:
//
// Arguments: [pEF] - pointer to CEnumFmt10
// [ulFlag] - flag determining prefix of all newlines of the
// out character array (default is 0 - no prefix)
// [nIndentLevel] - will add a indent prefix after the other prefix
// for ALL newlines (including those with no prefix)
//
// Requires:
//
// Returns: character array of structure dump or error (null terminated)
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Feb-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
char *DumpCEnumFmt10(CEnumFmt10 *pEF, ULONG ulFlag, int nIndentLevel) { HRESULT hresult; char *pszDump;
if (pEF == NULL) { return UtDupStringA(szDumpBadPtr); }
hresult = pEF->Dump(&pszDump, ulFlag, nIndentLevel);
if (hresult != NOERROR) { CoTaskMemFree(pszDump);
return DumpHRESULT(hresult); }
return pszDump; }
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DumpFMT, public (_DEBUG only)
//
// Synopsis: returns a string containing the contents of the data members
//
// Effects:
//
// Arguments: [pFMT] - a pointer to a FMT object
// [ulFlag] - a flag determining the prefix of all newlines of
// the out character array(default is 0 -no prefix)
// [nIndentLevel] - will add an indent prefix after the other prefix
// for all newlines(include those with no prefix)
//
// Requires:
//
// Returns: character array of structure dump or error (null terminated)
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Jan-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
char *DumpFMT(FMT *pFMT, ULONG ulFlag, int nIndentLevel) { int i; char *pszPrefix; char *pszDump; char *pszCLIPFORMAT; dbgstream dstrPrefix; dbgstream dstrDump;
if (pFMT == NULL) { return UtDupStringA(szDumpBadPtr); }
// determine prefix
if ( ulFlag & DEB_VERBOSE ) { dstrPrefix << pFMT << " _VB "; }
// determine indentation prefix
for (i = 0; i < nIndentLevel; i++) { dstrPrefix << DUMPTAB; }
pszPrefix = dstrPrefix.str();
// put data members in stream
pszCLIPFORMAT = DumpCLIPFORMAT(pFMT->cf); dstrDump << pszPrefix << "Clip format = " << pszCLIPFORMAT << endl; CoTaskMemFree(pszCLIPFORMAT);
dstrDump << pszPrefix << "Dword = " << pFMT->dw << endl;
// cleanup and provide pointer to character array
pszDump = dstrDump.str();
if (pszDump == NULL) { pszDump = UtDupStringA(szDumpErrorMessage); }
CoTaskMemFree(pszPrefix);
return pszDump; }
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DumpFMTCACHE, public (_DEBUG only)
//
// Synopsis: returns a string containing the contents of the data members
//
// Effects:
//
// Arguments: [pFMT] - a pointer to a FMTCACHE object
// [ulFlag] - a flag determining the prefix of all newlines of
// the out character array(default is 0 -no prefix)
// [nIndentLevel] - will add an indent prefix after the other prefix
// for all newlines(include those with no prefix)
//
// Requires:
//
// Returns: character array of structure dump or error (null terminated)
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 23-Jan-95 t-ScottH author
//
// Notes:
//
//--------------------------------------------------------------------------
#ifdef _DEBUG
char *DumpFMTCACHE(FMTCACHE *pFMT, ULONG ulFlag, int nIndentLevel) { int i; char *pszPrefix; char *pszDump; char *pszFORMATETC; char *pszDVASPECT; dbgstream dstrPrefix; dbgstream dstrDump;
if (pFMT == NULL) { return UtDupStringA(szDumpBadPtr); }
// determine prefix
if ( ulFlag & DEB_VERBOSE ) { dstrPrefix << pFMT << " _VB "; }
// determine indentation prefix
for (i = 0; i < nIndentLevel; i++) { dstrPrefix << DUMPTAB; }
pszPrefix = dstrPrefix.str();
// put data members in stream
pszFORMATETC = DumpFORMATETC(&pFMT->fmt, ulFlag, nIndentLevel); dstrDump << pszPrefix << "FORMATETC: " << endl; dstrDump << pszFORMATETC; CoTaskMemFree(pszFORMATETC);
pszDVASPECT = DumpDVASPECTFlags(pFMT->dwAspects); dstrDump << pszPrefix << "Aspect flags: = " << pszDVASPECT << endl; CoTaskMemFree(pszDVASPECT);
dstrDump << pszPrefix << "IsCacheValid? = "; if (pFMT->fUseMe == TRUE) { dstrDump << "TRUE" << endl; } else { dstrDump << "FALSE" << endl; }
// cleanup and provide pointer to character array
pszDump = dstrDump.str();
if (pszDump == NULL) { pszDump = UtDupStringA(szDumpErrorMessage); }
CoTaskMemFree(pszPrefix);
return pszDump; }
#endif // _DEBUG
|