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.

1310 lines
36 KiB

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
  7. //
  8. // MODULE: TapiInfo.c
  9. //
  10. // PURPOSE: Handles all Pretty Printing functions for the TapiComm sample.
  11. //
  12. // EXPORTED FUNCTIONS: These functions are for use by other modules.
  13. //
  14. // All of these pretty print to the debugging output.
  15. // OutputDebugLineCallback - Calls FormatLineCallback.
  16. // OutputDebugLineError - Calls OutputDebugLineErrorFileLine.
  17. // OutputDebugLastError - Calls OutputDebugLineErrorFileLine.
  18. // OutputDebugPrintf - Calls wsprintf
  19. // OutputDebugLineErrorFileLine - Calls FormatLineError
  20. // OutputDebugLastErrorFileLine - Calls FormatLastError
  21. //
  22. // All of these functions pretty print to a string buffer.
  23. // FormatLineError - Prints a LINEERR
  24. // FormatLastError - Prints a GetLastError error.
  25. // FormatLineCallback - Prints a lineCallbackFunc message.
  26. //
  27. // INTERNAL FUNCTION: These functions are for this module only.
  28. // strBinaryArrayAppend - prints a binary flag array to a buffer.
  29. #include <windows.h>
  30. #include <tapi.h>
  31. #include "TapiInfo.h"
  32. // Maximum length of all internal string buffers.
  33. #define MAXOUTPUTSTRINGLENGTH 4096
  34. // define to make accessing arrays easy.
  35. #define sizeofArray(pArray) (sizeof(pArray) / sizeof((pArray)[0]))
  36. //*****************************************
  37. // Internal prototypes.
  38. //*****************************************
  39. static long strBinaryArrayAppend(LPSTR pszOutputBuffer, DWORD dwFlags,
  40. LPSTR szStringArray[], DWORD dwSizeofStringArray);
  41. //*****************************************
  42. // Global arrays for interpreting TAPI constants.
  43. //*****************************************
  44. LPSTR pszLineErrorNameArray[] =
  45. {
  46. "",
  47. "LINEERR_ALLOCATED",
  48. "LINEERR_BADDEVICEID",
  49. "LINEERR_BEARERMODEUNAVAIL",
  50. "LINEERR Unused constant, ERROR!!",
  51. "LINEERR_CALLUNAVAIL",
  52. "LINEERR_COMPLETIONOVERRUN",
  53. "LINEERR_CONFERENCEFULL",
  54. "LINEERR_DIALBILLING",
  55. "LINEERR_DIALDIALTONE",
  56. "LINEERR_DIALPROMPT",
  57. "LINEERR_DIALQUIET",
  58. "LINEERR_INCOMPATIBLEAPIVERSION",
  59. "LINEERR_INCOMPATIBLEEXTVERSION",
  60. "LINEERR_INIFILECORRUPT",
  61. "LINEERR_INUSE",
  62. "LINEERR_INVALADDRESS",
  63. "LINEERR_INVALADDRESSID",
  64. "LINEERR_INVALADDRESSMODE",
  65. "LINEERR_INVALADDRESSSTATE",
  66. "LINEERR_INVALAPPHANDLE",
  67. "LINEERR_INVALAPPNAME",
  68. "LINEERR_INVALBEARERMODE",
  69. "LINEERR_INVALCALLCOMPLMODE",
  70. "LINEERR_INVALCALLHANDLE",
  71. "LINEERR_INVALCALLPARAMS",
  72. "LINEERR_INVALCALLPRIVILEGE",
  73. "LINEERR_INVALCALLSELECT",
  74. "LINEERR_INVALCALLSTATE",
  75. "LINEERR_INVALCALLSTATELIST",
  76. "LINEERR_INVALCARD",
  77. "LINEERR_INVALCOMPLETIONID",
  78. "LINEERR_INVALCONFCALLHANDLE",
  79. "LINEERR_INVALCONSULTCALLHANDLE",
  80. "LINEERR_INVALCOUNTRYCODE",
  81. "LINEERR_INVALDEVICECLASS",
  82. "LINEERR_INVALDEVICEHANDLE",
  83. "LINEERR_INVALDIALPARAMS",
  84. "LINEERR_INVALDIGITLIST",
  85. "LINEERR_INVALDIGITMODE",
  86. "LINEERR_INVALDIGITS",
  87. "LINEERR_INVALEXTVERSION",
  88. "LINEERR_INVALGROUPID",
  89. "LINEERR_INVALLINEHANDLE",
  90. "LINEERR_INVALLINESTATE",
  91. "LINEERR_INVALLOCATION",
  92. "LINEERR_INVALMEDIALIST",
  93. "LINEERR_INVALMEDIAMODE",
  94. "LINEERR_INVALMESSAGEID",
  95. "LINEERR Unused constant, ERROR!!",
  96. "LINEERR_INVALPARAM",
  97. "LINEERR_INVALPARKID",
  98. "LINEERR_INVALPARKMODE",
  99. "LINEERR_INVALPOINTER",
  100. "LINEERR_INVALPRIVSELECT",
  101. "LINEERR_INVALRATE",
  102. "LINEERR_INVALREQUESTMODE",
  103. "LINEERR_INVALTERMINALID",
  104. "LINEERR_INVALTERMINALMODE",
  105. "LINEERR_INVALTIMEOUT",
  106. "LINEERR_INVALTONE",
  107. "LINEERR_INVALTONELIST",
  108. "LINEERR_INVALTONEMODE",
  109. "LINEERR_INVALTRANSFERMODE",
  110. "LINEERR_LINEMAPPERFAILED",
  111. "LINEERR_NOCONFERENCE",
  112. "LINEERR_NODEVICE",
  113. "LINEERR_NODRIVER",
  114. "LINEERR_NOMEM",
  115. "LINEERR_NOREQUEST",
  116. "LINEERR_NOTOWNER",
  117. "LINEERR_NOTREGISTERED",
  118. "LINEERR_OPERATIONFAILED",
  119. "LINEERR_OPERATIONUNAVAIL",
  120. "LINEERR_RATEUNAVAIL",
  121. "LINEERR_RESOURCEUNAVAIL",
  122. "LINEERR_REQUESTOVERRUN",
  123. "LINEERR_STRUCTURETOOSMALL",
  124. "LINEERR_TARGETNOTFOUND",
  125. "LINEERR_TARGETSELF",
  126. "LINEERR_UNINITIALIZED",
  127. "LINEERR_USERUSERINFOTOOBIG",
  128. "LINEERR_REINIT",
  129. "LINEERR_ADDRESSBLOCKED",
  130. "LINEERR_BILLINGREJECTED",
  131. "LINEERR_INVALFEATURE",
  132. "LINEERR_NOMULTIPLEINSTANCE"
  133. };
  134. LPSTR psz_dwMsg[] = {
  135. "LINE_ADDRESSSTATE",
  136. "LINE_CALLINFO",
  137. "LINE_CALLSTATE",
  138. "LINE_CLOSE",
  139. "LINE_DEVSPECIFIC",
  140. "LINE_DEVSPECIFICFEATURE",
  141. "LINE_GATHERDIGITS",
  142. "LINE_GENERATE",
  143. "LINE_LINEDEVSTATE",
  144. "LINE_MONITORDIGITS",
  145. "LINE_MONITORMEDIA",
  146. "LINE_MONITORTONE",
  147. "LINE_REPLY",
  148. "LINE_REQUEST",
  149. "PHONE_BUTTON",
  150. "PHONE_CLOSE",
  151. "PHONE_DEVSPECIFIC",
  152. "PHONE_REPLY",
  153. "PHONE_STATE",
  154. "LINE_CREATE",
  155. "PHONE_CREATE"
  156. };
  157. LPSTR pszfLINEADDRESSSTATE[] =
  158. {
  159. "Unknown LINEADDRESSSTATE information",
  160. "LINEADDRESSSTATE_OTHER",
  161. "LINEADDRESSSTATE_DEVSPECIFIC",
  162. "LINEADDRESSSTATE_INUSEZERO",
  163. "LINEADDRESSSTATE_INUSEONE",
  164. "LINEADDRESSSTATE_INUSEMANY",
  165. "LINEADDRESSSTATE_NUMCALLS",
  166. "LINEADDRESSSTATE_FORWARD",
  167. "LINEADDRESSSTATE_TERMINALS",
  168. "LINEADDRESSSTATE_CAPSCHANGE"
  169. };
  170. LPSTR pszfLINECALLINFOSTATE[] =
  171. {
  172. "Unknown LINECALLINFOSTATE state",
  173. "LINECALLINFOSTATE_OTHER",
  174. "LINECALLINFOSTATE_DEVSPECIFIC",
  175. "LINECALLINFOSTATE_BEARERMODE",
  176. "LINECALLINFOSTATE_RATE",
  177. "LINECALLINFOSTATE_MEDIAMODE",
  178. "LINECALLINFOSTATE_APPSPECIFIC",
  179. "LINECALLINFOSTATE_CALLID",
  180. "LINECALLINFOSTATE_RELATEDCALLID",
  181. "LINECALLINFOSTATE_ORIGIN",
  182. "LINECALLINFOSTATE_REASON",
  183. "LINECALLINFOSTATE_COMPLETIONID",
  184. "LINECALLINFOSTATE_NUMOWNERINCR",
  185. "LINECALLINFOSTATE_NUMOWNERDECR",
  186. "LINECALLINFOSTATE_NUMMONITORS",
  187. "LINECALLINFOSTATE_TRUNK",
  188. "LINECALLINFOSTATE_CALLERID",
  189. "LINECALLINFOSTATE_CALLEDID",
  190. "LINECALLINFOSTATE_CONNECTEDID",
  191. "LINECALLINFOSTATE_REDIRECTIONID",
  192. "LINECALLINFOSTATE_REDIRECTINGID",
  193. "LINECALLINFOSTATE_DISPLAY",
  194. "LINECALLINFOSTATE_USERUSERINFO",
  195. "LINECALLINFOSTATE_HIGHLEVELCOMP",
  196. "LINECALLINFOSTATE_LOWLEVELCOMP",
  197. "LINECALLINFOSTATE_CHARGINGINFO",
  198. "LINECALLINFOSTATE_TERMINAL",
  199. "LINECALLINFOSTATE_DIALPARAMS",
  200. "LINECALLINFOSTATE_MONITORMODES"
  201. };
  202. LPSTR pszfLINECALLSTATE[] =
  203. {
  204. "Unknown LINECALLSTATE state",
  205. "LINECALLSTATE_IDLE",
  206. "LINECALLSTATE_OFFERING",
  207. "LINECALLSTATE_ACCEPTED",
  208. "LINECALLSTATE_DIALTONE",
  209. "LINECALLSTATE_DIALING",
  210. "LINECALLSTATE_RINGBACK",
  211. "LINECALLSTATE_BUSY",
  212. "LINECALLSTATE_SPECIALINFO",
  213. "LINECALLSTATE_CONNECTED",
  214. "LINECALLSTATE_PROCEEDING",
  215. "LINECALLSTATE_ONHOLD",
  216. "LINECALLSTATE_CONFERENCED",
  217. "LINECALLSTATE_ONHOLDPENDCONF",
  218. "LINECALLSTATE_ONHOLDPENDTRANSFER",
  219. "LINECALLSTATE_DISCONNECTED",
  220. "LINECALLSTATE_UNKNOWN"
  221. };
  222. LPSTR pszfLINEDIALTONEMODE[] =
  223. {
  224. "Unknown LINEDIALTONE information",
  225. "LINEDIALTONEMODE_NORMAL",
  226. "LINEDIALTONEMODE_SPECIAL",
  227. "LINEDIALTONEMODE_INTERNAL",
  228. "LINEDIALTONEMODE_EXTERNAL",
  229. "LINEDIALTONEMODE_UNKNOWN",
  230. "LINEDIALTONEMODE_UNAVAIL"
  231. };
  232. LPSTR pszfLINEBUSYMODE[] =
  233. {
  234. "Unknown LINEBUSYMODE information",
  235. "LINEBUSYMODE_STATION",
  236. "LINEBUSYMODE_TRUNK",
  237. "LINEBUSYMODE_UNKNOWN",
  238. "LINEBUSYMODE_UNAVAIL"
  239. };
  240. LPSTR pszfLINESPECIALINFO[] =
  241. {
  242. "Unknown LINESPECIALINFO information",
  243. "LINESPECIALINFO_NOCIRCUIT",
  244. "LINESPECIALINFO_CUSTIRREG",
  245. "LINESPECIALINFO_REORDER",
  246. "LINESPECIALINFO_UNKNOWN",
  247. "LINESPECIALINFO_UNAVAIL"
  248. };
  249. LPSTR pszfLINEDISCONNECTED[] =
  250. {
  251. "Unknown LINEDISCONNECTED information",
  252. "LINEDISCONNECTMODE_NORMAL",
  253. "LINEDISCONNECTMODE_UNKNOWN",
  254. "LINEDISCONNECTMODE_REJECT",
  255. "LINEDISCONNECTMODE_PICKUP",
  256. "LINEDISCONNECTMODE_FORWARDED",
  257. "LINEDISCONNECTMODE_BUSY",
  258. "LINEDISCONNECTMODE_NOANSWER",
  259. "LINEDISCONNECTMODE_BADADDRESS",
  260. "LINEDISCONNECTMODE_UNREACHABLE",
  261. "LINEDISCONNECTMODE_CONGESTION",
  262. "LINEDISCONNECTMODE_INCOMPATIBLE",
  263. "LINEDISCONNECTMODE_UNAVAIL",
  264. "LINEDISCONNECTMODE_NODIALTONE"
  265. };
  266. LPSTR pszfLINECALLPRIVILEGE[] =
  267. {
  268. "",
  269. "LINECALLPRIVILEGE_NONE",
  270. "LINECALLPRIVILEGE_MONITOR",
  271. "LINECALLPRIVILEGE_OWNER"
  272. };
  273. LPSTR pszfLINEGATHERTERM[] =
  274. {
  275. "Unknown LINEGATHERTERM message",
  276. "LINEGATHERTERM_BUFFERFULL",
  277. "LINEGATHERTERM_TERMDIGIT",
  278. "LINEGATHERTERM_FIRSTTIMEOUT",
  279. "LINEGATHERTERM_INTERTIMEOUT",
  280. "LINEGATHERTERM_CANCEL"
  281. };
  282. LPSTR pszfLINEGENERATETERM[] =
  283. {
  284. "Unknown LINEGENERATETERM message",
  285. "LINEGENERATETERM_DONE",
  286. "LINEGENERATETERM_CANCEL"
  287. };
  288. LPSTR pszfLINEDEVSTATE[] =
  289. {
  290. "Unknown LINEDEVESTATE state",
  291. "LINEDEVSTATE_OTHER",
  292. "LINEDEVSTATE_RINGING",
  293. "LINEDEVSTATE_CONNECTED",
  294. "LINEDEVSTATE_DISCONNECTED",
  295. "LINEDEVSTATE_MSGWAITON",
  296. "LINEDEVSTATE_MSGWAITOFF",
  297. "LINEDEVSTATE_INSERVICE",
  298. "LINEDEVSTATE_OUTOFSERVICE",
  299. "LINEDEVSTATE_MAINTENANCE",
  300. "LINEDEVSTATE_OPEN",
  301. "LINEDEVSTATE_CLOSE",
  302. "LINEDEVSTATE_NUMCALLS",
  303. "LINEDEVSTATE_NUMCOMPLETIONS",
  304. "LINEDEVSTATE_TERMINALS",
  305. "LINEDEVSTATE_ROAMMODE",
  306. "LINEDEVSTATE_BATTERY",
  307. "LINEDEVSTATE_SIGNAL",
  308. "LINEDEVSTATE_DEVSPECIFIC",
  309. "LINEDEVSTATE_REINIT",
  310. "LINEDEVSTATE_LOCK",
  311. "LINEDEVSTATE_CAPSCHANGE",
  312. "LINEDEVSTATE_CONFIGCHANGE",
  313. "LINEDEVSTATE_TRANSLATECHANGE",
  314. "LINEDEVSTATE_COMPLCANCEL",
  315. "LINEDEVSTATE_REMOVED"
  316. };
  317. LPSTR pszfLINEDIGITMODE[] =
  318. {
  319. "Unknown LINEDIGITMODE mode",
  320. "LINEDIGITMODE_PULSE",
  321. "LINEDIGITMODE_DTMF",
  322. "LINEDIGITMODE_DTMFEND"
  323. };
  324. LPSTR pszfLINEMEDIAMODE[] =
  325. {
  326. "Unknown LINEMEDIAMODE mode",
  327. "UnUsed LINEMEDIAMODE mode, ERROR!!",
  328. "LINEMEDIAMODE_UNKNOWN",
  329. "LINEMEDIAMODE_INTERACTIVEVOICE",
  330. "LINEMEDIAMODE_AUTOMATEDVOICE",
  331. "LINEMEDIAMODE_DATAMODEM",
  332. "LINEMEDIAMODE_G3FAX",
  333. "LINEMEDIAMODE_TDD",
  334. "LINEMEDIAMODE_G4FAX",
  335. "LINEMEDIAMODE_DIGITALDATA",
  336. "LINEMEDIAMODE_TELETEX",
  337. "LINEMEDIAMODE_VIDEOTEX",
  338. "LINEMEDIAMODE_TELEX",
  339. "LINEMEDIAMODE_MIXED",
  340. "LINEMEDIAMODE_ADSI",
  341. "LINEMEDIAMODE_VOICEVIEW"
  342. };
  343. LPSTR pszfLINEREQUESTMODE[] =
  344. {
  345. "Unknown LINEREQUESTMODE message",
  346. "LINEREQUESTMODE_MAKECALL",
  347. "LINEREQUESTMODE_MEDIACALL",
  348. "LINEREQUESTMODE_DROP"
  349. };
  350. //
  351. // MACRO: OutputDebugLineError(long, LPSTR)
  352. //
  353. // PURPOSE: Pretty print a line error to the debugging output.
  354. //
  355. // PARAMETERS:
  356. // lLineError - Actual error code to decipher.
  357. // pszPrefix - String to prepend to the printed message.
  358. //
  359. // RETURN VALUE:
  360. // none
  361. //
  362. // COMMENTS:
  363. // This macro is actually defined in the .h file.
  364. // It will take a LINEERR error, turn it into a human
  365. // readable string, prepend pszPrefix (so you
  366. // can tag your errors), append __FILE__ and __LINE__
  367. // and print it to the debugging output.
  368. // This macro is just a wrapper around OutputDebugLineErrorFileLine
  369. // that is necessary to get proper values for __FILE__ and __LINE__.
  370. //
  371. //
  372. /*
  373. #define OuputDebugLineError(lLineError, pszPrefix) \
  374. OutputDebugLineErrorFileLine(lLineError, pszPrefix,\
  375. __FILE__, __LINE__)
  376. */
  377. //
  378. // FUNCTION: OutputDebugLineErrorFileLine(..)
  379. //
  380. // PURPOSE: Pretty print a line error to the debugging output.
  381. //
  382. // PARAMETERS:
  383. // lLineError - Actual error code to decipher.
  384. // pszPrefix - String to prepend to the printed message.
  385. // szFileName - Filename the error occured in.
  386. // nLineNumber - Line number the error occured at.
  387. //
  388. // RETURN VALUE:
  389. // none
  390. //
  391. // COMMENTS:
  392. // This is the actual function that OutputDebugLineError
  393. // expands to. Its not likely to be usefull except
  394. // through the OutputDebugLineError macro, or to print
  395. // errors without line and file information.
  396. //
  397. // If szFileName == NULL, then the File and Line are not printed.
  398. //
  399. // Note that there is an internal string length limit of
  400. // MAXOUTPUTSTRINGLENGTH. If this length is exceeded,
  401. // the behavior will be the same as wsprintf, although
  402. // it will be undetectable. *KEEP szPrefix SHORT!*
  403. //
  404. //
  405. void OutputDebugLineErrorFileLine(
  406. long lLineError, LPSTR szPrefix,
  407. LPSTR szFileName, DWORD nLineNumber)
  408. {
  409. LPSTR szLineError;
  410. char szOutputLineError[MAXOUTPUTSTRINGLENGTH];
  411. if (szPrefix == NULL)
  412. szPrefix = "";
  413. // Pretty print the error message.
  414. szLineError = FormatLineError(lLineError, NULL, 0);
  415. // The only reason FormatLineError should fail is "Out of memory".
  416. if (szLineError == NULL)
  417. {
  418. if (szFileName == NULL)
  419. wsprintf(szOutputLineError, "%sOut of memory", szPrefix);
  420. else
  421. wsprintf(szOutputLineError,
  422. "%sOut of memory in file %s, line %d\r\n",
  423. szPrefix, szFileName, nLineNumber);
  424. OutputDebugString(szOutputLineError);
  425. return;
  426. }
  427. // If szFileName, then use it; else don't.
  428. if (szFileName != NULL)
  429. {
  430. wsprintf(szOutputLineError,
  431. "%s\r\n\tTapi Line Error: \"%s\" \r\n\tin File \"%s\", Line %d\r\n",
  432. szPrefix, szLineError, szFileName, nLineNumber);
  433. }
  434. else
  435. {
  436. wsprintf(szOutputLineError,
  437. "%s\r\n\tTapi Line Error: \"%s\"\r\n",
  438. szPrefix, szLineError);
  439. }
  440. // Pointer returned from FormatLineError *must* be freed!
  441. LocalFree(szLineError);
  442. // Print it!
  443. OutputDebugString(szOutputLineError);
  444. return;
  445. }
  446. //
  447. // FUNCTION: FormatLineError(long, LPSTR, DWORD)
  448. //
  449. // PURPOSE: Pretty print a line error to a string.
  450. //
  451. // PARAMETERS:
  452. // lLineError - Actual error code to decipher.
  453. // szOutputBuffer - String buffer to pretty print to.
  454. // dwSizeofOutputBuffer - Size of String buffer.
  455. //
  456. // RETURN VALUE:
  457. // Returns the buffer printed to.
  458. //
  459. // COMMENTS:
  460. // If szOutputBuffer isn't big enough to hold the whole string,
  461. // then the string gets truncated to fit the buffer.
  462. //
  463. // If szOutputBuffer == NULL, then dwSizeofOutputBuffer
  464. // is ignored, a buffer 'big enough' is LocalAlloc()d and
  465. // a pointer to it is returned. However, its *very* important
  466. // that this pointer be LocalFree()d by the calling application.
  467. //
  468. //
  469. LPSTR FormatLineError(long lLineError,
  470. LPSTR szOutputBuffer, DWORD dwSizeofOutputBuffer)
  471. {
  472. char szUnknownLineError[256];
  473. LPSTR szLineError;
  474. int nSizeofLineError;
  475. long lErrorIndex;
  476. DWORD * pdwLineError;
  477. // Strip off the high bit to make the error code positive.
  478. pdwLineError = (LPDWORD) &lLineError;
  479. lErrorIndex = (long) (0x7FFFFFFF & *pdwLineError);
  480. // Is it an unknown error?
  481. if ((lErrorIndex >= sizeofArray(pszLineErrorNameArray)) ||
  482. (lErrorIndex < 0))
  483. {
  484. nSizeofLineError =
  485. wsprintf(szUnknownLineError, "Unknown TAPI line error code: 0x%lx",
  486. lLineError);
  487. szLineError = szUnknownLineError;
  488. }
  489. else
  490. {
  491. szLineError = pszLineErrorNameArray[lErrorIndex];
  492. nSizeofLineError = strlen(szLineError);
  493. }
  494. // allocate a buffer if necessary
  495. if (szOutputBuffer == NULL)
  496. {
  497. szOutputBuffer = (LPSTR) LocalAlloc(LPTR, nSizeofLineError + 1);
  498. if (szOutputBuffer == NULL)
  499. return NULL;
  500. }
  501. else // truncate string if it won't fit in the specified buffer.
  502. {
  503. if ((DWORD) nSizeofLineError >= dwSizeofOutputBuffer)
  504. nSizeofLineError = dwSizeofOutputBuffer - 1;
  505. }
  506. // Put the string into the buffer and null terminate.
  507. memcpy(szOutputBuffer, szLineError, nSizeofLineError);
  508. szOutputBuffer[nSizeofLineError] = '\0';
  509. return szOutputBuffer;
  510. }
  511. //
  512. // MACRO: OutputDebugLastError(DWORD, LPSTR)
  513. //
  514. // PURPOSE: Pretty print a system error to the debugging output.
  515. //
  516. // PARAMETERS:
  517. // dwLastError - Actual error code to decipher.
  518. // pszPrefix - String to prepend to the printed message.
  519. //
  520. // RETURN VALUE:
  521. // none
  522. //
  523. // COMMENTS:
  524. // This macro is actually defined in the .h file.
  525. // It will take an error that was retrieved by GetLastError(),
  526. // turn it into a human readable string, prepend pszPrefix
  527. // (so you can tag your errors), append __FILE__ and __LINE__
  528. // and print it to the debugging output.
  529. //
  530. // This macro is just a wrapper around OutputDebugLastErrorFileLine
  531. // that is necessary to get proper values for __FILE__ and __LINE__.
  532. //
  533. //
  534. /*
  535. #define OuputDebugLastError(dwLastError, pszPrefix) \
  536. OutputDebugLastErrorFileLine(dwLastError, pszPrefix,\
  537. __FILE__, __LINE__)
  538. */
  539. //
  540. // FUNCTION: OutputDebugLastErrorFileLine(..)
  541. //
  542. // PURPOSE: Pretty print a line error to the debugging output.
  543. //
  544. // PARAMETERS:
  545. // dwLastError - Actual error code to decipher.
  546. // pszPrefix - String to prepend to the printed message.
  547. // szFileName - Filename the error occured in.
  548. // nLineNumber - Line number the error occured at.
  549. //
  550. // RETURN VALUE:
  551. // none
  552. //
  553. // COMMENTS:
  554. // This is the actual function that OutputDebugLastError
  555. // expands to. Its not likely to be usefull except
  556. // through the OutputDebugLastError macro or to print
  557. // errors without line and file information.
  558. //
  559. // If szFileName == NULL, then the File and Line are not printed.
  560. //
  561. // Note that there is an internal string length limit of
  562. // MAXOUTPUTSTRINGLENGTH. If this length is exceeded,
  563. // the behavior will be the same as wsprintf, although
  564. // it will be undetectable. *KEEP szPrefix SHORT!*
  565. //
  566. //
  567. void OutputDebugLastErrorFileLine(
  568. DWORD dwLastError, LPSTR szPrefix,
  569. LPSTR szFileName, DWORD nLineNumber)
  570. {
  571. LPSTR szLastError;
  572. char szOutputLastError[MAXOUTPUTSTRINGLENGTH];
  573. if (szPrefix == NULL)
  574. szPrefix = "";
  575. // Pretty print the error.
  576. szLastError = FormatLastError(dwLastError, NULL, 0);
  577. // The only reason FormatLastError should fail is "Out of memory".
  578. if (szLastError == NULL)
  579. {
  580. if (szFileName == NULL)
  581. wsprintf(szOutputLastError, "%sOut of memory\r\n", szPrefix);
  582. else
  583. wsprintf(szOutputLastError, "%sOut of memory in file %s, line %d\r\n",
  584. szPrefix, szFileName, nLineNumber);
  585. OutputDebugString(szOutputLastError);
  586. return;
  587. }
  588. // If szFileName, then use it; else don't.
  589. if (szFileName != NULL)
  590. {
  591. wsprintf(szOutputLastError,
  592. "%sGetLastError returned: \"%s\" in File \"%s\", Line %d\r\n",
  593. szPrefix, szLastError, szFileName, nLineNumber);
  594. }
  595. else
  596. {
  597. wsprintf(szOutputLastError,
  598. "%sGetLastError returned: \"%s\"\r\n",
  599. szPrefix, szLastError);
  600. }
  601. // Pointer returned from FormatLineError *must* be freed!
  602. LocalFree(szLastError);
  603. // Print it!
  604. OutputDebugString(szOutputLastError);
  605. return;
  606. }
  607. //
  608. // FUNCTION: FormatLastError(DWORD, LPSTR, DWORD)
  609. //
  610. // PURPOSE: Pretty print a system error to a string.
  611. //
  612. // PARAMETERS:
  613. // dwLastError - Actual error code to decipher.
  614. // szOutputBuffer - String buffer to pretty print to.
  615. // dwSizeofOutputBuffer - Size of String buffer.
  616. //
  617. // RETURN VALUE:
  618. // Returns the buffer printed to.
  619. //
  620. // COMMENTS:
  621. // If szOutputBuffer isn't big enough to hold the whole string,
  622. // then the string gets truncated to fit the buffer.
  623. //
  624. // If szOutputBuffer == NULL, then dwSizeofOutputBuffer
  625. // is ignored, a buffer 'big enough' is LocalAlloc()d and
  626. // a pointer to it is returned. However, its *very* important
  627. // that this pointer be LocalFree()d by the calling application.
  628. //
  629. //
  630. LPSTR FormatLastError(DWORD dwLastError,
  631. LPSTR szOutputBuffer, DWORD dwSizeofOutputBuffer)
  632. {
  633. DWORD dwRetFM;
  634. DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;
  635. // Should we allocate a buffer?
  636. if (szOutputBuffer == NULL)
  637. {
  638. // Actually, we make FormatMessage allocate the buffer, if needed.
  639. dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
  640. // minimum size FormatMessage should allocate.
  641. dwSizeofOutputBuffer = 1;
  642. }
  643. // Make FormatMessage pretty print the system error.
  644. dwRetFM = FormatMessage(
  645. dwFlags, NULL, dwLastError,
  646. MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  647. (LPTSTR) &szOutputBuffer, dwSizeofOutputBuffer,
  648. NULL);
  649. // FormatMessage failed to print the error.
  650. if (dwRetFM == 0)
  651. {
  652. DWORD dwGetLastError;
  653. LPSTR szFormatMessageError;
  654. dwGetLastError = GetLastError();
  655. // If we asked FormatMessage to allocate a buffer, then it
  656. // might have allocated one. Lets be safe and LocalFree it.
  657. if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
  658. {
  659. __try
  660. {
  661. LocalFree(szOutputBuffer);
  662. }
  663. __except(EXCEPTION_EXECUTE_HANDLER)
  664. {
  665. // Actually, we do nothing for this fault. If
  666. // there was a fault, it meant the buffer wasn't
  667. // allocated, and the LocalFree was unnecessary.
  668. ;
  669. }
  670. szOutputBuffer = (char *) LocalAlloc(LPTR, MAXOUTPUTSTRINGLENGTH);
  671. dwSizeofOutputBuffer = MAXOUTPUTSTRINGLENGTH;
  672. if (szOutputBuffer == NULL)
  673. {
  674. OutputDebugString("Out of memory trying to FormatLastError\r\n");
  675. return NULL;
  676. }
  677. }
  678. szFormatMessageError =
  679. FormatLastError(dwGetLastError, NULL, 0);
  680. if (szFormatMessageError == NULL)
  681. return NULL;
  682. wsprintf(szOutputBuffer,
  683. "FormatMessage failed on error 0x%lx for the following reason: %s",
  684. dwLastError, szFormatMessageError);
  685. LocalFree(szFormatMessageError);
  686. }
  687. return szOutputBuffer;
  688. }
  689. //
  690. // FUNCTION: OutputDebugLineCallback(...)
  691. //
  692. // PURPOSE: Pretty print a message passed into a lineCallbackFunc.
  693. //
  694. // PARAMETERS:
  695. // Standard lineCallbackFunc parameters.
  696. //
  697. // RETURN VALUE:
  698. // none.
  699. //
  700. // COMMENTS:
  701. //
  702. // This function takes all of the parameters passed into a
  703. // lineCallbackFunc callback function, and pretty prints the
  704. // meaning of the message. It then prints the result to
  705. // the debugging output.
  706. //
  707. //
  708. void OutputDebugLineCallback(
  709. DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance,
  710. DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
  711. {
  712. char szOutputBuff[MAXOUTPUTSTRINGLENGTH];
  713. FormatLineCallback(szOutputBuff,
  714. dwDevice, dwMsg, dwCallbackInstance,
  715. dwParam1, dwParam2, dwParam3);
  716. strcat(szOutputBuff,"\r\n");
  717. OutputDebugString(szOutputBuff);
  718. }
  719. //
  720. // FUNCTION: FormatLineCallback(...)
  721. //
  722. // PURPOSE: Pretty prints into a buffer a lineCallbackFunc message.
  723. //
  724. // PARAMETERS:
  725. // Standard lineCallbackFunc parameters.
  726. //
  727. // RETURN VALUE:
  728. // The pointer to the buffer that has the resulting string.
  729. //
  730. // COMMENTS:
  731. //
  732. // This function takes all of the parameters passed into a
  733. // lineCallbackFunc callback function, and pretty prints the
  734. // meaning of the message. It then returns the pointer to
  735. // the buffer containing this string.
  736. //
  737. // If szOutputBuffer == NULL, then a buffer is LocalAlloc()d
  738. // and returned. However, it is *very* important that this buffer
  739. // is LocalFree()d.
  740. //
  741. LPSTR FormatLineCallback(LPSTR szOutputBuffer,
  742. DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance,
  743. DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
  744. {
  745. long lBufferIndex = 0;
  746. // Allocate the buffer if necessary.
  747. if (szOutputBuffer == NULL)
  748. {
  749. szOutputBuffer = (LPSTR) LocalAlloc(LPTR, MAXOUTPUTSTRINGLENGTH);
  750. if (szOutputBuffer == NULL)
  751. return NULL;
  752. }
  753. // Is this a known message?
  754. if (dwMsg >= sizeofArray(psz_dwMsg))
  755. {
  756. wsprintf(szOutputBuffer, "Tapi Msg: Unknown dwMsg: '0x%lx', "
  757. "dwDevice: '0x%lx', dwInst: '0x%lx', "
  758. "dwP1: '0x%lx', dwP2: '0x%lx', dwP3: '0x%lx'", dwMsg,
  759. dwDevice, dwCallbackInstance, dwParam1, dwParam2, dwParam3);
  760. return szOutputBuffer;
  761. }
  762. // Lets start pretty printing.
  763. lBufferIndex +=
  764. wsprintf(szOutputBuffer, "Tapi Msg(%s) On(0x%lx)\r\n\t ",
  765. psz_dwMsg[dwMsg], dwDevice);
  766. // Which message was it? And start decoding it!
  767. // How the message is decoded depends entirely on the message.
  768. // READ THE HELP FILES if you more information on this.
  769. switch(dwMsg)
  770. {
  771. case LINE_ADDRESSSTATE:
  772. {
  773. lBufferIndex +=
  774. wsprintf(&(szOutputBuffer[lBufferIndex]),
  775. "Address ID: 0x%lx, Address State: ", dwParam1);
  776. lBufferIndex +=
  777. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  778. dwParam2,
  779. pszfLINEADDRESSSTATE, sizeofArray(pszfLINEADDRESSSTATE));
  780. break;
  781. }
  782. case LINE_CALLINFO:
  783. {
  784. lBufferIndex +=
  785. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  786. dwParam1,
  787. pszfLINECALLINFOSTATE, sizeofArray(pszfLINECALLINFOSTATE));
  788. break;
  789. }
  790. case LINE_CALLSTATE:
  791. {
  792. lBufferIndex +=
  793. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  794. dwParam3,
  795. pszfLINECALLPRIVILEGE, sizeofArray(pszfLINECALLPRIVILEGE));
  796. lBufferIndex +=
  797. wsprintf(&(szOutputBuffer[lBufferIndex]),
  798. "; ");
  799. lBufferIndex +=
  800. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  801. dwParam1,
  802. pszfLINECALLSTATE, sizeofArray(pszfLINECALLSTATE));
  803. switch(dwParam1)
  804. {
  805. case LINECALLSTATE_DIALTONE:
  806. {
  807. lBufferIndex +=
  808. wsprintf(&(szOutputBuffer[lBufferIndex]),
  809. ": ");
  810. lBufferIndex +=
  811. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  812. dwParam2,
  813. pszfLINEDIALTONEMODE, sizeofArray(pszfLINEDIALTONEMODE));
  814. break;
  815. }
  816. case LINECALLSTATE_BUSY:
  817. {
  818. lBufferIndex +=
  819. wsprintf(&(szOutputBuffer[lBufferIndex]),
  820. ": ");
  821. lBufferIndex +=
  822. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  823. dwParam2,
  824. pszfLINEBUSYMODE, sizeofArray(pszfLINEBUSYMODE));
  825. break;
  826. }
  827. case LINECALLSTATE_SPECIALINFO:
  828. {
  829. lBufferIndex +=
  830. wsprintf(&(szOutputBuffer[lBufferIndex]),
  831. ": ");
  832. lBufferIndex +=
  833. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  834. dwParam2,
  835. pszfLINESPECIALINFO, sizeofArray(pszfLINESPECIALINFO));
  836. break;
  837. }
  838. case LINECALLSTATE_DISCONNECTED:
  839. {
  840. lBufferIndex +=
  841. wsprintf(&(szOutputBuffer[lBufferIndex]),
  842. ": ");
  843. lBufferIndex +=
  844. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  845. dwParam2,
  846. pszfLINEDISCONNECTED, sizeofArray(pszfLINEDISCONNECTED));
  847. break;
  848. }
  849. case LINECALLSTATE_CONFERENCED:
  850. {
  851. lBufferIndex +=
  852. wsprintf(&(szOutputBuffer[lBufferIndex]),
  853. ": Parent conference call handle: 0x%lx", dwParam2);
  854. break;
  855. }
  856. }
  857. break;
  858. }
  859. case LINE_CLOSE:
  860. break;
  861. case LINE_DEVSPECIFIC:
  862. break;
  863. case LINE_DEVSPECIFICFEATURE:
  864. break;
  865. case LINE_GATHERDIGITS:
  866. {
  867. lBufferIndex +=
  868. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  869. dwParam1,
  870. pszfLINEGATHERTERM, sizeofArray(pszfLINEGATHERTERM));
  871. break;
  872. }
  873. case LINE_GENERATE:
  874. {
  875. lBufferIndex +=
  876. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  877. dwParam1,
  878. pszfLINEGENERATETERM, sizeofArray(pszfLINEGENERATETERM));
  879. break;
  880. }
  881. case LINE_LINEDEVSTATE:
  882. {
  883. lBufferIndex +=
  884. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  885. dwParam1,
  886. pszfLINEDEVSTATE, sizeofArray(pszfLINEDEVSTATE));
  887. switch(dwParam1)
  888. {
  889. case LINEDEVSTATE_RINGING:
  890. lBufferIndex +=
  891. wsprintf(&(szOutputBuffer[lBufferIndex]),
  892. "; Ring Mode: 0x%lx, Ring Count: %lu"
  893. ,dwParam2, dwParam3);
  894. break;
  895. case LINEDEVSTATE_REINIT:
  896. {
  897. switch(dwParam2)
  898. {
  899. case LINE_CREATE:
  900. lBufferIndex +=
  901. wsprintf(&(szOutputBuffer[lBufferIndex]),
  902. "; ReInit reason: LINE_CREATE, "
  903. "New Line Device ID '0x%lx'"
  904. , dwParam3);
  905. break;
  906. case LINE_LINEDEVSTATE:
  907. lBufferIndex +=
  908. wsprintf(&(szOutputBuffer[lBufferIndex]),
  909. "; ReInit reason: LINE_LINEDEVSTATE, ");
  910. lBufferIndex +=
  911. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  912. dwParam3,
  913. pszfLINEDEVSTATE, sizeofArray(pszfLINEDEVSTATE));
  914. break;
  915. case 0:
  916. break;
  917. default:
  918. lBufferIndex +=
  919. wsprintf(&(szOutputBuffer[lBufferIndex]),
  920. "; ReInit reason: %s, dwParam3: 0x%lx"
  921. ,psz_dwMsg[dwParam2], dwParam3);
  922. break;
  923. }
  924. break;
  925. }
  926. default:
  927. break;
  928. }
  929. break;
  930. }
  931. case LINE_MONITORDIGITS:
  932. {
  933. lBufferIndex +=
  934. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  935. dwParam2,
  936. pszfLINEDIGITMODE, sizeofArray(pszfLINEDIGITMODE));
  937. lBufferIndex +=
  938. wsprintf(&(szOutputBuffer[lBufferIndex]),
  939. ", Received: '%c'", LOBYTE(LOWORD(dwParam1)));
  940. break;
  941. }
  942. case LINE_MONITORMEDIA:
  943. {
  944. lBufferIndex +=
  945. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  946. dwParam1,
  947. pszfLINEMEDIAMODE, sizeofArray(pszfLINEMEDIAMODE));
  948. break;
  949. }
  950. case LINE_MONITORTONE:
  951. {
  952. lBufferIndex +=
  953. wsprintf(&(szOutputBuffer[lBufferIndex]),
  954. "AppSpecific tone '%lu'", dwParam1);
  955. break;
  956. }
  957. case LINE_REPLY:
  958. {
  959. if (dwParam2 == 0)
  960. {
  961. lBufferIndex +=
  962. wsprintf(&(szOutputBuffer[lBufferIndex]),
  963. "Request ID: 0x%lx; Successful reply!", dwParam1);
  964. }
  965. else
  966. {
  967. char szTmpBuff[256];
  968. FormatLineError((long) dwParam2, szTmpBuff, 255);
  969. lBufferIndex +=
  970. wsprintf(&(szOutputBuffer[lBufferIndex]),
  971. "Request ID: 0x%lx; UnSuccessful reply; %s",
  972. dwParam1, szTmpBuff);
  973. }
  974. break;
  975. }
  976. case LINE_REQUEST:
  977. {
  978. lBufferIndex +=
  979. strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  980. dwParam1,
  981. pszfLINEREQUESTMODE, sizeofArray(pszfLINEREQUESTMODE));
  982. switch(dwParam1)
  983. {
  984. case LINEREQUESTMODE_DROP:
  985. {
  986. char szHwndName[1024];
  987. SendMessage((HWND) dwParam2, WM_GETTEXT, 1024, (long) szHwndName);
  988. lBufferIndex +=
  989. wsprintf(&(szOutputBuffer[lBufferIndex]),
  990. ": hwnd dropping = 0x%lx, \"%s\"; wRequestID = %u",
  991. dwParam2, szHwndName, LOWORD(dwParam3));
  992. break;
  993. }
  994. default:
  995. break;
  996. }
  997. break;
  998. }
  999. case LINE_CREATE:
  1000. {
  1001. lBufferIndex +=
  1002. wsprintf(&(szOutputBuffer[lBufferIndex]),
  1003. "New Line Device ID '0x%lx'", dwParam1);
  1004. break;
  1005. }
  1006. case PHONE_CREATE:
  1007. {
  1008. lBufferIndex +=
  1009. wsprintf(&(szOutputBuffer[lBufferIndex]),
  1010. "New Phone Device ID '0x%lx'", dwParam1);
  1011. break;
  1012. }
  1013. default:
  1014. lBufferIndex +=
  1015. wsprintf(&(szOutputBuffer[lBufferIndex]),
  1016. "dwParam1: 0x%lx , dwParam2: 0x%lx , dwParam3: 0x%lx",
  1017. dwParam1, dwParam2, dwParam3);
  1018. break;
  1019. } // End switch(dwMsg)
  1020. // return that pointer!
  1021. return szOutputBuffer;
  1022. }
  1023. //
  1024. // FUNCTION: strBinaryArrayAppend(LPSTR, DWORD, LPSTR *, DWORD)
  1025. //
  1026. // PURPOSE: Takes a bitmapped DWORD, an array representing that
  1027. // binary mapping, and pretty prints it to a buffer.
  1028. //
  1029. // PARAMETERS:
  1030. // szOutputBuffer - Buffer to print to.
  1031. // dwFlags - Binary mapped flags to interpret.
  1032. // szStringArray - Array of strings.
  1033. // dwSizeofStringArray - number of elements in szStringArray.
  1034. //
  1035. // RETURN VALUE:
  1036. // The number of characters printed into szOutputBuffer.
  1037. //
  1038. // COMMENTS:
  1039. //
  1040. // This function takes dwFlags and checks each bit. If the
  1041. // bit is set, the appropriate string (taken from szStringArray)
  1042. // is printed to the szOutputBuffer string buffer. If there were
  1043. // more bits set in the string than elements in the array, and error
  1044. // is also tagged on the end.
  1045. //
  1046. // This function is intended to be used only within the TapiInfo module.
  1047. //
  1048. static long strBinaryArrayAppend(LPSTR szOutputBuffer, DWORD dwFlags,
  1049. LPSTR szStringArray[], DWORD dwSizeofStringArray)
  1050. {
  1051. DWORD dwIndex = 1, dwPower = 1;
  1052. long lBufferIndex = 0;
  1053. BOOL bFirst = TRUE;
  1054. // The zeroth element in every bitmapped array is the "unknown" or
  1055. // "unchanged" message.
  1056. if (dwFlags == 0)
  1057. {
  1058. lBufferIndex =
  1059. wsprintf(szOutputBuffer, "%s", szStringArray[0]);
  1060. return lBufferIndex;
  1061. }
  1062. // iterate through the flags and check each one.
  1063. while(dwIndex < dwSizeofStringArray)
  1064. {
  1065. // If we find one, print it.
  1066. if (dwFlags & dwPower)
  1067. // Seporate each printing with a ", " except the first one.
  1068. if (bFirst)
  1069. {
  1070. lBufferIndex +=
  1071. wsprintf(&(szOutputBuffer[lBufferIndex]),
  1072. "%s", szStringArray[dwIndex]);
  1073. bFirst = FALSE;
  1074. }
  1075. else
  1076. lBufferIndex +=
  1077. wsprintf(&(szOutputBuffer[lBufferIndex]),
  1078. ", %s", szStringArray[dwIndex]);
  1079. dwIndex ++;
  1080. dwFlags &= ~dwPower; // clear it so we know we checked it.
  1081. dwPower *= 2;
  1082. }
  1083. // If there are any flags left, they were not in the array.
  1084. if (dwFlags)
  1085. {
  1086. if (bFirst)
  1087. lBufferIndex +=
  1088. wsprintf(&(szOutputBuffer[lBufferIndex]),
  1089. "Unknown flags '0x%lx'", dwFlags);
  1090. else
  1091. lBufferIndex +=
  1092. wsprintf(&(szOutputBuffer[lBufferIndex]),
  1093. ", Unknown flags '0x%lx'", dwFlags);
  1094. }
  1095. // how many did we print into the buffer?
  1096. return lBufferIndex;
  1097. }
  1098. //
  1099. // FUNCTION: OutputDebugPrintf(LPCSTR, ...)
  1100. //
  1101. // PURPOSE: wsprintf to the debugging output.
  1102. //
  1103. // PARAMETERS:
  1104. // Exactly the same as wsprintf.
  1105. //
  1106. // RETURN VALUE:
  1107. // none.
  1108. //
  1109. // COMMENTS:
  1110. //
  1111. // This function takes exactly the same parameters as wsprintf and
  1112. // prints the results to the debugging output.
  1113. //
  1114. void __cdecl OutputDebugPrintf(LPCSTR lpszFormat, ...)
  1115. {
  1116. char szOutput[MAXOUTPUTSTRINGLENGTH];
  1117. va_list v1;
  1118. DWORD dwSize;
  1119. va_start(v1, lpszFormat);
  1120. dwSize = wvsprintf(szOutput, lpszFormat, v1);
  1121. if (szOutput[dwSize-1] != '\n')
  1122. strcat(szOutput, "\r\n");
  1123. OutputDebugString(szOutput);
  1124. }
  1125.