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.

860 lines
24 KiB

  1. //*** qistub.cpp -- QI helpers (retail and debug)
  2. // DESCRIPTION
  3. // this file has the shared-source 'master' implementation. it is
  4. // #included in each DLL that uses it.
  5. // clients do something like:
  6. // #include "priv.h" // for types, ASSERT, DM_*, DF_*, etc.
  7. // #include "../lib/qistub.cpp"
  8. #include "qistub.h"
  9. #include <strsafe.h>
  10. #define DM_MISC2 0 // misc stuff (verbose)
  11. // hack-o-rama: shlwapi/qistub.cpp does #undef DEBUG but its PCH was
  12. // built DEBUG, so lots of bad stuff happens. work-around it here.
  13. #undef DBEXEC
  14. #ifdef DEBUG
  15. #define DBEXEC(flg, expr) ((flg) ? (expr) : 0)
  16. #else
  17. #define DBEXEC(flg, expr) /*NOTHING*/
  18. #endif
  19. #ifdef DEBUG // {
  20. //*** CUniqueTab {
  21. // DESCRIPTION
  22. // key/data table insert and lookup, w/ interlock.
  23. class CUniqueTab
  24. {
  25. public:
  26. BOOL Init();
  27. void * Add(int val);
  28. void * Find(int val, int delta);
  29. void Reset(void);
  30. // n.b. *not* protected
  31. CUniqueTab(int cbElt);
  32. virtual ~CUniqueTab();
  33. protected:
  34. private:
  35. void _Lock(void) { EnterCriticalSection(&_hLock); }
  36. void _Unlock(void) { LeaveCriticalSection(&_hLock); }
  37. CRITICAL_SECTION _hLock;
  38. // key + (arbitrary) limit of 4 int's of client data
  39. #define CUT_CBELTMAX (SIZEOF(int) + 4 * SIZEOF(int))
  40. int _cbElt; // size of an entry (key + data)
  41. // (arbitrary) limit to catch clients running amuck
  42. #define CUT_CVALMAX 256 // actually, a LIM not a MAX
  43. HDSA _hValTab;
  44. };
  45. CUniqueTab::CUniqueTab(int cbElt)
  46. {
  47. ASSERT(cbElt >= SIZEOF(DWORD)); // need at least a key; data optional
  48. _cbElt = cbElt;
  49. _hValTab = DSA_Create(_cbElt, 4);
  50. return;
  51. }
  52. CUniqueTab::~CUniqueTab()
  53. {
  54. DSA_Destroy(_hValTab);
  55. DeleteCriticalSection(&_hLock);
  56. return;
  57. }
  58. BOOL CUniqueTab::Init()
  59. {
  60. return InitializeCriticalSectionAndSpinCount(&_hLock, 0);
  61. }
  62. struct cutent {
  63. int iKey;
  64. char bData[CUT_CBELTMAX - SIZEOF(int)];
  65. };
  66. struct cfinddata {
  67. int iKey;
  68. int dRange;
  69. void *pEntry;
  70. };
  71. int _UTFindCallback(void *pEnt, void *pData)
  72. {
  73. #define INFUNC(base, p, range) ((base) <= (p) && (p) <= (base) + (range))
  74. struct cfinddata *pcd = (struct cfinddata *)pData;
  75. if (INFUNC(*(int *)pEnt, pcd->iKey, pcd->dRange)) {
  76. pcd->pEntry = pEnt;
  77. return 0;
  78. }
  79. return 1;
  80. #undef INFUNC
  81. }
  82. //*** CUniqueTab::Add -- add entry if not already there
  83. //
  84. void * CUniqueTab::Add(int val)
  85. {
  86. struct cfinddata cd = { val, 0, NULL };
  87. _Lock();
  88. DSA_EnumCallback(_hValTab, _UTFindCallback, &cd);
  89. if (!cd.pEntry) {
  90. int i;
  91. // lazy,lazy,lazy: alloc max size and let DSA_AppendItem sort it out
  92. struct cutent elt = { val, 0 /*,0,...,0*/ };
  93. TraceMsg(DM_MISC2, "cut.add: add %x", val);
  94. if (DSA_GetItemCount(_hValTab) <= CUT_CVALMAX) {
  95. i = DSA_AppendItem(_hValTab, &elt);
  96. cd.pEntry = DSA_GetItemPtr(_hValTab, i);
  97. }
  98. }
  99. _Unlock();
  100. return cd.pEntry;
  101. }
  102. //*** CUniqueTab::Find -- find entry
  103. //
  104. void * CUniqueTab::Find(int val, int delta)
  105. {
  106. struct cfinddata cd = { val, delta, NULL };
  107. DSA_EnumCallback(_hValTab, _UTFindCallback, &cd);
  108. if (cd.pEntry) {
  109. // TODO: add p->data[0] dump
  110. TraceMsg(DM_MISC2, "cut.find: found %x+%d", val, delta);
  111. }
  112. return cd.pEntry;
  113. }
  114. //*** _UTResetCallback -- helper for CUniqueTab::Reset
  115. int _UTResetCallback(void *pEnt, void *pData)
  116. {
  117. struct cutent *pce = (struct cutent *)pEnt;
  118. int cbEnt = *(int *)pData;
  119. // perf: could move the SIZEOF(int) into caller, but seems safer here
  120. memset(pce->bData, 0, cbEnt - SIZEOF(int));
  121. return 1;
  122. }
  123. //*** Reset -- clear 'data' part of all entries
  124. //
  125. void CUniqueTab::Reset(void)
  126. {
  127. if (EVAL(_cbElt > SIZEOF(int))) {
  128. _Lock();
  129. DSA_EnumCallback(_hValTab, _UTResetCallback, &_cbElt);
  130. _Unlock();
  131. }
  132. return;
  133. }
  134. // }
  135. #endif // }
  136. //*** QueryInterface helpers {
  137. //*** FAST_IsEqualIID -- fast compare
  138. // (cast to 'LONG_PTR' so don't get overloaded ==)
  139. #define FAST_IsEqualIID(piid1, piid2) ((LONG_PTR)(piid1) == (LONG_PTR)(piid2))
  140. #ifdef DEBUG // {
  141. //*** DBNoOp -- do nothing (but suppress compiler optimizations)
  142. // NOTES
  143. // this won't fool compiler when it gets smarter, oh well...
  144. void DBNoOp()
  145. {
  146. return;
  147. }
  148. void DBBrkpt()
  149. {
  150. DBNoOp();
  151. return;
  152. }
  153. //*** DBBreakGUID -- debug hook (gets readable name, allows brkpt on IID)
  154. // DESCRIPTION
  155. // search for 'BRKPT' for various hooks.
  156. // patch 'DBQIiid' to brkpt on a specific iface
  157. // patch 'DBQIiSeq' to brkpt on Nth QI of specific iface
  158. // brkpt on interesting events noted below
  159. // NOTES
  160. // warning: returns ptr to *static* buffer!
  161. typedef enum {
  162. DBBRK_NIL = 0,
  163. DBBRK_ENTER = 0x01,
  164. DBBRK_TRACE = 0x02,
  165. DBBRK_S_XXX = 0x04,
  166. DBBRK_E_XXX = 0x08,
  167. DBBRK_BRKPT = 0x10,
  168. } DBBRK;
  169. DBBRK DBQIuTrace = DBBRK_NIL; // BRKPT patch to enable brkpt'ing
  170. GUID *DBQIiid = NULL; // BRKPT patch to brkpt on iface
  171. int DBQIiSeq = -1; // BRKPT patch to brkpt on Nth QI of DBQIiid
  172. long DBQIfReset = FALSE; // BRKPT patch to reset counters
  173. TCHAR *DBBreakGUID(const GUID *piid, DBBRK brkCmd)
  174. {
  175. static TCHAR szClass[GUIDSTR_MAX];
  176. SHStringFromGUID(*piid, szClass, ARRAYSIZE(szClass));
  177. // FEATURE: fold these 2 if's together
  178. if ((DBQIuTrace & brkCmd) &&
  179. (DBQIiid == NULL || IsEqualIID(*piid, *DBQIiid))) {
  180. TraceMsg(DM_TRACE, "util: DBBreakGUID brkCmd=%x clsid=%s (%s)", brkCmd, szClass, Dbg_GetREFIIDName(*piid));
  181. // BRKPT put brkpt here to brkpt on 'brkCmd' event
  182. DBBrkpt();
  183. }
  184. if (DBQIiid != NULL && IsEqualIID(*piid, *DBQIiid)) {
  185. //TraceMsg(DM_TRACE, "util: DBBreakGUID clsid=%s (%s)", szClass, Dbg_GetREFIIDName(*piid));
  186. if (brkCmd != DBBRK_TRACE) {
  187. // BRKPT put brkpt here to brkpt on 'DBQIiid' iface
  188. DBNoOp();
  189. }
  190. }
  191. // BRKPT put your brkpt(s) here for various events
  192. switch (brkCmd) {
  193. case DBBRK_ENTER:
  194. // QI called w/ this iface
  195. DBNoOp();
  196. break;
  197. case DBBRK_TRACE:
  198. // looped over this iface
  199. DBNoOp();
  200. break;
  201. case DBBRK_S_XXX:
  202. // successful QI for this iface
  203. DBNoOp();
  204. break;
  205. case DBBRK_E_XXX:
  206. // failed QI for this iface
  207. DBNoOp();
  208. break;
  209. case DBBRK_BRKPT:
  210. // various brkpt events, see backtrace to figure out which one
  211. DBNoOp();
  212. break;
  213. }
  214. return szClass;
  215. }
  216. #endif // }
  217. #ifdef DEBUG
  218. CUniqueTab *DBpQIFuncTab;
  219. STDAPI_(BOOL) DBIsQIFunc(int ret, int delta)
  220. {
  221. BOOL fRet = FALSE;
  222. if (DBpQIFuncTab)
  223. fRet = BOOLFROMPTR(DBpQIFuncTab->Find(ret, delta));
  224. return fRet;
  225. }
  226. #endif
  227. // perf: shell split means FAST_IsEqIID often fails, so QI_EASY is off.
  228. #define QI_EASY 0 // w/ shell split, seems to be too rare
  229. #ifdef DEBUG // {
  230. int DBcQITot, DBcQIUnk, DBcQIErr, DBcQIEasy, DBcQIHard;
  231. LPCQITAB DBpqitStats; // BRKPT: patch to enable QITABENT profiling
  232. #define DBSTAT_CNT 20
  233. int DBcStats[DBSTAT_CNT + 3]; // 0..n, overflow, IUnknown, E_FAIL
  234. #define DBSI_FAIL (-1)
  235. #define DBSI_IUNKNOWN (-2)
  236. #define DBSI_OVERFLOW (-3)
  237. #define DBSI_SPEC(i) (DBSTAT_CNT - 1 + (-(i)))
  238. //***
  239. // DESCRIPTION
  240. // search for 'BRKPT' for various hooks.
  241. // patch 'DBpqitStats' to gather stats on that QITAB
  242. // then break into debugger (ctrl+C) and dumpa 'DBcStats l 24'
  243. // then sort high count guys to the front, and 0 count guys to the end
  244. //
  245. void DBQIStats(LPCQITAB pqitab, INT_PTR i)
  246. {
  247. if (pqitab != DBpqitStats)
  248. return;
  249. if (i >= DBSTAT_CNT)
  250. i = DBSI_OVERFLOW;
  251. if (i < 0)
  252. i = DBSTAT_CNT - 1 + (-i);
  253. DBcStats[i]++;
  254. return;
  255. }
  256. void DBDumpQIStats()
  257. {
  258. int i;
  259. TCHAR *p;
  260. TCHAR buf[256];
  261. TraceMsg(TF_QISTUB, "qi stats: tot=%d unk=%d err=%d easy(%d)=%d hard=%d",
  262. DBcQITot, DBcQIUnk, DBcQIErr, QI_EASY, DBcQIEasy, DBcQIHard);
  263. if (DBpqitStats == NULL)
  264. return;
  265. p = buf;
  266. for (i = 0; i < DBSTAT_CNT; i++) {
  267. p += wnsprintf(p, ARRAYSIZE(buf) - (p-buf), TEXT(" %d"), DBcStats[i]);
  268. }
  269. StringCchPrintf(p, ARRAYSIZE(buf) - (p-buf), TEXT(" o=%d u=%d e=%d"),
  270. DBcStats[DBSI_SPEC(DBSI_OVERFLOW)],
  271. DBcStats[DBSI_SPEC(DBSI_IUNKNOWN)],
  272. DBcStats[DBSI_SPEC(DBSI_FAIL)]);
  273. TraceMsg(TF_QISTUB, "qi stats: %s", buf);
  274. return;
  275. }
  276. #endif // }
  277. //*** QISearch -- table-driven QI
  278. // ENTRY/EXIT
  279. // this IUnknown* of calling QI
  280. // pqit QI table of IID,cast_offset pairs
  281. // ppv the usual
  282. // hr the usual S_OK/E_NOINTERFACE, plus other E_* for errors
  283. // NOTES
  284. // perf: shell split means FAST_IsEqIID often fails, so QI_EASY is off.
  285. // perf: IUnknown v. rare, so goes last.
  286. // PERF: explicit 'E_NOIFACE' entry in qitab for common miss(es)?
  287. STDAPI_(void*) QIStub_CreateInstance(void* that, IUnknown* punk, REFIID riid); // qistub.cpp
  288. STDAPI QISearch(void* that, LPCQITAB pqitab, REFIID riid, LPVOID* ppv)
  289. {
  290. // do *not* move this!!! (must be 1st on frame)
  291. #ifdef DEBUG
  292. #if (_X86_)
  293. int var0; // *must* be 1st on frame
  294. #endif
  295. #endif
  296. LPCQITAB pqit;
  297. #ifdef DEBUG
  298. TCHAR *pst;
  299. DBEXEC(TRUE, DBcQITot++);
  300. #if ( _X86_) // QIStub only works for X86
  301. if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
  302. if (DBpQIFuncTab == NULL)
  303. DBpQIFuncTab = new CUniqueTab(SIZEOF(DWORD)); // LONG_PTR?
  304. if (DBpQIFuncTab && DBpQIFuncTab->Init()) {
  305. int n;
  306. int fp = (int) (1 + (int *)&var0);
  307. struct DBstkback sbtab[1] = { 0 };
  308. n = DBGetStackBack(&fp, sbtab, ARRAYSIZE(sbtab));
  309. DBpQIFuncTab->Add(sbtab[n - 1].ret);
  310. }
  311. }
  312. #endif
  313. if (DBQIuTrace)
  314. pst = DBBreakGUID(&riid, DBBRK_ENTER);
  315. #endif
  316. if (ppv == NULL)
  317. return E_POINTER;
  318. #if QI_EASY
  319. // 1st try the fast way
  320. for (pqit = pqitab; pqit->piid != NULL; pqit++) {
  321. DBEXEC(DBQIuTrace, (pst = DBBreakGUID(pqit->piid, DBBRK_TRACE)));
  322. if (FAST_IsEqualIID(&riid, pqit->piid)) {
  323. DBEXEC(TRUE, DBcQIEasy++);
  324. goto Lhit;
  325. }
  326. }
  327. #endif
  328. // no luck, try the hard way
  329. for (pqit = pqitab; pqit->piid != NULL; pqit++) {
  330. DBEXEC(DBQIuTrace, (pst = DBBreakGUID(pqit->piid, DBBRK_TRACE)));
  331. if (IsEqualIID(riid, *(pqit->piid))) {
  332. DBEXEC(TRUE, DBcQIHard++);
  333. #if QI_EASY
  334. Lhit:
  335. #else
  336. // keep 'easy' stats anyway
  337. DBEXEC(FAST_IsEqualIID(&riid, pqit->piid), DBcQIEasy++);
  338. #endif
  339. #ifdef DEBUG
  340. DBEXEC(TRUE, DBQIStats(pqitab, pqit - pqitab));
  341. #if ( _X86_) // QIStub only works for X86
  342. if (IsFlagSet(g_dwDumpFlags, DF_DEBUGQI)) {
  343. IUnknown* punk = (IUnknown*)((LONG_PTR)that + pqit->dwOffset);
  344. *ppv = QIStub_CreateInstance(that, punk, riid);
  345. if (*ppv) {
  346. pst = DBBreakGUID(&riid, DBBRK_S_XXX);
  347. return S_OK;
  348. }
  349. }
  350. #endif
  351. #endif
  352. Lcast:
  353. IUnknown* punk = (IUnknown*)((LONG_PTR)that + pqit->dwOffset);
  354. DBEXEC(TRUE, (pst = DBBreakGUID(&riid, DBBRK_S_XXX)));
  355. punk->AddRef();
  356. *ppv = punk;
  357. return S_OK;
  358. }
  359. }
  360. // no luck, try IUnknown (which is implicit in the table)
  361. // we try IUnknown last not 1st since stats show it's rare
  362. if (IsEqualIID(riid, IID_IUnknown)) {
  363. // just use 1st table entry
  364. pqit = pqitab;
  365. DBEXEC(TRUE, DBcQIUnk++);
  366. DBEXEC(TRUE, DBQIStats(pqitab, DBSI_IUNKNOWN));
  367. goto Lcast;
  368. }
  369. DBEXEC(DBQIuTrace, (pst = DBBreakGUID(&riid, DBBRK_E_XXX)));
  370. DBEXEC(TRUE, DBcQIErr++);
  371. DBEXEC(TRUE, DBQIStats(pqitab, DBSI_FAIL));
  372. *ppv = NULL;
  373. return E_NOINTERFACE;
  374. }
  375. // }
  376. #ifdef DEBUG // {
  377. #if ( _X86_) // { QIStub only works for X86
  378. //*** QIStub helpers {
  379. class CQIStub
  380. {
  381. public:
  382. virtual void thunk0();
  383. // FEATURE: should AddRef/Release up _iSeq? don't recommend it.
  384. virtual STDMETHODIMP_(ULONG) AddRef(void)
  385. { _cRef++; return _cRef; }
  386. virtual STDMETHODIMP_(ULONG) Release(void)
  387. { _cRef--; if (_cRef>0) return _cRef; delete this; return 0; }
  388. virtual void thunk3();
  389. virtual void thunk4();
  390. virtual void thunk5();
  391. virtual void thunk6();
  392. virtual void thunk7();
  393. virtual void thunk8();
  394. virtual void thunk9();
  395. virtual void thunk10();
  396. virtual void thunk11();
  397. virtual void thunk12();
  398. virtual void thunk13();
  399. virtual void thunk14();
  400. virtual void thunk15();
  401. virtual void thunk16();
  402. virtual void thunk17();
  403. virtual void thunk18();
  404. virtual void thunk19();
  405. virtual void thunk20();
  406. virtual void thunk21();
  407. virtual void thunk22();
  408. virtual void thunk23();
  409. virtual void thunk24();
  410. virtual void thunk25();
  411. virtual void thunk26();
  412. virtual void thunk27();
  413. virtual void thunk28();
  414. virtual void thunk29();
  415. virtual void thunk30();
  416. virtual void thunk31();
  417. virtual void thunk32();
  418. virtual void thunk33();
  419. virtual void thunk34();
  420. virtual void thunk35();
  421. virtual void thunk36();
  422. virtual void thunk37();
  423. virtual void thunk38();
  424. virtual void thunk39();
  425. virtual void thunk40();
  426. virtual void thunk41();
  427. virtual void thunk42();
  428. virtual void thunk43();
  429. virtual void thunk44();
  430. virtual void thunk45();
  431. virtual void thunk46();
  432. virtual void thunk47();
  433. virtual void thunk48();
  434. virtual void thunk49();
  435. virtual void thunk50();
  436. virtual void thunk51();
  437. virtual void thunk52();
  438. virtual void thunk53();
  439. virtual void thunk54();
  440. virtual void thunk55();
  441. virtual void thunk56();
  442. virtual void thunk57();
  443. virtual void thunk58();
  444. virtual void thunk59();
  445. virtual void thunk60();
  446. virtual void thunk61();
  447. virtual void thunk62();
  448. virtual void thunk63();
  449. virtual void thunk64();
  450. virtual void thunk65();
  451. virtual void thunk66();
  452. virtual void thunk67();
  453. virtual void thunk68();
  454. virtual void thunk69();
  455. virtual void thunk70();
  456. virtual void thunk71();
  457. virtual void thunk72();
  458. virtual void thunk73();
  459. virtual void thunk74();
  460. virtual void thunk75();
  461. virtual void thunk76();
  462. virtual void thunk77();
  463. virtual void thunk78();
  464. virtual void thunk79();
  465. virtual void thunk80();
  466. virtual void thunk81();
  467. virtual void thunk82();
  468. virtual void thunk83();
  469. virtual void thunk84();
  470. virtual void thunk85();
  471. virtual void thunk86();
  472. virtual void thunk87();
  473. virtual void thunk88();
  474. virtual void thunk89();
  475. virtual void thunk90();
  476. virtual void thunk91();
  477. virtual void thunk92();
  478. virtual void thunk93();
  479. virtual void thunk94();
  480. virtual void thunk95();
  481. virtual void thunk96();
  482. virtual void thunk97();
  483. virtual void thunk98();
  484. virtual void thunk99();
  485. protected:
  486. CQIStub(void *that, IUnknown* punk, REFIID riid);
  487. friend void* QIStub_CreateInstance(void *that, IUnknown* punk, REFIID riid);
  488. friend BOOL __stdcall DBIsQIStub(void *that);
  489. friend void __stdcall DBDumpQIStub(void *that);
  490. friend TCHAR *DBGetQIStubSymbolic(void *that);
  491. private:
  492. ~CQIStub();
  493. static void *_sar; // C (not C++) ptr to CQIStub::AddRef
  494. int _cRef;
  495. IUnknown* _punk; // vtable we hand off to
  496. void* _that; // "this" pointer of object we stub (for reference)
  497. IUnknown* _punkRef; // "punk" (for reference)
  498. REFIID _riid; // iid of interface (for reference)
  499. int _iSeq; // sequence #
  500. TCHAR _szName[GUIDSTR_MAX]; // legible name of interface (for reference)
  501. };
  502. struct DBQISeq
  503. {
  504. GUID * pIid;
  505. int iSeq;
  506. };
  507. //CASSERT(SIZEOF(GUID *) == SIZEOF(DWORD)); // CUniqueTab uses DWORD's
  508. // FEATURE: todo: _declspec(thread)
  509. CUniqueTab * DBpQISeqTab = NULL;
  510. extern "C" void *Dbg_GetREFIIDAtom(REFIID riid); // lib/dump.c (priv.h?)
  511. //***
  512. // NOTES
  513. // there's actually a race condition here -- another thread can come in
  514. // and do seq++, then we do the reset, etc. -- but the assumption is that
  515. // the developer has set the flag in a scenario where this isn't an issue.
  516. void DBQIReset(void)
  517. {
  518. ASSERT(!DBQIfReset); // caller should do test-and-clear
  519. if (DBpQISeqTab)
  520. DBpQISeqTab->Reset();
  521. return;
  522. }
  523. void *DBGetVtblEnt(void *that, int i);
  524. #define VFUNC_ADDREF 1 // AddRef is vtbl[1]
  525. void * CQIStub::_sar = NULL;
  526. CQIStub::CQIStub(void* that, IUnknown* punk, REFIID riid) : _cRef(1), _riid(riid)
  527. {
  528. _that = that;
  529. _punk = punk;
  530. if (_punk)
  531. _punk->AddRef();
  532. _punkRef = _punk; // for reference, so don't AddRef it!
  533. // c++ won't let me get &CQIStub::AddRef as a 'real' ptr (!@#$),
  534. // so we need to get it the hard way, viz. new'ing an object which
  535. // we know inherits it.
  536. if (_sar == NULL) {
  537. _sar = DBGetVtblEnt((void *)this, VFUNC_ADDREF);
  538. ASSERT(_sar != NULL);
  539. }
  540. StringCchCopy(_szName, ARRAYSIZE(_szName), Dbg_GetREFIIDName(riid));
  541. // generate sequence #
  542. if (DBpQISeqTab == NULL)
  543. DBpQISeqTab = new CUniqueTab(SIZEOF(struct DBQISeq));
  544. if (DBpQISeqTab && DBpQISeqTab->Init()) {
  545. struct DBQISeq *pqiseq;
  546. if (InterlockedExchange(&DBQIfReset, FALSE))
  547. DBQIReset();
  548. pqiseq = (struct DBQISeq *) DBpQISeqTab->Add((DWORD) Dbg_GetREFIIDAtom(riid));
  549. if (EVAL(pqiseq)) // (might fail on table overflow)
  550. _iSeq = pqiseq->iSeq++;
  551. }
  552. TraceMsg(TF_QISTUB, "ctor QIStub %s seq=%d (that=%x punk=%x) %x", _szName, _iSeq, _that, _punk, this);
  553. }
  554. CQIStub::~CQIStub()
  555. {
  556. TraceMsg(TF_QISTUB, "dtor QIStub %s (that=%x punk=%x) %x", _szName, _that, _punk, this);
  557. ATOMICRELEASE(_punk);
  558. }
  559. STDAPI_(void*) QIStub_CreateInstance(void* that, IUnknown* punk, REFIID riid)
  560. {
  561. CQIStub* pThis = new CQIStub(that, punk, riid);
  562. if (DBQIiSeq == pThis->_iSeq && IsEqualIID(riid, *DBQIiid)) {
  563. TCHAR *pst;
  564. // BRKPT put brkpt here to brkpt on seq#'th call to 'DBQIiid' iface
  565. pst = DBBreakGUID(&riid, DBBRK_BRKPT);
  566. }
  567. return(pThis);
  568. }
  569. //*** DBGetVtblEnt -- get vtable entry
  570. // NOTES
  571. // always uses 1st vtbl (so MI won't work...).
  572. void *DBGetVtblEnt(void *that, int i)
  573. {
  574. void **vptr;
  575. void *pfunc;
  576. __try {
  577. vptr = (void **) *(void **) that;
  578. pfunc = (vptr == 0) ? 0 : vptr[i];
  579. }
  580. __except(EXCEPTION_EXECUTE_HANDLER) {
  581. // since we're called from the DebMemLeak, we're only *guessing*
  582. // that we have a vptr etc., so we might fault.
  583. TraceMsg(TF_ALWAYS, "gve: GPF");
  584. pfunc = 0;
  585. }
  586. return pfunc;
  587. }
  588. //*** DBIsQIStub -- is 'this' a ptr to a 'CQIStub' object?
  589. // DESCRIPTION
  590. // we look at the vtbl and assume that if we have a ptr to CQIStub::AddRef,
  591. // then it's us.
  592. // NOTES
  593. // M00BUG we do a 'new' in here, which can cause pblms if we're in the middle
  594. // of intelli-leak and we end up doing a ReAlloc which moves the heap (raymondc
  595. // found such a case).
  596. // M00BUG in a release build (w/ identical COMDAT folding) we'll get false
  597. // hits since most/all AddRefs are identical and folded. if we ever need to
  598. // be more exact we can add a signature and key off that.
  599. // M00BUG hack hack we actually return a void *, just in case you want to
  600. // know the 'real' object. if that turns out to be useful, we should change
  601. // to return a void * instead of a BOOL.
  602. BOOL DBIsQIStub(void* that)
  603. {
  604. void *par;
  605. #if 0
  606. if (_sar == NULL)
  607. TraceMsg(DM_TRACE, "qis: _sar == NULL");
  608. #endif
  609. par = DBGetVtblEnt(that, VFUNC_ADDREF);
  610. #if 0
  611. TraceMsg(TF_ALWAYS, "IsQIStub(%x): par=%x _sar=%x", that, _sar, par);
  612. #endif
  613. return (CQIStub::_sar == par && CQIStub::_sar != NULL) ? (BOOL)((CQIStub *)that)->_punk : 0;
  614. #undef VFUNC_ADDREF
  615. }
  616. TCHAR *DBGetQIStubSymbolic(void* that)
  617. {
  618. class CQIStub *pqis = (CQIStub *) that;
  619. return pqis->_szName;
  620. }
  621. //*** DBDumpQIStub -- pretty-print a 'CQIStub'
  622. //
  623. STDAPI_(void) DBDumpQIStub(void* that)
  624. {
  625. class CQIStub *pqis = (CQIStub *) that;
  626. TraceMsg(TF_ALWAYS, "\tqistub(%x): cRef=0x%x iSeq=%x iid=%s", that, pqis->_cRef, pqis->_iSeq, pqis->_szName);
  627. }
  628. // Memory layout of CQIStub is:
  629. // lpVtbl // offset 0
  630. // _cRef // offset 4
  631. // _punk // offset 8
  632. //
  633. // "this" pointer stored in stack
  634. //
  635. // mov eax, ss:4[esp] ; get pThis
  636. // mov ecx, 8[eax] ; get real object (_punk)
  637. // mov eax, [ecx] ; load the real vtable (_punk->lpVtbl)
  638. // ; the above will fault if referenced after we're freed
  639. // mov ss:4[esp], ecx ; fix up stack object (_punk)
  640. // jmp dword ptr cs:(4*i)[eax] ; jump to the real function
  641. //
  642. #define QIStubThunk(i) \
  643. void _declspec(naked) CQIStub::thunk##i() \
  644. { \
  645. _asm mov eax, ss:4[esp] \
  646. _asm mov ecx, 8[eax] \
  647. _asm mov eax, [ecx] \
  648. _asm mov ss:4[esp], ecx \
  649. _asm jmp dword ptr cs:(4*i)[eax] \
  650. }
  651. QIStubThunk(0);
  652. QIStubThunk(3);
  653. QIStubThunk(4);
  654. QIStubThunk(5);
  655. QIStubThunk(6);
  656. QIStubThunk(7);
  657. QIStubThunk(8);
  658. QIStubThunk(9);
  659. QIStubThunk(10);
  660. QIStubThunk(11);
  661. QIStubThunk(12);
  662. QIStubThunk(13);
  663. QIStubThunk(14);
  664. QIStubThunk(15);
  665. QIStubThunk(16);
  666. QIStubThunk(17);
  667. QIStubThunk(18);
  668. QIStubThunk(19);
  669. QIStubThunk(20);
  670. QIStubThunk(21);
  671. QIStubThunk(22);
  672. QIStubThunk(23);
  673. QIStubThunk(24);
  674. QIStubThunk(25);
  675. QIStubThunk(26);
  676. QIStubThunk(27);
  677. QIStubThunk(28);
  678. QIStubThunk(29);
  679. QIStubThunk(30);
  680. QIStubThunk(31);
  681. QIStubThunk(32);
  682. QIStubThunk(33);
  683. QIStubThunk(34);
  684. QIStubThunk(35);
  685. QIStubThunk(36);
  686. QIStubThunk(37);
  687. QIStubThunk(38);
  688. QIStubThunk(39);
  689. QIStubThunk(40);
  690. QIStubThunk(41);
  691. QIStubThunk(42);
  692. QIStubThunk(43);
  693. QIStubThunk(44);
  694. QIStubThunk(45);
  695. QIStubThunk(46);
  696. QIStubThunk(47);
  697. QIStubThunk(48);
  698. QIStubThunk(49);
  699. QIStubThunk(50);
  700. QIStubThunk(51);
  701. QIStubThunk(52);
  702. QIStubThunk(53);
  703. QIStubThunk(54);
  704. QIStubThunk(55);
  705. QIStubThunk(56);
  706. QIStubThunk(57);
  707. QIStubThunk(58);
  708. QIStubThunk(59);
  709. QIStubThunk(60);
  710. QIStubThunk(61);
  711. QIStubThunk(62);
  712. QIStubThunk(63);
  713. QIStubThunk(64);
  714. QIStubThunk(65);
  715. QIStubThunk(66);
  716. QIStubThunk(67);
  717. QIStubThunk(68);
  718. QIStubThunk(69);
  719. QIStubThunk(70);
  720. QIStubThunk(71);
  721. QIStubThunk(72);
  722. QIStubThunk(73);
  723. QIStubThunk(74);
  724. QIStubThunk(75);
  725. QIStubThunk(76);
  726. QIStubThunk(77);
  727. QIStubThunk(78);
  728. QIStubThunk(79);
  729. QIStubThunk(80);
  730. QIStubThunk(81);
  731. QIStubThunk(82);
  732. QIStubThunk(83);
  733. QIStubThunk(84);
  734. QIStubThunk(85);
  735. QIStubThunk(86);
  736. QIStubThunk(87);
  737. QIStubThunk(88);
  738. QIStubThunk(89);
  739. QIStubThunk(90);
  740. QIStubThunk(91);
  741. QIStubThunk(92);
  742. QIStubThunk(93);
  743. QIStubThunk(94);
  744. QIStubThunk(95);
  745. QIStubThunk(96);
  746. QIStubThunk(97);
  747. QIStubThunk(98);
  748. QIStubThunk(99);
  749. // }
  750. #endif // }
  751. #endif // }