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.

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