powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Проиграть Wav в модем
12 сообщений из 12, страница 1 из 1
Проиграть Wav в модем
    #34263771
Igor Gryb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Привет всем.,
может кто-то знает как ето сделать.
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34263781
Akh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как ты себе представляешь результат? :) Чтобы модем песню исполнял включенной пищалкой?
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34263794
Igor Gryb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нет мне нужно, чтобы он додзвонился на телефон
и когда подняли трубку на другом конце, он тогда проиграл песню.
:-)
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34263832
Akh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Igor GrybНет мне нужно, чтобы он додзвонился на телефон
и когда подняли трубку на другом конце, он тогда проиграл песню.
:-)

Ааа... Тогда точно не знаю. Но можно попробовать загнать файл в модем (Alaw 8000, mono). И посмотреть что получится.
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34263876
Akh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И проблема - модем с трубкой коннектится?
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34263896
Igor Gryb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я не дзвонил, но думаю модем додзвонится на
обичний телефон без проблем... я только собираю информацию.
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34263947
Akh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Igor Grybя не дзвонил, но думаю модем додзвонится на
обичний телефон без проблем... я только собираю информацию.

Точно не помню. Лет 7, наверное, прошло. Но, возможно, зависит от модема.
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34263986
miksoft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати, подобная тема уже была
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34264041
Akh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
miksoftКстати, подобная тема уже была

Повеселило. Особенно, когда четаешь по диагонали.

Зато полезное - действительно, должен быть fax-modem.
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34264185
miksoft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AkhЗато полезное - действительно, должен быть fax-modem.Строго говоря, не fax-modem, а voice-modem. А уж есть ли там fax, имхо, не важно...
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34264197
Akh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
miksoft AkhЗато полезное - действительно, должен быть fax-modem.Строго говоря, не fax-modem, а voice-modem. А уж есть ли там fax, имхо, не важно...

Тьфу, блин. Это я и хотел сказать. :)
...
Рейтинг: 0 / 0
Проиграть Wav в модем
    #34275509
--null--
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Все уже мудрые люди из Microsoft когда-то написали.
Как раз именно это и делает.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
627.
628.
629.
630.
631.
632.
633.
634.
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647.
648.
649.
650.
651.
652.
653.
654.
655.
656.
657.
658.
659.
660.
661.
662.
663.
664.
665.
666.
667.
668.
669.
670.
671.
672.
673.
674.
675.
676.
677.
678.
679.
680.
681.
682.
683.
684.
685.
686.
687.
688.
689.
690.
691.
692.
693.
694.
695.
696.
697.
698.
699.
700.
701.
702.
703.
704.
705.
706.
707.
708.
709.
710.
711.
712.
713.
714.
715.
716.
717.
718.
719.
720.
721.
722.
723.
724.
725.
726.
727.
728.
729.
730.
731.
732.
733.
734.
735.
736.
737.
738.
739.
740.
741.
742.
743.
744.
745.
746.
747.
748.
749.
750.
751.
752.
753.
754.
755.
756.
757.
758.
759.
760.
761.
762.
763.
764.
765.
766.
767.
768.
769.
770.
771.
772.
773.
774.
775.
776.
777.
778.
779.
780.
781.
782.
783.
784.
785.
786.
787.
788.
789.
790.
791.
792.
793.
794.
795.
796.
797.
798.
799.
800.
801.
802.
803.
804.
805.
806.
807.
808.
809.
810.
811.
812.
813.
814.
815.
816.
817.
818.
819.
820.
821.
822.
823.
824.
825.
826.
827.
828.
829.
830.
831.
832.
833.
834.
835.
836.
837.
838.
839.
840.
841.
842.
843.
844.
845.
846.
847.
848.
849.
850.
851.
852.
853.
854.
855.
856.
857.
858.
859.
860.
861.
862.
863.
864.
865.
866.
867.
868.
869.
870.
871.
872.
873.
874.
875.
876.
877.
878.
879.
880.
881.
882.
883.
884.
885.
886.
887.
888.
889.
890.
891.
892.
893.
894.
895.
896.
897.
898.
899.
900.
901.
902.
903.
904.
905.
906.
907.
908.
909.
910.
911.
912.
913.
914.
915.
916.
917.
918.
919.
920.
921.
922.
923.
924.
925.
926.
927.
928.
929.
930.
931.
932.
933.
934.
935.
936.
937.
938.
939.
940.
941.
942.
943.
944.
945.
946.
947.
948.
949.
950.
951.
952.
953.
954.
955.
956.
957.
958.
959.
960.
961.
962.
963.
964.
965.
966.
967.
968.
969.
970.
971.
972.
973.
974.
975.
976.
977.
978.
979.
980.
981.
982.
983.
984.
985.
986.
987.
988.
989.
990.
991.
992.
993.
994.
995.
996.
997.
998.
999.
1000.
1001.
1002.
1003.
1004.
1005.
1006.
1007.
1008.
1009.
1010.
1011.
1012.
1013.
1014.
1015.
1016.
1017.
1018.
1019.
1020.
1021.
1022.
1023.
1024.
1025.
1026.
1027.
1028.
1029.
1030.
1031.
1032.
1033.
1034.
1035.
1036.
1037.
1038.
1039.
1040.
1041.
1042.
1043.
1044.
1045.
1046.
1047.
1048.
1049.
1050.
1051.
1052.
1053.
1054.
1055.
1056.
1057.
1058.
1059.
1060.
1061.
1062.
1063.
1064.
1065.
1066.
1067.
1068.
1069.
1070.
1071.
1072.
1073.
1074.
1075.
1076.
1077.
1078.
1079.
1080.
1081.
1082.
1083.
1084.
1085.
1086.
1087.
1088.
1089.
1090.
1091.
1092.
1093.
1094.
1095.
1096.
1097.
1098.
1099.
1100.
1101.
1102.
1103.
1104.
1105.
1106.
1107.
1108.
1109.
1110.
1111.
1112.
1113.
1114.
1115.
1116.
1117.
1118.
1119.
1120.
1121.
1122.
1123.
1124.
1125.
1126.
1127.
1128.
1129.
1130.
1131.
1132.
1133.
1134.
1135.
1136.
1137.
1138.
1139.
1140.
1141.
1142.
1143.
1144.
1145.
1146.
1147.
1148.
1149.
1150.
1151.
1152.
1153.
1154.
1155.
1156.
1157.
1158.
1159.
1160.
1161.
1162.
1163.
1164.
1165.
1166.
1167.
1168.
1169.
1170.
1171.
1172.
1173.
1174.
1175.
1176.
1177.
1178.
1179.
1180.
1181.
1182.
1183.
1184.
1185.
1186.
1187.
1188.
1189.
1190.
1191.
1192.
1193.
1194.
1195.
1196.
1197.
1198.
1199.
1200.
1201.
1202.
1203.
1204.
1205.
1206.
1207.
1208.
1209.
1210.
1211.
1212.
1213.
1214.
1215.
1216.
1217.
1218.
1219.
1220.
1221.
1222.
1223.
1224.
1225.
1226.
1227.
1228.
1229.
1230.
1231.
1232.
1233.
1234.
1235.
1236.
1237.
1238.
1239.
1240.
1241.
1242.
1243.
1244.
1245.
1246.
1247.
1248.
1249.
1250.
1251.
1252.
1253.
1254.
1255.
1256.
1257.
1258.
1259.
1260.
1261.
1262.
1263.
1264.
1265.
1266.
1267.
1268.
1269.
1270.
1271.
1272.
1273.
1274.
1275.
1276.
/*----------------------------------------------------------*\
TapiWave

This sample console application is designed to demonstrate
how to use TAPI to play and record wave files using a voice modem.

\*----------------------------------------------------------*/

