You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2002 lines
49 KiB
2002 lines
49 KiB
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
|