На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела Visual Basic: Общие вопросы
Здесь обсуждаются вопросы по языку Visual Basic 1-6 (а так же по схожим языкам, как, например, PowerBASIC).
Вопросы по Visual Basic .NET (это который входит в состав Visual Studio 2002/2003/2005/2008+, для тех, кто не в курсе) обсуждаются в разделе .NET.

Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что Вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются. Студенты, вам сюда: ПОМОЩЬ СТУДЕНТАМ!
4. Используйте теги [ code=vba ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Формулируйте свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной (и более) давности, без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта user posted image FAQ Раздела user posted image Кладовка user posted image Наши Исходники user posted image API-Guide user posted image Поиск по Разделу user posted image MSDN Library Online user posted image Google

Ваше мнение о модераторах: user posted image SCINER, user posted image B.V.
Модераторы: SCINER, B.V.
  
> Консольная звонилка (PowerBasic)
    Уважаемые форумчане! Возникла необходимость написания консольной звонилки.

    Имеется код с использованием TAPI, который я немогу заставить адекватно работать. Длительные поиски не привели к успеху (встречалась пара подобных вопросов без ответов), задавал вопрос на другом форуме - ответа не получил, поэтому решил спросить и здесь.
    В чем заключается проблема: не удается получить ответ из CallBack функции.

    ExpandedWrap disabled
      #Compile Exe
      #Dim All
       
      #Include "Tapi32.inc"
      #Include "WinUser.inc"
       
       
       
      Global hCall As Dword
       
      Function PBMain
          Local numberToDial As String
          numberToDial = $DefNumberToDial
          ' Зациклено в исследовательских целях
          1:
          Con.Input "Nomer: ", numberToDial
          dial(numberToDial)
          GoTo 1
      End Function
       
       
      Function Dial(phoneNumber As String) As Long
         Local lRet As Long, hApiVersion As Long, numLines As Long, lineNo As Long
         Local minVer As Long, maxVer As Long, dwAPIVersion As Dword
         Local hLine As Dword
         Local numberToDial As AsciiZ * 32
         Local lineParams As LINECALLPARAMS, extID As LINEEXTENSIONID
         Local lip As LINEINITIALIZEEXPARAMS
         Local hInstance As Dword, hTapiApp As Dword
         Local i As Long
       
         Local Msg As tagMsg
       
         lip.dwtotalsize = Len(lip)
       
         lip.dwoptions = %LINEINITIALIZEEXOPTION_USEHIDDENWINDOW
       
       
         hApiVersion = %TAPI_CURRENT_VERSION
         numberToDial = phoneNumber
       
         hInstance = GetModuleHandle(ByVal %NULL)
        
         'PeekMessage(msg, %Null, 0, 0, %PM_REMOVE)
       
         lRet = lineInitializeEx(hTapiApp, hInstance, CodePtr(tapiCallback), "weqweqweqeweqwe", numLines, hApiVersion, lip)
       
         If lRet Then
             Print "Error on LineInitialize: " + Str$(lRet)
         End If
       
         lineNo = -1
       
         For i = 0 To numLines - 1
       
            minVer = &h00010004
            maxVer = &h00020000
       
            lRet = LineNegotiateAPIVersion(ByVal hTapiApp, ByVal i, ByVal minVer, ByVal maxVer, dwAPIVersion, extID)
       
            If lRet Then
               Print "Error negotiation API Version: " + Str$(lRet)
            End If
       
            lRet = LineOpen (ByVal hTapiApp, ByVal i, hLine, ByVal dwAPIVersion, ByVal 0, ByVal 0, ByVal %LINECALLPRIVILEGE_NONE, ByVal %LINEMEDIAMODE_DATAMODEM, lineParams)
       
            If lRet Then
                Print "Error on LineOpen: " + Str$(lRet)
            Else
                lineNo = i
                Exit For
            End If
       
         Next i
       
         If lineNo < 0 Then Print "Could not find modem": Exit Function
       
         lineParams.dwTotalSize = SizeOf(LINECALLPARAMS)
         lineParams.dwMediaMode = %LINEMEDIAMODE_DATAMODEM
       
         lRet = LineMakeCall (ByVal hLine, hCall, numberToDial, ByVal 0, lineParams)
       
         If lRet < 0 Then
            Print "Error making call: " + Str$(lRet)
            Exit Function
         End If
       
         While PeekMessage(msg, %Null, 0, 0, %PM_REMOVE)
              TranslateMessage(msg)
              DispatchMessage(msg) '<-- вот здесь прога падает
         Loop
       
         Print ">>>"
       
         LineDrop(ByVal hCall, ByVal 0, ByVal 0)
         LineClose(ByVal hLine)
         LineShutdown(ByVal hTapiApp)
       
      End Function
       
       
       
      Function TapiCallback(ByVal hDevice&, ByVal dwMsg&, ByVal CBInstance&,_
                            ByVal Param1&, ByVal Param2&, ByVal Param3&) As Long
       
         Local nDim As Long, Dword As Long, dwNeed As Dword, sDevice As AsciiZ * 16
       
       
          If dwMsg& = %LINE_REPLY Then
              If Param2& < 0 Then
                  Print "Line Reply Error"
              Else
                  Print "Line Reply Ok"
              End If
          ElseIf dwMsg& = %LINE_CALLSTATE Then
       
              Select Case Param1&
                  Case %LINECALLSTATE_IDLE
                      If hCall <> 0 Then
                          Print "Line Idle"
                      End If
                  Case %LINECALLSTATE_CONNECTED
                      If hCall <> 0 Then
                          Print "Connected"
                      End If
                  Case %LINECALLSTATE_PROCEEDING
                      Print "Proceeding"
                  Case %LINECALLSTATE_DIALING
                      Print "Dialing..."
                  Case %LINECALLSTATE_DISCONNECTED
       
                      If Param2& = %LINEDISCONNECTMODE_NORMAL Then
                          Print "Disconnected Normal"
                      ElseIf Param2& = %LINEDISCONNECTMODE_BUSY Then
                          Print "Disconnected Busy"
                      ElseIf Param2& = %LINEDISCONNECTMODE_NODIALTONE Then
                          Print "No dial tone"
                      ElseIf Param2& = %LINEDISCONNECTMODE_NOANSWER Then
                          Print "No Answer"
                      End If
                  Case %LINECALLSTATE_BUSY
                      Print "Line Busy"
              End Select
          End If
       
      End Function


    после LineMakeCall (если закомментирован цикл с PeekMessage) сразуже происходит вызов LineDrop, соответсвенно я никуда не звоню. Если между ними вставить что-то вроде Waitkey$ вызов происходит и завершается после нажатия любой клавиши. С незакомментированным циклом PeekMessage программа падает на DispatchMessage(msg) - Unhandled exception... (XP) или Прекращена работа программы (Win7). Без вызова DispatchMessage вызов произходит нормально (почти) и LineDrop происходит после отбоя вызываемого номера. Но смысл весь в том, что нужно видеть процесс дозвона и отбоя, а для этого использовать callback.

    В чем мооя ошибка? В какую сторну ковырять? Help!!!

    p.s. Извиняюсь за сумбурное изложение... :blush:
      А почему у тебя TapiCallback ничего не возвращает?
        B.V., а она должна что-то возвращать?

        MSDN:

        ExpandedWrap disabled
          LONG WINAPI lineInitializeEx(
            LPHLINEAPP lphLineApp,                            
            HINSTANCE hInstance,                              
            LINECALLBACK lpfnCallback,                        
            LPCSTR lpszFriendlyAppName,                        
            LPDWORD lpdwNumDevs,                              
            LPDWORD lpdwAPIVersion,                            
            LPLINEINITIALIZEEXPARAMS lpLineInitializeExParams  
          );

        lpfnCallback

        Address of a callback function that is invoked to determine status and events on the line device, addresses, or calls, when the application is using the "hidden window" method of event notification (for more information see lineCallbackFunc). This parameter is ignored and should be set to NULL when the application chooses to use the "event handle" or "completion port" event notification mechanisms.

        вот я и передаю в функцию lineInitializeEx адрес tapiCallback при помощи функции CODEPTR

        lineInitializeEx(hTapiApp, hInstance, CodePtr(tapiCallback)...

        и в том-же MSDN сказано, что lineCallbackFunc не возвращает значения.

        В моём примере TapiCallback можно объявить и как процедуру, а не как функцию. Похоже разницы от этого никакой, так-что дело не в этом. (Кстати подобный код в PBWin
        работает (без While PeekMessage ... Loop) - дозванивается и выводит сообщения, например в ListBox). В итоге всё снова упирается в особенности консоли и очередь сообщений, а т.к. я в этом далеко не спец приходится спрашивать... :-?
          Цитата gigamaxx @
          В итоге всё снова упирается в особенности консоли и очередь сообщений

          Все упирается в неверное использование PeekMessage, которая в отличие от GetMessage не ждет появления событий в очереди. В итоге твой цикл "быстренько" обрабатывает сообщения, которые уже есть в очереди и завершается, не дожидаясь поступления новых сообщений. Причем поскольку ты зациклил вызов dial "в исследовательских" целях, то не исключено, что при повторных проходах PeekMessage извлекает из очереди сообщения, посланные (и не обработанные) в предыдущем цикле, которые могут быть уже невалидными из-за реинициализации линии.
          Для начала просто замени PeekMessage на GetMessage - если все заработает, то можно будет дальше что-то дорабатывть (например, добавить таймер, чтобы не ждать у моря погоды, и т.п.)
            Цитата gigamaxx @
            Похоже разницы от этого никакой, так-что дело не в этом.

            Я и не говорил, что дело в этом. Просто если процедура обработки объявлена как функция и при этом ничего не возвращает, это логическая ошибка в коде
              leo, с GetMessage не работает, к тому-же из её описания следует что функция возвращает значение не нуль, если сообщение не wm_Quit; 0 - в пpотивном случае.
              Получается, что выхода из цикла не будет (что я и наблюдаю), пока не прийдет wm_Quit.

              B.V. Согласен

              Раскопал пример на С++ Прикреплённый файлПрикреплённый файлtapiwave.zip (61.29 Кбайт, скачиваний: 148)

              Тоже консоль, дозвон и проигрывание wav файла. Так вот внем collback работает! После lineMakeCall идет вызов функции PumpMessages, за ней - lineShutdown.
              (Готовый exe-шник работает, а скомпилировать самому у меня не получилось ни под 6-й студией, ни под 2010 Express).
              Так вот в примере это выглядит так (сокращено):

              ExpandedWrap disabled
                      lRet = lineMakeCall(hLine, &hCall, szPhoneNumber, 0, lpLineCallParams);
                 
                      ...
                      // TAPI callback is called only when messages are dispatched!
                 
                      while (!bReadyToEnd || hCall)
                      {
                      PumpMessages(TRUE);
                      }
                      ...
                      lineShutdown(hLineApp);


              и сама функция PumpMessages:

              ExpandedWrap disabled
                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;
                }


              которую я преобразовал в код PowerBasic, отбросив лишнее:

              ExpandedWrap disabled
                Function PumpMessages(bWaitForMessage As Integer) As Integer
                 
                   Static MSG As tagmsg
                 
                   If bWaitForMessage Then
                 
                      If Not GetMessage(msg, %NULL, 0, 0) Then
                         Function = 0
                      End If
                 
                   Else
                 
                      If Not PeekMessage(msg, %NULL, 0, 0, %PM_REMOVE) Then
                         Function = 1
                      End If
                 
                   End If
                 
                   TranslateMessage(msg)
                   DispatchMessage(msg)
                 
                   Function = 1
                 
                End Function


              вызываю так:

              ExpandedWrap disabled
                  
                  lRet = LineMakeCall (ByVal hLine, hCall, numberToDial, ByVal 0, lineParams)
                 
                   While hCall
                     PumpMessages(1)
                   Loop
                 
                   LineDrop(ByVal hCall, ByVal 0, ByVal 0)


              Не работает - падает....

              p.s. Не ясно, почему в PumpMessages передаётся TRUE, ведь тогда блок else никогда не выполняеся? или я что-то не так понимаю? Если принять, что bWaitForMessage
              всегда равно 1, то получается так:

              ExpandedWrap disabled
                Function PumpMessages() As Integer
                 
                   Static MSG As tagmsg
                 
                   If Not GetMessage(msg, %NULL, 0, 0) Then
                      Function = 0
                   End If
                 
                   TranslateMessage(msg)
                   DispatchMessage(msg)
                 
                   Function = 1
                 
                End Function
                 
                и вызов функции:
                 
                While hCall
                  PumpMessages
                Loop


              тоже не работает.

              Добавлено
              PS Как редактировать сообщение? В конце сообщения добавилось 4 одинаковых вложения
              Прикреплённый файлПрикреплённый файлtapiwave.zip (61.29 Кбайт, скачиваний: 120)
              Прикреплённый файлПрикреплённый файлtapiwave.zip (61.29 Кбайт, скачиваний: 107)
              Прикреплённый файлПрикреплённый файлtapiwave.zip (61.29 Кбайт, скачиваний: 127)
              Прикреплённый файлПрикреплённый файлtapiwave.zip (61.29 Кбайт, скачиваний: 123)
              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
              0 пользователей:


              Рейтинг@Mail.ru
              [ Script execution time: 0.0980 ]   [ 18 queries used ]   [ Generated: 27.06.26, 07:02 GMT ]