//#define UNICODE
//#define _UNICODE

#pragma comment(linker, "/subsystem:console")
#pragma comment(lib, "tapi32")

#include <windows.h>
#include <mmsystem.h>
#include <tchar.h>
#include <stdio.h>

#ifdef UNICODE
#define TAPI_CURRENT_VERSION 0x00020000
#else
#define TAPI_CURRENT_VERSION 0x00010004
#endif
#include <tapi.h>


TCHAR szAppName[] = TEXT("TapiWave");
TCHAR szAppFileName[] = TEXT("TapiWave.exe");


// TAPI constants; command line settable
DWORD dwDeviceID =  0 ;
DWORD dwAddressID =  0 ;

// TAPI global variables.
HINSTANCE hInstance;
HLINEAPP hLineApp =  0 ;
DWORD dwNumDevs;
DWORD dwAPIVersion;
HLINE hLine;
HCALL hCall =  0 ;
LINEEXTENSIONID LineExtensionID;


#if TAPI_CURRENT_VERSION >= 0x00020000
LINEINITIALIZEEXPARAMS lineInitializeExParams = {
   sizeof(lineInitializeExParams),  0 ,  0 ,
   LINEINITIALIZEEXOPTION_USEHIDDENWINDOW,
   NULL,  0 
   };
#endif


TCHAR szPhoneNumber[ 256 ] = TEXT("45776");

#define BIGBUFF  8096 

LPVARSTRING             pVarString        = NULL;
LPLINEDEVSTATUS         pLineDevStatus    = NULL;
LPLINECALLINFO          pLineCallInfo     = NULL;
LPLINECALLPARAMS        pLineCallParams   = NULL;
LPLINETRANSLATEOUTPUT   pTranslateOutput  = NULL;

// State machine information.
DWORD dwMakeCallAsyncID= 0 ;
DWORD dwLineDropAsyncID= 0 ;
BOOL bDropped = FALSE;
BOOL bConnected = FALSE;
BOOL bAnswered  = FALSE;
BOOL bReadyToEnd = FALSE;
BOOL bPrintedEnd = FALSE;

// Constants in how the state machine behaves.
BOOL bCommandLineError = FALSE;
BOOL bLogExtraInfo = FALSE;
BOOL bAnswer = TRUE;

// Variables so we can ^C to shutdown and clean up properly.
DWORD dwThreadID;
DWORD dwWaveThreadID;
DWORD dwTimeToWaitBeforePlaying =  5000 ;

// /// Waveaudio content ///

HANDLE hWaveThread = NULL;
UINT WaveInID =  0 ;
UINT WaveOutID =  0 ;
BOOL bWaveLocal = FALSE;
TCHAR szFileName[ 1024 ] = TEXT("greeting.wav");
DWORD dwWaveMapped = WAVE_MAPPED;


// Prototypes
void CALLBACK lineCallbackFunc(
    DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance, 
    DWORD dwParam1, DWORD dwParam2, DWORD dwParam3);
BOOL SetupEnvironment (int argc, LPTSTR argv[]);
void PrintHelp();
BOOL BreakHandlerRoutine(DWORD dwCtrlType);
BOOL GetCallInfo();
void StopEverything();
BOOL PumpMessages(BOOL bWaitForMessage);
DWORD WINAPI WaveThread(LPVOID pVoid);



void PlayFromMemory (LPSTR szWavData);
DWORD WINAPI ThreadRecorded (LPVOID pvThreadParam);
void RecordToMemory (LPSTR szWavData);
void BuildWavData (LPSTR szFilename, LPSTR szWavData, DWORD dwMaxBufferSize);

void __cdecl MyPrintf(LPCTSTR pszFormat, ...);
LPCTSTR FormatError(DWORD dwError);
LPCTSTR FormatErrorBuffer(DWORD dwError, LPTSTR pszBuff, DWORD dwNumChars);
BOOL WINAPI HandlerRoutine(DWORD dwCtrlType);
LPTSTR FormatTapiError (long lError);


// Console app starting place.
int __cdecl _tmain(int argc, _TCHAR *argv[], _TCHAR *envp[])
{
   LONG lRet;
   MSG msg;

   // Setup basic stuff.
   hInstance = GetModuleHandle(NULL);
   dwThreadID = GetCurrentThreadId();
   SetConsoleCtrlHandler((PHANDLER_ROUTINE) BreakHandlerRoutine, TRUE);	

   if (!SetupEnvironment(argc, argv))
      goto end;

   if (bWaveLocal)
   {
      hWaveThread = CreateThread(NULL,  0 , WaveThread, NULL,  0 , &dwWaveThreadID);
      goto end;
   }

   // Prime the message queue.  TAPI callback is called as a result
   // of messages being dispatched.  By default, console apps don't have 
   // a message queue to hold these messages.  PeekMessage will create it.
   PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);

   pVarString       = LocalAlloc(LPTR, BIGBUFF);
   pLineDevStatus   = LocalAlloc(LPTR, BIGBUFF);
   pLineCallInfo    = LocalAlloc(LPTR, BIGBUFF);
   pLineCallParams  = LocalAlloc(LPTR, BIGBUFF);
   pTranslateOutput = LocalAlloc(LPTR, BIGBUFF);

   pVarString       -> dwTotalSize = BIGBUFF;
   pLineDevStatus   -> dwTotalSize = BIGBUFF;
   pLineCallInfo    -> dwTotalSize = BIGBUFF;
   pTranslateOutput -> dwTotalSize = BIGBUFF;

   pLineCallParams -> dwTotalSize = BIGBUFF;
   pLineCallParams -> dwBearerMode       = LINEBEARERMODE_VOICE;
   pLineCallParams -> dwMediaMode        = LINEMEDIAMODE_AUTOMATEDVOICE,
   pLineCallParams -> dwCallParamFlags   = 0;
   pLineCallParams -> dwAddressMode      = LINEADDRESSMODE_ADDRESSID;
   pLineCallParams -> dwAddressID        = dwAddressID;

