|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: oregverb.cpp
//
// Contents: Implementation of the enumerator for regdb verbs
//
// Classes: CEnumVerb
//
// Functions: OleRegEnumVerbs
//
// History: dd-mmm-yy Author Comment
// 12-Sep-95 davidwor made cache thread-safe
// 08-Sep-95 davidwor optimized caching code
// 12-Jul-95 t-gabes cache verbs and enumerator
// 01-Feb-95 t-ScottH add Dump method to CEnumVerb and API
// DumpCEnumVerb
// 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-93 jasonful author
//
//--------------------------------------------------------------------------
#include <le2int.h>
#pragma SEG(oregverb)
#include <reterr.h>
#include "oleregpv.h"
#ifdef _DEBUG
#include <dbgdump.h>
#endif // _DEBUG
ASSERTDATA
#define MAX_STR 256
#define MAX_VERB 33
#define OLEIVERB_LOWEST OLEIVERB_HIDE
// reg db key
static const OLECHAR VERB[] = OLESTR("\\Verb");
// stdfileediting key
static const OLECHAR STDFILE[] = OLESTR("\\Protocol\\StdFileEditing");
// default verbs
static const OLECHAR DEFVERB[] = OLESTR("Software\\Microsoft\\OLE1\\UnregisteredVerb");
// default verb
static const OLECHAR EDIT[] = OLESTR("Edit");
//+-------------------------------------------------------------------------
//
// Struct: VerbList
//
// Purpose: to hold the enumerator's list of verbs
//
// History: dd-mmm-yy Author Comment
// 12-Jul-95 t-gabes author
//
// Notes:
//
//--------------------------------------------------------------------------
typedef struct VerbList { ULONG cRef; // reference count
CLSID clsid; // CLSID of the cached verbs
ULONG cVerbs; // count of verbs in oleverb array
OLEVERB oleverb[1]; // variable-size list of verbs
} VERBLIST, *LPVERBLIST;
STDAPI MakeVerbList(HKEY hkey, REFCLSID rclsid, LPVERBLIST *ppVerbList); STDAPI OleReleaseEnumVerbCache(void);
//+-------------------------------------------------------------------------
//
// Class: CEnumVerb
//
// Purpose: enumerates the verbs listed in the reg db for a given class
//
// Interface: IEnumOLEVERB
//
// History: dd-mmm-yy Author Comment
// 02-Aug-95 t-gabes rewrote to use cache
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
class FAR CEnumVerb : public IEnumOLEVERB, public CPrivAlloc { // *** IUnknown methods ***
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG,AddRef) (THIS); STDMETHOD_(ULONG,Release) (THIS);
// *** IEnumOLEVERB methods ***
STDMETHOD(Next) (THIS_ ULONG celt, LPOLEVERB reelt, ULONG FAR* pceltFetched); STDMETHOD(Skip) (THIS_ ULONG celt); STDMETHOD(Reset) (THIS); STDMETHOD(Clone) (THIS_ LPENUMOLEVERB FAR* ppenm);
ULONG GetRefCount (void);
#ifdef _DEBUG
HRESULT Dump (char **ppszDump, ULONG ulFlag, int nIndentLevel); friend char *DumpCEnumVerb (CEnumVerb *pEV, ULONG ulFlag, int nIndentLevel); #endif // _DEBUG
private: CEnumVerb (LPVERBLIST pVerbs, LONG iVerb=0);
ULONG m_cRef; // reference count
LONG m_iVerb; // current verb number (0 is the first)
LPVERBLIST m_VerbList; // all the verbs for this class
friend HRESULT STDAPICALLTYPE OleRegEnumVerbs (REFCLSID, LPENUMOLEVERB FAR*); friend HRESULT STDAPICALLTYPE OleReleaseEnumVerbCache(void); };
//+-------------------------------------------------------------------------
//
// Struct: EnumVerbCache
//
// Purpose: to cache the enumerator for the last enumerated class
//
// History: dd-mmm-yy Author Comment
// 12-Jul-95 t-gabes author
//
//
//--------------------------------------------------------------------------
typedef struct { CEnumVerb* pEnum; // pointer to the cached enumerator
#ifdef _DEBUG
LONG iCalls; // total calls counter
LONG iHits; // cache hit counter
#endif // _DEBUG
} EnumVerbCache;
// Last enumerator used
EnumVerbCache g_EnumCache = { NULL };
//+-------------------------------------------------------------------------
//
// Function: OleRegEnumVerbs
//
// Synopsis: Creates an enumerator to go through the verbs in the reg db
// for the given class ID
//
// Effects:
//
// Arguments: [clsid] -- the class ID we're interested in
// [ppenum] -- where to put the enumerator pointer
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Algorithm: Makes sure that the info is in the database and then
// creates the enumerator
//
// History: dd-mmm-yy Author Comment
// 12-Sep-95 davidwor modified to make thread-safe
// 08-Sep-95 davidwor optimized caching code
// 12-Jul-95 t-gabes rewrote to use cache
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(OleRegEnumVerbs)
STDAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB FAR* ppenum) { OLETRACEIN((API_OleRegEnumVerbs, PARAMFMT("clsid= %I, ppenum= %p"), &clsid, ppenum)); VDATEHEAP();
CEnumVerb* pEnum; LPVERBLIST pVerbList; BOOL fOle1Class; OLECHAR szKey[MAX_STR]; int cchBase; HKEY hkey; HRESULT hresult;
VDATEPTROUT_LABEL (ppenum, LPENUMOLEVERB, errSafeRtn, hresult); *ppenum = NULL;
#ifdef _DEBUG
// Increment total calls counter
InterlockedIncrement(&g_EnumCache.iCalls); #endif // _DEBUG
// Grab the global enumerator and put a NULL in its place. If another
// thread calls into OleRegEnumVerbs during this operation they won't
// be able to mess with the enumerator we're working with.
pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, 0); if (pEnum != NULL) { if (IsEqualCLSID(clsid, pEnum->m_VerbList->clsid)) { #ifdef _DEBUG
// Increment cache hits counter
InterlockedIncrement(&g_EnumCache.iHits); #endif
if (1 == pEnum->GetRefCount()) { // No other references -> AddRef and return this copy
*ppenum = pEnum; pEnum->AddRef(); pEnum->Reset(); LEDebugOut((DEB_TRACE, "VERB Enumerator cache handed out\n")); } else { // Has additional references -> return a Cloned copy
if (NOERROR == pEnum->Clone(ppenum)) { (*ppenum)->Reset(); LEDebugOut((DEB_TRACE, "VERB Enumerator cache cloned\n")); } }
// Swap our enumerator with the current contents of the global. If
// another thread called OleRegEnumVerbs during this operation and
// stored an enumerator in the global, we need to Release it.
pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, (PVOID)pEnum); if (pEnum != NULL) { pEnum->Release(); LEDebugOut((DEB_TRACE, "VERB Enumerator cache released (replacing global)\n")); }
goto errRtn; } else { // Our clsid didn't match the clsid of the cache so we'll release the
// cached enumerator and proceed with creating a new enumerator to
// store in the global cache.
pEnum->Release(); LEDebugOut((DEB_TRACE, "VERB Enumerator cache released (different CLSID)\n")); } }
fOle1Class = CoIsOle1Class(clsid);
if (fOle1Class) { // Fills out szKey and cchBase as follows:
// szKey - "<ProgID>\Protocol\StdFileEditing"
// cchBase - length of "<ProgID>" portion
LPOLESTR psz;
RetErr(ProgIDFromCLSID(clsid, &psz));
cchBase = _xstrlen(psz);
memcpy(szKey, psz, cchBase * sizeof(OLECHAR)); memcpy(&szKey[cchBase], STDFILE, sizeof(STDFILE));
PubMemFree(psz); } else { // Fills out szKey and cchBase as follows:
// szKey - "CLSID\{clsid}"
// cchBase - length of full szKey string
memcpy(szKey, szClsidRoot, sizeof(szClsidRoot));
if (0 == StringFromCLSID2(clsid, &szKey[sizeof(szClsidRoot) / sizeof(OLECHAR) - 1], sizeof(szKey))) return ResultFromScode(E_OUTOFMEMORY);
cchBase = _xstrlen(szKey); }
// append "\Verb" to the end
_xstrcat(szKey, VERB);
if (ERROR_SUCCESS != RegOpenKeyEx( HKEY_CLASSES_ROOT, szKey, NULL, KEY_READ, &hkey)) { // verb key doesn't exist, so figure out why
szKey[cchBase] = OLESTR('\0'); // szKey now contains one of the following:
// OLE1 - "<ProgID>"
// OLE2 - "CLSID\{clsid}"
if (ERROR_SUCCESS != RegOpenKeyEx( HKEY_CLASSES_ROOT, szKey, NULL, KEY_READ, &hkey)) { // the class isn't registered
return ReportResult(0, REGDB_E_CLASSNOTREG, 0, 0); }
CLOSE(hkey);
// The class has no verbs. This is fine for OLE1 but not OLE2
if (!fOle1Class) return ResultFromScode(OLEOBJ_E_NOVERBS);
// if hkey is NULL, MakeVerbList will use the default verb
hkey = NULL; }
// make the verb list
RetErr(MakeVerbList(hkey, clsid, &pVerbList)); Assert(pVerbList != NULL);
// create a CEnumVerb object (this calls AddRef on pVerbList)
pEnum = new FAR CEnumVerb(pVerbList); if (NULL == pEnum) { PrivMemFree(pVerbList); hresult = ResultFromScode(E_OUTOFMEMORY); goto errSafeRtn; }
// set the out parameter and AddRef on behalf of the caller
*ppenum = pEnum; pEnum->AddRef();
LEDebugOut((DEB_TRACE, "VERB Enumerator cache created\n"));
// Swap our enumerator with the current contents of the global. If
// another thread called OleRegEnumVerbs during this operation and
// stored an enumerator in the global, we need to Release it.
pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, (PVOID)pEnum); if (pEnum != NULL) { pEnum->Release(); LEDebugOut((DEB_TRACE, "VERB Enumerator cache released (replacing global)\n")); }
errRtn: hresult = *ppenum ? NOERROR : ResultFromScode (E_OUTOFMEMORY);
// hook the new interface
CALLHOOKOBJECTCREATE(S_OK, CLSID_NULL, IID_IEnumOLEVERB, (IUnknown **)ppenum);
errSafeRtn: LEDebugOut((DEB_TRACE, "VERB Enumerator cache hits/calls: (%d/%d)\n", g_EnumCache.iHits, g_EnumCache.iCalls)); OLETRACEOUT((API_OleRegEnumVerbs, hresult));
return hresult; }
//+-------------------------------------------------------------------------
//
// Function: MakeVerbList
//
// Synopsis: gets the list of verbs from the reg db
//
// Effects:
//
// Arguments: [hkey] -- handle to reg key to get verbs from
// NULL for default verb
// [rclsid] -- CLSID to store with verb list
// [ppVerbList] -- OUT paramater for where to put result
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: none
//
// Algorithm: Calls RegEnumKey to loop through the reg keys and create a
// list of verbs, which are then collected into one
// larger list. Also, flags and attribs are parsed out.
//
// History: dd-mmm-yy Author Comment
// 12-Sep-95 davidwor modified to make thread-safe
// 08-Sep-95 davidwor optimized caching code
// 14-Jul-95 t-gabes Author
//
// Notes:
// OLEVERB flags are given default values if they are not in
// reg db. This works well for OLE 1.0
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_MakeVerbList)
STDAPI MakeVerbList (HKEY hkey, REFCLSID rclsid, LPVERBLIST *ppVerbList) { VDATEHEAP();
LONG cbValue; LPVERBLIST pVerbList; OLECHAR szBuf[MAX_VERB]; // regdb buffer
OLEVERB * rgVerbs = NULL; // verb info array
OLECHAR * pszNames = NULL; // list of NULL-delimited verb names
DWORD cchSpace = 0; // space left for verb names (in bytes)
DWORD cchName; // size of one name (in bytes)
DWORD cVerbs; // number of verbs
DWORD iVerbs; // verb array index
LONG maxVerbIdx = 0; LONG maxVerbNum = OLEIVERB_LOWEST; LONG minVerbNum = OLEIVERB_LOWEST - 1; HRESULT hresult = NOERROR;
VDATEPTROUT(ppVerbList, LPVERBLIST); *ppVerbList = NULL;
if (NULL == hkey) { /*
* No verbs registered */
cbValue = sizeof(szBuf);
// read the default verb name from the reg db
if (ERROR_SUCCESS != RegQueryValue( HKEY_CLASSES_ROOT, DEFVERB, szBuf, &cbValue)) { // when all else fails, use the string "Edit"
_xstrcpy(szBuf, EDIT); cbValue = sizeof(EDIT); }
pVerbList = (LPVERBLIST)PrivMemAlloc(sizeof(VERBLIST) + cbValue); if (NULL == pVerbList) return ResultFromScode(E_OUTOFMEMORY);
// fill out a single verb with the defaults
pVerbList->cRef = 0; pVerbList->clsid = rclsid; pVerbList->cVerbs = 1; pVerbList->oleverb[0].lVerb = 0; pVerbList->oleverb[0].fuFlags = MF_STRING | MF_UNCHECKED | MF_ENABLED; pVerbList->oleverb[0].grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU; pVerbList->oleverb[0].lpszVerbName = (LPOLESTR)&pVerbList->oleverb[1]; memcpy(pVerbList->oleverb[0].lpszVerbName, szBuf, cbValue);
*ppVerbList = pVerbList; return NOERROR; }
/*
* Have registered verbs */
// determine number of subkeys
hresult = RegQueryInfoKey( hkey, NULL, NULL, NULL, &cVerbs, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (ERROR_SUCCESS != hresult || !cVerbs) { // they have a "Verb" key but no verb subkeys
hresult = ResultFromScode(OLEOBJ_E_NOVERBS); goto errRtn; }
// preallocate this much space for verb names (in bytes)
cchSpace = sizeof(OLECHAR) * cVerbs * 32;
// allocate the VerbList with space for each OLEVERB
// and space for 32 characters for each verb name
pVerbList = (LPVERBLIST)PrivMemAlloc( sizeof(VERBLIST) + sizeof(OLEVERB) * (cVerbs - 1) + cchSpace);
if (NULL == pVerbList) { hresult = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
pVerbList->cRef = 0; pVerbList->clsid = rclsid; pVerbList->cVerbs = cVerbs;
// Allocate temporary storage for the verbs. Later we'll move the verbs
// from this list into the final VerbList in sorted order.
rgVerbs = (OLEVERB *)PrivMemAlloc(sizeof(OLEVERB) * cVerbs);
if (NULL == rgVerbs) { hresult = ResultFromScode(E_OUTOFMEMORY); goto errRtn; }
// point pszNames at the first verb name
pszNames = (OLECHAR *)&pVerbList->oleverb[cVerbs];
for (iVerbs = 0; iVerbs < cVerbs; iVerbs++) { LPOLESTR psz = pszNames;
// read a verb number
hresult = RegEnumKey(hkey, iVerbs, szBuf, MAX_VERB); if (NOERROR != hresult) goto errRtn;
// this is how much space remains
cbValue = cchSpace;
// read a verb name on the verb number
hresult = RegQueryValue(hkey, szBuf, pszNames, &cbValue); if (NOERROR != hresult) goto errRtn;
// for safety, make sure verb name isn't too long
if (cbValue > (MAX_VERB + 8) * sizeof(OLECHAR)) { cbValue = (MAX_VERB + 8) * sizeof(OLECHAR); pszNames[MAX_VERB + 8 - 1] = OLESTR('\0'); }
rgVerbs[iVerbs].lVerb = Atol(szBuf);
if (rgVerbs[iVerbs].lVerb > maxVerbNum) { maxVerbNum = rgVerbs[iVerbs].lVerb; maxVerbIdx = iVerbs; }
rgVerbs[iVerbs].fuFlags = MF_STRING | MF_UNCHECKED | MF_ENABLED; rgVerbs[iVerbs].grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU;
// see if the verb name is followed by a delimiter
while (*psz && *psz != DELIM[0]) psz++;
// determine size of verb name (in characters)
cchName = (ULONG)(psz - pszNames + 1);
if (*psz == DELIM[0]) { // Parse the menu flags and attributes by finding each delimiter
// and stuffing a 0 over it. This breaks the string into three
// parts which can be handled separately.
LPOLESTR pszFlags;
*psz++ = OLESTR('\0'); // replace delimiter with 0
pszFlags = psz; // remember start of flags
while (*psz && *psz != DELIM[0]) psz++;
if (*psz == DELIM[0]) { *psz++ = OLESTR('\0'); // replace delimiter with 0
if (*psz != 0) rgVerbs[iVerbs].grfAttribs = Atol(psz); }
// now that the flags portion ends with a 0 we can parse it
if (*pszFlags != 0) rgVerbs[iVerbs].fuFlags = Atol(pszFlags); }
rgVerbs[iVerbs].lpszVerbName = pszNames;
pszNames += cchName; // move pointer to next verb name position
cchSpace -= cchName; // calculate how much space is left
}
// sort the verbs while putting them in the final verb list
for (iVerbs = 0; iVerbs < cVerbs; iVerbs++) { LONG minCurNum = maxVerbNum, minCurIdx = maxVerbIdx; LONG idx, num;
// find next verb
for (idx = 0; idx < (LONG)cVerbs; idx++) { num = rgVerbs[idx].lVerb; if (num < minCurNum && num > minVerbNum) { minCurNum = num; minCurIdx = idx; } }
pVerbList->oleverb[iVerbs].lVerb = rgVerbs[minCurIdx].lVerb; pVerbList->oleverb[iVerbs].fuFlags = rgVerbs[minCurIdx].fuFlags; pVerbList->oleverb[iVerbs].grfAttribs = rgVerbs[minCurIdx].grfAttribs; pVerbList->oleverb[iVerbs].lpszVerbName = rgVerbs[minCurIdx].lpszVerbName;
minVerbNum = minCurNum; }
*ppVerbList = pVerbList;
errRtn: if (rgVerbs) PrivMemFree(rgVerbs); if (hkey) CLOSE(hkey);
return hresult; }
//+-------------------------------------------------------------------------
//
// Function: OleReleaseEnumVerbCache
//
// Synopsis: Releases the cache if necessary
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: NOERROR
//
// Signals:
//
// Modifies:
//
// Algorithm: Just call Release method
//
// History: dd-mmm-yy Author Comment
// 12-Sep-95 davidwor modified to make thread-safe
// 18-Jul-95 t-gabes Author
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(OleReleaseEnumVerbCache)
STDAPI OleReleaseEnumVerbCache(void) { CEnumVerb* pEnum;
pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, 0);
if (NULL != pEnum) { pEnum->Release(); LEDebugOut((DEB_TRACE, "VERB Enumerator cache released\n")); }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::CEnumVerb
//
// Synopsis: Constructor for the verb enumerator
//
// Effects:
//
// Arguments:
// [pVerbs] -- ptr to the verb list
// [iVerb] -- the index of the verb we're on
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 12-Sep-95 davidwor modified to make thread-safe
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_ctor)
CEnumVerb::CEnumVerb (LPVERBLIST pVerbs, LONG iVerb) { VDATEHEAP();
m_cRef = 1; m_iVerb = iVerb; m_VerbList = pVerbs;
// AddRef the VerbList since we now have a reference to it
InterlockedIncrement((long *)&m_VerbList->cRef); }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::QueryInterface
//
// Synopsis: returns the interface implementation
//
// Effects:
//
// Arguments: [iid] -- the requested interface id
// [ppv] -- where to put a pointer to the interface
//
// Requires:
//
// Returns: NOERROR, E_NOINTERFACE
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumOLEVERB
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_QueryInterface)
STDMETHODIMP CEnumVerb::QueryInterface(REFIID iid, LPVOID FAR* ppv) { VDATEHEAP();
VDATEPTROUT(ppv, LPVOID);
if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IEnumOLEVERB)) { *ppv = this; AddRef(); return NOERROR; }
*ppv = NULL; return ResultFromScode(E_NOINTERFACE); }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::AddRef
//
// Synopsis: increments the reference count
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: ULONG -- the new reference count
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumOLEVERB
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 12-Sep-95 davidwor modified to make thread-safe
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_AddRef)
STDMETHODIMP_(ULONG) CEnumVerb::AddRef(void) { VDATEHEAP();
return InterlockedIncrement((long *)&m_cRef); }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::Release
//
// Synopsis: decrements the reference count
//
// Effects: will delete the object when ref count goes to zero
//
// Arguments: void
//
// Requires:
//
// Returns: ULONG -- the new ref count
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumOLEVERB
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 12-Sep-95 davidwor modified to make thread-safe
// 18-Jul-95 t-gabes release verb cache when finished
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_Release)
STDMETHODIMP_(ULONG) CEnumVerb::Release(void) { VDATEHEAP();
ULONG cRef;
cRef = InterlockedDecrement((long *)&m_cRef); if (0 == cRef) { if (0 == InterlockedDecrement((long *)&m_VerbList->cRef)) { // no more references to m_VerbList so free it
PrivMemFree(m_VerbList); LEDebugOut((DEB_TRACE, "VERB Enumerator verb list released\n")); }
delete this; return 0; }
return cRef; }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::Next
//
// Synopsis: gets the next [cverb] verbs from the verb list
//
// Effects:
//
// Arguments: [cverb] -- the number of verbs to get
// [rgverb] -- where to put the verbs
// [pcverbFetched] -- where to put the num of verbs retrieved
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumOLEVERB
//
// Algorithm: loops through [cverb] times and grabs the info from the
// reg db
//
// History: dd-mmm-yy Author Comment
// 17-Jul-95 t-gabes rewrote to use cache
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_Next)
STDMETHODIMP CEnumVerb::Next (ULONG cverb, LPOLEVERB rgverb, ULONG FAR* pcverbFetched) { VDATEHEAP();
ULONG iVerb; // number successfully fetched
HRESULT hresult = NOERROR;
if (!rgverb) { if (pcverbFetched) *pcverbFetched = 0; VDATEPTROUT(rgverb, OLEVERB); }
if (pcverbFetched) { VDATEPTROUT(pcverbFetched, ULONG); } else if (cverb != 1) { // the spec says that if pcverbFetched == NULL, then
// the count of elements to fetch must be 1
return ResultFromScode(E_INVALIDARG); }
for (iVerb = 0; iVerb < cverb; iVerb++) { if (m_iVerb >= (LONG)m_VerbList->cVerbs) { // no more
hresult = ResultFromScode(S_FALSE); goto errRtn; }
OLEVERB *lpov = &m_VerbList->oleverb[m_iVerb++];
rgverb[iVerb].lVerb = lpov->lVerb; rgverb[iVerb].fuFlags = lpov->fuFlags; rgverb[iVerb].grfAttribs = lpov->grfAttribs; rgverb[iVerb].lpszVerbName = UtDupString(lpov->lpszVerbName); }
errRtn: if (pcverbFetched) { *pcverbFetched = iVerb; }
return hresult; }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::Skip
//
// Synopsis: skips [c] verbs in the enumeration
//
// Effects:
//
// Arguments: [c] -- the number of verbs to skip
//
// Requires:
//
// Returns: HRESULT
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumOLEVERB
//
// Algorithm: adds [c] to the verb index
//
// History: dd-mmm-yy Author Comment
// 17-Jul-95 t-gabes rewrote to use cache
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_Skip)
STDMETHODIMP CEnumVerb::Skip(ULONG c) { VDATEHEAP();
m_iVerb += c; if (m_iVerb > (LONG)m_VerbList->cVerbs) { // skipping too many
m_iVerb = m_VerbList->cVerbs; return ResultFromScode(S_FALSE); }
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::Reset
//
// Synopsis: resets the verb enumeration to the beginning
//
// Effects:
//
// Arguments: void
//
// Requires:
//
// Returns: NOERROR
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumOLEVERB
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 17-Jul-95 t-gabes rewrote to use cache
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_Reset)
STDMETHODIMP CEnumVerb::Reset(void) { VDATEHEAP();
m_iVerb = 0;
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::Clone
//
// Synopsis: creates a copy of the enumerator
//
// Effects:
//
// Arguments: [ppenum] -- where to put a pointer to the new clone
//
// Requires:
//
// Returns: NOERROR, E_OUTOFMEMORY
//
// Signals:
//
// Modifies:
//
// Derivation: IEnumOLEVERB
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 01-Dec-93 alexgo 32bit port
//
// Notes:
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_Clone)
STDMETHODIMP CEnumVerb::Clone(LPENUMOLEVERB FAR* ppenum) { VDATEHEAP();
VDATEPTROUT(ppenum, LPENUMOLEVERB);
*ppenum = new FAR CEnumVerb(m_VerbList, m_iVerb); if (!*ppenum) return ResultFromScode(E_OUTOFMEMORY);
return NOERROR; }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::GetRefCount
//
// Synopsis: Gets the reference count for the class
//
// Effects:
//
// Arguments: none
//
// Requires:
//
// Returns: ref count
//
// Signals:
//
// Modifies:
//
// Derivation:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 12-Jul-95 t-gabes Author
//
// Notes: This is needed so OleRegEnumVerbs knows when to dup the cache
//
//--------------------------------------------------------------------------
#pragma SEG(CEnumVerb_GetRefCount)
ULONG CEnumVerb::GetRefCount (void) { VDATEHEAP();
return m_cRef; }
//+-------------------------------------------------------------------------
//
// Member: CEnumVerb::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 CEnumVerb::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel) { int i; char *pszPrefix; 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 << "Address of verb list = " << m_VerbList << endl;
dstrDump << pszPrefix << "Current Verb Number = " << m_iVerb << endl;
// cleanup and provide pointer to character array
*ppszDump = dstrDump.str();
if (*ppszDump == NULL) { *ppszDump = UtDupStringA(szDumpErrorMessage); }
CoTaskMemFree(pszPrefix);
return NOERROR; }
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DumpCEnumVerb, public (_DEBUG only)
//
// Synopsis: calls the CEnumVerb::Dump method, takes care of errors and
// returns the zero terminated string
//
// Effects:
//
// Arguments: [pEV] - pointer to CEnumVerb
// [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 *DumpCEnumVerb(CEnumVerb *pEV, ULONG ulFlag, int nIndentLevel) { char *pszDump;
if (NULL == pEV) { return UtDupStringA(szDumpBadPtr); }
pEV->Dump(&pszDump, ulFlag, nIndentLevel);
return pszDump; }
#endif // _DEBUG
|