Leaked source code of windows server 2003
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.

1249 lines
34 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 != OpenClassesRootKeyEx(
  258. szKey,
  259. KEY_READ,
  260. &hkey))
  261. {
  262. // verb key doesn't exist, so figure out why
  263. szKey[cchBase] = OLESTR('\0');
  264. // szKey now contains one of the following:
  265. // OLE1 - "<ProgID>"
  266. // OLE2 - "CLSID\{clsid}"
  267. if (ERROR_SUCCESS != OpenClassesRootKeyEx(
  268. szKey,
  269. KEY_READ,
  270. &hkey))
  271. {
  272. // the class isn't registered
  273. return ReportResult(0, REGDB_E_CLASSNOTREG, 0, 0);
  274. }
  275. CLOSE(hkey);
  276. // The class has no verbs. This is fine for OLE1 but not OLE2
  277. if (!fOle1Class)
  278. return ResultFromScode(OLEOBJ_E_NOVERBS);
  279. // if hkey is NULL, MakeVerbList will use the default verb
  280. hkey = NULL;
  281. }
  282. // make the verb list
  283. RetErr(MakeVerbList(hkey, clsid, &pVerbList));
  284. Assert(pVerbList != NULL);
  285. // create a CEnumVerb object (this calls AddRef on pVerbList)
  286. pEnum = new FAR CEnumVerb(pVerbList);
  287. if (NULL == pEnum)
  288. {
  289. PrivMemFree(pVerbList);
  290. hresult = ResultFromScode(E_OUTOFMEMORY);
  291. goto errSafeRtn;
  292. }
  293. // set the out parameter and AddRef on behalf of the caller
  294. *ppenum = pEnum;
  295. pEnum->AddRef();
  296. LEDebugOut((DEB_TRACE, "VERB Enumerator cache created\n"));
  297. // Swap our enumerator with the current contents of the global. If
  298. // another thread called OleRegEnumVerbs during this operation and
  299. // stored an enumerator in the global, we need to Release it.
  300. pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, (PVOID)pEnum);
  301. if (pEnum != NULL)
  302. {
  303. pEnum->Release();
  304. LEDebugOut((DEB_TRACE, "VERB Enumerator cache released (replacing global)\n"));
  305. }
  306. errRtn:
  307. hresult = *ppenum ? NOERROR : ResultFromScode (E_OUTOFMEMORY);
  308. // hook the new interface
  309. CALLHOOKOBJECTCREATE(S_OK, CLSID_NULL, IID_IEnumOLEVERB, (IUnknown **)ppenum);
  310. errSafeRtn:
  311. LEDebugOut((DEB_TRACE, "VERB Enumerator cache hits/calls: (%d/%d)\n", g_EnumCache.iHits, g_EnumCache.iCalls));
  312. OLETRACEOUT((API_OleRegEnumVerbs, hresult));
  313. return hresult;
  314. }
  315. //+-------------------------------------------------------------------------
  316. //
  317. // Function: MakeVerbList
  318. //
  319. // Synopsis: gets the list of verbs from the reg db
  320. //
  321. // Effects:
  322. //
  323. // Arguments: [hkey] -- handle to reg key to get verbs from
  324. // NULL for default verb
  325. // [rclsid] -- CLSID to store with verb list
  326. // [ppVerbList] -- OUT paramater for where to put result
  327. //
  328. // Requires:
  329. //
  330. // Returns: HRESULT
  331. //
  332. // Signals:
  333. //
  334. // Modifies:
  335. //
  336. // Derivation: none
  337. //
  338. // Algorithm: Calls RegEnumKey to loop through the reg keys and create a
  339. // list of verbs, which are then collected into one
  340. // larger list. Also, flags and attribs are parsed out.
  341. //
  342. // History: dd-mmm-yy Author Comment
  343. // 12-Sep-95 davidwor modified to make thread-safe
  344. // 08-Sep-95 davidwor optimized caching code
  345. // 14-Jul-95 t-gabes Author
  346. //
  347. // Notes:
  348. // OLEVERB flags are given default values if they are not in
  349. // reg db. This works well for OLE 1.0
  350. //
  351. //--------------------------------------------------------------------------
  352. #pragma SEG(CEnumVerb_MakeVerbList)
  353. STDAPI MakeVerbList
  354. (HKEY hkey,
  355. REFCLSID rclsid,
  356. LPVERBLIST *ppVerbList)
  357. {
  358. VDATEHEAP();
  359. LONG cbValue;
  360. LPVERBLIST pVerbList;
  361. OLECHAR szBuf[MAX_VERB]; // regdb buffer
  362. OLEVERB * rgVerbs = NULL; // verb info array
  363. OLECHAR * pszNames = NULL; // list of NULL-delimited verb names
  364. DWORD cchSpace = 0; // space left for verb names (in bytes)
  365. DWORD cchName; // size of one name (in bytes)
  366. DWORD cVerbs; // number of verbs
  367. DWORD iVerbs; // verb array index
  368. LONG maxVerbIdx = 0;
  369. LONG maxVerbNum = OLEIVERB_LOWEST;
  370. LONG minVerbNum = OLEIVERB_LOWEST - 1;
  371. HRESULT hresult = NOERROR;
  372. VDATEPTROUT(ppVerbList, LPVERBLIST);
  373. *ppVerbList = NULL;
  374. if (NULL == hkey)
  375. {
  376. /*
  377. * No verbs registered
  378. */
  379. cbValue = sizeof(szBuf);
  380. // read the default verb name from the reg db
  381. if (ERROR_SUCCESS != QueryClassesRootValue(
  382. DEFVERB,
  383. szBuf,
  384. &cbValue))
  385. {
  386. // when all else fails, use the string "Edit"
  387. _xstrcpy(szBuf, EDIT);
  388. cbValue = sizeof(EDIT);
  389. }
  390. pVerbList = (LPVERBLIST)PrivMemAlloc(sizeof(VERBLIST) + cbValue);
  391. if (NULL == pVerbList)
  392. return ResultFromScode(E_OUTOFMEMORY);
  393. // fill out a single verb with the defaults
  394. pVerbList->cRef = 0;
  395. pVerbList->clsid = rclsid;
  396. pVerbList->cVerbs = 1;
  397. pVerbList->oleverb[0].lVerb = 0;
  398. pVerbList->oleverb[0].fuFlags = MF_STRING | MF_UNCHECKED | MF_ENABLED;
  399. pVerbList->oleverb[0].grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU;
  400. pVerbList->oleverb[0].lpszVerbName = (LPOLESTR)&pVerbList->oleverb[1];
  401. memcpy(pVerbList->oleverb[0].lpszVerbName, szBuf, cbValue);
  402. *ppVerbList = pVerbList;
  403. return NOERROR;
  404. }
  405. /*
  406. * Have registered verbs
  407. */
  408. // determine number of subkeys
  409. hresult = RegQueryInfoKey(
  410. hkey, NULL, NULL, NULL, &cVerbs,
  411. NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  412. if (ERROR_SUCCESS != hresult || !cVerbs)
  413. {
  414. // they have a "Verb" key but no verb subkeys
  415. hresult = ResultFromScode(OLEOBJ_E_NOVERBS);
  416. goto errRtn;
  417. }
  418. // preallocate this much space for verb names (in bytes)
  419. cchSpace = sizeof(OLECHAR) * cVerbs * 32;
  420. // allocate the VerbList with space for each OLEVERB
  421. // and space for 32 characters for each verb name
  422. pVerbList = (LPVERBLIST)PrivMemAlloc(
  423. sizeof(VERBLIST) +
  424. sizeof(OLEVERB) * (cVerbs - 1) +
  425. cchSpace);
  426. if (NULL == pVerbList)
  427. {
  428. hresult = ResultFromScode(E_OUTOFMEMORY);
  429. goto errRtn;
  430. }
  431. pVerbList->cRef = 0;
  432. pVerbList->clsid = rclsid;
  433. pVerbList->cVerbs = cVerbs;
  434. // Allocate temporary storage for the verbs. Later we'll move the verbs
  435. // from this list into the final VerbList in sorted order.
  436. rgVerbs = (OLEVERB *)PrivMemAlloc(sizeof(OLEVERB) * cVerbs);
  437. if (NULL == rgVerbs)
  438. {
  439. hresult = ResultFromScode(E_OUTOFMEMORY);
  440. goto errRtn;
  441. }
  442. // point pszNames at the first verb name
  443. pszNames = (OLECHAR *)&pVerbList->oleverb[cVerbs];
  444. for (iVerbs = 0; iVerbs < cVerbs; iVerbs++)
  445. {
  446. LPOLESTR psz = pszNames;
  447. // read a verb number
  448. hresult = RegEnumKey(hkey, iVerbs, szBuf, MAX_VERB);
  449. if (NOERROR != hresult)
  450. goto errRtn;
  451. // this is how much space remains
  452. cbValue = cchSpace;
  453. // read a verb name on the verb number
  454. hresult = RegQueryValue(hkey, szBuf, pszNames, &cbValue);
  455. if (NOERROR != hresult)
  456. goto errRtn;
  457. // for safety, make sure verb name isn't too long
  458. if (cbValue > (MAX_VERB + 8) * sizeof(OLECHAR))
  459. {
  460. cbValue = (MAX_VERB + 8) * sizeof(OLECHAR);
  461. pszNames[MAX_VERB + 8 - 1] = OLESTR('\0');
  462. }
  463. rgVerbs[iVerbs].lVerb = Atol(szBuf);
  464. if (rgVerbs[iVerbs].lVerb > maxVerbNum)
  465. {
  466. maxVerbNum = rgVerbs[iVerbs].lVerb;
  467. maxVerbIdx = iVerbs;
  468. }
  469. rgVerbs[iVerbs].fuFlags = MF_STRING | MF_UNCHECKED | MF_ENABLED;
  470. rgVerbs[iVerbs].grfAttribs = OLEVERBATTRIB_ONCONTAINERMENU;
  471. // see if the verb name is followed by a delimiter
  472. while (*psz && *psz != DELIM[0])
  473. psz++;
  474. // determine size of verb name (in characters)
  475. cchName = (ULONG)(psz - pszNames + 1);
  476. if (*psz == DELIM[0])
  477. {
  478. // Parse the menu flags and attributes by finding each delimiter
  479. // and stuffing a 0 over it. This breaks the string into three
  480. // parts which can be handled separately.
  481. LPOLESTR pszFlags;
  482. *psz++ = OLESTR('\0'); // replace delimiter with 0
  483. pszFlags = psz; // remember start of flags
  484. while (*psz && *psz != DELIM[0])
  485. psz++;
  486. if (*psz == DELIM[0])
  487. {
  488. *psz++ = OLESTR('\0'); // replace delimiter with 0
  489. if (*psz != 0)
  490. rgVerbs[iVerbs].grfAttribs = Atol(psz);
  491. }
  492. // now that the flags portion ends with a 0 we can parse it
  493. if (*pszFlags != 0)
  494. rgVerbs[iVerbs].fuFlags = Atol(pszFlags);
  495. }
  496. rgVerbs[iVerbs].lpszVerbName = pszNames;
  497. pszNames += cchName; // move pointer to next verb name position
  498. cchSpace -= cchName; // calculate how much space is left
  499. }
  500. // sort the verbs while putting them in the final verb list
  501. for (iVerbs = 0; iVerbs < cVerbs; iVerbs++)
  502. {
  503. LONG minCurNum = maxVerbNum,
  504. minCurIdx = maxVerbIdx;
  505. LONG idx, num;
  506. // find next verb
  507. for (idx = 0; idx < (LONG)cVerbs; idx++)
  508. {
  509. num = rgVerbs[idx].lVerb;
  510. if (num < minCurNum && num > minVerbNum)
  511. {
  512. minCurNum = num;
  513. minCurIdx = idx;
  514. }
  515. }
  516. pVerbList->oleverb[iVerbs].lVerb = rgVerbs[minCurIdx].lVerb;
  517. pVerbList->oleverb[iVerbs].fuFlags = rgVerbs[minCurIdx].fuFlags;
  518. pVerbList->oleverb[iVerbs].grfAttribs = rgVerbs[minCurIdx].grfAttribs;
  519. pVerbList->oleverb[iVerbs].lpszVerbName = rgVerbs[minCurIdx].lpszVerbName;
  520. minVerbNum = minCurNum;
  521. }
  522. *ppVerbList = pVerbList;
  523. errRtn:
  524. if (rgVerbs)
  525. PrivMemFree(rgVerbs);
  526. if (hkey)
  527. CLOSE(hkey);
  528. return hresult;
  529. }
  530. //+-------------------------------------------------------------------------
  531. //
  532. // Function: OleReleaseEnumVerbCache
  533. //
  534. // Synopsis: Releases the cache if necessary
  535. //
  536. // Effects:
  537. //
  538. // Arguments: void
  539. //
  540. // Requires:
  541. //
  542. // Returns: NOERROR
  543. //
  544. // Signals:
  545. //
  546. // Modifies:
  547. //
  548. // Algorithm: Just call Release method
  549. //
  550. // History: dd-mmm-yy Author Comment
  551. // 12-Sep-95 davidwor modified to make thread-safe
  552. // 18-Jul-95 t-gabes Author
  553. //
  554. // Notes:
  555. //
  556. //--------------------------------------------------------------------------
  557. #pragma SEG(OleReleaseEnumVerbCache)
  558. STDAPI OleReleaseEnumVerbCache(void)
  559. {
  560. CEnumVerb* pEnum;
  561. pEnum = (CEnumVerb *)InterlockedExchangePointer((PVOID *)&g_EnumCache.pEnum, 0);
  562. if (NULL != pEnum)
  563. {
  564. pEnum->Release();
  565. LEDebugOut((DEB_TRACE, "VERB Enumerator cache released\n"));
  566. }
  567. return NOERROR;
  568. }
  569. //+-------------------------------------------------------------------------
  570. //
  571. // Member: CEnumVerb::CEnumVerb
  572. //
  573. // Synopsis: Constructor for the verb enumerator
  574. //
  575. // Effects:
  576. //
  577. // Arguments:
  578. // [pVerbs] -- ptr to the verb list
  579. // [iVerb] -- the index of the verb we're on
  580. //
  581. // Requires:
  582. //
  583. // Returns:
  584. //
  585. // Signals:
  586. //
  587. // Modifies:
  588. //
  589. // Derivation:
  590. //
  591. // Algorithm:
  592. //
  593. // History: dd-mmm-yy Author Comment
  594. // 12-Sep-95 davidwor modified to make thread-safe
  595. // 01-Dec-93 alexgo 32bit port
  596. //
  597. // Notes:
  598. //
  599. //--------------------------------------------------------------------------
  600. #pragma SEG(CEnumVerb_ctor)
  601. CEnumVerb::CEnumVerb
  602. (LPVERBLIST pVerbs,
  603. LONG iVerb)
  604. {
  605. VDATEHEAP();
  606. m_cRef = 1;
  607. m_iVerb = iVerb;
  608. m_VerbList = pVerbs;
  609. // AddRef the VerbList since we now have a reference to it
  610. InterlockedIncrement((long *)&m_VerbList->cRef);
  611. }
  612. //+-------------------------------------------------------------------------
  613. //
  614. // Member: CEnumVerb::QueryInterface
  615. //
  616. // Synopsis: returns the interface implementation
  617. //
  618. // Effects:
  619. //
  620. // Arguments: [iid] -- the requested interface id
  621. // [ppv] -- where to put a pointer to the interface
  622. //
  623. // Requires:
  624. //
  625. // Returns: NOERROR, E_NOINTERFACE
  626. //
  627. // Signals:
  628. //
  629. // Modifies:
  630. //
  631. // Derivation: IEnumOLEVERB
  632. //
  633. // Algorithm:
  634. //
  635. // History: dd-mmm-yy Author Comment
  636. // 01-Dec-93 alexgo 32bit port
  637. //
  638. // Notes:
  639. //
  640. //--------------------------------------------------------------------------
  641. #pragma SEG(CEnumVerb_QueryInterface)
  642. STDMETHODIMP CEnumVerb::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  643. {
  644. VDATEHEAP();
  645. VDATEPTROUT(ppv, LPVOID);
  646. if (IsEqualIID(iid, IID_IUnknown) ||
  647. IsEqualIID(iid, IID_IEnumOLEVERB))
  648. {
  649. *ppv = this;
  650. AddRef();
  651. return NOERROR;
  652. }
  653. *ppv = NULL;
  654. return ResultFromScode(E_NOINTERFACE);
  655. }
  656. //+-------------------------------------------------------------------------
  657. //
  658. // Member: CEnumVerb::AddRef
  659. //
  660. // Synopsis: increments the reference count
  661. //
  662. // Effects:
  663. //
  664. // Arguments: void
  665. //
  666. // Requires:
  667. //
  668. // Returns: ULONG -- the new reference count
  669. //
  670. // Signals:
  671. //
  672. // Modifies:
  673. //
  674. // Derivation: IEnumOLEVERB
  675. //
  676. // Algorithm:
  677. //
  678. // History: dd-mmm-yy Author Comment
  679. // 12-Sep-95 davidwor modified to make thread-safe
  680. // 01-Dec-93 alexgo 32bit port
  681. //
  682. // Notes:
  683. //
  684. //--------------------------------------------------------------------------
  685. #pragma SEG(CEnumVerb_AddRef)
  686. STDMETHODIMP_(ULONG) CEnumVerb::AddRef(void)
  687. {
  688. VDATEHEAP();
  689. return InterlockedIncrement((long *)&m_cRef);
  690. }
  691. //+-------------------------------------------------------------------------
  692. //
  693. // Member: CEnumVerb::Release
  694. //
  695. // Synopsis: decrements the reference count
  696. //
  697. // Effects: will delete the object when ref count goes to zero
  698. //
  699. // Arguments: void
  700. //
  701. // Requires:
  702. //
  703. // Returns: ULONG -- the new ref count
  704. //
  705. // Signals:
  706. //
  707. // Modifies:
  708. //
  709. // Derivation: IEnumOLEVERB
  710. //
  711. // Algorithm:
  712. //
  713. // History: dd-mmm-yy Author Comment
  714. // 12-Sep-95 davidwor modified to make thread-safe
  715. // 18-Jul-95 t-gabes release verb cache when finished
  716. // 01-Dec-93 alexgo 32bit port
  717. //
  718. // Notes:
  719. //
  720. //--------------------------------------------------------------------------
  721. #pragma SEG(CEnumVerb_Release)
  722. STDMETHODIMP_(ULONG) CEnumVerb::Release(void)
  723. {
  724. VDATEHEAP();
  725. ULONG cRef;
  726. cRef = InterlockedDecrement((long *)&m_cRef);
  727. if (0 == cRef)
  728. {
  729. if (0 == InterlockedDecrement((long *)&m_VerbList->cRef))
  730. {
  731. // no more references to m_VerbList so free it
  732. PrivMemFree(m_VerbList);
  733. LEDebugOut((DEB_TRACE, "VERB Enumerator verb list released\n"));
  734. }
  735. delete this;
  736. return 0;
  737. }
  738. return cRef;
  739. }
  740. //+-------------------------------------------------------------------------
  741. //
  742. // Member: CEnumVerb::Next
  743. //
  744. // Synopsis: gets the next [cverb] verbs from the verb list
  745. //
  746. // Effects:
  747. //
  748. // Arguments: [cverb] -- the number of verbs to get
  749. // [rgverb] -- where to put the verbs
  750. // [pcverbFetched] -- where to put the num of verbs retrieved
  751. //
  752. // Requires:
  753. //
  754. // Returns: HRESULT
  755. //
  756. // Signals:
  757. //
  758. // Modifies:
  759. //
  760. // Derivation: IEnumOLEVERB
  761. //
  762. // Algorithm: loops through [cverb] times and grabs the info from the
  763. // reg db
  764. //
  765. // History: dd-mmm-yy Author Comment
  766. // 17-Jul-95 t-gabes rewrote to use cache
  767. // 01-Dec-93 alexgo 32bit port
  768. //
  769. // Notes:
  770. //
  771. //--------------------------------------------------------------------------
  772. #pragma SEG(CEnumVerb_Next)
  773. STDMETHODIMP CEnumVerb::Next
  774. (ULONG cverb,
  775. LPOLEVERB rgverb,
  776. ULONG FAR* pcverbFetched)
  777. {
  778. VDATEHEAP();
  779. ULONG iVerb; // number successfully fetched
  780. HRESULT hresult = NOERROR;
  781. if (!rgverb)
  782. {
  783. if (pcverbFetched)
  784. *pcverbFetched = 0;
  785. VDATEPTROUT(rgverb, OLEVERB);
  786. }
  787. if (pcverbFetched)
  788. {
  789. VDATEPTROUT(pcverbFetched, ULONG);
  790. }
  791. else if (cverb != 1)
  792. {
  793. // the spec says that if pcverbFetched == NULL, then
  794. // the count of elements to fetch must be 1
  795. return ResultFromScode(E_INVALIDARG);
  796. }
  797. for (iVerb = 0; iVerb < cverb; iVerb++)
  798. {
  799. if (m_iVerb >= (LONG)m_VerbList->cVerbs)
  800. {
  801. // no more
  802. hresult = ResultFromScode(S_FALSE);
  803. goto errRtn;
  804. }
  805. OLEVERB *lpov = &m_VerbList->oleverb[m_iVerb++];
  806. rgverb[iVerb].lVerb = lpov->lVerb;
  807. rgverb[iVerb].fuFlags = lpov->fuFlags;
  808. rgverb[iVerb].grfAttribs = lpov->grfAttribs;
  809. rgverb[iVerb].lpszVerbName = UtDupString(lpov->lpszVerbName);
  810. }
  811. errRtn:
  812. if (pcverbFetched)
  813. {
  814. *pcverbFetched = iVerb;
  815. }
  816. return hresult;
  817. }
  818. //+-------------------------------------------------------------------------
  819. //
  820. // Member: CEnumVerb::Skip
  821. //
  822. // Synopsis: skips [c] verbs in the enumeration
  823. //
  824. // Effects:
  825. //
  826. // Arguments: [c] -- the number of verbs to skip
  827. //
  828. // Requires:
  829. //
  830. // Returns: HRESULT
  831. //
  832. // Signals:
  833. //
  834. // Modifies:
  835. //
  836. // Derivation: IEnumOLEVERB
  837. //
  838. // Algorithm: adds [c] to the verb index
  839. //
  840. // History: dd-mmm-yy Author Comment
  841. // 17-Jul-95 t-gabes rewrote to use cache
  842. // 01-Dec-93 alexgo 32bit port
  843. //
  844. // Notes:
  845. //
  846. //--------------------------------------------------------------------------
  847. #pragma SEG(CEnumVerb_Skip)
  848. STDMETHODIMP CEnumVerb::Skip(ULONG c)
  849. {
  850. VDATEHEAP();
  851. m_iVerb += c;
  852. if (m_iVerb > (LONG)m_VerbList->cVerbs)
  853. {
  854. // skipping too many
  855. m_iVerb = m_VerbList->cVerbs;
  856. return ResultFromScode(S_FALSE);
  857. }
  858. return NOERROR;
  859. }
  860. //+-------------------------------------------------------------------------
  861. //
  862. // Member: CEnumVerb::Reset
  863. //
  864. // Synopsis: resets the verb enumeration to the beginning
  865. //
  866. // Effects:
  867. //
  868. // Arguments: void
  869. //
  870. // Requires:
  871. //
  872. // Returns: NOERROR
  873. //
  874. // Signals:
  875. //
  876. // Modifies:
  877. //
  878. // Derivation: IEnumOLEVERB
  879. //
  880. // Algorithm:
  881. //
  882. // History: dd-mmm-yy Author Comment
  883. // 17-Jul-95 t-gabes rewrote to use cache
  884. // 01-Dec-93 alexgo 32bit port
  885. //
  886. // Notes:
  887. //
  888. //--------------------------------------------------------------------------
  889. #pragma SEG(CEnumVerb_Reset)
  890. STDMETHODIMP CEnumVerb::Reset(void)
  891. {
  892. VDATEHEAP();
  893. m_iVerb = 0;
  894. return NOERROR;
  895. }
  896. //+-------------------------------------------------------------------------
  897. //
  898. // Member: CEnumVerb::Clone
  899. //
  900. // Synopsis: creates a copy of the enumerator
  901. //
  902. // Effects:
  903. //
  904. // Arguments: [ppenum] -- where to put a pointer to the new clone
  905. //
  906. // Requires:
  907. //
  908. // Returns: NOERROR, E_OUTOFMEMORY
  909. //
  910. // Signals:
  911. //
  912. // Modifies:
  913. //
  914. // Derivation: IEnumOLEVERB
  915. //
  916. // Algorithm:
  917. //
  918. // History: dd-mmm-yy Author Comment
  919. // 01-Dec-93 alexgo 32bit port
  920. //
  921. // Notes:
  922. //
  923. //--------------------------------------------------------------------------
  924. #pragma SEG(CEnumVerb_Clone)
  925. STDMETHODIMP CEnumVerb::Clone(LPENUMOLEVERB FAR* ppenum)
  926. {
  927. VDATEHEAP();
  928. VDATEPTROUT(ppenum, LPENUMOLEVERB);
  929. *ppenum = new FAR CEnumVerb(m_VerbList, m_iVerb);
  930. if (!*ppenum)
  931. return ResultFromScode(E_OUTOFMEMORY);
  932. return NOERROR;
  933. }
  934. //+-------------------------------------------------------------------------
  935. //
  936. // Member: CEnumVerb::GetRefCount
  937. //
  938. // Synopsis: Gets the reference count for the class
  939. //
  940. // Effects:
  941. //
  942. // Arguments: none
  943. //
  944. // Requires:
  945. //
  946. // Returns: ref count
  947. //
  948. // Signals:
  949. //
  950. // Modifies:
  951. //
  952. // Derivation:
  953. //
  954. // Algorithm:
  955. //
  956. // History: dd-mmm-yy Author Comment
  957. // 12-Jul-95 t-gabes Author
  958. //
  959. // Notes: This is needed so OleRegEnumVerbs knows when to dup the cache
  960. //
  961. //--------------------------------------------------------------------------
  962. #pragma SEG(CEnumVerb_GetRefCount)
  963. ULONG CEnumVerb::GetRefCount (void)
  964. {
  965. VDATEHEAP();
  966. return m_cRef;
  967. }
  968. //+-------------------------------------------------------------------------
  969. //
  970. // Member: CEnumVerb::Dump, public (_DEBUG only)
  971. //
  972. // Synopsis: return a string containing the contents of the data members
  973. //
  974. // Effects:
  975. //
  976. // Arguments: [ppszDump] - an out pointer to a null terminated character array
  977. // [ulFlag] - flag determining prefix of all newlines of the
  978. // out character array (default is 0 - no prefix)
  979. // [nIndentLevel] - will add a indent prefix after the other prefix
  980. // for ALL newlines (including those with no prefix)
  981. //
  982. // Requires:
  983. //
  984. // Returns: HRESULT
  985. //
  986. // Signals:
  987. //
  988. // Modifies: [ppszDump] - argument
  989. //
  990. // Derivation:
  991. //
  992. // Algorithm: use dbgstream to create a string containing information on the
  993. // content of data structures
  994. //
  995. // History: dd-mmm-yy Author Comment
  996. // 01-Feb-95 t-ScottH author
  997. //
  998. // Notes:
  999. //
  1000. //--------------------------------------------------------------------------
  1001. #ifdef _DEBUG
  1002. HRESULT CEnumVerb::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
  1003. {
  1004. int i;
  1005. char *pszPrefix;
  1006. dbgstream dstrPrefix;
  1007. dbgstream dstrDump;
  1008. // determine prefix of newlines
  1009. if ( ulFlag & DEB_VERBOSE )
  1010. {
  1011. dstrPrefix << this << " _VB ";
  1012. }
  1013. // determine indentation prefix for all newlines
  1014. for (i = 0; i < nIndentLevel; i++)
  1015. {
  1016. dstrPrefix << DUMPTAB;
  1017. }
  1018. pszPrefix = dstrPrefix.str();
  1019. // put data members in stream
  1020. dstrDump << pszPrefix << "No. of References = " << m_cRef << endl;
  1021. dstrDump << pszPrefix << "Address of verb list = " << m_VerbList << endl;
  1022. dstrDump << pszPrefix << "Current Verb Number = " << m_iVerb << endl;
  1023. // cleanup and provide pointer to character array
  1024. *ppszDump = dstrDump.str();
  1025. if (*ppszDump == NULL)
  1026. {
  1027. *ppszDump = UtDupStringA(szDumpErrorMessage);
  1028. }
  1029. CoTaskMemFree(pszPrefix);
  1030. return NOERROR;
  1031. }
  1032. #endif // _DEBUG
  1033. //+-------------------------------------------------------------------------
  1034. //
  1035. // Function: DumpCEnumVerb, public (_DEBUG only)
  1036. //
  1037. // Synopsis: calls the CEnumVerb::Dump method, takes care of errors and
  1038. // returns the zero terminated string
  1039. //
  1040. // Effects:
  1041. //
  1042. // Arguments: [pEV] - pointer to CEnumVerb
  1043. // [ulFlag] - flag determining prefix of all newlines of the
  1044. // out character array (default is 0 - no prefix)
  1045. // [nIndentLevel] - will add a indent prefix after the other prefix
  1046. // for ALL newlines (including those with no prefix)
  1047. //
  1048. // Requires:
  1049. //
  1050. // Returns: character array of structure dump or error (null terminated)
  1051. //
  1052. // Signals:
  1053. //
  1054. // Modifies:
  1055. //
  1056. // Algorithm:
  1057. //
  1058. // History: dd-mmm-yy Author Comment
  1059. // 01-Feb-95 t-ScottH author
  1060. //
  1061. // Notes:
  1062. //
  1063. //--------------------------------------------------------------------------
  1064. #ifdef _DEBUG
  1065. char *DumpCEnumVerb(CEnumVerb *pEV, ULONG ulFlag, int nIndentLevel)
  1066. {
  1067. char *pszDump;
  1068. if (NULL == pEV)
  1069. {
  1070. return UtDupStringA(szDumpBadPtr);
  1071. }
  1072. pEV->Dump(&pszDump, ulFlag, nIndentLevel);
  1073. return pszDump;
  1074. }
  1075. #endif // _DEBUG