#if TAPI_CURRENT_VERSION >= 0x00020000
   dwAPIVersion = TAPI_CURRENT_VERSION;
   lRet = lineInitializeEx(&hLineApp, hInstance, lineCallbackFunc, 
                         szAppName, &dwNumDevs, 
                         &dwAPIVersion, &lineInitializeExParams);
#else
   // Note that you can't use this function and be UNICODE
   lRet = lineInitialize(&hLineApp, hInstance, lineCallbackFunc, 
                         szAppName, &dwNumDevs);
#endif
   if (lRet)
   {
      MyPrintf(TEXT("lineInitialize failed: %s.\r\n"), FormatTapiError(lRet));
      goto end;
   }

   if (lRet = lineNegotiateAPIVersion(hLineApp, dwDeviceID, 
      0x00010004, 0x00010004, &dwAPIVersion, &LineExtensionID))
   {
      MyPrintf(TEXT("lineNegotiateAPIVersion failed: %s.\r\n"), FormatTapiError(lRet));
      goto end;
   }

   if (lRet = lineOpen(hLineApp, dwDeviceID, &hLine, dwAPIVersion,  0 ,  0 ,
            LINECALLPRIVILEGE_NONE,  0 , NULL))
   {
      MyPrintf(TEXT("lineOpen failed: %s.\r\n"), FormatTapiError(lRet));
      goto end;
   }
   
   while (TRUE)
   {
      if (lRet = lineGetLineDevStatus(hLine, pLineDevStatus))
      {
         MyPrintf(TEXT("lineGetLineDevStatus failed: %s.\r\n"), FormatTapiError(lRet));
         goto end;
      }

      if (pLineDevStatus->dwNeededSize > pLineDevStatus->dwTotalSize)
      {
         LocalReAlloc(pLineDevStatus, pLineDevStatus->dwNeededSize, LMEM_MOVEABLE);
         pLineDevStatus->dwTotalSize = pLineDevStatus->dwNeededSize;
         continue;
      }
      break;
   }

   if (pLineDevStatus -> dwOpenMediaModes)
      MyPrintf(TEXT("!!!WARNING!!!  Another application is already waiting for calls.\r\n\r\n"));

   if (!((pLineDevStatus -> dwLineFeatures) & LINEFEATURE_MAKECALL))
      MyPrintf(TEXT("!!!WARNING!!!  No call appearances available at this time.\r\n\r\n"));

   if (bAnswer)
   {
      lineClose(hLine);

      if (lRet = lineOpen(hLineApp, dwDeviceID, &hLine, dwAPIVersion,  0 ,  0 ,
            LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_AUTOMATEDVOICE, NULL))
      {
         MyPrintf(TEXT("lineOpen failed: %s.\r\n"), FormatTapiError(lRet));
         goto end;
      }

      MyPrintf(TEXT("Waiting for a call on TAPI Line Device %lu\r\n"), dwDeviceID);
   }
   else
   {

      if (lRet = lineTranslateAddress(hLineApp, dwDeviceID, dwAPIVersion, szPhoneNumber,
                      0 ,  0 , pTranslateOutput))
      {
         MyPrintf(TEXT("lineTranslateAddress failed: %s.\r\n"), FormatTapiError(lRet));
         goto end;
      }

      lRet = lineMakeCall(hLine, &hCall, szPhoneNumber,  0 , pLineCallParams);
      if (lRet <  0 )
      {
         MyPrintf(TEXT("lineMakeCall failed: %s.\r\n"), FormatTapiError(lRet));
         goto end;
      }
      else
      {
         dwMakeCallAsyncID = lRet;
      }
   }

   // TAPI callback is called only when messages are dispatched!
   while (PumpMessages(TRUE));

  end:

   StopEverything();

   if (hLineApp)
      lineShutdown(hLineApp);
   hLineApp =  0 ;

   if (pLineDevStatus)
      LocalFree(pLineDevStatus);
   if (pLineCallInfo)
      LocalFree(pLineCallInfo);
   if (pLineCallParams)
      LocalFree(pLineCallParams);
   if (pVarString)
      LocalFree(pVarString);
   if (pTranslateOutput)
      LocalFree(pTranslateOutput);

   return  1 ;
}



