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.

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