Source code of Windows XP (NT5)
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.

1254 lines
33 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: oregverb.cpp
  7. //
  8. // Contents: Implementation of the enumerator for regdb verbs
  9. //
  10. // Classes: CEnumVerb
  11. //
  12. // Functions: OleRegEnumVerbs
  13. //
  14. // History: dd-mmm-yy Author Comment
  15. // 12-Sep-95 davidwor made cache thread-safe
  16. // 08-Sep-95 davidwor optimized caching code
  17. // 12-Jul-95 t-gabes cache verbs and enumerator
  18. // 01-Feb-95 t-ScottH add Dump method to CEnumVerb and API
  19. // DumpCEnumVerb
  20. // 25-Jan-94 alexgo first pass at converting to Cairo-style
  21. // memory allocations.
  22. // 11-Jan-94 alexgo added VDATEHEAP macros to every function
  23. // 31-Dec-93 erikgav chicago port
  24. // 01-Dec-93 alexgo 32bit port
  25. // 12-Nov-93 jasonful author
  26. //
  27. //--------------------------------------------------------------------------
  28. #include <le2int.h>
  29. #pragma SEG(oregverb)
  30. #include <reterr.h>
  31. #include "oleregpv.h"
  32. #ifdef _DEBUG
  33. #include <dbgdump.h>
  34. #endif // _DEBUG
  35. ASSERTDATA
  36. #define MAX_STR 256
  37. #define MAX_VERB 33
  38. #define OLEIVERB_LOWEST OLEIVERB_HIDE
  39. // reg db key
  40. static const OLECHAR VERB[] = OLESTR("\\Verb");
  41. // stdfileediting key
  42. static const OLECHAR STDFILE[] = OLESTR("\\Protocol\\StdFileEditing");
  43. // default verbs
  44. static const OLECHAR DEFVERB[] =
  45. OLESTR("Software\\Microsoft\\OLE1\\UnregisteredVerb");
  46. // default verb
  47. static const OLECHAR EDIT[] = OLESTR("Edit");
  48. //+-------------------------------------------------------------------------
  49. //
  50. // Struct: VerbList
  51. //
  52. // Purpose: to hold the enumerator's list of verbs
  53. //
  54. // History: dd-mmm-yy Author Comment
  55. // 12-Jul-95 t-gabes author
  56. //
  57. // Notes:
  58. //
  59. //--------------------------------------------------------------------------
  60. typedef struct VerbList
  61. {
  62. ULONG cRef; // reference count
  63. CLSID clsid; // CLSID of the cached verbs
  64. ULONG cVerbs; // count of verbs in oleverb array
  65. OLEVERB oleverb[1]; // variable-size list of verbs
  66. } VERBLIST, *LPVERBLIST;
  67. STDAPI MakeVerbList(HKEY hkey, REFCLSID rclsid, LPVERBLIST *ppVerbList);
  68. STDAPI OleReleaseEnumVerbCache(void);
  69. //+-------------------------------------------------------------------------
  70. //
  71. // Class: CEnumVerb
  72. //
  73. // Purpose: enumerates the verbs listed in the reg db for a given class
  74. //
  75. // Interface: IEnumOLEVERB
  76. //
  77. // History: dd-mmm-yy Author Comment
  78. // 02-Aug-95 t-gabes rewrote to use cache
  79. // 01-Dec-93 alexgo 32bit port
  80. //
  81. // Notes:
  82. //
  83. //--------------------------------------------------------------------------
  84. class FAR CEnumVerb : public IEnumOLEVERB, public CPrivAlloc
  85. {
  86. // *** IUnknown methods ***
  87. STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj);
  88. STDMETHOD_(ULONG,AddRef) (THIS);
  89. STDMETHOD_(ULONG,Release) (THIS);
  90. // *** IEnumOLEVERB methods ***
  91. STDMETHOD(Next) (THIS_ ULONG celt, LPOLEVERB reelt,
  92. ULONG FAR* pceltFetched);
  93. STDMETHOD(Skip) (THIS_ ULONG celt);
  94. STDMETHOD(Reset) (THIS);
  95. STDMETHOD(Clone) (THIS_ LPENUMOLEVERB FAR* ppenm);
  96. ULONG GetRefCount (void);
  97. #ifdef _DEBUG
  98. HRESULT Dump (char **ppszDump, ULONG ulFlag, int nIndentLevel);
  99. friend char *DumpCEnumVerb (CEnumVerb *pEV, ULONG ulFlag, int nIndentLevel);
  100. #endif // _DEBUG
  101. private:
  102. CEnumVerb (LPVERBLIST pVerbs, LONG iVerb=0);
  103. ULONG m_cRef; // reference count
  104. LONG m_iVerb; // current verb number (0 is the first)
  105. LPVERBLIST m_VerbList; // all the verbs for this class
  106. friend HRESULT STDAPICALLTYPE OleRegEnumVerbs (REFCLSID, LPENUMOLEVERB FAR*);
  107. friend HRESULT STDAPICALLTYPE OleReleaseEnumVerbCache(void);
  108. };
  109. //+-------------------------------------------------------------------------
  110. //
  111. // Struct: EnumVerbCache
  112. //
  113. // Purpose: to cache the enumerator for the last enumerated class
  114. //
  115. // History: dd-mmm-yy Author Comment
  116. // 12-Jul-95 t-gabes author
  117. //
  118. //
  119. //--------------------------------------------------------------------------
  120. typedef struct
  121. {
  122. CEnumVerb* pEnum; // pointer to the cached enumerator
  123. #ifdef _DEBUG
  124. LONG iCalls; // total calls counter
  125. LONG iHits; // cache hit counter
  126. #endif // _DEBUG
  127. } EnumVerbCache;
  128. // Last enumerator used
  129. EnumVerbCache g_EnumCache = { NULL };
  130. //+-------------------------------------------------------------------------
  131. //
  132. // Function: OleRegEnumVerbs
  133. //
  134. // Synopsis: Creates an enumerator to go through the verbs in the reg db
  135. // for the given class ID
  136. //
  137. // Effects:
  138. //
  139. // Arguments: [clsid] -- the class ID we're interested in
  140. // [ppenum] -- where to put the enumerator pointer
  141. //
  142. // Requires:
  143. //
  144. // Returns: HRESULT
  145. //
  146. // Signals:
  147. //
  148. // Modifies:
  149. //
  150. // Algorithm: Makes sure that the info is in the database and then
  151. // creates the enumerator
  152. //
  153. // History: dd-mmm-yy Author Comment
  154. // 12-Sep-95 davidwor modified to make thread-safe
  155. // 08-Sep-95 davidwor optimized caching code
  156. // 12-Jul-95 t-gabes rewrote to use cache
  157. // 01-Dec-93 alexgo 32bit port
  158. //
  159. // Notes:
  160. //
  161. //--------------------------------------------------------------------------
  162. #pragma SEG(OleRegEnumVerbs)
  163. STDAPI OleRegEnumVerbs
  164. (REFCLSID clsid,
  165. LPENUMOLEVERB FAR* ppenum)
  166. {
  167. OLETRACEIN((API_OleRegEnumVerbs, PARAMFMT("clsid= %I, ppenum= %p"),
  168. &clsid, ppenum));
  169. VDATEHEAP();
  170. CEnumVerb* pEnum;
  171. LPVERBLIST pVerbList;
  172. BOOL fOle1Class;
  173. OLECHAR szKey[MAX_STR];
  174. int cchBase;
  175. HKEY hkey;
  176. HRESULT hresult;
  177. VDATEPTROUT_LABEL (ppenum, LPENUMOLEVERB, errSafeRtn, hresult);
  178. *ppenum = NULL;
  179. #ifdef _DEBUG
  180. // Increment total calls counter
  181. InterlockedIncrement(&g_EnumCache.iCalls);
  182. #endif // _DEBUG
  183. // Grab the global enumerator and put a NULL in its place. If another
  184. // thread calls into OleRegEnumVerbs during this operation they won't
  185. // be able to mess with the enumerator we're working with.
  186. pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, 0);
  187. if (pEnum != NULL)
  188. {
  189. if (IsEqualCLSID(clsid, pEnum->m_VerbList->clsid))
  190. {
  191. #ifdef _DEBUG
  192. // Increment cache hits counter
  193. InterlockedIncrement(&g_EnumCache.iHits);
  194. #endif
  195. if (1 == pEnum->GetRefCount())
  196. {
  197. // No other references -> AddRef and return this copy
  198. *ppenum = pEnum;
  199. pEnum->AddRef();
  200. pEnum->Reset();
  201. LEDebugOut((DEB_TRACE, "VERB Enumerator cache handed out\n"));
  202. }
  203. else
  204. {
  205. // Has additional references -> return a Cloned copy
  206. if (NOERROR == pEnum->Clone(ppenum))
  207. {
  208. (*ppenum)->Reset();
  209. LEDebugOut((DEB_TRACE, "VERB Enumerator cache cloned\n"));
  210. }
  211. }
  212. // Swap our enumerator with the current contents of the global. If
  213. // another thread called OleRegEnumVerbs during this operation and
  214. // stored an enumerator in the global, we need to Release it.
  215. pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, (PVOID)pEnum);
  216. if (pEnum != NULL)
  217. {
  218. pEnum->Release();
  219. LEDebugOut((DEB_TRACE, "VERB Enumerator cache released (replacing global)\n"));
  220. }
  221. goto errRtn;
  222. }
  223. else
  224. {
  225. // Our clsid didn't match the clsid of the cache so we'll release the
  226. // cached enumerator and proceed with creating a new enumerator to
  227. // store in the global cache.
  228. pEnum->Release();
  229. LEDebugOut((DEB_TRACE, "VERB Enumerator cache released (different CLSID)\n"));
  230. }
  231. }
  232. fOle1Class = CoIsOle1Class(clsid);
  233. if (fOle1Class)
  234. {
  235. // Fills out szKey and cchBase as follows:
  236. // szKey - "<ProgID>\Protocol\StdFileEditing"
  237. // cchBase - length of "<ProgID>" portion
  238. LPOLESTR psz;
  239. RetErr(ProgIDFromCLSID(clsid, &psz));
  240. cchBase = _xstrlen(psz);
  241. memcpy(szKey, psz, cchBase * sizeof(OLECHAR));
  242. memcpy(&szKey[cchBase], STDFILE, sizeof(STDFILE));
  243. PubMemFree(psz);
  244. }
  245. else
  246. {
  247. // Fills out szKey and cchBase as follows:
  248. // szKey - "CLSID\{clsid}"
  249. // cchBase - length of full szKey string
  250. memcpy(szKey, szClsidRoot, sizeof(szClsidRoot));
  251. if (0 == StringFromCLSID2(clsid, &szKey[sizeof(szClsidRoot) / sizeof(OLECHAR) - 1], sizeof(szKey)))
  252. return ResultFromScode(E_OUTOFMEMORY);
  253. cchBase = _xstrlen(szKey);
  254. }
  255. // append "\Verb" to the end
  256. _xstrcat(szKey, VERB);
  257. if (ERROR_SUCCESS != RegOpenKeyEx(
  258. HKEY_CLASSES_ROOT,
  259. szKey,
  260. NULL,
  261. KEY_READ,
  262. &hkey))
  263. {
  264. // verb key doesn't exist, so figure out why
  265. szKey[cchBase] = OLESTR('\0');
  266. // szKey now contains one of the following:
  267. // OLE1 - "<ProgID>"
  268. // OLE2 - "CLSID\{clsid}"
  269. if (ERROR_SUCCESS != RegOpenKeyEx(
  270. HKEY_CLASSES_ROOT,
  271. szKey,
  272. NULL,
  273. KEY_READ,
  274. &hkey))
  275. {
  276. // the class isn't registered
  277. return ReportResult(0, REGDB_E_CLASSNOTREG, 0, 0);
  278. }
  279. CLOSE(hkey);
  280. // The class has no verbs. This is fine for OLE1 but not OLE2
  281. if (!fOle1Class)
  282. return ResultFromScode(OLEOBJ_E_NOVERBS);
  283. // if hkey is NULL, MakeVerbList will use the default verb
  284. hkey = NULL;
  285. }
  286. // make the verb list
  287. RetErr(MakeVerbList(hkey, clsid, &pVerbList));
  288. Assert(pVerbList != NULL);
  289. // create a CEnumVerb object (this calls AddRef on pVerbList)
  290. pEnum = new FAR CEnumVerb(pVerbList);
  291. if (NULL == pEnum)
  292. {
  293. PrivMemFree(pVerbList);
  294. hresult = ResultFromScode(E_OUTOFMEMORY);
  295. goto errSafeRtn;
  296. }
  297. // set the out parameter and AddRef on behalf of the caller
  298. *ppenum = pEnum;
  299. pEnum->AddRef();
  300. LEDebugOut((DEB_TRACE, "VERB Enumerator cache created\n"));
  301. // Swap our enumerator with the current contents of the global. If
  302. // another thread called OleRegEnumVerbs during this operation and
  303. // stored an enumerator in the global, we need to Release it.
  304. pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, (PVOID)pEnum);
  305. if (pEnum != NULL)
  306. {
  307. pEnum->Release();
  308. LEDebugOut((DEB_TRACE, "VERB Enumerator cache released (replacing global)\n"));
  309. }
  310. errRtn:
  311. hresult = *ppenum ? NOERROR : ResultFromScode (E_OUTOFMEMORY);
  312. // hook the new interface
  313. CALLHOOKOBJECTCREATE(S_OK, CLSID_NULL, IID_IEnumOLEVERB, (IUnknown **)ppenum);
  314. errSafeRtn:
  315. LEDebugOut((DEB_TRACE, "VERB Enumerator cache hits/calls: (%d/%d)\n", g_EnumCache.iHits, g_EnumCache.iCalls));
  316. OLETRACEOUT((API_OleRegEnumVerbs, hresult));
  317. return hresult;
  318. }
  319. //+-------------------------------------------------------------------------
  320. //
  321. // Function: MakeVerbList
  322. //
  323. // Synopsis: gets the list of verbs from the reg db
  324. //
  325. // Effects:
  326. //
  327. // Arguments: [hkey] -- handle to reg key to get verbs from
  328. // NULL for default verb
  329. // [rclsid] -- CLSID to store with verb list
  330. // [ppVerbList] -- OUT paramater for where to put result
  331. //
  332. // Requires:
  333. //
  334. // Returns: HRESULT
  335. //
  336. // Signals:
  337. //
  338. // Modifies:
  339. //
  340. // Derivation: none
  341. //
  342. // Algorithm: Calls RegEnumKey to loop through the reg keys and create a
  343. // list of verbs, which are then collected into one
  344. // larger list. Also, flags and attribs are parsed out.
  345. //
  346. // History: dd-mmm-yy Author Comment
  347. // 12-Sep-95 davidwor modified to make thread-safe
  348. // 08-Sep-95 davidwor optimized caching code
  349. // 14-Jul-95 t-gabes Author
  350. //
  351. // Notes:
  352. // OLEVERB flags are given default values if they are not in
  353. // reg db. This works well for OLE 1.0
  354. //
  355. //--------------------------------------------------------------------------
  356. #pragma SEG(CEnumVerb_MakeVerbList)
  357. STDAPI MakeVerbList
  358. (HKEY hkey,
  359. REFCLSID rclsid,
  360. LPVERBLIST *ppVerbList)
  361. {
  362. VDATEHEAP();
  363. LONG cbValue;
  364. LPVERBLIST pVerbList;
  365. OLECHAR szBuf[MAX_VERB]; // regdb buffer
  366. OLEVERB * rgVerbs = NULL; // verb info array
  367. OLECHAR * pszNames = NULL; // list of NULL-delimited verb names
  368. DWORD cchSpace = 0; // space left for verb names (in bytes)
  369. DWORD cchName; // size of one name (in bytes)
  370. DWORD cVerbs; // number of verbs
  371. DWORD iVerbs; // verb array index
  372. LONG maxVerbIdx = 0;
  373. LONG maxVerbNum = OLEIVERB_LOWEST;
  374. LONG minVerbNum = OLEIVERB_LOWEST - 1;
  375. HRESULT hresult = NOERROR;
  376. VDATEPTROUT(ppVerbList, LPVERBLIST);
  377. *ppVerbList = NULL;
  378. if (NULL == hkey)
  379. {
  380. /*
  381. * No verbs registered
  382. */
  383. cbValue = sizeof(szBuf);
  384. // read the default verb name from the reg db
  385. if (ERROR_SUCCESS != RegQueryValue(
  386. HKEY_CLASSES_ROOT,
  387. DEFVERB,
  388. szBuf,
  389. &cbValue))
  390. {
  391. // when all else fails, use the string "Edit"
  392. _xstrcpy(szBuf, EDIT);
  393. cbValue = sizeof(EDIT);
  394. }
  395. pVerbList = (LPVERBLIST)PrivMemAlloc(sizeof(VERBLIST) + cbValue);
  396. if (NULL == pVerbList)
  397. return ResultFromScode(E_OUTOFMEMORY);
  398. // fill out a single verb with the defaults
  399. pVerbList->cRef = 0;
  400. pVerbList->clsid = rclsid;
  401. pVerbList->cVerbs = 1;
  402. pVerbList->oleverb[0].lVerb = 0;
  403. pVerbList->oleverb[0].fuFlags = MF_STRING | MF_UNCHECKED | MF_ENABLED;
  404. pVerbList->oleverb[0].grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU;
  405. pVerbList->oleverb[0].lpszVerbName = (LPOLESTR)&pVerbList->oleverb[1];
  406. memcpy(pVerbList->oleverb[0].lpszVerbName, szBuf, cbValue);
  407. *ppVerbList = pVerbList;
  408. return NOERROR;
  409. }
  410. /*
  411. * Have registered verbs
  412. */
  413. // determine number of subkeys
  414. hresult = RegQueryInfoKey(
  415. hkey, NULL, NULL, NULL, &cVerbs,
  416. NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  417. if (ERROR_SUCCESS != hresult || !cVerbs)
  418. {
  419. // they have a "Verb" key but no verb subkeys
  420. hresult = ResultFromScode(OLEOBJ_E_NOVERBS);
  421. goto errRtn;
  422. }
  423. // preallocate this much space for verb names (in bytes)
  424. cchSpace = sizeof(OLECHAR) * cVerbs * 32;
  425. // allocate the VerbList with space for each OLEVERB
  426. // and space for 32 characters for each verb name
  427. pVerbList = (LPVERBLIST)PrivMemAlloc(
  428. sizeof(VERBLIST) +
  429. sizeof(OLEVERB) * (cVerbs - 1) +
  430. cchSpace);
  431. if (NULL == pVerbList)
  432. {
  433. hresult = ResultFromScode(E_OUTOFMEMORY);
  434. goto errRtn;
  435. }
  436. pVerbList->cRef = 0;
  437. pVerbList->clsid = rclsid;
  438. pVerbList->cVerbs = cVerbs;
  439. // Allocate temporary storage for the verbs. Later we'll move the verbs
  440. // from this list into the final VerbList in sorted order.
  441. rgVerbs = (OLEVERB *)PrivMemAlloc(sizeof(OLEVERB) * cVerbs);
  442. if (NULL == rgVerbs)
  443. {
  444. hresult = ResultFromScode(E_OUTOFMEMORY);
  445. goto errRtn;
  446. }
  447. // point pszNames at the first verb name
  448. pszNames = (OLECHAR *)&pVerbList->oleverb[cVerbs];
  449. for (iVerbs = 0; iVerbs < cVerbs; iVerbs++)
  450. {
  451. LPOLESTR psz = pszNames;
  452. // read a verb number
  453. hresult = RegEnumKey(hkey, iVerbs, szBuf, MAX_VERB);
  454. if (NOERROR != hresult)
  455. goto errRtn;
  456. // this is how much space remains
  457. cbValue = cchSpace;
  458. // read a verb name on the verb number
  459. hresult = RegQueryValue(hkey, szBuf, pszNames, &cbValue);
  460. if (NOERROR != hresult)
  461. goto errRtn;
  462. // for safety, make sure verb name isn't too long
  463. if (cbValue > (MAX_VERB + 8) * sizeof(OLECHAR))
  464. {
  465. cbValue = (MAX_VERB + 8) * sizeof(OLECHAR);
  466. pszNames[MAX_VERB + 8 - 1] = OLESTR('\0');
  467. }
  468. rgVerbs[iVerbs].lVerb = Atol(szBuf);
  469. if (rgVerbs[iVerbs].lVerb > maxVerbNum)
  470. {
  471. maxVerbNum = rgVerbs[iVerbs].lVerb;
  472. maxVerbIdx = iVerbs;
  473. }
  474. rgVerbs[iVerbs].fuFlags = MF_STRING | MF_UNCHECKED | MF_ENABLED;
  475. rgVerbs[iVerbs].grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU;
  476. // see if the verb name is followed by a delimiter
  477. while (*psz && *psz != DELIM[0])
  478. psz++;
  479. // determine size of verb name (in characters)
  480. cchName = (ULONG)(psz - pszNames + 1);
  481. if (*psz == DELIM[0])
  482. {
  483. // Parse the menu flags and attributes by finding each delimiter
  484. // and stuffing a 0 over it. This breaks the string into three
  485. // parts which can be handled separately.
  486. LPOLESTR pszFlags;
  487. *psz++ = OLESTR('\0'); // replace delimiter with 0
  488. pszFlags = psz; // remember start of flags
  489. while (*psz && *psz != DELIM[0])
  490. psz++;
  491. if (*psz == DELIM[0])
  492. {
  493. *psz++ = OLESTR('\0'); // replace delimiter with 0
  494. if (*psz != 0)
  495. rgVerbs[iVerbs].grfAttribs = Atol(psz);
  496. }
  497. // now that the flags portion ends with a 0 we can parse it
  498. if (*pszFlags != 0)
  499. rgVerbs[iVerbs].fuFlags = Atol(pszFlags);
  500. }
  501. rgVerbs[iVerbs].lpszVerbName = pszNames;
  502. pszNames += cchName; // move pointer to next verb name position
  503. cchSpace -= cchName; // calculate how much space is left
  504. }
  505. // sort the verbs while putting them in the final verb list
  506. for (iVerbs = 0; iVerbs < cVerbs; iVerbs++)
  507. {
  508. LONG minCurNum = maxVerbNum,
  509. minCurIdx = maxVerbIdx;
  510. LONG idx, num;
  511. // find next verb
  512. for (idx = 0; idx < (LONG)cVerbs; idx++)
  513. {
  514. num = rgVerbs[idx].lVerb;
  515. if (num < minCurNum && num > minVerbNum)
  516. {
  517. minCurNum = num;
  518. minCurIdx = idx;
  519. }
  520. }
  521. pVerbList->oleverb[iVerbs].lVerb = rgVerbs[minCurIdx].lVerb;
  522. pVerbList->oleverb[iVerbs].fuFlags = rgVerbs[minCurIdx].fuFlags;
  523. pVerbList->oleverb[iVerbs].grfAttribs = rgVerbs[minCurIdx].grfAttribs;
  524. pVerbList->oleverb[iVerbs].lpszVerbName = rgVerbs[minCurIdx].lpszVerbName;
  525. minVerbNum = minCurNum;
  526. }
  527. *ppVerbList = pVerbList;
  528. errRtn:
  529. if (rgVerbs)
  530. PrivMemFree(rgVerbs);
  531. if (hkey)
  532. CLOSE(hkey);
  533. return hresult;
  534. }
  535. //+-------------------------------------------------------------------------
  536. //
  537. // Function: OleReleaseEnumVerbCache
  538. //
  539. // Synopsis: Releases the cache if necessary
  540. //
  541. // Effects:
  542. //
  543. // Arguments: void
  544. //
  545. // Requires:
  546. //
  547. // Returns: NOERROR
  548. //
  549. // Signals:
  550. //
  551. // Modifies:
  552. //
  553. // Algorithm: Just call Release method
  554. //
  555. // History: dd-mmm-yy Author Comment
  556. // 12-Sep-95 davidwor modified to make thread-safe
  557. // 18-Jul-95 t-gabes Author
  558. //
  559. // Notes:
  560. //
  561. //--------------------------------------------------------------------------
  562. #pragma SEG(OleReleaseEnumVerbCache)
  563. STDAPI OleReleaseEnumVerbCache(void)
  564. {
  565. CEnumVerb* pEnum;
  566. pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, 0);
  567. if (NULL != pEnum)
  568. {
  569. pEnum->Release();
  570. LEDebugOut((DEB_TRACE, "VERB Enumerator cache released\n"));
  571. }
  572. return NOERROR;
  573. }
  574. //+-------------------------------------------------------------------------
  575. //
  576. // Member: CEnumVerb::CEnumVerb
  577. //
  578. // Synopsis: Constructor for the verb enumerator
  579. //
  580. // Effects:
  581. //
  582. // Arguments:
  583. // [pVerbs] -- ptr to the verb list
  584. // [iVerb] -- the index of the verb we're on
  585. //
  586. // Requires:
  587. //
  588. // Returns:
  589. //
  590. // Signals:
  591. //
  592. // Modifies:
  593. //
  594. // Derivation:
  595. //
  596. // Algorithm:
  597. //
  598. // History: dd-mmm-yy Author Comment
  599. // 12-Sep-95 davidwor modified to make thread-safe
  600. // 01-Dec-93 alexgo 32bit port
  601. //
  602. // Notes:
  603. //
  604. //--------------------------------------------------------------------------
  605. #pragma SEG(CEnumVerb_ctor)
  606. CEnumVerb::CEnumVerb
  607. (LPVERBLIST pVerbs,
  608. LONG iVerb)
  609. {
  610. VDATEHEAP();
  611. m_cRef = 1;
  612. m_iVerb = iVerb;
  613. m_VerbList = pVerbs;
  614. // AddRef the VerbList since we now have a reference to it
  615. InterlockedIncrement((long *)&m_VerbList->cRef);
  616. }
  617. //+-------------------------------------------------------------------------
  618. //
  619. // Member: CEnumVerb::QueryInterface
  620. //
  621. // Synopsis: returns the interface implementation
  622. //
  623. // Effects:
  624. //
  625. // Arguments: [iid] -- the requested interface id
  626. // [ppv] -- where to put a pointer to the interface
  627. //
  628. // Requires:
  629. //
  630. // Returns: NOERROR, E_NOINTERFACE
  631. //
  632. // Signals:
  633. //
  634. // Modifies:
  635. //
  636. // Derivation: IEnumOLEVERB
  637. //
  638. // Algorithm:
  639. //
  640. // History: dd-mmm-yy Author Comment
  641. // 01-Dec-93 alexgo 32bit port
  642. //
  643. // Notes:
  644. //
  645. //--------------------------------------------------------------------------
  646. #pragma SEG(CEnumVerb_QueryInterface)
  647. STDMETHODIMP CEnumVerb::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  648. {
  649. VDATEHEAP();
  650. VDATEPTROUT(ppv, LPVOID);
  651. if (IsEqualIID(iid, IID_IUnknown) ||
  652. IsEqualIID(iid, IID_IEnumOLEVERB))
  653. {
  654. *ppv = this;
  655. AddRef();
  656. return NOERROR;
  657. }
  658. *ppv = NULL;
  659. return ResultFromScode(E_NOINTERFACE);
  660. }
  661. //+-------------------------------------------------------------------------
  662. //
  663. // Member: CEnumVerb::AddRef
  664. //
  665. // Synopsis: increments the reference count
  666. //
  667. // Effects:
  668. //
  669. // Arguments: void
  670. //
  671. // Requires:
  672. //
  673. // Returns: ULONG -- the new reference count
  674. //
  675. // Signals:
  676. //
  677. // Modifies:
  678. //
  679. // Derivation: IEnumOLEVERB
  680. //
  681. // Algorithm:
  682. //
  683. // History: dd-mmm-yy Author Comment
  684. // 12-Sep-95 davidwor modified to make thread-safe
  685. // 01-Dec-93 alexgo 32bit port
  686. //
  687. // Notes:
  688. //
  689. //--------------------------------------------------------------------------
  690. #pragma SEG(CEnumVerb_AddRef)
  691. STDMETHODIMP_(ULONG) CEnumVerb::AddRef(void)
  692. {
  693. VDATEHEAP();
  694. return InterlockedIncrement((long *)&m_cRef);
  695. }
  696. //+-------------------------------------------------------------------------
  697. //
  698. // Member: CEnumVerb::Release
  699. //
  700. // Synopsis: decrements the reference count
  701. //
  702. // Effects: will delete the object when ref count goes to zero
  703. //
  704. // Arguments: void
  705. //
  706. // Requires:
  707. //
  708. // Returns: ULONG -- the new ref count
  709. //
  710. // Signals:
  711. //
  712. // Modifies:
  713. //
  714. // Derivation: IEnumOLEVERB
  715. //
  716. // Algorithm:
  717. //
  718. // History: dd-mmm-yy Author Comment
  719. // 12-Sep-95 davidwor modified to make thread-safe
  720. // 18-Jul-95 t-gabes release verb cache when finished
  721. // 01-Dec-93 alexgo 32bit port
  722. //
  723. // Notes:
  724. //
  725. //--------------------------------------------------------------------------
  726. #pragma SEG(CEnumVerb_Release)
  727. STDMETHODIMP_(ULONG) CEnumVerb::Release(void)
  728. {
  729. VDATEHEAP();
  730. ULONG cRef;
  731. cRef = InterlockedDecrement((long *)&m_cRef);
  732. if (0 == cRef)
  733. {
  734. if (0 == InterlockedDecrement((long *)&m_VerbList->cRef))
  735. {
  736. // no more references to m_VerbList so free it
  737. PrivMemFree(m_VerbList);
  738. LEDebugOut((DEB_TRACE, "VERB Enumerator verb list released\n"));
  739. }
  740. delete this;
  741. return 0;
  742. }
  743. return cRef;
  744. }
  745. //+-------------------------------------------------------------------------
  746. //
  747. // Member: CEnumVerb::Next
  748. //
  749. // Synopsis: gets the next [cverb] verbs from the verb list
  750. //
  751. // Effects:
  752. //
  753. // Arguments: [cverb] -- the number of verbs to get
  754. // [rgverb] -- where to put the verbs
  755. // [pcverbFetched] -- where to put the num of verbs retrieved
  756. //
  757. // Requires:
  758. //
  759. // Returns: HRESULT
  760. //
  761. // Signals:
  762. //
  763. // Modifies:
  764. //
  765. // Derivation: IEnumOLEVERB
  766. //
  767. // Algorithm: loops through [cverb] times and grabs the info from the
  768. // reg db
  769. //
  770. // History: dd-mmm-yy Author Comment
  771. // 17-Jul-95 t-gabes rewrote to use cache
  772. // 01-Dec-93 alexgo 32bit port
  773. //
  774. // Notes:
  775. //
  776. //--------------------------------------------------------------------------
  777. #pragma SEG(CEnumVerb_Next)
  778. STDMETHODIMP CEnumVerb::Next
  779. (ULONG cverb,
  780. LPOLEVERB rgverb,
  781. ULONG FAR* pcverbFetched)
  782. {
  783. VDATEHEAP();
  784. ULONG iVerb; // number successfully fetched
  785. HRESULT hresult = NOERROR;
  786. if (!rgverb)
  787. {
  788. if (pcverbFetched)
  789. *pcverbFetched = 0;
  790. VDATEPTROUT(rgverb, OLEVERB);
  791. }
  792. if (pcverbFetched)
  793. {
  794. VDATEPTROUT(pcverbFetched, ULONG);
  795. }
  796. else if (cverb != 1)
  797. {
  798. // the spec says that if pcverbFetched == NULL, then
  799. // the count of elements to fetch must be 1
  800. return ResultFromScode(E_INVALIDARG);
  801. }
  802. for (iVerb = 0; iVerb < cverb; iVerb++)
  803. {
  804. if (m_iVerb >= (LONG)m_VerbList->cVerbs)
  805. {
  806. // no more
  807. hresult = ResultFromScode(S_FALSE);
  808. goto errRtn;
  809. }
  810. OLEVERB *lpov = &m_VerbList->oleverb[m_iVerb++];
  811. rgverb[iVerb].lVerb = lpov->lVerb;
  812. rgverb[iVerb].fuFlags = lpov->fuFlags;
  813. rgverb[iVerb].grfAttribs = lpov->grfAttribs;
  814. rgverb[iVerb].lpszVerbName = UtDupString(lpov->lpszVerbName);
  815. }
  816. errRtn:
  817. if (pcverbFetched)
  818. {
  819. *pcverbFetched = iVerb;
  820. }
  821. return hresult;
  822. }
  823. //+-------------------------------------------------------------------------
  824. //
  825. // Member: CEnumVerb::Skip
  826. //
  827. // Synopsis: skips [c] verbs in the enumeration
  828. //
  829. // Effects:
  830. //
  831. // Arguments: [c] -- the number of verbs to skip
  832. //
  833. // Requires:
  834. //
  835. // Returns: HRESULT
  836. //
  837. // Signals:
  838. //
  839. // Modifies:
  840. //
  841. // Derivation: IEnumOLEVERB
  842. //
  843. // Algorithm: adds [c] to the verb index
  844. //
  845. // History: dd-mmm-yy Author Comment
  846. // 17-Jul-95 t-gabes rewrote to use cache
  847. // 01-Dec-93 alexgo 32bit port
  848. //
  849. // Notes:
  850. //
  851. //--------------------------------------------------------------------------
  852. #pragma SEG(CEnumVerb_Skip)
  853. STDMETHODIMP CEnumVerb::Skip(ULONG c)
  854. {
  855. VDATEHEAP();
  856. m_iVerb += c;
  857. if (m_iVerb > (LONG)m_VerbList->cVerbs)
  858. {
  859. // skipping too many
  860. m_iVerb = m_VerbList->cVerbs;
  861. return ResultFromScode(S_FALSE);
  862. }
  863. return NOERROR;
  864. }
  865. //+-------------------------------------------------------------------------
  866. //
  867. // Member: CEnumVerb::Reset
  868. //
  869. // Synopsis: resets the verb enumeration to the beginning
  870. //
  871. // Effects:
  872. //
  873. // Arguments: void
  874. //
  875. // Requires:
  876. //
  877. // Returns: NOERROR
  878. //
  879. // Signals:
  880. //
  881. // Modifies:
  882. //
  883. // Derivation: IEnumOLEVERB
  884. //
  885. // Algorithm:
  886. //
  887. // History: dd-mmm-yy Author Comment
  888. // 17-Jul-95 t-gabes rewrote to use cache
  889. // 01-Dec-93 alexgo 32bit port
  890. //
  891. // Notes:
  892. //
  893. //--------------------------------------------------------------------------
  894. #pragma SEG(CEnumVerb_Reset)
  895. STDMETHODIMP CEnumVerb::Reset(void)
  896. {
  897. VDATEHEAP();
  898. m_iVerb = 0;
  899. return NOERROR;
  900. }
  901. //+-------------------------------------------------------------------------
  902. //
  903. // Member: CEnumVerb::Clone
  904. //
  905. // Synopsis: creates a copy of the enumerator
  906. //
  907. // Effects:
  908. //
  909. // Arguments: [ppenum] -- where to put a pointer to the new clone
  910. //
  911. // Requires:
  912. //
  913. // Returns: NOERROR, E_OUTOFMEMORY
  914. //
  915. // Signals:
  916. //
  917. // Modifies:
  918. //
  919. // Derivation: IEnumOLEVERB
  920. //
  921. // Algorithm:
  922. //
  923. // History: dd-mmm-yy Author Comment
  924. // 01-Dec-93 alexgo 32bit port
  925. //
  926. // Notes:
  927. //
  928. //--------------------------------------------------------------------------
  929. #pragma SEG(CEnumVerb_Clone)
  930. STDMETHODIMP CEnumVerb::Clone(LPENUMOLEVERB FAR* ppenum)
  931. {
  932. VDATEHEAP();
  933. VDATEPTROUT(ppenum, LPENUMOLEVERB);
  934. *ppenum = new FAR CEnumVerb(m_VerbList, m_iVerb);
  935. if (!*ppenum)
  936. return ResultFromScode(E_OUTOFMEMORY);
  937. return NOERROR;
  938. }
  939. //+-------------------------------------------------------------------------
  940. //
  941. // Member: CEnumVerb::GetRefCount
  942. //
  943. // Synopsis: Gets the reference count for the class
  944. //
  945. // Effects:
  946. //
  947. // Arguments: none
  948. //
  949. // Requires:
  950. //
  951. // Returns: ref count
  952. //
  953. // Signals:
  954. //
  955. // Modifies:
  956. //
  957. // Derivation:
  958. //
  959. // Algorithm:
  960. //
  961. // History: dd-mmm-yy Author Comment
  962. // 12-Jul-95 t-gabes Author
  963. //
  964. // Notes: This is needed so OleRegEnumVerbs knows when to dup the cache
  965. //
  966. //--------------------------------------------------------------------------
  967. #pragma SEG(CEnumVerb_GetRefCount)
  968. ULONG CEnumVerb::GetRefCount (void)
  969. {
  970. VDATEHEAP();
  971. return m_cRef;
  972. }
  973. //+-------------------------------------------------------------------------
  974. //
  975. // Member: CEnumVerb::Dump, public (_DEBUG only)
  976. //
  977. // Synopsis: return a string containing the contents of the data members
  978. //
  979. // Effects:
  980. //
  981. // Arguments: [ppszDump] - an out pointer to a null terminated character array
  982. // [ulFlag] - flag determining prefix of all newlines of the
  983. // out character array (default is 0 - no prefix)
  984. // [nIndentLevel] - will add a indent prefix after the other prefix
  985. // for ALL newlines (including those with no prefix)
  986. //
  987. // Requires:
  988. //
  989. // Returns: HRESULT
  990. //
  991. // Signals:
  992. //
  993. // Modifies: [ppszDump] - argument
  994. //
  995. // Derivation:
  996. //
  997. // Algorithm: use dbgstream to create a string containing information on the
  998. // content of data structures
  999. //
  1000. // History: dd-mmm-yy Author Comment
  1001. // 01-Feb-95 t-ScottH author
  1002. //
  1003. // Notes:
  1004. //
  1005. //--------------------------------------------------------------------------
  1006. #ifdef _DEBUG
  1007. HRESULT CEnumVerb::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
  1008. {
  1009. int i;
  1010. char *pszPrefix;
  1011. dbgstream dstrPrefix;
  1012. dbgstream dstrDump;
  1013. // determine prefix of newlines
  1014. if ( ulFlag & DEB_VERBOSE )
  1015. {
  1016. dstrPrefix << this << " _VB ";
  1017. }
  1018. // determine indentation prefix for all newlines
  1019. for (i = 0; i < nIndentLevel; i++)
  1020. {
  1021. dstrPrefix << DUMPTAB;
  1022. }
  1023. pszPrefix = dstrPrefix.str();
  1024. // put data members in stream
  1025. dstrDump << pszPrefix << "No. of References = " << m_cRef << endl;
  1026. dstrDump << pszPrefix << "Address of verb list = " << m_VerbList << endl;
  1027. dstrDump << pszPrefix << "Current Verb Number = " << m_iVerb << endl;
  1028. // cleanup and provide pointer to character array
  1029. *ppszDump = dstrDump.str();
  1030. if (*ppszDump == NULL)
  1031. {
  1032. *ppszDump = UtDupStringA(szDumpErrorMessage);
  1033. }
  1034. CoTaskMemFree(pszPrefix);
  1035. return NOERROR;
  1036. }
  1037. #endif // _DEBUG
  1038. //+-------------------------------------------------------------------------
  1039. //
  1040. // Function: DumpCEnumVerb, public (_DEBUG only)
  1041. //
  1042. // Synopsis: calls the CEnumVerb::Dump method, takes care of errors and
  1043. // returns the zero terminated string
  1044. //
  1045. // Effects:
  1046. //
  1047. // Arguments: [pEV] - pointer to CEnumVerb
  1048. // [ulFlag] - flag determining prefix of all newlines of the
  1049. // out character array (default is 0 - no prefix)
  1050. // [nIndentLevel] - will add a indent prefix after the other prefix
  1051. // for ALL newlines (including those with no prefix)
  1052. //
  1053. // Requires:
  1054. //
  1055. // Returns: character array of structure dump or error (null terminated)
  1056. //
  1057. // Signals:
  1058. //
  1059. // Modifies:
  1060. //
  1061. // Algorithm:
  1062. //
  1063. // History: dd-mmm-yy Author Comment
  1064. // 01-Feb-95 t-ScottH author
  1065. //
  1066. // Notes:
  1067. //
  1068. //--------------------------------------------------------------------------
  1069. #ifdef _DEBUG
  1070. char *DumpCEnumVerb(CEnumVerb *pEV, ULONG ulFlag, int nIndentLevel)
  1071. {
  1072. char *pszDump;
  1073. if (NULL == pEV)
  1074. {
  1075. return UtDupStringA(szDumpBadPtr);
  1076. }
  1077. pEV->Dump(&pszDump, ulFlag, nIndentLevel);
  1078. return pszDump;
  1079. }
  1080. #endif // _DEBUG