// Here's the TAPI callback.  Mondo switch statement!
void CALLBACK lineCallbackFunc(
    DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance, 
    DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
   LONG lRet;

   /*
   if (bLogExtraInfo)
      MyPrintf(TEXT("LCBF: %s\r\n"),    // LCBF stands for lineCallBackFunc
         FormatLineCallback(
               dwDevice, dwMsg, dwCallbackInstance, 
               dwParam1, dwParam2, dwParam3,
               szBuff));
               */

   switch(dwMsg)
   {
      case LINE_LINEDEVSTATE:
         if (dwParam1 == LINEDEVSTATE_REINIT)
         {
            MyPrintf(TEXT("LINEDEVSTATE_REINIT\r\n"));
            StopEverything();
         }
         break;

      case LINE_REPLY:
         if (dwParam2 == dwLineDropAsyncID)
         {
            if (dwParam2 != 0)
            {
               MyPrintf(TEXT("lineDrop LINE_REPLY with failure: %s.  Stopping.\r\r\n"), 
                  FormatTapiError((long) dwParam2));
               StopEverything();
            }
         }
         else if (dwParam2 == dwMakeCallAsyncID)
         {
            if (dwParam2 != 0)
            {
               MyPrintf(TEXT("lineMakeCall LINE_REPLY with failure: %s.  Stopping.\r\r\n"), 
                  FormatTapiError((long) dwParam2));
               StopEverything();
            }
         }


         // else ignore it.
         break;

      case LINE_CALLSTATE:
      {
         // Is this a new call?
         if (dwParam3 == LINECALLPRIVILEGE_OWNER)
         {
            // Do we already have a call?
            if (hCall && (hCall != (HCALL) dwDevice))
            {
               if (dwMsg == LINECALLSTATE_IDLE)
                  lineDeallocateCall((HCALL) dwDevice);
               else
               {
                  MyPrintf(TEXT("New call; %lu, but already managing one.  Dropping it.\r\r\n"),
                        dwDevice);
                  lineDrop((HCALL) dwDevice, NULL, 0);
               }
               break;
            }

            if (hCall)
               MyPrintf(
                  TEXT("Given OWNER privs to a call already owned?\r\n")
                  TEXT(" - Should only happen if handed a call already owned.\r\n"));
            else
            {
               hCall = (HCALL) dwDevice;
               MyPrintf(TEXT("New incoming hCall 0x%lx on TAPI Line Device.\r\r\n"),
                  hCall, dwDeviceID);
            }
         }

         if (hCall != (HCALL) dwDevice)
         {
            if (dwMsg == LINECALLSTATE_IDLE)
               lineDeallocateCall((HCALL) dwDevice);
            else
            {
               lineDrop((HCALL) dwDevice, NULL, 0);
               MyPrintf(TEXT("LINE_CALLSTATE 0x%lx for non-main hCall: 0x%lx.  Dropping.\r\n"), 
                  dwParam1, dwDevice);
            }
            break;
         }

         switch (dwParam1)
         {
            case LINECALLSTATE_IDLE:
            {
               MyPrintf(TEXT("IDLE.\n\r\n"));
               lRet = lineDeallocateCall(hCall);

               // Should make sure lineDeallocateCall succeeded

               hCall = 0;
               StopEverything();
               break;
            }

            case LINECALLSTATE_BUSY:
            case LINECALLSTATE_DISCONNECTED:
               if (dwParam1 == LINECALLSTATE_BUSY)
                  MyPrintf(TEXT("BUSY.  Hanging up.\r\n"));
               else
                  MyPrintf(TEXT("DISCONNECTED.  Hanging up.\r\n"));

               if (!bDropped)
                  dwLineDropAsyncID = lineDrop(hCall, NULL, 0);
               if (dwLineDropAsyncID < 0)
               {
                  MyPrintf(TEXT("lineDrop failed.  Terminating\r\n"));
                  hCall = 0;
                  StopEverything();
               }

               bDropped = TRUE;

               break;

            case LINECALLSTATE_OFFERING:
            case LINECALLSTATE_ACCEPTED:  // Could be handed off an accepted call
               if (bAnswered)
                  break;

               if (dwParam1 == LINECALLSTATE_OFFERING)
                  MyPrintf(TEXT("Answering an OFFERING call.\r\n\r\n"));
               else
                  MyPrintf(TEXT("Answering an ACCEPTED call.\r\n\r\n"));

               lRet = lineAnswer(hCall, NULL, 0);

               // Should check to make sure lineAnswer succeeded

               bAnswered = TRUE;

               break;

            case LINECALLSTATE_CONNECTED:
               if (!bConnected)
               {
                  bConnected = TRUE;
                  MyPrintf(TEXT("CONNECTED.\r\n"));

                  hWaveThread = CreateThread(NULL, 0, WaveThread, NULL, 0, &dwWaveThreadID);
               }
               break;
         }

         break;
      }
   }
}


BOOL GetCallInfo()
{
   LONG lRet;
   while (TRUE)
   {
      if (lRet = lineGetCallInfo(hCall, pLineCallInfo))
      {
         MyPrintf(TEXT("lineGetCallInfo failed: %s.\r\n"), FormatTapiError(lRet));
         return FALSE;
      }

      if (pLineCallInfo->dwNeededSize > pLineCallInfo->dwTotalSize)
      {
         LocalReAlloc(pLineCallInfo, pLineCallInfo->dwNeededSize, LMEM_MOVEABLE);
         pLineCallInfo->dwTotalSize = pLineCallInfo->dwNeededSize;
         continue;
      }

      return TRUE;
   }
}


// Parse the command line and change the default settings.
BOOL SetupEnvironment (int argc, LPTSTR argv[])
{
   int i = 0, j;
   TCHAR chFlag;
   BOOL bMaxCallsSet = FALSE;

   if (argc == 1)
   {
      PrintHelp();
      return FALSE;
   }

   while (++i < argc)
   {
      j = 0;
      if ((argv[i][j] == TEXT('/')) || (argv[i][j] == TEXT('-')) || (argv[i][j] == TEXT('+')))
         j = 1;

      chFlag = argv[i][j++];

      if (argv[i][j] == TEXT(':'))
         j++;
      if (argv[i][j] == TEXT('\"'))
         j++;

      switch(tolower(chFlag))
      {
         case TEXT('?'):
            MyPrintf(TEXT("Runs a test of the TAPI and WAVE system.\r\n"));
            PrintHelp();
            return FALSE;

         case TEXT('l'):
            dwDeviceID = _ttoi(&argv[i][j]);
            if (!dwDeviceID)
            {
               MyPrintf(TEXT("Invalid [L]ine selection.\r\n"));
               bCommandLineError = TRUE;
               PrintHelp();
               return FALSE;
            }
            break;

         case TEXT('i'):
            dwAddressID = _ttoi(&argv[i][j]);
            if (!dwAddressID)
            {
               MyPrintf(TEXT("Invalid Address [I]D selection.\r\n"));
               bCommandLineError = TRUE;
               PrintHelp();
               return FALSE;
            }
            break;

         case TEXT('x'):
            bLogExtraInfo = TRUE;
            MyPrintf(TEXT("Extra call and data flow information will be displayed.\r\n"));
            break;

         case TEXT('a'):
            bAnswer = TRUE;
            break;

         case TEXT('d'):
            lstrcpy(szPhoneNumber, &argv[i][j]);
            bAnswer = FALSE;
            break;

         case TEXT('f'):
            lstrcpy(szFileName, &argv[i][j]);
            break;

         case TEXT('w'):
            WaveInID = _ttoi(&argv[i][j]);
            if (!WaveInID && (argv[i][j] != TEXT('0')))
            {
               MyPrintf(TEXT("Invalid [W]ave ID selection.\r\n"));
               bCommandLineError = TRUE;
               PrintHelp();
               return FALSE;
            }
            if (WaveInID == 99)
            {
               MyPrintf(TEXT("Using WAVE_MAPPER.\r\n"));
               WaveOutID = WaveInID = WAVE_MAPPER;
               dwWaveMapped = 0;
            }
            else
               WaveOutID = WaveInID;

            bWaveLocal = TRUE;
            break;

         case TEXT('z'):
            dwWaveMapped = 0;
            break;

         case TEXT('p'):
            dwTimeToWaitBeforePlaying = _ttoi(&argv[i][j]);
            break;
      }
   }

   return TRUE;
}


