DUMP.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:16k
源码类别:

Windows编程

开发平台:

Visual C++

  1. //--------------------------------------------------------------------
  2. // Microsoft OLE DB Sample Consumer
  3. // (C) Copyright 1995 - 1998 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File name: DUMP.CPP
  6. //
  7. //      Dumpoutput routines for the SAMPCLNT sample OLE DB consumer.
  8. //
  9. //      See README.TXT for more information on the SAMPCLNT sample.
  10. //
  11. // Functions:
  12. //
  13. //      See SAMPCLNT.H for function prototypes
  14. //
  15. #include "sampclnt.h"
  16. void DumpErrorMsg
  17. (
  18.     const char* format,
  19.     ...
  20. )
  21. {
  22. va_list argptr;     
  23. assert(format != NULL);
  24. // log this message to stderr and to our log file
  25. va_start( argptr, format );
  26. tvfprintf( stderr, format, argptr);
  27.     tvfprintf( g_fpLogFile, format, argptr);
  28. va_end( argptr );
  29. }    
  30. void DumpStatusMsg
  31. (
  32.     const char* format,
  33.     ...
  34. )
  35. {
  36. va_list argptr;
  37. assert(format != NULL);
  38. // log this message to stdout and to our log file
  39. va_start( argptr, format );
  40. tvfprintf( stdout, format, argptr );
  41.     tvfprintf( g_fpLogFile, format, argptr );
  42. va_end( argptr );
  43. }    
  44. HRESULT DumpErrorHResult
  45. (
  46. HRESULT      hr_return,
  47. const char  *format, // can be NULL
  48. ... 
  49. )
  50. {
  51. char     buff[100];
  52. int      cBytesWritten;
  53. va_list  argptr;
  54. //
  55. // Dump an error message.
  56. // Print the text of the HRESULT,
  57. // Return the HRESULT we were passed.
  58.     // these result codes were generated from the oledberr.h 
  59. static Note ResultCodes[] = {
  60. // oledberr.h error codes
  61. NOTE(DB_E_BADACCESSORHANDLE),
  62. NOTE(DB_E_BADACCESSORHANDLE),
  63. NOTE(DB_E_ROWLIMITEXCEEDED),
  64. NOTE(DB_E_READONLYACCESSOR),
  65. NOTE(DB_E_SCHEMAVIOLATION),
  66. NOTE(DB_E_BADROWHANDLE),
  67. NOTE(DB_E_OBJECTOPEN),
  68. NOTE(DB_E_BADBINDINFO),
  69. NOTE(DB_SEC_E_PERMISSIONDENIED),
  70. NOTE(DB_E_NOTAREFERENCECOLUMN),
  71. NOTE(DB_E_NOCOMMAND),
  72. NOTE(DB_E_BADBOOKMARK),
  73. NOTE(DB_E_BADLOCKMODE),
  74. NOTE(DB_E_PARAMNOTOPTIONAL),
  75. NOTE(DB_E_BADRATIO),
  76. NOTE(DB_E_ERRORSINCOMMAND),
  77. NOTE(DB_E_BADSTARTPOSITION),
  78. NOTE(DB_E_NOTREENTRANT),
  79. NOTE(DB_E_NOAGGREGATION),
  80. NOTE(DB_E_DELETEDROW),
  81. NOTE(DB_E_CANTFETCHBACKWARDS),
  82. NOTE(DB_E_ROWSNOTRELEASED),
  83. NOTE(DB_E_BADSTORAGEFLAG),
  84. NOTE(DB_E_BADSTATUSVALUE),
  85. NOTE(DB_E_CANTSCROLLBACKWARDS),
  86. NOTE(DB_E_INTEGRITYVIOLATION),
  87. NOTE(DB_E_ABORTLIMITREACHED),
  88. NOTE(DB_E_DUPLICATEINDEXID),
  89. NOTE(DB_E_NOINDEX),
  90. NOTE(DB_E_INDEXINUSE),
  91. NOTE(DB_E_NOTABLE),
  92. NOTE(DB_E_CONCURRENCYVIOLATION),
  93. NOTE(DB_E_BADCOPY),
  94. NOTE(DB_E_BADPRECISION),
  95. NOTE(DB_E_BADSCALE),
  96. NOTE(DB_E_BADID),
  97. NOTE(DB_E_BADTYPE),
  98. NOTE(DB_E_DUPLICATECOLUMNID),
  99. NOTE(DB_E_DUPLICATETABLEID),
  100. NOTE(DB_E_TABLEINUSE),
  101. NOTE(DB_E_NOLOCALE),
  102. NOTE(DB_E_BADRECORDNUM),
  103. NOTE(DB_E_BOOKMARKSKIPPED),
  104. NOTE(DB_E_BADPROPERTYVALUE),
  105. NOTE(DB_E_INVALID),
  106. NOTE(DB_E_BADACCESSORFLAGS),
  107. NOTE(DB_E_BADSTORAGEFLAGS),
  108. NOTE(DB_E_BYREFACCESSORNOTSUPPORTED),
  109. NOTE(DB_E_NULLACCESSORNOTSUPPORTED),
  110. NOTE(DB_E_NOTPREPARED),
  111. NOTE(DB_E_BADACCESSORTYPE),
  112. NOTE(DB_E_WRITEONLYACCESSOR),
  113. NOTE(DB_SEC_E_AUTH_FAILED),
  114. NOTE(DB_E_CANCELED),
  115. NOTE(DB_E_BADSOURCEHANDLE),
  116. NOTE(DB_S_ROWLIMITEXCEEDED),
  117. NOTE(DB_S_COLUMNTYPEMISMATCH),
  118. NOTE(DB_S_TYPEINFOOVERRIDDEN),
  119. NOTE(DB_S_BOOKMARKSKIPPED),
  120. NOTE(DB_S_ENDOFROWSET),
  121. NOTE(DB_S_BUFFERFULL),
  122. NOTE(DB_S_CANTRELEASE),
  123. NOTE(DB_S_DIALECTIGNORED),
  124. NOTE(DB_S_UNWANTEDPHASE),
  125. NOTE(DB_S_COLUMNSCHANGED),
  126. NOTE(DB_S_ERRORSRETURNED),
  127. NOTE(DB_S_BADROWHANDLE),
  128. NOTE(DB_S_DELETEDROW),
  129. NOTE(DB_S_STOPLIMITREACHED),
  130. NOTE(DB_S_LOCKUPGRADED),
  131. NOTE(DB_S_PROPERTIESCHANGED),
  132. NOTE(DB_S_ERRORSOCCURRED),
  133. NOTE(DB_S_PARAMUNAVAILABLE),
  134. NOTE(DB_S_MULTIPLECHANGES),
  135. // winerr.h
  136. NOTE(E_UNEXPECTED),
  137. NOTE(E_NOTIMPL),
  138. NOTE(E_OUTOFMEMORY),
  139. NOTE(E_INVALIDARG),
  140. NOTE(E_NOINTERFACE),
  141. NOTE(E_POINTER),
  142. NOTE(E_HANDLE),
  143. NOTE(E_ABORT),
  144. NOTE(E_FAIL),
  145. NOTE(E_ACCESSDENIED),
  146. NOTE(S_OK),
  147. NOTE(S_FALSE),
  148. NOTE(E_UNEXPECTED),
  149. NOTE(E_NOTIMPL),
  150. NOTE(E_OUTOFMEMORY),
  151. NOTE(E_INVALIDARG),
  152. NOTE(E_NOINTERFACE),
  153. NOTE(E_POINTER),
  154. NOTE(E_HANDLE),
  155. NOTE(E_ABORT),
  156. NOTE(E_FAIL),
  157. NOTE(E_ACCESSDENIED),
  158. // BindMoniker Errors
  159. NOTE(MK_E_NOOBJECT),
  160. NOTE(MK_E_EXCEEDEDDEADLINE),
  161. NOTE(MK_E_CONNECTMANUALLY),
  162. NOTE(MK_E_INTERMEDIATEINTERFACENOTSUPPORTED),
  163. NOTE(STG_E_ACCESSDENIED),
  164. NOTE(MK_E_SYNTAX),
  165. NOTE(MK_E_CANTOPENFILE),
  166. };
  167. // Format the message.
  168. // Print name of hresult code.
  169. if (format)
  170. {
  171. va_start( argptr, format );
  172. cBytesWritten = _vsnprintf( buff, sizeof(buff), format, argptr );
  173. va_end( argptr );
  174. }
  175. else
  176. strcpy( buff, "" );
  177. // log to stderr and also to our log file
  178. tfprintf( stderr, "%.*s: Returned %.30sn", 
  179. sizeof(buff), buff, 
  180. GetNoteString( ResultCodes, NUMELEM(ResultCodes), GetScode(hr_return)) );
  181.         
  182.     tfprintf( g_fpLogFile, "%.*s: Returned %.30sn", 
  183. sizeof(buff), buff, 
  184. GetNoteString( ResultCodes, NUMELEM(ResultCodes), GetScode(hr_return)) );
  185. return ResultFromScode( hr_return );
  186. }
  187. void DumpColumnsInfo
  188. (
  189.     DBCOLUMNINFO* pColInfo,
  190.     ULONG       cCol
  191.     )
  192. {
  193. ULONG j;
  194. assert(pColInfo != NULL);
  195.  
  196. tfprintf( g_fpLogFile, "nColumn Information:nn"); 
  197.     
  198. for (j=0; j < cCol; j++)
  199. {
  200. WriteColumnInfo( g_fpLogFile, &pColInfo[j] );
  201. }
  202. }
  203. void WriteColumnInfo
  204. (
  205. FILE* fp,
  206. DBCOLUMNINFO* p 
  207. )
  208. {
  209. DBID      *pCol;
  210.     DBKIND      eKind;
  211. wchar_t  wszGuidBuff[MAX_GUID_STRING];
  212.     wchar_t     wszNameBuff[MAX_GUID_STRING];    
  213.     
  214. static char *szDbcolkind[] = { "Guid+Name", "Guid+PropID", "Name", 
  215.     "Guid+Name", "Guid+PropID", "PropID", "Guid" };
  216. assert(p != NULL);
  217. // For DBTYPEENUM.  Doesn't need to be in order.
  218. // Below we mask off the high bits.
  219. static Note typenotes[] = 
  220.     {
  221. NOTE(DBTYPE_EMPTY),
  222. NOTE(DBTYPE_NULL),
  223. NOTE(DBTYPE_I2),
  224. NOTE(DBTYPE_I4),
  225. NOTE(DBTYPE_R4),
  226. NOTE(DBTYPE_R8),
  227. NOTE(DBTYPE_CY),
  228. NOTE(DBTYPE_DATE),
  229. NOTE(DBTYPE_BSTR),
  230. NOTE(DBTYPE_IDISPATCH),
  231. NOTE(DBTYPE_ERROR),
  232. NOTE(DBTYPE_BOOL),
  233. NOTE(DBTYPE_VARIANT),
  234. NOTE(DBTYPE_IUNKNOWN),
  235. NOTE(DBTYPE_DECIMAL),
  236. NOTE(DBTYPE_UI1),
  237. NOTE(DBTYPE_ARRAY),
  238. NOTE(DBTYPE_BYREF),
  239. NOTE(DBTYPE_I1),
  240. NOTE(DBTYPE_UI2),
  241. NOTE(DBTYPE_UI4),
  242. NOTE(DBTYPE_I8),
  243. NOTE(DBTYPE_UI8),
  244. NOTE(DBTYPE_GUID),
  245. NOTE(DBTYPE_VECTOR),
  246. NOTE(DBTYPE_RESERVED),
  247. NOTE(DBTYPE_BYTES),
  248. NOTE(DBTYPE_STR),
  249. NOTE(DBTYPE_WSTR),
  250. NOTE(DBTYPE_NUMERIC),
  251. NOTE(DBTYPE_UDT),
  252. NOTE(DBTYPE_DBDATE),
  253. NOTE(DBTYPE_DBTIME),
  254. NOTE(DBTYPE_DBTIMESTAMP),
  255.     };
  256. static Note flagnotes[] = 
  257.     {
  258. NOTE(DBCOLUMNFLAGS_ISBOOKMARK),
  259. NOTE(DBCOLUMNFLAGS_MAYDEFER),
  260. NOTE(DBCOLUMNFLAGS_WRITE),
  261. NOTE(DBCOLUMNFLAGS_WRITEUNKNOWN),
  262. NOTE(DBCOLUMNFLAGS_ISFIXEDLENGTH),
  263. NOTE(DBCOLUMNFLAGS_ISNULLABLE),
  264. NOTE(DBCOLUMNFLAGS_MAYBENULL),
  265. NOTE(DBCOLUMNFLAGS_ISLONG),
  266. NOTE(DBCOLUMNFLAGS_ISROWID),
  267. NOTE(DBCOLUMNFLAGS_ISROWVER),
  268. NOTE(DBCOLUMNFLAGS_CACHEDEFERRED),
  269. };
  270. pCol = & p->columnid;
  271.     eKind = pCol->eKind;
  272.     // stringize GUID for pretty printing
  273.     switch (eKind)
  274.         {
  275.         case DBKIND_GUID_NAME:
  276.         case DBKIND_GUID_PROPID:
  277.         case DBKIND_GUID:
  278.         StringFromGUID2( pCol->uGuid.guid, wszGuidBuff, sizeof(wszGuidBuff) );
  279.             break;
  280.         case DBKIND_PGUID_NAME:
  281.         case DBKIND_PGUID_PROPID:          
  282.         StringFromGUID2( *(pCol->uGuid.pguid), wszGuidBuff, sizeof(wszGuidBuff) );
  283.             break;
  284.         default:
  285.             wcscpy( wszGuidBuff, L"<none>" );
  286.             break;    
  287.         }
  288.         
  289.     // stringize name or propID for pretty printing   
  290.     switch (eKind)
  291.         {
  292.         case DBKIND_GUID_NAME:
  293.         case DBKIND_NAME:
  294.         case DBKIND_PGUID_NAME:
  295.             swprintf( wszNameBuff, L"[name=%.50S]", pCol->uName.pwszName ? pCol->uName.pwszName : L"(unknown)" );
  296.             break;
  297.         case DBKIND_GUID_PROPID:
  298.         case DBKIND_PGUID_PROPID:
  299.         case DBKIND_PROPID:
  300.             swprintf( wszNameBuff, L"[propid=%lu]", pCol->uName.ulPropid );
  301.             break;
  302.         default:
  303.             wcscpy( wszNameBuff, L"" );
  304.             break;    
  305.         }   
  306.     // pretty print column info
  307.     tfprintf( fp, "ColumnId [kind=%.40s] [guid=%.40S] %.60Sn", 
  308.         szDbcolkind[eKind], wszGuidBuff, wszNameBuff );
  309.         
  310. // Now move on to other stuff...
  311. // Name in DBCOLUMNINFO different than name in DBCOLUMNID (maybe).
  312. tfprintf(fp, "  Name          = '%.50S'n", p->pwszName );
  313. tfprintf(fp, "  iOrdinal      = %dn", p->iOrdinal);
  314. tfprintf(fp, "  wType         = %.100sn", 
  315. GetNoteString( typenotes, NUMELEM(typenotes),
  316.     p->wType & (~DBTYPE_BYREF) & (~DBTYPE_ARRAY) & (~DBTYPE_VECTOR) ) );
  317. if (p->wType & DBTYPE_BYREF)
  318. tfprintf(fp, "      (BYREF)n");
  319. if (p->wType & DBTYPE_ARRAY)
  320. tfprintf(fp, "      (ARRAY)n");
  321. if (p->wType & DBTYPE_VECTOR)
  322. tfprintf(fp, "      (VECTOR)n");
  323. tfprintf(fp, "  ulColumnSize  = %ldn", p->ulColumnSize );
  324. tfprintf(fp, "  bPrecision    = %dn",  p->bPrecision );
  325. tfprintf(fp, "  bScale        = %dn",  p->bScale );
  326. tfprintf(fp, "  dwFlags       = %snn",
  327. GetNoteStringBitvals( flagnotes, NUMELEM(flagnotes), p->dwFlags ) );
  328. }
  329. char* GetNoteString
  330.     ( 
  331. Note * rgNote, 
  332. int    cNote,
  333. DWORD  dwValue 
  334. )
  335. {
  336. int j;
  337. assert(rgNote != NULL);
  338. // Scan a table of value/string,
  339. // return ptr to string found.
  340. for (j=0; j < cNote; j++) {
  341. if (rgNote[j].dwFlag == dwValue)
  342. return rgNote[j].szText;
  343. }
  344. return "<unknown>";
  345. }
  346. char* GetNoteStringBitvals
  347. (
  348. Note*  rgNote,
  349. int     cNote,
  350. DWORD   dwValue 
  351. )
  352. {
  353. static char buff[400];
  354. int j;
  355. assert(rgNote != NULL);
  356. // Make a string that combines all the bits ORed together.
  357. strcpy(buff, "");
  358. for (j=0; j < cNote; j++) {
  359. if (rgNote[j].dwFlag & dwValue) {
  360. if (buff[0])
  361. strcat( buff, " | " );
  362. strcat( buff, rgNote[j].szText );
  363. }
  364. }
  365. assert(strlen(buff) < sizeof(buff));
  366. return buff;
  367. }
  368. ULONG CalcPrettyPrintMaxColWidth
  369.     (
  370.     DBBINDING* rgBind,
  371.     ULONG       cBind
  372.     )
  373. {
  374. ULONG cMaxWidth;
  375.     ULONG   cTotalWidth;
  376.     ULONG iBind;
  377. assert(rgBind != NULL);
  378. cMaxWidth = DEFAULT_CBMAXLENGTH;
  379. while (1)
  380. {
  381. cTotalWidth = 0;
  382. for (iBind=0; iBind < cBind; iBind++)
  383. cTotalWidth += min( cMaxWidth, rgBind[iBind].cbMaxLen ) + 1;
  384. if (cTotalWidth < PRETTYPRINT_MAXTOTALWIDTH || cMaxWidth < PRETTYPRINT_MINCOLWIDTH)
  385. break;
  386. cMaxWidth--;
  387. }
  388. return cMaxWidth;
  389. }
  390. void DumpColumnHeadings
  391. (
  392. DBBINDING* rgBind, 
  393. ULONG cBind, 
  394. DBCOLUMNINFO*  pColInfo, 
  395. ULONG cCol,
  396.     ULONG cMaxColWidth
  397. )
  398. {
  399. ULONG iBind;
  400. assert(rgBind != NULL);
  401.     assert(pColInfo != NULL);
  402.  
  403. for (iBind=0; iBind < cBind; iBind++)
  404. tfprintf( g_fpLogFile, "%-*.*S ",
  405. min( cMaxColWidth, rgBind[iBind].cbMaxLen ),
  406. min( cMaxColWidth, rgBind[iBind].cbMaxLen ),
  407. LookupColumnName( pColInfo, cCol, rgBind[iBind].iOrdinal ) );
  408. tfprintf( g_fpLogFile, "n" );
  409. for (iBind=0; iBind < cBind; iBind++)
  410. tfprintf( g_fpLogFile, "%-*.*s ",
  411. min( cMaxColWidth, rgBind[iBind].cbMaxLen ),
  412. min( cMaxColWidth, rgBind[iBind].cbMaxLen ),
  413. "------------------------------" );
  414. tfprintf( g_fpLogFile, "n" );
  415. }
  416. WCHAR* LookupColumnName
  417. (
  418. DBCOLUMNINFO* rgColInfo,
  419. ULONG  cCol,
  420. ULONG  iCol 
  421. )
  422. {
  423. ULONG j;
  424. assert(rgColInfo != NULL);
  425. // A really slow way to get the column name, given the ordinal.
  426. // The problem is that result-set ordinals do not necessarily match
  427. // the index into the ColumnInfo array.
  428. // (May have bookmark, which is always column 0.)
  429. for (j=0; j < cCol; j++)
  430. if (rgColInfo[j].iOrdinal == iCol)
  431. return rgColInfo[j].pwszName;
  432.             
  433. return L"Error";
  434. }
  435. void DumpRow
  436. (
  437.     DBBINDING*  rgBind,
  438.     ULONG cBind,
  439.     ULONG cMaxColWidth,
  440.     BYTE*  pData
  441.     )
  442. {
  443. ULONG  iBind;
  444.     COLUMNDATA* pColumn;
  445.     
  446. assert(rgBind);
  447. assert( offsetof(COLUMNDATA, dwLength) == 0);
  448.     
  449. // Print each column we're bound to.
  450. for (iBind=0; iBind < cBind; iBind++)
  451. {
  452. // Columns are bound differently; not so easy.
  453. // Print out to at least DEFAULT_CBMAXLENGTH width (pretty),
  454. // Limit to first dwLength characters.
  455. pColumn = (COLUMNDATA *) (pData + rgBind[iBind].obLength);
  456. PrintColumn( pColumn, rgBind, iBind, cMaxColWidth );
  457. }
  458. tfprintf( g_fpLogFile, "n" );
  459. }    
  460. void PrintColumn
  461. (
  462. COLUMNDATA    *pColumn,
  463. DBBINDING     *rgBind,
  464. ULONG          iBind,
  465. ULONG          cMaxColWidth 
  466. )
  467. {
  468. void* p;
  469. ULONG   ulPrintWidth;
  470. ULONG   ulPrintPrecision;
  471. DWORD   dwStatus;
  472. DWORD   dwLength;
  473. BOOL    fDidVariant;
  474. BOOL    fIsUnicode;
  475. char* sFormat;
  476. HRESULT hr;
  477.     assert(pColumn != NULL);
  478.     assert(rgBind != NULL);
  479.     
  480. // Pretty print a column.
  481. // May have different type of binding.
  482. fDidVariant = FALSE;
  483. fIsUnicode  = FALSE;
  484. dwStatus = pColumn->dwStatus;
  485. dwLength = pColumn->dwLength;
  486. if (dwStatus == DBSTATUS_S_ISNULL)
  487. {
  488. p = "<null>";
  489. dwLength = strlen( (char *) p);
  490. }
  491.     else if (dwStatus == DBBINDSTATUS_UNSUPPORTEDCONVERSION)
  492.         {
  493.         p = "<unsupportedconversion>";
  494. dwLength = strlen( (char *) p);
  495.         }    
  496. else
  497. {
  498. switch (rgBind[iBind].wType) 
  499. {
  500. case DBTYPE_STR:
  501. // We have a string in our buffer, so use it.
  502. p = (void *) &pColumn->bData;
  503. break;
  504. case DBTYPE_VARIANT:
  505. // We have a variant in our buffer, so convert to string.
  506. p = (void *) &pColumn->bData;
  507. hr = VariantChangeTypeEx(
  508. (VARIANT *) p, // Destination (convert in place)
  509. (VARIANT *) p, // Source
  510. LOCALE_SYSTEM_DEFAULT, // LCID
  511. 0, // dwFlags
  512. VT_BSTR );
  513. if (FAILED(hr))
  514.              {
  515. DumpErrorHResult( hr, "VariantChangeTypeEx, field %d", iBind );
  516.                 return;
  517.                 }
  518. p = (wchar_t *) (((VARIANT *)p)->bstrVal) ;
  519. dwLength = ((DWORD *)p)[-1] / sizeof(wchar_t);
  520. fDidVariant = TRUE;
  521. fIsUnicode  = TRUE;
  522. break;
  523. default:
  524. p = "??? unknown type ???";
  525. break;
  526. }
  527. }
  528. // Print the column.
  529. // If it has been truncated or rounded, print a '#' in
  530. // the far right-hand column.
  531. ulPrintWidth     = min( cMaxColWidth, rgBind[iBind].cbMaxLen );
  532. ulPrintPrecision = min( cMaxColWidth, dwLength );
  533. if (dwStatus == DBSTATUS_S_TRUNCATED ||  cMaxColWidth < dwLength)
  534. {
  535. ulPrintWidth--;
  536. ulPrintPrecision--;
  537. }
  538. sFormat = fIsUnicode ? "%-*.*S" : "%-*.*s";
  539. tfprintf( g_fpLogFile, sFormat, ulPrintWidth, ulPrintPrecision, p );
  540. if (dwStatus == DBSTATUS_S_TRUNCATED ||  cMaxColWidth < dwLength)
  541. tfprintf( g_fpLogFile, "#" );
  542. tfprintf( g_fpLogFile, " " );
  543. // Free memory used by the variant.
  544. if (fDidVariant)
  545. VariantClear( (VARIANT *) &pColumn->bData );
  546.         
  547. return;
  548. }
  549. void tfprintf
  550. (
  551. FILE* fp,
  552. const char* format,
  553. ... 
  554. )
  555. {
  556. int  cBytesWritten;
  557. char  buff[400];
  558. va_list argptr;
  559. assert(format != NULL);
  560. // Dump a formatted string.
  561.     // _vsnprintf prevents overflowing our buffer.
  562. va_start( argptr, format );
  563. cBytesWritten = _vsnprintf( buff, sizeof(buff), format, argptr );
  564. va_end( argptr );
  565. buff[sizeof(buff)-1] = '';
  566. // Can't use fprintf, because string could contain '%'.
  567. if (fp)
  568. fputs( buff, fp );
  569. }
  570. void tvfprintf
  571. (
  572. FILE* fp,
  573. const char* format,
  574. va_list argptr 
  575. )
  576. {
  577. int  cBytesWritten;
  578. char  buff[400];
  579. assert(format != NULL);
  580. // Dump a formatted string.
  581.     // _vsnprintf prevents overflowing our buffer.
  582. cBytesWritten = _vsnprintf( buff, sizeof(buff), format, argptr );
  583. buff[sizeof(buff)-1] = '';
  584. // Can't use fprintf, because string could contain '%'.
  585. if (fp)
  586. fputs( buff, fp );
  587. }