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.

1222 lines
27 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File:
  4. // cdebug.cpp
  5. //
  6. // Contents:
  7. // Ole2 internal debugging support; implementation of debugstream
  8. // and IDebug for interface/class
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History:
  15. // 24-Jan-94 alexgo first pass at converting to Cairo-style
  16. // memory allocation
  17. // 12/31/93 - ChrisWe - defined DbgWarn for use by reterr.h
  18. // 12/31/93 - ChrisWe - make compile with _DEBUG defined
  19. // 03-Jan-95 BruceMa Use olewcstombs, etc.
  20. //
  21. //-----------------------------------------------------------------------------
  22. #include <le2int.h>
  23. //REVIEW32: RemLookupSHUnk not supported in cairo compobj
  24. #ifndef WIN32
  25. #include <olerem.h> //for RemLookupSHUnk
  26. #endif
  27. #pragma SEG(cdebug)
  28. #pragma SEG(cdebug)
  29. #include <string.h>
  30. #ifdef _MAC
  31. #define Yield()
  32. #endif
  33. //
  34. // Redefine UNICODE functions to ANSI for Chicago support.
  35. //
  36. #if !defined(UNICODE)
  37. #define swprintf wsprintfA
  38. #undef _xstrcpy
  39. #undef _xstrlen
  40. #define _xstrcpy strcpy
  41. #define _xstrlen strlen
  42. #endif
  43. #ifdef _DEBUG
  44. FARINTERNAL_(void) DbgWarn(LPSTR psz, LPSTR pszFileName, ULONG uLineno)
  45. {
  46. static const char msg[] = "Unexpected result: ";
  47. const char *pszmsg;
  48. TCHAR buf[250];
  49. // pick a message
  50. pszmsg = psz ? psz : msg;
  51. // write this out to the debugger
  52. #ifdef UNICODE
  53. MultiByteToWideChar(CP_ACP, 0, pszmsg, strlen(pszmsg)+1,
  54. buf, sizeof(buf));
  55. OutputDebugString(buf);
  56. MultiByteToWideChar(CP_ACP, 0, pszFileName, strlen(pszFileName)+1,
  57. buf, sizeof(buf));
  58. OutputDebugString(buf);
  59. wsprintf(buf, TEXT(", line %lu\n"), uLineno);
  60. #else // !UNICODE
  61. OutputDebugString(pszmsg);
  62. OutputDebugString(pszFileName);
  63. wsprintfA(buf, TEXT(", line %lu\n"), uLineno);
  64. #endif // UNICODE
  65. OutputDebugString(buf);
  66. }
  67. #endif // _DEBUG
  68. //some constants used only in this file
  69. #define DBGMARGIN 45
  70. #define DBGTABSIZE 4
  71. #define HEADER 1
  72. #define NOHEADER 0
  73. // mattp!!!! NYI for MAC
  74. #ifdef _MAC
  75. TCHAR vDebugStr[300];
  76. #pragma SEG(DbgReplyFilter)
  77. pascal BOOL DbgReplyFilter (
  78. long lParam,
  79. HighLevelEventMsgPtr lpmsg,
  80. TargetIDPtr lptargetid)
  81. {
  82. //#pragma unused (lptargetid)
  83. TargetID sender;
  84. unsigned long msgRefcon;
  85. unsigned long cb;
  86. long msgClass = (long)(lpmsg->theMsgEvent.message);
  87. long msgType = *(long *)&(lpmsg->theMsgEvent.where);
  88. if ((msgType != 'Sync') || (msgClass != 'Dbg2')) { // i
  89. return false;
  90. }
  91. AcceptHighLevelEvent(&sender, &msgRefcon, NULL, &cb); // here we dispose of the auto reply
  92. return true;
  93. }
  94. void OutputDebugString(const TCHAR *s)
  95. {
  96. //*vDebugStr = sprintf(vDebugStr+1, "%s", s);
  97. //DebugStr((Str255) vDebugStr);
  98. if (SendHighLevelEvent('LSpy', 'Dbg2', 'TEXT', 'Eric',(TCHAR*) s, _xstrlen(s))) {
  99. long timeout = TickCount() + 60; //timeout in 1 second
  100. OSErr err;
  101. #if 0
  102. while (timeout > TickCount()) {
  103. EventRecord evt;
  104. if (GetSpecificHighLevelEvent(
  105. (GetSpecificFilterProcPtr) DbgReplyFilter, NULL, &err)) {
  106. // DebugStr("\pgot dbg2 return reciept");
  107. break;
  108. }
  109. WaitNextEvent(NULL, &evt, 3, NULL);
  110. }
  111. #else
  112. SystemTask();
  113. #endif
  114. }
  115. else
  116. ;//DebugStr("\pBad send hl");
  117. }
  118. #endif // _MAC
  119. ASSERTDATA
  120. #define DBGLOGFILENAME TEXT("debug.log")
  121. static void GetCurDateTime(LPTSTR lpsz);
  122. #pragma SEG(DbgLogOpen)
  123. STDAPI_(HFILE) DbgLogOpen(LPCTSTR lpszFile, LPCTSTR lpszMode)
  124. {
  125. #ifdef _DEBUG
  126. #ifndef _MAC
  127. HFILE fh;
  128. LPSTR lpsz;
  129. #ifdef _UNICODE
  130. char buf[2 * MAX_PATH];
  131. #endif
  132. AssertSz( lpszFile && lpszMode, "Invalid arguments to DbgLogOpen");
  133. switch (lpszMode[0]) {
  134. case TEXT('w'):
  135. #ifdef _UNICODE
  136. WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, lpszFile, -1, buf, MAX_PATH, NULL, NULL);
  137. lpsz = buf;
  138. #else
  139. lpsz = (LPSTR)lpszFile;
  140. #endif
  141. // Open for writing (overwrite if exists)
  142. fh = _lcreat(lpsz, 0);
  143. break;
  144. case TEXT('r'):
  145. // Open for reading
  146. #ifdef _UNICODE
  147. WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, lpszFile, -1, buf, MAX_PATH, NULL, NULL);
  148. lpsz = buf;
  149. #else
  150. lpsz = (LPSTR)lpszFile;
  151. #endif
  152. fh = _lopen(lpsz, OF_READ);
  153. break;
  154. case TEXT('a'):
  155. #ifdef _UNICODE
  156. WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, lpszFile, -1, buf, MAX_PATH, NULL, NULL);
  157. lpsz = buf;
  158. #else
  159. lpsz = (LPSTR)lpszFile;
  160. #endif
  161. // Open for appending
  162. // to append to log file seek to end before writing
  163. if ((fh = _lopen(lpsz, OF_READWRITE)) != -1) {
  164. #ifdef WIN32
  165. _llseek(fh, 0L, FILE_END);
  166. #else
  167. _llseek(fh, 0L, SEEK_END);
  168. #endif // WIN32
  169. } else {
  170. // file does not exist, create a new one.
  171. fh = _lcreat(lpsz, 0);
  172. }
  173. break;
  174. }
  175. return fh;
  176. #endif //_MAC
  177. #else
  178. (void) lpszFile;
  179. (void) lpszMode;
  180. return -1;
  181. #endif //_DEBUG
  182. }
  183. #pragma SEG(DbgLogClose)
  184. STDAPI_(void) DbgLogClose(HFILE fh)
  185. {
  186. #ifdef _DEBUG
  187. #ifndef _MAC
  188. if (fh != -1)
  189. _lclose(fh);
  190. #endif
  191. #else
  192. (void) fh;
  193. #endif
  194. }
  195. #pragma SEG(DbgLogWrite)
  196. STDAPI_(void) DbgLogWrite(HFILE fh, LPCTSTR lpszStr)
  197. {
  198. #ifdef _DEBUG
  199. LPSTR lpsz;
  200. #ifdef _UNICODE
  201. char buf[2 * MAX_PATH];
  202. #endif
  203. #ifndef _MAC
  204. if (fh != -1 && lpszStr)
  205. {
  206. #ifdef _UNICODE
  207. WideCharToMultiByte (CP_ACP, WC_COMPOSITECHECK, lpszStr, -1, buf, MAX_PATH, NULL, NULL);
  208. lpsz = buf;
  209. #else
  210. lpsz = (LPSTR)lpszStr;
  211. #endif // _UNICODE
  212. _lwrite(fh, lpsz, strlen(lpsz)); // NOTE NOT UNICODE
  213. }
  214. #endif // _MAC
  215. #else
  216. (void) fh;
  217. (void) lpszStr;
  218. #endif
  219. }
  220. #pragma SEG(DbgLogTimeStamp)
  221. STDAPI_(void) DbgLogTimeStamp(HFILE fh, LPCTSTR lpsz)
  222. {
  223. #ifdef _DEBUG
  224. TCHAR buffer[80];
  225. GetCurDateTime(buffer);
  226. DbgLogOutputDebugString(fh, TEXT("\n***************************************\n"));
  227. if (lpsz) DbgLogOutputDebugString(fh, lpsz);
  228. DbgLogOutputDebugString(fh, TEXT(": "));
  229. DbgLogOutputDebugString(fh, buffer);
  230. DbgLogOutputDebugString(fh, TEXT("\n"));
  231. DbgLogOutputDebugString(fh, TEXT(".......................................\n\n"));
  232. #else
  233. (void) fh;
  234. (void) lpsz;
  235. #endif
  236. }
  237. #pragma SEG(DbgLogWriteBanner)
  238. STDAPI_(void) DbgLogWriteBanner(HFILE fh, LPCTSTR lpsz)
  239. {
  240. #ifdef _DEBUG
  241. DbgLogOutputDebugString(fh, TEXT("\n***************************************\n"));
  242. if (lpsz) DbgLogOutputDebugString(fh, lpsz);
  243. DbgLogOutputDebugString(fh, TEXT("\n"));
  244. DbgLogOutputDebugString(fh, TEXT(".......................................\n\n"));
  245. #else
  246. (void) fh;
  247. (void) lpsz;
  248. #endif
  249. }
  250. #pragma SEG(DbgLogOutputDebugString)
  251. STDAPI_(void) DbgLogOutputDebugString(HFILE fh, LPCTSTR lpsz)
  252. {
  253. #ifdef _DEBUG
  254. #ifndef _MAC
  255. if (fh != -1)
  256. DbgLogWrite(fh, lpsz);
  257. OutputDebugString(lpsz);
  258. #endif
  259. #else
  260. (void)fh;
  261. (void)lpsz;
  262. #endif
  263. }
  264. #ifdef _DEBUG
  265. #pragma SEG(GetCurDateTime)
  266. static void GetCurDateTime(LPTSTR lpsz)
  267. {
  268. unsigned year, month, day, dayOfweek, hours, min, sec;
  269. static const TCHAR FAR* const dayNames[7] =
  270. { TEXT("Sun"), TEXT("Mon"), TEXT("Tue"), TEXT("Wed"),
  271. TEXT("Thu"), TEXT("Fri"), TEXT("Sat") };
  272. static const TCHAR FAR* const monthNames[12] =
  273. { TEXT("Jan"), TEXT("Feb"), TEXT("Mar"), TEXT("Apr"), TEXT("May"),
  274. TEXT("Jun"), TEXT("Jul"), TEXT("Aug"),
  275. TEXT("Sep"), TEXT("Oct"), TEXT("Nov"), TEXT("Dec") };
  276. #ifndef _MAC
  277. #ifdef WIN32
  278. SYSTEMTIME st;
  279. GetLocalTime(&st);
  280. year = st.wYear;
  281. month = st.wMonth - 1;
  282. dayOfweek = st.wDayOfWeek;
  283. day = st.wDay;
  284. hours = st.wHour;
  285. min = st.wMinute;
  286. sec = st.wSecond;
  287. #else
  288. _asm {
  289. // Call GetDate
  290. mov ah, 0x2a
  291. int 0x21
  292. mov year, cx
  293. mov month, dx
  294. mov day, dx
  295. mov dayOfweek, ax
  296. // Call GetTime
  297. mov ah, 0x2c
  298. int 0x21
  299. mov hours, cx
  300. mov min, cx
  301. mov sec, dx
  302. }
  303. month >>= 8;
  304. month -= 1;
  305. day &= 0xFF;
  306. dayOfweek &= 0xFF;
  307. hours >>= 8;
  308. min &= 0xFF;
  309. sec >>= 8;
  310. #endif //_WIN32
  311. #else // defined(_MAC)
  312. // REVIEW MAC -- need function here to get current date & time
  313. day = 9;
  314. month = 1;
  315. year = 1960;
  316. hours = 12;
  317. min = 30;
  318. sec = 17;
  319. #endif //_MAC
  320. // Format time as: Wed Jan 02 02:03:55 1990
  321. // Format time as: Wed 05/02/1992 02:03:55
  322. #if defined(UNICODE)
  323. wsprintf(lpsz, TEXT("%ws %ws %02d %02d:%02d:%02d %d"),
  324. dayNames[dayOfweek],monthNames[month], day, hours, min, sec, year);
  325. #else
  326. wsprintfA(lpsz, "%s %s %02d %02d:%02d:%02d %d",
  327. dayNames[dayOfweek],monthNames[month], day, hours, min, sec, year);
  328. #endif
  329. }
  330. class FAR CDebugLog
  331. {
  332. private:
  333. HFILE m_fhLog;
  334. public:
  335. CDebugLog( ) { m_fhLog = -1; }
  336. CDebugLog( LPCTSTR lpszFileName );
  337. ~CDebugLog() { DbgLogClose(m_fhLog); }
  338. HFILE Open(LPCTSTR lpszFileName, LPCTSTR lpszMode)
  339. { return (m_fhLog = DbgLogOpen(lpszFileName, lpszMode)); }
  340. void Close(void) { DbgLogClose(m_fhLog); m_fhLog = -1; }
  341. void OutputDebugString(LPCTSTR lpsz) { DbgLogOutputDebugString(m_fhLog, lpsz); }
  342. void TimeStamp(LPCTSTR lpsz) { DbgLogTimeStamp(m_fhLog, lpsz); }
  343. void WriteBanner(LPCTSTR lpsz) { DbgLogWriteBanner(m_fhLog, lpsz); }
  344. };
  345. //-------------------------------------------------------------------------
  346. // Thought for the decade:
  347. // All these methods and all these functions and crud, for what?
  348. // So we can avoid calling the shared, system-provided, *printf?
  349. // Was it worth it? Is Barney a genius? He sure knows how to lead
  350. // everyone down the garden path...
  351. //-------------------------------------------------------------------------
  352. class FAR CDebugStream : public CPrivAlloc
  353. {
  354. public:
  355. STDSTATIC_(IDebugStream FAR *) Create( // no aggregation
  356. int margin, int tabsize, BOOL fHeader);
  357. private:
  358. CDebugStream( int margin, int tabsize, BOOL fHeader );
  359. ~CDebugStream();
  360. void OutputDebugString( LPCTSTR lpsz ) {m_DbgLog.OutputDebugString(lpsz);}
  361. implementations:
  362. implement CDSImpl : IDebugStream
  363. {
  364. public:
  365. CDSImpl( CDebugStream FAR * pDebugStream )
  366. { m_pDebugStream = pDebugStream; }
  367. ~CDSImpl( void ) ; //{ if (m_pDebugStream->m_pendingReturn) ForceReturn(); }
  368. void PrintString( LPTSTR );
  369. void ForceReturn( void );
  370. void ReturnIfPending( void );
  371. STDMETHOD(QueryInterface)(REFIID iid, LPVOID FAR* ppvObj );
  372. STDMETHOD_(ULONG,AddRef)( void );
  373. STDMETHOD_(ULONG,Release)( void );
  374. STDMETHOD_(IDebugStream&, operator << ) ( IUnknown FAR * pDebug );
  375. STDMETHOD_(IDebugStream&, operator << ) ( REFCLSID rclsid );
  376. STDMETHOD_(IDebugStream&, operator << ) ( int n );
  377. STDMETHOD_(IDebugStream&, operator << ) ( long l );
  378. STDMETHOD_(IDebugStream&, operator << ) ( ULONG l );
  379. STDMETHOD_(IDebugStream&, operator << ) ( LPCTSTR sz );
  380. STDMETHOD_(IDebugStream&, operator << ) ( TCHAR ch );
  381. STDMETHOD_(IDebugStream&, operator << ) ( void FAR * pv );
  382. STDMETHOD_(IDebugStream&, operator << ) ( CBool b );
  383. STDMETHOD_(IDebugStream&, operator << ) ( CAtom atom );
  384. STDMETHOD_(IDebugStream&, operator << ) ( CHwnd hwnd );
  385. STDMETHOD_(IDebugStream&, Tab) ( void );
  386. STDMETHOD_(IDebugStream&, Indent) ( void );
  387. STDMETHOD_(IDebugStream&, UnIndent) ( void );
  388. STDMETHOD_(IDebugStream&, Return) ( void );
  389. STDMETHOD_(IDebugStream&, LF) ( void );
  390. CDebugStream FAR * m_pDebugStream;
  391. };
  392. DECLARE_NC(CDebugStream,CDSImpl)
  393. CDSImpl m_DebugStream;
  394. shared_state:
  395. ULONG m_refs;
  396. int m_indent;
  397. int m_position;
  398. int m_margin;
  399. int m_tabsize;
  400. BOOL m_pendingReturn;
  401. CDebugLog m_DbgLog;
  402. };
  403. #endif // _DEBUG
  404. /*
  405. * The member variable m_pendingReturn is a hack to allow
  406. * the sequence of operations Return, UnIndent put the character
  407. * at the *beginning of the unindented line* The debugwindow does
  408. * not seem to support going to the beginning of the line or
  409. * backspacing, so we do not actually do a Return until we know
  410. * that the next operation is not UnIndent.
  411. *
  412. */
  413. /*
  414. * Implementation of per process list heads
  415. */
  416. #ifdef NEVER // per-proces debug lists not used
  417. static IDebug FAR * GetIDHead()
  418. {
  419. if this gets enabled, the map should be in the etask
  420. }
  421. static void SetIDHead(IDebug FAR* pIDHead)
  422. {
  423. if this gets enabled, the map should be in the etask
  424. }
  425. #endif // NEVER
  426. /*
  427. * Implementation of IDebug constructor and destructor
  428. */
  429. #ifdef NEVER
  430. __export IDebug::IDebug( void )
  431. {
  432. SETPVTBL(IDebug);
  433. //#ifdef _DEBUG
  434. BOOL fIsShared = (SHARED == PlacementOf(this));
  435. IDebug FAR* pIDHead = (fIsShared ? pIDHeadShared : GetIDHead());
  436. pIDPrev = NULL;
  437. if (pIDHead)
  438. pIDHead->pIDPrev = this;
  439. pIDNext = pIDHead;
  440. if (fIsShared) pIDHeadShared = this;
  441. else SetIDHead(this);
  442. }
  443. #endif //NEVER
  444. #ifdef NEVER
  445. __export IDebug::~IDebug( void )
  446. {
  447. //#ifdef _DEBUG
  448. BOOL fIsShared = (SHARED == PlacementOf(this));
  449. if (pIDPrev)
  450. pIDPrev->pIDNext = pIDNext;
  451. else
  452. if (fIsShared) pIDHeadShared = pIDNext;
  453. else
  454. SetIDHead(pIDNext);
  455. if (pIDNext)
  456. pIDNext->pIDPrev = pIDPrev;
  457. }
  458. #endif //NEVER
  459. //REVIEW: maybe we should expose this later
  460. STDAPI OleGetClassID( LPUNKNOWN pUnk, LPCLSID lpclsid )
  461. {
  462. LPRUNNABLEOBJECT lpRunnableObject = NULL;
  463. LPPERSIST lpPersist = NULL;
  464. HRESULT hresult = NOERROR;
  465. VDATEIFACE(pUnk);
  466. VDATEPTROUT(lpclsid, LPCLSID);
  467. *lpclsid = CLSID_NULL;
  468. pUnk->QueryInterface(IID_IRunnableObject, (LPLPVOID)&lpRunnableObject);
  469. if( lpRunnableObject ){
  470. hresult = lpRunnableObject->GetRunningClass(lpclsid);
  471. lpRunnableObject->Release();
  472. } else {
  473. pUnk->QueryInterface(IID_IPersist, (LPLPVOID)&lpPersist);
  474. if( lpPersist ){
  475. hresult = lpPersist->GetClassID( lpclsid );
  476. lpPersist->Release();
  477. }
  478. }
  479. return hresult;
  480. }
  481. #ifdef _DEBUG
  482. CDebugStream::CDebugStream( int margin, int tabsize, BOOL fHeader) : m_DebugStream(this)
  483. {
  484. #ifndef _MAC
  485. static BOOL fAppendFile = FALSE;
  486. // Create the debug log file. Overwrite the existing file if it exists.
  487. m_DbgLog.Open(DBGLOGFILENAME, (fAppendFile ? TEXT("a") : TEXT("w")));
  488. if( fHeader )
  489. // only add creation timestamp to top of file.
  490. if (! fAppendFile) {
  491. m_DbgLog.TimeStamp(TEXT("Created"));
  492. fAppendFile = TRUE;
  493. } else {
  494. m_DbgLog.WriteBanner(NULL);
  495. }
  496. #endif
  497. m_indent = 0;
  498. m_position = m_indent;
  499. m_margin = margin;
  500. m_tabsize = tabsize;
  501. m_refs = 1;
  502. m_pendingReturn = FALSE;
  503. }
  504. CDebugStream::~CDebugStream()
  505. {
  506. m_DbgLog.Close();
  507. }
  508. NC(CDebugStream,CDSImpl)::~CDSImpl(void)
  509. {
  510. if (m_pDebugStream->m_pendingReturn) ForceReturn();
  511. }
  512. STDMETHODIMP NC(CDebugStream,CDSImpl)::QueryInterface(REFIID iidInterface,
  513. void FAR* FAR* ppvObj )
  514. {
  515. VDATEPTROUT(ppvObj, LPLPVOID);
  516. if (IsEqualGUID(iidInterface, IID_IUnknown) ||
  517. IsEqualGUID(iidInterface, IID_IDebugStream))
  518. {
  519. *ppvObj = (void FAR *)this;
  520. return NOERROR;
  521. } else
  522. {
  523. *ppvObj = NULL;
  524. return ReportResult(0, E_NOINTERFACE, 0, 0);
  525. }
  526. }
  527. STDMETHODIMP_(ULONG) NC(CDebugStream,CDSImpl)::AddRef( void )
  528. {
  529. return ++m_pDebugStream->m_refs;
  530. }
  531. STDMETHODIMP_(ULONG) NC(CDebugStream,CDSImpl)::Release( void )
  532. {
  533. if (--m_pDebugStream->m_refs == 0) {
  534. delete m_pDebugStream;
  535. return 0;
  536. }
  537. return m_pDebugStream->m_refs;
  538. }
  539. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (int n)
  540. {
  541. TCHAR buffer[12];
  542. ReturnIfPending();
  543. buffer[swprintf(buffer, TEXT("%d"), n)] = TEXT('\0');
  544. PrintString(buffer);
  545. return *this;
  546. }
  547. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (long l)
  548. {
  549. TCHAR buffer[16];
  550. ReturnIfPending();
  551. buffer[swprintf(buffer, TEXT("%ld"), l)] = TEXT('\0');
  552. PrintString(buffer);
  553. return *this;
  554. }
  555. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (ULONG l)
  556. {
  557. TCHAR buffer[16];
  558. ReturnIfPending();
  559. buffer[swprintf(buffer, TEXT("%lu"), l)] = TEXT('\0');
  560. PrintString(buffer);
  561. return *this;
  562. }
  563. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (CAtom atom)
  564. {
  565. TCHAR buffer[128];
  566. ReturnIfPending();
  567. if( (ATOM)atom ){
  568. if( !GetAtomName((ATOM)atom, buffer, sizeof(buffer)) )
  569. buffer[swprintf(buffer, TEXT("Invalid atom"))] = TEXT('\0');
  570. }else
  571. buffer[swprintf(buffer, TEXT("NULL atom"))] = TEXT('\0');
  572. PrintString(buffer);
  573. return *this;
  574. }
  575. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (CHwnd hwnd)
  576. {
  577. TCHAR szBuf[128];
  578. ReturnIfPending();
  579. if( (HWND)hwnd )
  580. szBuf[swprintf(szBuf, TEXT("window handle: %x"), (HWND)hwnd)] = TEXT('\0');
  581. else
  582. szBuf[swprintf(szBuf, TEXT("NULL window handle"))] = TEXT('\0');
  583. PrintString(szBuf);
  584. return *this;
  585. }
  586. LPTSTR FindBreak( LPTSTR sz, int currentPosition, int margin )
  587. {
  588. LPTSTR szBreak = sz;
  589. LPTSTR szPtr = sz;
  590. if( !sz )
  591. return NULL;
  592. while (*szPtr)
  593. {
  594. while (*(szPtr) && *(szPtr++) <= TEXT(' '));
  595. while (*(szPtr) && *(szPtr++) > TEXT(' '));
  596. if (currentPosition+(szPtr-sz) < margin)
  597. {
  598. szBreak = szPtr;
  599. }
  600. else return szBreak;
  601. }
  602. return szPtr;
  603. }
  604. /*
  605. * PrintString is an internal utility routine that can assume that
  606. * everything in the string (other than the null at the end) is >=
  607. * ' '. Thus it knows that when it prints a single character, the
  608. * position on the debug terminal advances a single columm. This
  609. * would not be the case if the string could contain tabs,
  610. * returns, etc.
  611. */
  612. void NC(CDebugStream,CDSImpl)::PrintString(LPTSTR sz)
  613. {
  614. // assert sz != NULL
  615. LPTSTR szUnprinted = sz;
  616. LPTSTR szPtr = sz;
  617. TCHAR chSave;
  618. #ifdef _MAC
  619. Puts(sz);
  620. return;
  621. #endif
  622. if( !sz )
  623. return;
  624. while (*szUnprinted)
  625. {
  626. szPtr = FindBreak( szUnprinted, m_pDebugStream->m_position, m_pDebugStream->m_margin );
  627. if (szPtr == szUnprinted && m_pDebugStream->m_position > m_pDebugStream->m_indent)
  628. {
  629. Return();
  630. szPtr = FindBreak( szUnprinted, m_pDebugStream->m_position, m_pDebugStream->m_margin );
  631. if (szPtr == szUnprinted) // text won't fit even after word wrapping
  632. {
  633. m_pDebugStream->OutputDebugString(szUnprinted);
  634. m_pDebugStream->m_position += _xstrlen(szUnprinted);
  635. return;
  636. }
  637. }
  638. chSave = *szPtr;
  639. *szPtr = TEXT('\0');
  640. if (m_pDebugStream->m_position == m_pDebugStream->m_indent) // no text on line, skip blanks
  641. {
  642. while (*szUnprinted == TEXT(' ')) szUnprinted++;
  643. }
  644. m_pDebugStream->OutputDebugString(szUnprinted);
  645. *szPtr = chSave;
  646. m_pDebugStream->m_position += (ULONG) (szPtr - szUnprinted);
  647. szUnprinted = szPtr;
  648. }
  649. }
  650. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (TCHAR ch)
  651. {
  652. TCHAR buffer[2] = TEXT("a");
  653. if (ch==TEXT('\n')) Return();
  654. else if (ch==TEXT('\t')) Tab();
  655. else if (ch >= TEXT(' '))
  656. {
  657. ReturnIfPending();
  658. if (m_pDebugStream->m_position >= m_pDebugStream->m_margin) Return();
  659. *buffer = ch;
  660. m_pDebugStream->OutputDebugString(buffer);
  661. m_pDebugStream->m_position++;
  662. }
  663. return *this;
  664. }
  665. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (LPCTSTR sz)
  666. {
  667. LPTSTR szCopy;
  668. TCHAR chSave;
  669. LPTSTR szPtr;
  670. LPTSTR szPtrSave;
  671. ReturnIfPending();
  672. if (!sz)
  673. return *this;
  674. szCopy = (LPTSTR)PubMemAlloc(sizeof(TCHAR)*(2+_xstrlen(sz)));
  675. if (!szCopy)
  676. {
  677. Return();
  678. *this << TEXT("Memory allocation error in DebugStream");
  679. Return();
  680. return *this;
  681. }
  682. _xstrcpy( szCopy, sz );
  683. for (szPtr = szCopy, szPtrSave = szCopy; *szPtr; szPtr++)
  684. {
  685. if ( *szPtr < TEXT(' '))// we hit a control character or the end
  686. {
  687. chSave = *szPtr;
  688. *szPtr = TEXT('\0');
  689. PrintString( szPtrSave );
  690. if (chSave != TEXT('\0'))
  691. *szPtr = chSave;
  692. szPtrSave = szPtr+1;
  693. switch (chSave)
  694. {
  695. case TEXT('\t'): Tab();
  696. break;
  697. case TEXT('\n'): Return();
  698. break;
  699. case TEXT('\r'): m_pDebugStream->OutputDebugString(TEXT("\r"));
  700. break;
  701. default:
  702. break;
  703. }
  704. }
  705. }
  706. PrintString( szPtrSave );
  707. PubMemFree(szCopy);
  708. return *this;
  709. }
  710. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << (CBool b)
  711. {
  712. ReturnIfPending();
  713. if (b) *this << TEXT("TRUE");
  714. else *this << TEXT("FALSE");
  715. return *this;
  716. }
  717. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator << ( void FAR * pv )
  718. {
  719. TCHAR buffer[12];
  720. ReturnIfPending();
  721. if (pv == NULL)
  722. *this << TEXT("NULL");
  723. else
  724. {
  725. buffer[swprintf(buffer, TEXT("%lX"), pv)] = TEXT('\0');
  726. PrintString(buffer);
  727. }
  728. return *this;
  729. }
  730. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator <<
  731. ( REFCLSID rclsid )
  732. {
  733. TCHAR sz[256];
  734. #if !defined(_CHICAGO_)
  735. if (IsEqualGUID(rclsid, CLSID_NULL))
  736. _xstrcpy(sz, TEXT("NULL CLSID"));
  737. else if (StringFromCLSID2(rclsid, sz, sizeof(sz)) == 0)
  738. _xstrcpy(sz, TEXT("Unknown CLSID"));
  739. *this << sz;
  740. #endif
  741. return *this;
  742. }
  743. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::operator <<
  744. ( IUnknown FAR * pUnk )
  745. {
  746. IDebug FAR * pDebug = NULL;
  747. CLSID clsid = CLSID_NULL;
  748. ReturnIfPending();
  749. if (!pUnk) {
  750. *this << TEXT("NULL interface");
  751. } else if( IsValidInterface(pUnk) ) {
  752. pUnk->QueryInterface(IID_IDebug, (void FAR* FAR*)&pDebug);
  753. if (pDebug) {
  754. pDebug->Dump( this );
  755. if ( !pDebug->IsValid( 0 ) )
  756. *this << TEXT("Object is not valid") << TEXT('\n');
  757. /*
  758. * NB: Debug interfaces are *not* ref counted (so as not to skew the
  759. * counts of the objects they are debugging! :)
  760. */
  761. } else {
  762. OleGetClassID(pUnk, (LPCLSID)&clsid);
  763. *this << clsid << TEXT(" @ ")<<(VOID FAR *)pUnk << TEXT(" doesn't support debug dumping");
  764. }
  765. } else {
  766. *this << TEXT("Invalid interface @ ") << (VOID FAR *)pUnk;
  767. }
  768. return *this;
  769. }
  770. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::Tab( void )
  771. {
  772. ReturnIfPending();
  773. int advance = m_pDebugStream->m_tabsize * ( 1 + m_pDebugStream->m_position/m_pDebugStream->m_tabsize) - m_pDebugStream->m_position;
  774. if (m_pDebugStream->m_position + advance < m_pDebugStream->m_margin)
  775. {
  776. for (int i = 0; i < advance; i++)
  777. m_pDebugStream->OutputDebugString(TEXT(" "));
  778. m_pDebugStream->m_position += advance;
  779. }
  780. return *this;
  781. }
  782. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::Indent( void )
  783. {
  784. if (m_pDebugStream->m_indent + m_pDebugStream->m_tabsize < m_pDebugStream->m_margin)
  785. m_pDebugStream->m_indent += m_pDebugStream->m_tabsize;
  786. if (!m_pDebugStream->m_pendingReturn)
  787. while (m_pDebugStream->m_position < m_pDebugStream->m_indent)
  788. operator<<(TEXT(' '));
  789. return *this;
  790. }
  791. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::UnIndent( void )
  792. {
  793. if (m_pDebugStream->m_indent > 0) m_pDebugStream->m_indent -= m_pDebugStream->m_tabsize;
  794. return *this;
  795. }
  796. void NC(CDebugStream,CDSImpl)::ForceReturn( void )
  797. {
  798. m_pDebugStream->OutputDebugString(TEXT("\n"));
  799. for (int i = 0; i<m_pDebugStream->m_indent; i++)
  800. m_pDebugStream->OutputDebugString(TEXT(" "));
  801. m_pDebugStream->m_position = m_pDebugStream->m_indent;
  802. m_pDebugStream->m_pendingReturn = FALSE;
  803. }
  804. void NC(CDebugStream,CDSImpl)::ReturnIfPending( void )
  805. {
  806. if (m_pDebugStream->m_pendingReturn) ForceReturn();
  807. }
  808. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::Return( void )
  809. {
  810. ReturnIfPending();
  811. m_pDebugStream->m_pendingReturn = TRUE;
  812. Yield(); // let dbwin get control
  813. return *this;
  814. }
  815. STDMETHODIMP_(IDebugStream&) NC(CDebugStream,CDSImpl)::LF( void )
  816. {
  817. return Return();
  818. }
  819. STDSTATICIMP_(IDebugStream FAR *) CDebugStream::Create( // no aggregation
  820. int margin, int tabsize, BOOL fHeader )
  821. {
  822. CDebugStream FAR * pcds = new CDebugStream( margin, tabsize, fHeader );
  823. if( !pcds ){
  824. AssertSz( pcds, "Out of Memory");
  825. return NULL;
  826. }
  827. return &(pcds->m_DebugStream);
  828. }
  829. #endif // _DEBUG
  830. STDAPI_(IDebugStream FAR *) MakeDebugStream( short margin, short tabsize, BOOL fHeader)
  831. {
  832. #ifdef _DEBUG
  833. return CDebugStream::Create( margin, tabsize, fHeader );
  834. #else
  835. (void) margin;
  836. (void) tabsize;
  837. (void) fHeader;
  838. return NULL;
  839. #endif // _DEBUG
  840. }
  841. //
  842. // IDebug helpers
  843. //
  844. STDAPI_(void) DbgDumpObject( IUnknown FAR * pUnk, DWORD dwReserved )
  845. {
  846. #ifdef _DEBUG
  847. IDebugStream FAR * pcds = MakeDebugStream( DBGMARGIN, DBGTABSIZE, NOHEADER );
  848. (void)dwReserved;
  849. if( pcds ) {
  850. *pcds << pUnk;
  851. pcds->Return();
  852. pcds->Release();
  853. }
  854. #else
  855. (void) pUnk;
  856. (void) dwReserved;
  857. #endif
  858. }
  859. STDAPI_(void) DbgDumpExternalObject( IUnknown FAR * pUnk, DWORD dwReserved )
  860. {
  861. //REVIEW32: Compobj does not support RemLookupSHUnk yet (alexgo 11/8/93)
  862. #ifdef WIN32
  863. (void)dwReserved;
  864. (void)pUnk;
  865. #elif _DEBUG
  866. SHREG shreg;
  867. (void) dwReserved;
  868. if( IsValidInterface(pUnk) ){
  869. if( RemLookupSHUnk(pUnk, NULL, &shreg) == NOERROR ){
  870. DbgDumpObject(shreg.m_pSM, 0);
  871. shreg.m_pSM->Release();
  872. }
  873. }
  874. #else
  875. (void) dwReserved;
  876. (void) pUnk;
  877. #endif
  878. }
  879. STDAPI_(BOOL) DbgIsObjectValid( IUnknown FAR * pUnk )
  880. {
  881. #ifdef _DEBUG
  882. BOOL fReturn = TRUE; // default value for objects that don't
  883. // support IDebug
  884. IDebug FAR * pDebug = NULL;
  885. if( IsValidInterface(pUnk) ){
  886. pUnk->QueryInterface( IID_IDebug, (void FAR* FAR*)&pDebug);
  887. if (pDebug)
  888. fReturn = pDebug->IsValid();
  889. //IDebug is not addref'd
  890. return fReturn;
  891. }
  892. return FALSE;
  893. #else
  894. (void) pUnk;
  895. return TRUE;
  896. #endif
  897. }
  898. STDAPI_(void) DbgDumpClassName( IUnknown FAR * pUnk )
  899. {
  900. #ifdef _DEBUG
  901. CLSID clsid;
  902. IDebugStream FAR * pcds = MakeDebugStream( DBGMARGIN, DBGTABSIZE, NOHEADER );
  903. if( pcds ) {
  904. if( IsValidInterface(pUnk) ){
  905. OleGetClassID( pUnk, (LPCLSID)&clsid);
  906. *pcds << clsid << TEXT(" @ ") << (void FAR* )pUnk << TEXT('\n');
  907. }else if (!pUnk)
  908. *pcds << TEXT("NULL interface") << TEXT('\n');
  909. else
  910. *pcds << (void FAR *)pUnk << TEXT(" is not a valid interface") << TEXT('\n');
  911. pcds->Release();
  912. }
  913. #else
  914. (void)pUnk;
  915. #endif
  916. }
  917. STDAPI_(void) DumpAllObjects( void )
  918. {
  919. //#ifdef _DEBUG
  920. #ifdef NEVER
  921. IDebug FAR * pID = GetIDHead();
  922. IDebugStream FAR * pcds = MakeDebugStream( DBGMARGIN, DBGTABSIZE, NOHEADER );
  923. *pcds << TEXT("----TASK OBJECTS-------\n");
  924. while (pID)
  925. {
  926. pID->Dump( pcds );
  927. pID = pID->pIDNext;
  928. }
  929. *pcds << TEXT("----SHARED OBJECTS-------\n");
  930. pID = pIDHeadShared;
  931. while (pID)
  932. {
  933. pID->Dump( pcds );
  934. pID = pID->pIDNext;
  935. }
  936. pcds->Release();
  937. #endif
  938. }
  939. STDAPI_(BOOL) ValidateAllObjects( BOOL fSuspicious )
  940. {
  941. //#ifdef _DEBUG
  942. #ifdef NEVER
  943. IDebug FAR * pID = GetIDHead();
  944. int pass = 0;
  945. IDebugStream FAR * pcds = MakeDebugStream( DBGMARGIN, DBGTABSIZE, NOHEADER);
  946. BOOL fReturn = TRUE;
  947. while (pID)
  948. {
  949. if (!(pID->IsValid(fSuspicious)))
  950. {
  951. fReturn = FALSE;
  952. if (pass == 0)
  953. *pcds <<
  954. TEXT("\n****INVALID OBJECT*****\n");
  955. else
  956. *pcds << TEXT("\n****INVALID SHARED MEMORY OBJECT*****\n");
  957. pID->Dump( pcds );
  958. pcds->Return();
  959. }
  960. pID = pID->pIDNext;
  961. if ((pID == NULL) && (pass++ == 0))
  962. pID = pIDHeadShared;
  963. }
  964. pcds->Release();
  965. return fReturn;
  966. #endif //NEVER
  967. (void) fSuspicious;
  968. return TRUE;
  969. }
  970. #ifdef _DEBUG
  971. extern "C"
  972. BOOL CALLBACK __loadds DebCallBack(WORD wID, DWORD dwData)
  973. {
  974. // TCHAR rgchBuf[50];
  975. //// BOOL fTraceStack = FALSE;
  976. //// STACKTRACEENTRY ste;
  977. //// WORD wSS, wCS, wIP, wBP;
  978. // NFYLOADSEG FAR* pNFY = (NFYLOADSEG FAR *)dwData;
  979. //
  980. // if (wID == NFY_LOADSEG)
  981. // {
  982. // if (0 == _xstrcmp(pNFY->lpstrModuleName, TEXT("OLE2")))
  983. // {
  984. // swprintf(rgchBuf, TEXT("Load seg %02x(%#04x), module %s"), pNFY->wSegNum,
  985. // pNFY->wSelector, pNFY->lpstrModuleName);
  986. // OutputDebugString(rgchBuf);
  987. // _asm int 3
  988. //// if (fTraceStack)
  989. //// {
  990. //// _asm mov wSS, SS
  991. //// _asm mov wCS, CS
  992. //// _asm mov wIP, IP
  993. //// _asm mov wBP, BP
  994. //// ste.dwSize = sizeof(STACKTRACEENTRY);
  995. //// if (StackTraceCSIPFirst(&ste, wSS, wCS, wIP, wBP))
  996. //// {
  997. //// while (fTraceStack && StackTraceNext(&ste));
  998. //// }
  999. ////
  1000. //// }
  1001. // }
  1002. // }
  1003. // else if (wID == NFY_FREESEG)
  1004. // {
  1005. // }
  1006. (void) wID;
  1007. (void) dwData;
  1008. return FALSE;
  1009. }
  1010. BOOL InstallHooks(void)
  1011. {
  1012. // return NotifyRegister(NULL, (LPFNNOTIFYCALLBACK)DebCallBack, NF_NORMAL);
  1013. return TRUE;
  1014. }
  1015. BOOL UnInstallHooks()
  1016. {
  1017. // return NotifyUnRegister(NULL);
  1018. return TRUE;
  1019. }
  1020. #endif