// Print the help screen.
void PrintHelp()
{
   MyPrintf(
TEXT("\r\n")
TEXT("%s [options]\r\n")
TEXT("\r\n")
TEXT("[Wave File]  File to record to or play back.\r\n")
TEXT("\r\n")
TEXT("Options:\r\n")
TEXT("/L:#        Line Device ID (dwDeviceID) to use.\r\n")
//TEXT("/I:#        Line Address ID to use.  Ignored when AutoAnswer is set.\r\n")
TEXT("/X          Display extra call and data flow information.\r\n")
TEXT("/F:file     Use file as the wave file\r\n")
TEXT("/D:[number] Dial number\r\n")
TEXT("/A          Answer a call\r\n")
TEXT("\r\n")
//TEXT("/W:#        Specify a wave ID to use for both IN and OUT.\r\n")
//TEXT("            If this flag is used, all TAPI is bypassed.\r\n")
//TEXT("            A wave ID of 99 means to use WAVE_MAPPER.\r\n")
TEXT("/Z          Don't use WAVE_MAPPED\r\n")
TEXT("/P:#        Pause # milliseconds after dialing, before playing.\r\n")
TEXT("\r\n")
TEXT("defaults: /L:%lu /I:%lu\n /F:%s /A\r\n"),
TEXT("\r\n"),
   szAppName, dwDeviceID, dwAddressID, szFileName);
}




// Break Hander: Try and terminate gracefully.
// Note that ^Break can call lineShutdown *DURING* a lineMakeCall.  Very
// unpredictable results; TAPI is not re-entrant and is *usually* protected by
// the Win16 Mutex.  However, a Break Handler is a special case.
BOOL BreakHandlerRoutine(DWORD dwCtrlType)
{
   // ^BREAK will always break.  
   // Use with care; it can mess up TAPI if in the middle of a TAPI API.
   if (dwCtrlType == CTRL_BREAK_EVENT)
   {
      MyPrintf(TEXT("\r\n^[Break] terminated!  TAPI may not be left in a usable state.\r\n\r\n"));

      lineShutdown(hLineApp);
      LocalFree(pLineDevStatus);
      LocalFree(pLineCallInfo);
      LocalFree(pLineCallParams);
      ExitProcess( 1 );
   }
   else
   {
      if (hCall)
         MyPrintf(TEXT("\r\n^C Dropping call in progress.\r\n\r\n"));
      else 
         MyPrintf(TEXT("\r\n^C stopped.\r\n\r\n"));

      StopEverything();
   }
   return TRUE;
}

BOOL PumpMessages(BOOL bWaitForMessage)
{
	static MSG msg;

   if (bReadyToEnd)
	   return FALSE;

   if (bWaitForMessage)
   {
      if (!GetMessage(&msg, NULL,  0 ,  0 ))
         return FALSE;
   }
   else
      if (!PeekMessage(&msg, NULL,  0 ,  0 , PM_REMOVE))
         return TRUE;
      else
         if (msg.message == WM_QUIT)
            return FALSE;

   TranslateMessage(&msg);
   DispatchMessage(&msg);

   return TRUE;
}


void StopEverything()
{
   bReadyToEnd = TRUE;

   WaitForSingleObject(hWaveThread, INFINITE);

   if (hCall && !bDropped)
   {
      dwLineDropAsyncID = lineDrop(hCall, NULL,  0 );
      if (dwLineDropAsyncID <  0 )
      {
         MyPrintf(TEXT("lineDrop failed.  Terminating\r\n"));
         hCall =  0 ;
      }
      bDropped = TRUE;
   }

   // lets prime the pump with a message.
   PostThreadMessage(dwThreadID, WM_USER,  0 ,  0 );
}


// ---------------

typedef struct MYWAVEDATA_tag
{
   struct MYWAVEDATA_tag * pNext;
   WAVEHDR wavehdr;
   BYTE data[ 1 ];
} MYWAVEDATA, *PMYWAVEDATA;

PrintWaveInfo(WaveInID, WaveOutID);
PMYWAVEDATA LoadWaveInfo(WAVEFORMATEX* pFormat);
LPTSTR FormatWaveOutError(MMRESULT mmResult);
LPTSTR FormatWaveInError(MMRESULT mmResult);


// CONNECTED!  Now do data steam testing.  Return FALSE to stop TAPI.
DWORD WINAPI WaveThread(LPVOID pVoid)
{
   DWORD i;
   HWAVEIN     hWaveIn = NULL;
   HWAVEOUT    hWaveOut = NULL;
   MMRESULT mmResult;
   PMYWAVEDATA pWaveData, pWaveCurr;
   BYTE WaveFormatBytes[ 4096 ];
   PWAVEFORMATEX  pFormat = (PWAVEFORMATEX) WaveFormatBytes;

   // Get the wave devices to use
   if (!bWaveLocal)
   {
      LONG lRet;

      if (lRet = lineGetID( 0 ,  0 , hCall, LINECALLSELECT_CALL, pVarString, TEXT("wave/in")))
      {
         MyPrintf(TEXT("lineGetID failed %s\r\n"), FormatTapiError(lRet));
         return FALSE;
      }

      WaveInID = *(UINT *)((LPBYTE)pVarString + pVarString->dwStringOffset);

      if (lRet = lineGetID( 0 ,  0 , hCall, LINECALLSELECT_CALL, pVarString, TEXT("wave/out")))
      {
         MyPrintf(TEXT("lineGetID failed %s\r\n"), FormatTapiError(lRet));
         return FALSE;
      }

      WaveOutID = *(UINT *)((LPBYTE)pVarString + pVarString->dwStringOffset);
   }

   MyPrintf(TEXT("Using WaveInID %lu and WaveOutID %lu\r\n"),
          (DWORD) WaveInID, (DWORD) WaveOutID);

   PrintWaveInfo(WaveInID, WaveOutID);


   // Load the wave data from file.  Yes, this assumes we are playing.
   pFormat->cbSize = sizeof(WaveFormatBytes);
   pWaveData = LoadWaveInfo(pFormat);
   if (pWaveData == NULL)
      return  0 ;


   // Open a waveform output device.
   mmResult = waveOutOpen(&hWaveOut, WaveOutID, pFormat,  0  , 0L, dwWaveMapped);
   if (mmResult)
   {
      MyPrintf(TEXT("waveOutOpen returned %s\r\n"), FormatWaveOutError(mmResult));
      goto end;
   }


   // First, sleep 5 seconds to give the other end time to answer.
   // This is an important step as modems have no idea when the other end actually answered.
   // A sleep isn't the best way to wait, but it works for now.
   MyPrintf(TEXT("Waiting %lu milliseconds for other end to answer because modems don't know when a VOICE call has answered\r\n"), 
      dwTimeToWaitBeforePlaying);
   for(i = dwTimeToWaitBeforePlaying; i; i-=100)
   {
      if (!(i%1000))
         MyPrintf(TEXT("%lu\r\n"), i/1000);
      if (bReadyToEnd)
         break;
      Sleep(100);
   }

   // Now start playing, looping through the wave file repeatedly.

   pWaveCurr = pWaveData;
   
   while(!bReadyToEnd)
   {
      // If a buffer is queued, wait till its done.
      if (pWaveCurr->wavehdr.dwFlags & WHDR_INQUEUE)
      {
         if (bLogExtraInfo)
            MyPrintf(TEXT("Waiting for wave buffer to finish rendering\r\n"));
         Sleep(250);
         continue;
      }

      // If we've used it, we need to unprepare the header
      if (pWaveCurr->wavehdr.dwFlags & WHDR_DONE )
      {
         if(mmResult = waveOutUnprepareHeader(hWaveOut, &pWaveCurr->wavehdr, sizeof(WAVEHDR)))
         {
            MyPrintf(TEXT("waveOutUnprepareHeader returned %s\r\n"), FormatWaveOutError(mmResult));
            break;
         }
      }

      pWaveCurr->wavehdr.dwFlags = 0;

      // prepare each WAVEHDR
      if(mmResult = waveOutPrepareHeader(hWaveOut, &pWaveCurr->wavehdr, sizeof(WAVEHDR)))
      {
         MyPrintf(TEXT("waveOutPrepareHeader returned %s\r\n"), FormatWaveOutError(mmResult));
         break;
      }

      // Send to the output device.
      if (mmResult = waveOutWrite(hWaveOut, &pWaveCurr->wavehdr, sizeof(WAVEHDR)))
      {
         MyPrintf(TEXT("waveOutWrite returned %s\r\n"), FormatWaveOutError(mmResult));
         break;
      }

      if (!(pWaveCurr->wavehdr.dwFlags & WHDR_INQUEUE))
      {
         MyPrintf(TEXT("waveOutWrite did not succesfully queue."));
         break;
      }

      if (bLogExtraInfo)
         MyPrintf(TEXT("Wave buffer successfully queued.\r\n"));

      pWaveCurr = pWaveCurr->pNext;
      if (!pWaveCurr)
         pWaveCurr = pWaveData;
   }

  end:

   if (hWaveOut)
   {
      if (mmResult = waveOutReset(hWaveOut))
         MyPrintf(TEXT("waveOutReset returned %s\r\n"), FormatWaveOutError(mmResult));

      Sleep(500);  // Give it 1/2 sec to actually reset.
   
      if(mmResult = waveOutClose(hWaveOut))
         MyPrintf(TEXT("waveOutClose returned %s\r\n"), FormatWaveOutError(mmResult));

      Sleep(500); // Give it 1/2 sec to clean up.
      hWaveOut = 0;
   }

   while(pWaveData)
   {
      pWaveCurr = pWaveData;
      pWaveData = pWaveCurr->pNext;

      LocalFree(pWaveCurr);
   }

   return FALSE;
}



