TapiInfo.C
上传用户:woweijixie
上传日期:2018-12-11
资源大小:131k
文件大小:38k
源码类别:

TAPI编程

开发平台:

Visual C++

  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.     "No change to LINECALLPRIVILEGE",
  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.     
  325. LPSTR pszfLINEMEDIAMODE[] =
  326. {
  327.     "Unknown LINEMEDIAMODE mode",
  328.     "UnUsed LINEMEDIAMODE mode, ERROR!!",
  329.     "LINEMEDIAMODE_UNKNOWN",
  330.     "LINEMEDIAMODE_INTERACTIVEVOICE",
  331.     "LINEMEDIAMODE_AUTOMATEDVOICE",
  332.     "LINEMEDIAMODE_DATAMODEM",
  333.     "LINEMEDIAMODE_G3FAX",
  334.     "LINEMEDIAMODE_TDD",
  335.     "LINEMEDIAMODE_G4FAX",
  336.     "LINEMEDIAMODE_DIGITALDATA",
  337.     "LINEMEDIAMODE_TELETEX",
  338.     "LINEMEDIAMODE_VIDEOTEX",
  339.     "LINEMEDIAMODE_TELEX",
  340.     "LINEMEDIAMODE_MIXED",
  341.     "LINEMEDIAMODE_ADSI",
  342.     "LINEMEDIAMODE_VOICEVIEW"
  343. };
  344. LPSTR pszfLINEREQUESTMODE[] =
  345. {
  346.     "Unknown LINEREQUESTMODE message",
  347.     "LINEREQUESTMODE_MAKECALL",
  348.     "LINEREQUESTMODE_MEDIACALL",
  349.     "LINEREQUESTMODE_DROP"
  350. };
  351. //
  352. //  MACRO: OutputDebugLineError(long, LPSTR)
  353. //
  354. //  PURPOSE: Pretty print a line error to the debugging output.
  355. //
  356. //  PARAMETERS:
  357. //    lLineError - Actual error code to decipher.
  358. //    pszPrefix  - String to prepend to the printed message.
  359. //
  360. //  RETURN VALUE:
  361. //    none
  362. //
  363. //  COMMENTS:
  364. //    This macro is actually defined in the .h file.
  365. //    It will take a LINEERR error, turn it into a human
  366. //    readable string, prepend pszPrefix (so you
  367. //    can tag your errors), append __FILE__ and __LINE__
  368. //    and print it to the debugging output.
  369. //    This macro is just a wrapper around OutputDebugLineErrorFileLine
  370. //    that is necessary to get proper values for __FILE__ and __LINE__.
  371. //
  372. //
  373. /*
  374. #define OuputDebugLineError(lLineError, pszPrefix) 
  375.     OutputDebugLineErrorFileLine(lLineError, pszPrefix,
  376.         __FILE__, __LINE__)
  377. */
  378. //
  379. //  FUNCTION: OutputDebugLineErrorFileLine(..)
  380. //
  381. //  PURPOSE: Pretty print a line error to the debugging output.
  382. //
  383. //  PARAMETERS:
  384. //    lLineError  - Actual error code to decipher.
  385. //    pszPrefix   - String to prepend to the printed message.
  386. //    szFileName  - Filename the error occured in.
  387. //    nLineNumber - Line number the error occured at.
  388. //
  389. //  RETURN VALUE:
  390. //    none
  391. //
  392. //  COMMENTS:
  393. //    This is the actual function that OutputDebugLineError
  394. //    expands to.  Its not likely to be usefull except
  395. //    through the OutputDebugLineError macro, or to print
  396. //    errors without line and file information.
  397. //
  398. //    If szFileName == NULL, then the File and Line are not printed.
  399. //   
  400. //    Note that there is an internal string length limit of
  401. //    MAXOUTPUTSTRINGLENGTH.  If this length is exceeded,
  402. //    the behavior will be the same as wsprintf, although
  403. //    it will be undetectable.  *KEEP szPrefix SHORT!*
  404. //
  405. //
  406. void OutputDebugLineErrorFileLine(
  407.     long lLineError, LPSTR szPrefix, 
  408.     LPSTR szFileName, DWORD nLineNumber)
  409. {
  410.     LPSTR szLineError;
  411.     char szOutputLineError[MAXOUTPUTSTRINGLENGTH];
  412.     if (szPrefix == NULL)
  413.         szPrefix = "";
  414.     // Pretty print the error message.
  415.     szLineError = FormatLineError(lLineError, NULL, 0);
  416.     // The only reason FormatLineError should fail is "Out of memory".
  417.     if (szLineError == NULL)
  418.     {
  419.         if (szFileName == NULL)
  420.             wsprintf(szOutputLineError, "%sOut of memory", szPrefix);
  421.         else
  422.             wsprintf(szOutputLineError, 
  423.                 "%sOut of memory in file %s, line %drn",
  424.                 szPrefix, szFileName, nLineNumber);
  425.         OutputDebugString(szOutputLineError);
  426.         return;
  427.     }
  428.     // If szFileName, then use it; else don't.
  429.     if (szFileName != NULL)
  430.     {
  431.         wsprintf(szOutputLineError,
  432.             "%sTapi Line Error: "%s" in File "%s", Line %drn",
  433.             szPrefix, szLineError, szFileName, nLineNumber);
  434.     }
  435.     else
  436.     {
  437.         wsprintf(szOutputLineError,
  438.             "%sTapi Line Error: "%s"rn",
  439.             szPrefix, szLineError);
  440.     }
  441.     // Pointer returned from FormatLineError *must* be freed!
  442.     LocalFree(szLineError);
  443.     // Print it!
  444.     OutputDebugString(szOutputLineError);
  445.     return;
  446. }
  447. //
  448. //  FUNCTION: FormatLineError(long, LPSTR, DWORD)
  449. //
  450. //  PURPOSE: Pretty print a line error to a string.
  451. //
  452. //  PARAMETERS:
  453. //    lLineError           - Actual error code to decipher.
  454. //    szOutputBuffer       - String buffer to pretty print to.
  455. //    dwSizeofOutputBuffer - Size of String buffer.
  456. //
  457. //  RETURN VALUE:
  458. //    Returns the buffer printed to.
  459. //
  460. //  COMMENTS:
  461. //    If szOutputBuffer isn't big enough to hold the whole string,
  462. //    then the string gets truncated to fit the buffer.
  463. //
  464. //    If szOutputBuffer == NULL, then dwSizeofOutputBuffer
  465. //    is ignored, a buffer 'big enough' is LocalAlloc()d and
  466. //    a pointer to it is returned.  However, its *very* important
  467. //    that this pointer be LocalFree()d by the calling application.
  468. //
  469. //
  470. LPSTR FormatLineError(long lLineError,
  471.     LPSTR szOutputBuffer, DWORD dwSizeofOutputBuffer)
  472. {
  473.     char szUnknownLineError[256];
  474.     LPSTR szLineError;
  475.     int nSizeofLineError;
  476.     long lErrorIndex;
  477.     DWORD * pdwLineError;
  478.     // Strip off the high bit to make the error code positive.
  479.     pdwLineError = &lLineError;
  480.     lErrorIndex = (long) (0x7FFFFFFF & *pdwLineError);
  481.     // Is it an unknown error?
  482.     if ((lErrorIndex >= sizeofArray(pszLineErrorNameArray)) ||
  483.         (lErrorIndex < 0))
  484.     {
  485.         nSizeofLineError = 
  486.             wsprintf(szUnknownLineError, "Unknown TAPI line error code: 0x%lx",
  487.                 lLineError);
  488.         szLineError = szUnknownLineError;
  489.     }
  490.     else
  491.     {
  492.         szLineError = pszLineErrorNameArray[lErrorIndex];
  493.         nSizeofLineError = strlen(szLineError);
  494.     }
  495.     // allocate a buffer if necessary
  496.     if (szOutputBuffer == NULL)
  497.     {
  498.         szOutputBuffer = (LPSTR) LocalAlloc(LPTR, nSizeofLineError + 1);
  499.         if (szOutputBuffer == NULL)
  500.             return NULL;
  501.     }
  502.     else // truncate string if it won't fit in the specified buffer.
  503.     {
  504.         if ((DWORD) nSizeofLineError >= dwSizeofOutputBuffer)
  505.             nSizeofLineError = dwSizeofOutputBuffer - 1;
  506.     }
  507.     // Put the string into the buffer and null terminate.
  508.     memcpy(szOutputBuffer, szLineError, nSizeofLineError);
  509.     szOutputBuffer[nSizeofLineError] = '';
  510.     return szOutputBuffer;
  511. }
  512. //
  513. //  MACRO: OutputDebugLastError(DWORD, LPSTR)
  514. //
  515. //  PURPOSE: Pretty print a system error to the debugging output.
  516. //
  517. //  PARAMETERS:
  518. //    dwLastError - Actual error code to decipher.
  519. //    pszPrefix   - String to prepend to the printed message.
  520. //
  521. //  RETURN VALUE:
  522. //    none
  523. //
  524. //  COMMENTS:
  525. //    This macro is actually defined in the .h file.
  526. //    It will take an error that was retrieved by GetLastError(),
  527. //    turn it into a human readable string, prepend pszPrefix
  528. //    (so you can tag your errors), append __FILE__ and __LINE__
  529. //    and print it to the debugging output.
  530. //
  531. //    This macro is just a wrapper around OutputDebugLastErrorFileLine
  532. //    that is necessary to get proper values for __FILE__ and __LINE__.
  533. //
  534. //
  535. /*
  536. #define OuputDebugLastError(dwLastError, pszPrefix) 
  537.     OutputDebugLastErrorFileLine(dwLastError, pszPrefix,
  538.         __FILE__, __LINE__)
  539. */
  540. //
  541. //  FUNCTION: OutputDebugLastErrorFileLine(..)
  542. //
  543. //  PURPOSE: Pretty print a line error to the debugging output.
  544. //
  545. //  PARAMETERS:
  546. //    dwLastError - Actual error code to decipher.
  547. //    pszPrefix   - String to prepend to the printed message.
  548. //    szFileName  - Filename the error occured in.
  549. //    nLineNumber - Line number the error occured at.
  550. //
  551. //  RETURN VALUE:
  552. //    none
  553. //
  554. //  COMMENTS:
  555. //    This is the actual function that OutputDebugLastError
  556. //    expands to.  Its not likely to be usefull except
  557. //    through the OutputDebugLastError macro or to print
  558. //    errors without line and file information.
  559. //
  560. //    If szFileName == NULL, then the File and Line are not printed.
  561. //   
  562. //    Note that there is an internal string length limit of
  563. //    MAXOUTPUTSTRINGLENGTH.  If this length is exceeded,
  564. //    the behavior will be the same as wsprintf, although
  565. //    it will be undetectable.  *KEEP szPrefix SHORT!*
  566. //
  567. //
  568. void OutputDebugLastErrorFileLine(
  569.     DWORD dwLastError, LPSTR szPrefix, 
  570.     LPSTR szFileName, DWORD nLineNumber)
  571. {
  572.     LPSTR szLastError;
  573.     char szOutputLastError[MAXOUTPUTSTRINGLENGTH];
  574.     if (szPrefix == NULL)
  575.         szPrefix = "";
  576.     // Pretty print the error.
  577.     szLastError = FormatLastError(dwLastError, NULL, 0);
  578.     // The only reason FormatLastError should fail is "Out of memory".
  579.     if (szLastError == NULL)
  580.     {
  581.         if (szFileName == NULL)
  582.             wsprintf(szOutputLastError, "%sOut of memoryrn", szPrefix);
  583.         else
  584.             wsprintf(szOutputLastError, "%sOut of memory in file %s, line %drn",
  585.                 szPrefix, szFileName, nLineNumber);
  586.         OutputDebugString(szOutputLastError);
  587.         return;
  588.     }
  589.     // If szFileName, then use it; else don't.
  590.     if (szFileName != NULL)
  591.     {
  592.         wsprintf(szOutputLastError,
  593.             "%sGetLastError returned: "%s" in File "%s", Line %drn",
  594.             szPrefix, szLastError, szFileName, nLineNumber);
  595.     }
  596.     else
  597.     {
  598.         wsprintf(szOutputLastError,
  599.             "%sGetLastError returned: "%s"rn",
  600.             szPrefix, szLastError);
  601.     }
  602.     // Pointer returned from FormatLineError *must* be freed!
  603.     LocalFree(szLastError);
  604.     // Print it!
  605.     OutputDebugString(szOutputLastError);
  606.     return;
  607. }
  608. //
  609. //  FUNCTION: FormatLastError(DWORD, LPSTR, DWORD)
  610. //
  611. //  PURPOSE: Pretty print a system error to a string.
  612. //
  613. //  PARAMETERS:
  614. //    dwLastError          - Actual error code to decipher.
  615. //    szOutputBuffer       - String buffer to pretty print to.
  616. //    dwSizeofOutputBuffer - Size of String buffer.
  617. //
  618. //  RETURN VALUE:
  619. //    Returns the buffer printed to.
  620. //
  621. //  COMMENTS:
  622. //    If szOutputBuffer isn't big enough to hold the whole string,
  623. //    then the string gets truncated to fit the buffer.
  624. //
  625. //    If szOutputBuffer == NULL, then dwSizeofOutputBuffer
  626. //    is ignored, a buffer 'big enough' is LocalAlloc()d and
  627. //    a pointer to it is returned.  However, its *very* important
  628. //    that this pointer be LocalFree()d by the calling application.
  629. //
  630. //
  631. LPSTR FormatLastError(DWORD dwLastError,
  632.     LPSTR szOutputBuffer, DWORD dwSizeofOutputBuffer)
  633. {
  634.     DWORD dwRetFM;
  635.     DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM;
  636.     // Should we allocate a buffer?
  637.     if (szOutputBuffer == NULL)
  638.     {
  639.         // Actually, we make FormatMessage allocate the buffer, if needed.
  640.         dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
  641.         // minimum size FormatMessage should allocate.
  642.         dwSizeofOutputBuffer = 1;  
  643.     }
  644.     // Make FormatMessage pretty print the system error.
  645.     dwRetFM = FormatMessage(
  646.         dwFlags, NULL, dwLastError,
  647.         MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  648.         (LPTSTR) &szOutputBuffer, dwSizeofOutputBuffer,
  649.         NULL);
  650.     // FormatMessage failed to print the error.
  651.     if (dwRetFM == 0)
  652.     {
  653.         DWORD dwGetLastError;
  654.         LPSTR szFormatMessageError;
  655.         dwGetLastError = GetLastError();
  656.         // If we asked FormatMessage to allocate a buffer, then it
  657.         // might have allocated one.  Lets be safe and LocalFree it.
  658.         if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
  659.         {
  660.             __try
  661.             {
  662.                 LocalFree(szOutputBuffer);
  663.             }
  664.             __except(EXCEPTION_EXECUTE_HANDLER)
  665.             {
  666.                 // Actually, we do nothing for this fault.  If
  667.                 // there was a fault, it meant the buffer wasn't
  668.                 // allocated, and the LocalFree was unnecessary.
  669.                 ;
  670.             }
  671.             szOutputBuffer = LocalAlloc(LPTR, MAXOUTPUTSTRINGLENGTH);
  672.             dwSizeofOutputBuffer = MAXOUTPUTSTRINGLENGTH;
  673.             if (szOutputBuffer == NULL)
  674.             {
  675.                 OutputDebugString("Out of memory trying to FormatLastErrorrn");
  676.                 return NULL;
  677.             }
  678.         }
  679.         szFormatMessageError = 
  680.             FormatLastError(dwGetLastError, NULL, 0);
  681.         if (szFormatMessageError == NULL)
  682.             return NULL;
  683.         wsprintf(szOutputBuffer, 
  684.             "FormatMessage failed on error 0x%lx for the following reason: %s",
  685.             dwLastError, szFormatMessageError);
  686.         LocalFree(szFormatMessageError);
  687.     }
  688.     return szOutputBuffer;
  689. }
  690. //
  691. //  FUNCTION: OutputDebugLineCallback(...)
  692. //
  693. //  PURPOSE: Pretty print a message passed into a lineCallbackFunc.
  694. //
  695. //  PARAMETERS:
  696. //    Standard lineCallbackFunc parameters.
  697. //
  698. //  RETURN VALUE:
  699. //    none.
  700. //
  701. //  COMMENTS:
  702. //
  703. //    This function takes all of the parameters passed into a
  704. //    lineCallbackFunc callback function, and pretty prints the
  705. //    meaning of the message.  It then prints the result to
  706. //    the debugging output.
  707. //
  708. //
  709. void OutputDebugLineCallback(
  710.     DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance, 
  711.     DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
  712. {
  713.     char szOutputBuff[MAXOUTPUTSTRINGLENGTH];
  714.     FormatLineCallback(szOutputBuff, 
  715.         dwDevice, dwMsg, dwCallbackInstance, 
  716.         dwParam1, dwParam2, dwParam3);
  717.     strcat(szOutputBuff,"rn");
  718.     OutputDebugString(szOutputBuff);
  719. }
  720. //
  721. //  FUNCTION: FormatLineCallback(...)
  722. //
  723. //  PURPOSE: Pretty prints into a buffer a lineCallbackFunc message.
  724. //
  725. //  PARAMETERS:
  726. //    Standard lineCallbackFunc parameters.
  727. //
  728. //  RETURN VALUE:
  729. //    The pointer to the buffer that has the resulting string.
  730. //
  731. //  COMMENTS:
  732. //
  733. //    This function takes all of the parameters passed into a
  734. //    lineCallbackFunc callback function, and pretty prints the
  735. //    meaning of the message.  It then returns the pointer to
  736. //    the buffer containing this string.
  737. //
  738. //    If szOutputBuffer == NULL, then a buffer is LocalAlloc()d
  739. //    and returned.  However, it is *very* important that this buffer
  740. //    is LocalFree()d.
  741. //
  742. LPSTR FormatLineCallback(LPSTR szOutputBuffer,
  743.     DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance, 
  744.     DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
  745. {
  746.     long lBufferIndex = 0;
  747.     // Allocate the buffer if necessary.
  748.     if (szOutputBuffer == NULL)
  749.     {
  750.         szOutputBuffer = (LPSTR) LocalAlloc(LPTR, MAXOUTPUTSTRINGLENGTH);
  751.         if (szOutputBuffer == NULL)
  752.             return NULL;
  753.     }
  754.     // Is this a known message?
  755.     if (dwMsg >= sizeofArray(psz_dwMsg))
  756.     {
  757.         wsprintf(szOutputBuffer, "lineCallback: Unknown dwMsg: '0x%lx', "
  758.             "dwDevice: '0x%lx', dwCallbackInstance: '0x%lx', "
  759.             "dwParam1: '0x%lx', dwParam2: '0x%lx', dwParam3: '0x%lx'", dwMsg, 
  760.             dwDevice, dwCallbackInstance, dwParam1, dwParam2, dwParam3);
  761.         return szOutputBuffer;
  762.     }
  763.     // Lets start pretty printing.
  764.     lBufferIndex +=
  765.         wsprintf(szOutputBuffer, "lineCallback: %s; dwDevice: '0x%lx'; ",
  766.             psz_dwMsg[dwMsg], dwDevice);
  767.     // Which message was it?  And start decoding it!
  768.     // How the message is decoded depends entirely on the message.
  769.     // READ THE HELP FILES if you more information on this.
  770.     switch(dwMsg)
  771.     {
  772.         case LINE_ADDRESSSTATE:
  773.         {
  774.             lBufferIndex +=
  775.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  776.                     "Address ID: 0x%lx, Address State: ", dwParam1);
  777.             lBufferIndex +=
  778.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  779.                     dwParam2,
  780.                     pszfLINEADDRESSSTATE, sizeofArray(pszfLINEADDRESSSTATE));
  781.             break;
  782.         }
  783.         case LINE_CALLINFO:
  784.         {
  785.             lBufferIndex +=
  786.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  787.                     dwParam1,
  788.                     pszfLINECALLINFOSTATE, sizeofArray(pszfLINECALLINFOSTATE));
  789.             break;
  790.         }
  791.         case LINE_CALLSTATE:
  792.         {
  793.             lBufferIndex +=
  794.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  795.                     dwParam3,
  796.                     pszfLINECALLPRIVILEGE, sizeofArray(pszfLINECALLPRIVILEGE));
  797.             lBufferIndex +=
  798.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  799.                     "; ");
  800.             lBufferIndex += 
  801.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  802.                     dwParam1,
  803.                     pszfLINECALLSTATE, sizeofArray(pszfLINECALLSTATE));
  804.     
  805.             switch(dwParam1)
  806.             {
  807.                 case LINECALLSTATE_DIALTONE:
  808.                 {
  809.                     lBufferIndex +=
  810.                         wsprintf(&(szOutputBuffer[lBufferIndex]),
  811.                             ": ");
  812.                     lBufferIndex += 
  813.                         strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  814.                         dwParam2,
  815.                         pszfLINEDIALTONEMODE, sizeofArray(pszfLINEDIALTONEMODE));
  816.                     break;
  817.                 }
  818.                 case LINECALLSTATE_BUSY:
  819.                 {
  820.                     lBufferIndex +=
  821.                         wsprintf(&(szOutputBuffer[lBufferIndex]),
  822.                             ": ");
  823.                     lBufferIndex += 
  824.                         strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  825.                         dwParam2,
  826.                         pszfLINEBUSYMODE, sizeofArray(pszfLINEBUSYMODE));
  827.                     break;
  828.                 }
  829.                 case LINECALLSTATE_SPECIALINFO:
  830.                 {
  831.                     lBufferIndex +=
  832.                         wsprintf(&(szOutputBuffer[lBufferIndex]),
  833.                             ": ");
  834.                     lBufferIndex += 
  835.                         strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  836.                         dwParam2,
  837.                         pszfLINESPECIALINFO, sizeofArray(pszfLINESPECIALINFO));
  838.                     break;
  839.                 }
  840.                 case LINECALLSTATE_DISCONNECTED:
  841.                 {
  842.                     lBufferIndex +=
  843.                         wsprintf(&(szOutputBuffer[lBufferIndex]),
  844.                             ": ");
  845.                     lBufferIndex += 
  846.                         strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  847.                         dwParam2,
  848.                         pszfLINEDISCONNECTED, sizeofArray(pszfLINEDISCONNECTED));
  849.                     break;
  850.                 }
  851.                 case LINECALLSTATE_CONFERENCED:
  852.                 {
  853.                     lBufferIndex +=
  854.                         wsprintf(&(szOutputBuffer[lBufferIndex]),
  855.                             ": Parent conference call handle: 0x%lx", dwParam2);
  856.                     break;
  857.                 }
  858.             }
  859.             break;
  860.         }
  861.         case LINE_CLOSE:
  862.             break;
  863.         case LINE_DEVSPECIFIC:
  864.             break;
  865.         case LINE_DEVSPECIFICFEATURE:
  866.             break;
  867.         case LINE_GATHERDIGITS:
  868.         {
  869.             lBufferIndex +=
  870.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  871.                     dwParam1,
  872.                     pszfLINEGATHERTERM, sizeofArray(pszfLINEGATHERTERM));
  873.             break;
  874.         }
  875.         case LINE_GENERATE:
  876.         {
  877.             lBufferIndex +=
  878.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  879.                     dwParam1,
  880.                     pszfLINEGENERATETERM, sizeofArray(pszfLINEGENERATETERM));
  881.             break;
  882.         }
  883.         case LINE_LINEDEVSTATE:
  884.         {
  885.             lBufferIndex +=
  886.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  887.                     dwParam1,
  888.                     pszfLINEDEVSTATE, sizeofArray(pszfLINEDEVSTATE));
  889.             switch(dwParam1)
  890.             {
  891.                 case LINEDEVSTATE_RINGING:
  892.                     lBufferIndex +=
  893.                         wsprintf(&(szOutputBuffer[lBufferIndex]),
  894.                             "; Ring Mode: 0x%lx, Ring Count: %lu"
  895.                             ,dwParam2, dwParam3);
  896.                     break;
  897.                 case LINEDEVSTATE_REINIT:
  898.                 {
  899.                     switch(dwParam2)
  900.                     {
  901.                         case LINE_CREATE:
  902.                             lBufferIndex +=
  903.                                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  904.                                     "; ReInit reason: LINE_CREATE, "
  905.                                         "New Line Device ID '0x%lx'"
  906.                                     , dwParam3);
  907.                             break;
  908.                             
  909.                         case LINE_LINEDEVSTATE:
  910.                             lBufferIndex +=
  911.                                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  912.                                     "; ReInit reason: LINE_LINEDEVSTATE, ");
  913.                             lBufferIndex +=
  914.                                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  915.                                     dwParam3,
  916.                                     pszfLINEDEVSTATE, sizeofArray(pszfLINEDEVSTATE));
  917.                             break;
  918.                         
  919.                         case 0:
  920.                             break;
  921.                         default:
  922.                             lBufferIndex +=
  923.                                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  924.                                     "; ReInit reason: %s, dwParam3: 0x%lx"
  925.                                     ,psz_dwMsg[dwParam2], dwParam3);
  926.                             break;
  927.                     }
  928.                     break;
  929.                 }
  930.                 default:
  931.                     break;
  932.             }
  933.             break;
  934.         }
  935.         case LINE_MONITORDIGITS:
  936.         {
  937.             lBufferIndex += 
  938.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  939.                 dwParam2,
  940.                 pszfLINEDIGITMODE, sizeofArray(pszfLINEDIGITMODE));
  941.             lBufferIndex +=
  942.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  943.                     ", Received: '%c'", LOBYTE(LOWORD(dwParam1)));
  944.             
  945.             break;
  946.         }
  947.         case LINE_MONITORMEDIA:
  948.         {
  949.             lBufferIndex +=
  950.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  951.                     dwParam1,
  952.                     pszfLINEMEDIAMODE, sizeofArray(pszfLINEMEDIAMODE));
  953.             break;
  954.         }
  955.         case LINE_MONITORTONE:
  956.         {
  957.             lBufferIndex +=
  958.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  959.                     "AppSpecific tone '%lu'", dwParam1);
  960.             break;
  961.         }
  962.         case LINE_REPLY:
  963.         {
  964.             if (dwParam2 == 0)
  965.             {
  966.                 lBufferIndex +=
  967.                     wsprintf(&(szOutputBuffer[lBufferIndex]),
  968.                         "Request ID: 0x%lx; Successful reply!", dwParam1);
  969.             }
  970.             else
  971.             {
  972.                 char szTmpBuff[256];
  973.                 FormatLineError((long) dwParam2, szTmpBuff, 255);
  974.                 lBufferIndex +=
  975.                     wsprintf(&(szOutputBuffer[lBufferIndex]),
  976.                         "Request ID: 0x%lx; UnSuccessful reply; %s",
  977.                         dwParam1, szTmpBuff);
  978.             }
  979.             break;
  980.         }
  981.         case LINE_REQUEST:
  982.         {
  983.             lBufferIndex += 
  984.                 strBinaryArrayAppend(&(szOutputBuffer[lBufferIndex]),
  985.                 dwParam1,
  986.                 pszfLINEREQUESTMODE, sizeofArray(pszfLINEREQUESTMODE));
  987.             switch(dwParam1)
  988.             {
  989.                 case LINEREQUESTMODE_DROP:
  990.                 {
  991.                     char szHwndName[1024];
  992.                     SendMessage((HWND) dwParam2, WM_GETTEXT, 1024, (long) szHwndName);
  993.                     lBufferIndex +=
  994.                         wsprintf(&(szOutputBuffer[lBufferIndex]),
  995.                             ": hwnd dropping = 0x%lx, "%s"; wRequestID = %u",
  996.                             dwParam2, szHwndName, LOWORD(dwParam3));
  997.                     break;
  998.                 }
  999.                 default:
  1000.                     break;
  1001.             }
  1002.             break;
  1003.         }
  1004.         case LINE_CREATE:
  1005.         {
  1006.             lBufferIndex +=
  1007.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  1008.                     "New Line Device ID '0x%lx'", dwParam1);
  1009.             break;
  1010.         }
  1011.         case PHONE_CREATE:
  1012.         {
  1013.             lBufferIndex +=
  1014.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  1015.                     "New Phone Device ID '0x%lx'", dwParam1);
  1016.             break;
  1017.         }
  1018.         default:
  1019.             lBufferIndex +=
  1020.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  1021.                     "dwParam1: 0x%lx , dwParam2: 0x%lx , dwParam3: 0x%lx",
  1022.                     dwParam1, dwParam2, dwParam3);
  1023.             break;
  1024.     } // End switch(dwMsg)
  1025.     // return that pointer!
  1026.     return szOutputBuffer;
  1027. }
  1028. //
  1029. //  FUNCTION: strBinaryArrayAppend(LPSTR, DWORD, LPSTR *, DWORD)
  1030. //
  1031. //  PURPOSE: Takes a bitmapped DWORD, an array representing that
  1032. //    binary mapping, and pretty prints it to a buffer.
  1033. //
  1034. //  PARAMETERS:
  1035. //    szOutputBuffer      - Buffer to print to.
  1036. //    dwFlags             - Binary mapped flags to interpret.
  1037. //    szStringArray       - Array of strings.
  1038. //    dwSizeofStringArray - number of elements in szStringArray.
  1039. //
  1040. //  RETURN VALUE:
  1041. //    The number of characters printed into szOutputBuffer.
  1042. //
  1043. //  COMMENTS:
  1044. //
  1045. //    This function takes dwFlags and checks each bit.  If the
  1046. //    bit is set, the appropriate string (taken from szStringArray)
  1047. //    is printed to the szOutputBuffer string buffer.  If there were
  1048. //    more bits set in the string than elements in the array, and error
  1049. //    is also tagged on the end.
  1050. //
  1051. //    This function is intended to be used only within the TapiInfo module.
  1052. //
  1053. static long strBinaryArrayAppend(LPSTR szOutputBuffer, DWORD dwFlags,
  1054.      LPSTR szStringArray[], DWORD dwSizeofStringArray)
  1055. {
  1056.     DWORD dwIndex = 1, dwPower = 1;
  1057.     long lBufferIndex = 0;
  1058.     BOOL bFirst = TRUE;
  1059.     // The zeroth element in every bitmapped array is the "unknown" or
  1060.     // "unchanged" message.
  1061.     if (dwFlags == 0)
  1062.     {
  1063.         lBufferIndex =
  1064.             wsprintf(szOutputBuffer, "%s", szStringArray[0]);
  1065.         return lBufferIndex;
  1066.     }
  1067.     // iterate through the flags and check each one.
  1068.     while(dwIndex < dwSizeofStringArray)
  1069.     {
  1070.         // If we find one, print it.
  1071.         if (dwFlags & dwPower)
  1072.             // Seporate each printing with a ", " except the first one.
  1073.             if (bFirst)
  1074.             {
  1075.                 lBufferIndex +=
  1076.                     wsprintf(&(szOutputBuffer[lBufferIndex]),
  1077.                         "%s", szStringArray[dwIndex]);
  1078.                 bFirst = FALSE;
  1079.             }
  1080.             else
  1081.                 lBufferIndex +=
  1082.                     wsprintf(&(szOutputBuffer[lBufferIndex]),
  1083.                         ", %s", szStringArray[dwIndex]);
  1084.         dwIndex ++;
  1085.         dwFlags &= ~dwPower;  // clear it so we know we checked it.
  1086.         dwPower *= 2;
  1087.     }
  1088.     // If there are any flags left, they were not in the array.
  1089.     if (dwFlags)
  1090.     {
  1091.         if (bFirst)
  1092.             lBufferIndex +=
  1093.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  1094.                     "Unknown flags '0x%lx'", dwFlags);
  1095.         else
  1096.             lBufferIndex +=
  1097.                 wsprintf(&(szOutputBuffer[lBufferIndex]),
  1098.                     ", Unknown flags '0x%lx'", dwFlags);
  1099.     }
  1100.     // how many did we print into the buffer?
  1101.     return lBufferIndex;
  1102. }
  1103. //
  1104. //  FUNCTION: OutputDebugPrintf(LPCSTR, ...)
  1105. //
  1106. //  PURPOSE: wsprintf to the debugging output.
  1107. //
  1108. //  PARAMETERS:
  1109. //    Exactly the same as wsprintf.
  1110. //
  1111. //  RETURN VALUE:
  1112. //    none.
  1113. //
  1114. //  COMMENTS:
  1115. //
  1116. //    This function takes exactly the same parameters as wsprintf and
  1117. //    prints the results to the debugging output.
  1118. //
  1119. void __cdecl OutputDebugPrintf(LPCSTR lpszFormat, ...)
  1120. {
  1121.     char szOutput[MAXOUTPUTSTRINGLENGTH];
  1122.     va_list v1;
  1123.     DWORD dwSize;
  1124.     va_start(v1, lpszFormat);
  1125.     dwSize = wvsprintf(szOutput, lpszFormat, v1);
  1126.     if (szOutput[dwSize-1] != 'n')
  1127.         strcat(szOutput, "rn");
  1128.     OutputDebugString(szOutput);
  1129. }