//+------------------------------------------------------------------------- // // 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 #pragma SEG(oregverb) #include #include "oleregpv.h" #ifdef _DEBUG #include #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 - "\Protocol\StdFileEditing" // cchBase - length of "" 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 - "" // 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