PrintWaveInfo(WaveInID, WaveOutID)
{
   WAVEINCAPS in;
   WAVEOUTCAPS out;

   if (MMSYSERR_NOERROR == waveInGetDevCaps(WaveInID, &in, sizeof(in)))
   {
      MyPrintf(
         TEXT("WaveInDevCaps:\r\n")
         TEXT("  wMid: 0x%04X\r\n")
         TEXT("  wPid: 0x%04X\r\n")
         TEXT("  vDriverVersion: 0x%04X\r\n")
         TEXT("  pszPname: %s\r\n")
         TEXT("  dwFormats: 0x%08X\r\n")
         TEXT("  dwChannels: 0x%04X\r\n")
         ,
         in.wMid, in.wPid, in.vDriverVersion, in.szPname, in.dwFormats, in.wChannels);
   }
   else
      MyPrintf(TEXT("waveInGetDevCaps failed.\r\n"));

   if (MMSYSERR_NOERROR == waveOutGetDevCaps(WaveOutID, &out, sizeof(out)))
   {
      MyPrintf(
         TEXT("WaveOutDevCaps:\r\n")
         TEXT("  wMid: 0x%04X\r\n")
         TEXT("  wPid: 0x%04X\r\n")
         TEXT("  vDriverVersion: 0x%04X\r\n")
         TEXT("  pszPname: %s\r\n")
         TEXT("  dwFormats: 0x%08X\r\n")
         TEXT("  dwChannels: 0x%04X\r\n")
         ,
         out.wMid, out.wPid, out.vDriverVersion, out.szPname, out.dwFormats, out.wChannels);
   }
   else
      MyPrintf(TEXT("waveInGetDevCaps failed.\r\n"));

   // TODO Find out if its capable of simultaneous recording and playing
}


PMYWAVEDATA LoadWaveInfo(WAVEFORMATEX* pFormat)
{
   MMRESULT       mmResult;
   HMMIO          hmmio = {0};
   MMCKINFO       mmckinfoParent;
   MMCKINFO       mmckinfoSubchunk;
   DWORD          dwFmtSize;
   DWORD          dwChunkSize;
   PMYWAVEDATA    pWaveHead = NULL, 
                  pWaveCurr = NULL,
                  pWavePrev = NULL;
   BOOL bLooping = TRUE;
   DWORD dwBuffers = 0;

   // Open the given file for reading using buffered I/O.
   if(!(hmmio = mmioOpen(szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF)))
   {
      MyPrintf(TEXT("mmioOpen failed to open file.\r\n"));
      return NULL;
   }

   // Locate a 'RIFF' chunk with a 'WAVE' form type to make sure it's a WAVE file.
   mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
   if (mmResult = mmioDescend(hmmio, &mmckinfoParent, NULL, MMIO_FINDRIFF))
   {
      MyPrintf(TEXT("mmioDescend RIFF WAVE returned %s\r\n"), FormatWaveOutError(mmResult));
      goto end;
   }

   //  Now, find the format chunk (form type 'fmt '). It should be
   //  a subchunk of the 'RIFF' parent chunk.
   mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
   if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,
      MMIO_FINDCHUNK))
   {
      MyPrintf(TEXT("Wave file corrupt.\r\n"));
      goto end;
   }

   // Get the size of the format chunk, allocate and lock memory for it.
   dwFmtSize = mmckinfoSubchunk.cksize;
   if (pFormat->cbSize < dwFmtSize)
   {
      MyPrintf(TEXT("Format chunk not big enough.\r\n"));
      goto end;
   }

   // Read the format chunk.
   if (mmioRead(hmmio, (HPSTR) pFormat, dwFmtSize) != (LONG) dwFmtSize)
   {
      MyPrintf(TEXT("mmioRead: failed to read FMT chunk.\r\n"));
      goto end;
   }

   MyPrintf(TEXT("wFormatTag = %lu\r\n"),        (DWORD) pFormat->wFormatTag);
   MyPrintf(TEXT("nChannels = %lu\r\n"),         (DWORD) pFormat->nChannels );
   MyPrintf(TEXT("nSamplesPerSec = %lu\r\n"),    (DWORD) pFormat->nSamplesPerSec);
   MyPrintf(TEXT("nAvgBytesPerSec = %lu\r\n"),   (DWORD) pFormat->nAvgBytesPerSec);
   MyPrintf(TEXT("nBlockAlign = %lu\r\n"),       (DWORD) pFormat->nBlockAlign);
   MyPrintf(TEXT("wBitsPerSample = %lu\r\n"),    (DWORD) pFormat->wBitsPerSample);
   MyPrintf(TEXT("cbSize = %lu\r\n"),            (DWORD) pFormat->cbSize);

   // Ascend out of the format subchunk.
   mmioAscend(hmmio, &mmckinfoSubchunk, 0);

   // Find the data subchunk.
   mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
   if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,
      MMIO_FINDCHUNK))
   {
      MyPrintf(TEXT("mmioDescend: No DATA chunk.\r\n"));
      goto end;
   }

   //  Get the size of the data subchunk.
   if (mmckinfoSubchunk.cksize == 0L)
   {
      MyPrintf(TEXT("Data chunk actually has no data.\r\n"));
      goto end;
   }
   MyPrintf(TEXT("Size of data is %lu\r\n"),mmckinfoSubchunk.cksize);

   // Now read the data and allocate MYWAVEDATA buffers
   dwChunkSize = (pFormat->nAvgBytesPerSec/4);
   dwChunkSize -= dwChunkSize % pFormat->nBlockAlign;
   if (dwChunkSize < pFormat->nBlockAlign)
   {
      MyPrintf(TEXT("Couldn't calculate a good block size\r\n"));
      goto end;
   }

   while(bLooping)
   {
      LONG lRead;

      pWaveCurr = (PMYWAVEDATA) LocalAlloc(LPTR, dwChunkSize + sizeof(MYWAVEDATA));
      pWaveCurr->wavehdr.lpData = pWaveCurr->data;

      if (pWaveHead == NULL)
         pWaveHead = pWaveCurr;

      // Read the waveform data subchunk.
      lRead = mmioRead(hmmio, pWaveCurr->data, dwChunkSize);
      pWaveCurr->wavehdr.dwBufferLength = lRead;
      if (lRead == -1)
      {
         MyPrintf(TEXT("Error reading from file.\r\n"));
         pWaveHead = NULL; // Leak leak
         goto end;
      }

      if (lRead == 0)
      {
         LocalFree(pWaveCurr);
         break;
      }

      if ((DWORD)lRead != dwChunkSize)
      {
         bLooping = FALSE;
      }

      if (pWavePrev != NULL)
         pWavePrev->pNext = pWaveCurr;
      pWavePrev = pWaveCurr;
      dwBuffers++;
   }

   MyPrintf(TEXT("There were %lu buffers read from %s\r\n"), dwBuffers, szFileName);

  end:

   mmioClose(hmmio, 0);

   return pWaveHead;
}



 
/*=== Printing routines =============================================================*/

/*
  This is easily used to do error messages like this:

  MyPrintf(TEXT("API blah failed with error: %s\r\n"), FormatError(GetLastError()));
*/

#define MAX_PRINT_STRING 1024

//#define MSG_BOX_PRINT

#ifdef _DEBUG
#define MSG_DEBUG_PRINT
#endif

#define MSG_CONSOLE_PRINT

//#define MSG_FILE_PRINT 

#ifdef MSG_FILE_PRINT
TCHAR szFilePrint[MAX_PATH] = TEXT(".\\out.txt");
BOOL bZeroFile = FALSE;
#endif

LPTSTR FormatWaveError(MMRESULT mmrError, MMRESULT (WINAPI *pfn) (MMRESULT, LPTSTR, UINT), LPTSTR szErr)
{
   _declspec(thread) static TCHAR szOutput[MAX_PRINT_STRING];
   MMRESULT mmResult2;
   mmResult2 = pfn(mmrError, szOutput, MAX_PRINT_STRING);
   if (mmResult2 != MMSYSERR_NOERROR)
   {
      TCHAR szTmp[256];
      MMRESULT mmResult3;

      mmResult3 = pfn(mmResult2, szOutput, 256);
      if (mmResult2 != MMSYSERR_NOERROR)
         wsprintf(szOutput, TEXT("%s returned an %lu on %lu"), szErr, mmResult2, mmrError);
      else
         wsprintf(szOutput, TEXT("%s on error %lu"), szTmp, mmrError);
   }
   return szOutput;
}

LPTSTR FormatWaveOutError(MMRESULT mmrError)
{
   return FormatWaveError(mmrError, waveOutGetErrorText, TEXT("waveOutGetError"));
}

LPTSTR FormatWaveInError(MMRESULT mmrError)
{
   return FormatWaveError(mmrError, waveInGetErrorText, TEXT("waveInGetError"));
}


// Turn a TAPI Line error into a printable string.
LPTSTR FormatTapiError (long lError)
{
   static LPTSTR pszLineError[] = 
   {
     TEXT("LINEERR No Error"),
     TEXT("LINEERR_ALLOCATED"),
     TEXT("LINEERR_BADDEVICEID"),
     TEXT("LINEERR_BEARERMODEUNAVAIL"),
     TEXT("LINEERR Unused constant, ERROR!!"),
     TEXT("LINEERR_CALLUNAVAIL"),
     TEXT("LINEERR_COMPLETIONOVERRUN"),
     TEXT("LINEERR_CONFERENCEFULL"),
     TEXT("LINEERR_DIALBILLING"),
     TEXT("LINEERR_DIALDIALTONE"),
     TEXT("LINEERR_DIALPROMPT"),
     TEXT("LINEERR_DIALQUIET"),
     TEXT("LINEERR_INCOMPATIBLEAPIVERSION"),
     TEXT("LINEERR_INCOMPATIBLEEXTVERSION"),
     TEXT("LINEERR_INIFILECORRUPT"),
     TEXT("LINEERR_INUSE"),
     TEXT("LINEERR_INVALADDRESS"),
     TEXT("LINEERR_INVALADDRESSID"),
     TEXT("LINEERR_INVALADDRESSMODE"),
     TEXT("LINEERR_INVALADDRESSSTATE"),
     TEXT("LINEERR_INVALAPPHANDLE"),
     TEXT("LINEERR_INVALAPPNAME"),
     TEXT("LINEERR_INVALBEARERMODE"),
     TEXT("LINEERR_INVALCALLCOMPLMODE"),
     TEXT("LINEERR_INVALCALLHANDLE"),
     TEXT("LINEERR_INVALCALLPARAMS"),
     TEXT("LINEERR_INVALCALLPRIVILEGE"),
     TEXT("LINEERR_INVALCALLSELECT"),
     TEXT("LINEERR_INVALCALLSTATE"),
     TEXT("LINEERR_INVALCALLSTATELIST"),
     TEXT("LINEERR_INVALCARD"),
     TEXT("LINEERR_INVALCOMPLETIONID"),
     TEXT("LINEERR_INVALCONFCALLHANDLE"),
     TEXT("LINEERR_INVALCONSULTCALLHANDLE"),
     TEXT("LINEERR_INVALCOUNTRYCODE"),
     TEXT("LINEERR_INVALDEVICECLASS"),
     TEXT("LINEERR_INVALDEVICEHANDLE"),
     TEXT("LINEERR_INVALDIALPARAMS"),
     TEXT("LINEERR_INVALDIGITLIST"),
     TEXT("LINEERR_INVALDIGITMODE"),
     TEXT("LINEERR_INVALDIGITS"),
     TEXT("LINEERR_INVALEXTVERSION"),
     TEXT("LINEERR_INVALGROUPID"),
     TEXT("LINEERR_INVALLINEHANDLE"),
     TEXT("LINEERR_INVALLINESTATE"),
     TEXT("LINEERR_INVALLOCATION"),
     TEXT("LINEERR_INVALMEDIALIST"),
     TEXT("LINEERR_INVALMEDIAMODE"),
     TEXT("LINEERR_INVALMESSAGEID"),
     TEXT("LINEERR Unused constant, ERROR!!"),
     TEXT("LINEERR_INVALPARAM"),
     TEXT("LINEERR_INVALPARKID"),
     TEXT("LINEERR_INVALPARKMODE"),
     TEXT("LINEERR_INVALPOINTER"),
     TEXT("LINEERR_INVALPRIVSELECT"),
     TEXT("LINEERR_INVALRATE"),
     TEXT("LINEERR_INVALREQUESTMODE"),
     TEXT("LINEERR_INVALTERMINALID"),
     TEXT("LINEERR_INVALTERMINALMODE"),
     TEXT("LINEERR_INVALTIMEOUT"),
     TEXT("LINEERR_INVALTONE"),
     TEXT("LINEERR_INVALTONELIST"),
     TEXT("LINEERR_INVALTONEMODE"),
     TEXT("LINEERR_INVALTRANSFERMODE"),
     TEXT("LINEERR_LINEMAPPERFAILED"),
     TEXT("LINEERR_NOCONFERENCE"),
     TEXT("LINEERR_NODEVICE"),
     TEXT("LINEERR_NODRIVER"),
     TEXT("LINEERR_NOMEM"),
     TEXT("LINEERR_NOREQUEST"),
     TEXT("LINEERR_NOTOWNER"),
     TEXT("LINEERR_NOTREGISTERED"),
     TEXT("LINEERR_OPERATIONFAILED"),
     TEXT("LINEERR_OPERATIONUNAVAIL"),
     TEXT("LINEERR_RATEUNAVAIL"),
     TEXT("LINEERR_RESOURCEUNAVAIL"),
     TEXT("LINEERR_REQUESTOVERRUN"),
     TEXT("LINEERR_STRUCTURETOOSMALL"),
     TEXT("LINEERR_TARGETNOTFOUND"),
     TEXT("LINEERR_TARGETSELF"),
     TEXT("LINEERR_UNINITIALIZED"),
     TEXT("LINEERR_USERUSERINFOTOOBIG"),
     TEXT("LINEERR_REINIT"),
     TEXT("LINEERR_ADDRESSBLOCKED"),
     TEXT("LINEERR_BILLINGREJECTED"),
     TEXT("LINEERR_INVALFEATURE"),
     TEXT("LINEERR_NOMULTIPLEINSTANCE")
   };

   _declspec(thread) static TCHAR szError[512];
   DWORD dwError;
   HMODULE hTapiUIMod = GetModuleHandle(TEXT("TAPIUI.DLL"));

   if (hTapiUIMod)
   {
      dwError = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
                    (LPCVOID)hTapiUIMod, TAPIERROR_FORMATMESSAGE(lError),
                    0, szError, sizeof(szError)/sizeof(TCHAR), NULL);
      if (dwError)
         return szError;
   }

   // Strip off the high bit to make the error code positive.
   dwError = (DWORD)lError & 0x7FFFFFFF;

   if ((lError > 0) || (dwError > sizeof(pszLineError)/sizeof(pszLineError[0])))
   {
      wsprintf(szError, TEXT("Unknown TAPI error code: 0x%lx"), lError);
      return szError;
   }

   return pszLineError[dwError];
}



void __cdecl MyPrintf(LPCTSTR pszFormat, ...)
{
   _declspec(thread) static TCHAR szOutput[MAX_PRINT_STRING]; // max printable string length
   va_list v1;
   DWORD dwSize;

   va_start(v1, pszFormat);

   dwSize = wvsprintf(szOutput, pszFormat, v1); 

#ifdef MSG_DEBUG_PRINT
   OutputDebugString(szOutput);
#endif

#ifdef MSG_CONSOLE_PRINT
   _tprintf(szOutput);
#endif

#ifdef MSG_BOX_PRINT
   MessageBox(NULL, szOutput,TEXT("MyPrintf Output"), MB_OK);
#endif

#ifdef MSG_FILE_PRINT
   {
	   static HANDLE hFile = NULL;
	   DWORD dwNumWritten;
	   if (hFile == NULL)
	   {
		   hFile = CreateFile(szFilePrint, GENERIC_WRITE, FILE_SHARE_READ, NULL, 
			   bZeroFile ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

		   if (hFile == INVALID_HANDLE_VALUE)
			   MyPrintf(TEXT("CreateFile output log file %s failed with %s\r\n"), szFilePrint, FormatError(GetLastError()));
		   else
            SetFilePointer(hFile, 0, NULL, FILE_END);
	   }
	   if (hFile != INVALID_HANDLE_VALUE)
      {
         OVERLAPPED ol = {0};
         LockFileEx(hFile, 0, 0, 1, 0, &ol);
		   WriteFile(hFile, szOutput, dwSize*sizeof(TCHAR), &dwNumWritten, NULL);
         UnlockFileEx(hFile, 0, 1, 0, &ol);
      }
   }
#endif
}

LPCTSTR FormatError(DWORD dwError)
{
   _declspec(thread) static TCHAR szBuff[MAX_PRINT_STRING];
   return FormatErrorBuffer(dwError, szBuff, MAX_PRINT_STRING);
}

LPCTSTR FormatErrorBuffer(DWORD dwError, LPTSTR pszBuff, DWORD dwNumChars)
{
   DWORD dwRetFM = 0;

   dwRetFM = wsprintf(pszBuff, TEXT("%lu - "), dwError);
   dwRetFM = FormatMessage(
      FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0,
      &pszBuff[dwRetFM], dwNumChars - dwRetFM, NULL);

   if (dwRetFM == 0)
   {
      wsprintf(pszBuff, TEXT("FormatMessage failed on %lu with %lu"),
         dwError, GetLastError());
   }

   return pszBuff;
}

...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Проиграть Wav в модем
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]