Что нового

Падает приложение на CallBack функции

kodges

Новичок
Сообщения
42
Репутация
0
Моя программа подключается к программе Quik через trans2quik.dll для получения транзакций. Соединение устанавливается все нормально, регистрируются колбек функции, запускается импорт транзакций из Quik в мою программу, но проблема в том что там импорт идет потоком и для импорта 50 транзакций соответственно колбек функция вызывается 50 раз. Раз 10-15 отрабатывается корректно, а потом скрипт падает с ошибкой. Время выполнения колбек функции менее секунды. Ошибка в подключенной библиотеке:
"C:\Program Files (x86)\AutoIt3\Include\WinAPIGdiInternals.au3" (458) : ==> Variable used without being declared.:
При том что в указанной строке переменная нормально объявлена с помощью Local.
Код:
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <DateTimeConstants.au3>
#include <WinAPI.au3>
#include <Date.au3>
#include <Array.au3>


Opt("GUIOnEventMode", 1)            ; Включает режим OnEvent (по событию)
Opt("MustDeclareVars", 1)            ; Явное объявление переменных


Global $DEBUG_INFO = True
Local $ErrMessage = DllStructCreate("char[1024]")
Local $hDll = DllOpen(@ScriptDir & "\trans2quik.dll")
Local $QuikConnectStatus = False, $ImportQuikConnectLabel
local $TradeArray[0]
Local $DLLResult

;-- Регистрируем колбек функции
Local $CallbackStatusOrder = DllCallbackRegister("pfnOrderStatusCallback", "ptr", "long;INT64;INT64;str;str;double;INT64;double;long;INT64")
Local $CallbackStatusConnect = DllCallbackRegister("pfConnectionStatusCallback", "ptr", "long;long;str")

_ConnectToQuik()

Sleep(5000)
Exit

While 1
    Sleep(10)
WEnd

;-- Функция подключения к Quik
Func _ConnectToQuik()
    __DEBUG__("_ConnectToQuik", "START")
    If $QuikConnectStatus = True Then
        __DEBUG__("_ConnectToQuik", "END")
        Return
    EndIf
    Local $PathQuik = "C:\Market\Quik"

    ;-- Устанавливаем соединение
    __DEBUG__("Устанавливаем соединение с Quik", "")
    $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_CONNECT", "str", $PathQuik, "long*", 0, "ptr", DllStructGetPtr($ErrMessage), "dword", DllStructGetSize($ErrMessage))
    If Not $DLLResult[0] = 0 Then
        GUICtrlSetData($ImportQuikConnectLabel, "Подключение отсутствует")
        GUICtrlSetBkColor($ImportQuikConnectLabel, 0xffcfad)
        ConsoleWrite("Не удалось подключиться к Quik. Res:" & $DLLResult[0] & "; ErrCode:" & $DLLResult[2] & "; ErrMess:" & DllStructGetData($ErrMessage, 1) & @CRLF)
        AdlibRegister("_ConnectToQuik", 5000)
        $QuikConnectStatus = False
        __DEBUG__("Не удалось установить соедиенение с Quik", "")
    Else
        ;-- Устанавливаем колбек статуса соединения
        $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_SET_CONNECTION_STATUS_CALLBACK", "ptr", DllCallbackGetPtr($CallbackStatusConnect), "long*", 0, "str", DllStructGetPtr($ErrMessage), "dword", DllStructGetSize($ErrMessage))
        If Not $DLLResult[0] = 0 Then
            ConsoleWrite("Не удалось установить колбек статуса соединения. Res:" & $DLLResult[0] & "; ErrCode:" & $DLLResult[2] & "; ErrMess:" & DllStructGetData($ErrMessage, 1) & @CRLF)
            ConsoleWrite("Отключаемся от Quik." & @CRLF)
            DllCall($hDll, "long", "TRANS2QUIK_DISCONNECT", "long*", 0, "ptr", DllStructGetPtr($ErrMessage), "dword", DllStructGetSize($ErrMessage))
            AdlibRegister("_ConnectToQuik", 5000)
            $QuikConnectStatus = False
            __DEBUG__("_ConnectToQuik", "END")
            Return
        Else
            __DEBUG__("Колбек функция статуса соединения установлена успешно", "")
        EndIf
        ;-- Подписываемся на получение трейдов
        $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_SUBSCRIBE_TRADES", "str", "", "str", "")
        If Not $DLLResult[0] = 0 Then
            ConsoleWrite("Не удалось подписаться на получение трейдов. Res:" & $DLLResult[0] & "; ErrCode:" & $DLLResult[2] & "; ErrMess:" & DllStructGetData($ErrMessage, 1) & @CRLF)
            ConsoleWrite("Отключаемся от Quik." & @CRLF)
            DllCall($hDll, "long", "TRANS2QUIK_DISCONNECT", "long*", 0, "ptr", DllStructGetPtr($ErrMessage), "dword", DllStructGetSize($ErrMessage))
            AdlibRegister("_ConnectToQuik", 5000)
            $QuikConnectStatus = False
            __DEBUG__("_ConnectToQuik", "END")
            Return
        Else
            __DEBUG__("Подписка на получение трейдов прошла успешно", "")
        EndIf
        ;-- Устанавливаем колбек получение трейдов
        $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_START_TRADES", "ptr", DllCallbackGetPtr($CallbackStatusOrder))
        If Not $DLLResult[0] = 0 Then
            ConsoleWrite("Не удалось установить колбек получаение трейдов. Res:" & $DLLResult[0] & "; ErrCode:" & $DLLResult[2] & "; ErrMess:" & DllStructGetData($ErrMessage, 1) & @CRLF)
            ConsoleWrite("Отключаемся от Quik." & @CRLF)
            DllCall($hDll, "long", "TRANS2QUIK_DISCONNECT", "long*", 0, "ptr", DllStructGetPtr($ErrMessage), "dword", DllStructGetSize($ErrMessage))
            AdlibRegister("_ConnectToQuik", 5000)
            $QuikConnectStatus = False
            __DEBUG__("_ConnectToQuik", "END")
            Return
        Else
            __DEBUG__("Колбек функция получения трейдов установлена успешно", "")
        EndIf
        GUICtrlSetData($ImportQuikConnectLabel, "Подключение установлено")
        GUICtrlSetBkColor($ImportQuikConnectLabel, 0xcdffad)
        AdlibUnRegister("_ConnectToQuik")
        $QuikConnectStatus = True
        __DEBUG__("Соединение с Quik установлено", "")
    EndIf
    __DEBUG__("_ConnectToQuik", "END")
EndFunc   ;==>_ConnectToQuik


;-- Колбек функция получения информации о сделках
Func pfnOrderStatusCallback($nMode, $dNumber, $dOrderNumber, $ClassCode, $SecCode, $dPrice, $nQty, $dValue, $nIsSell, $tDescriptor)
    __DEBUG__("pfnOrderStatusCallback", "START")
    Local $hTimer = TimerInit()
    Local $tArray[14]
    Local $date = DllCall($hDll, "long", "TRANS2QUIK_TRADE_DATE", "INT64", $tDescriptor)[0]
    Local $time = DllCall($hDll, "long", "TRANS2QUIK_TRADE_TIME", "INT64", $tDescriptor)[0]
    $date = StringMid($date, 1, 4) & "-" & StringMid($date, 5, 2) & "-" & StringMid($date, 7, 2)
    $time = StringMid($time, 1, 2) & ":" & StringMid($time, 3, 2) & ":" & StringMid($time, 5, 2)
    Local $Operation = ($nIsSell == 0) ? 1 : 0
    $tArray[0] = $date & " " & $time
    $tArray[1] = $dNumber
    $tArray[2] = DllCall($hDll, "str", "TRANS2QUIK_TRADE_ACCOUNT", "INT64", $tDescriptor)[0]
    $tArray[3] = $ClassCode
    $tArray[4] = $SecCode
    $tArray[5] = $Operation
    $tArray[6] = $nQty
    $tArray[7] = $dPrice
    $tArray[8] = $dValue
    $tArray[9] = $dValue / ($dPrice * $nQty)
    $tArray[10] = DllCall($hDll, "double", "TRANS2QUIK_TRADE_TS_COMMISSION", "INT64", $tDescriptor)[0]
    $tArray[11] = DllCall($hDll, "str", "TRANS2QUIK_TRADE_BROKERREF", "INT64", $tDescriptor)[0]
    $tArray[12] = DllCall($hDll, "str", "TRANS2QUIK_TRADE_CURRENCY", "INT64", $tDescriptor)[0]
    $tArray[13] = DllCall($hDll, "long", "TRANS2QUIK_TRADE_KIND", "INT64", $tDescriptor)[0]
    _ArrayAdd($TradeArray, _ArrayToString($tArray, ";"))
    ConsoleWrite($nMode & "|"& $dNumber & @CRLF)
    Local $iDiff = TimerDiff($hTimer)
    ConsoleWrite("время работы: "& $iDiff & @CRLF)
    __DEBUG__("pfnOrderStatusCallback", "END")
EndFunc   ;==>pfnOrderStatusCallback


;-- Колбек функция проверки подключения к Quik
Func pfConnectionStatusCallback($nConnectionEvent, $pnExtendedErrorCode, $lpstrErrorMessage)
    __DEBUG__("pfConnectionStatusCallback", "START")
    Switch $nConnectionEvent
        Case 8
            ConsoleWrite("Соединение между терминалом QUIK и сервером установлено. Res:" & $nConnectionEvent & "; ErrCode:" & $pnExtendedErrorCode & "; ErrMess:" & $lpstrErrorMessage & @CRLF)
        Case 9
            ConsoleWrite("Соединение между терминалом QUIK и сервером разорвано. Res:" & $nConnectionEvent & "; ErrCode:" & $pnExtendedErrorCode & "; ErrMess:" & $lpstrErrorMessage & @CRLF)
        Case 10
            ConsoleWrite("Соединение между DLL и терминалом QUIK установлено. Res:" & $nConnectionEvent & "; ErrCode:" & $pnExtendedErrorCode & "; ErrMess:" & $lpstrErrorMessage & @CRLF)
        Case 11
            ConsoleWrite("Соединение между DLL и терминалом QUIK разорвано. Res:" & $nConnectionEvent & "; ErrCode:" & $pnExtendedErrorCode & "; ErrMess:" & $lpstrErrorMessage & @CRLF)
            AdlibRegister("_ConnectToQuik", 5000)
    EndSwitch
    __DEBUG__("pfConnectionStatusCallback", "END")
EndFunc   ;==>pfConnectionStatusCallback


;-- Функция вывода дебаг информации в консоль
Func __DEBUG__($_Func = "", $_Status = "")
    If $DEBUG_INFO = True Then
        Local $Date ;= @YEAR & "-" & @MON & "-" & @MDAY & " "
        Local $Time = @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC
        ConsoleWrite($Date & $Time & ' - ' & $_Func & '(): ' & $_Status & @CRLF)
    EndIf
EndFunc   ;==>__DEBUG__

Вывод в консоль получается такой:
Код:
....
16:23:44.241 - pfnOrderStatusCallback(): START
1|1925034015996323417
16:23:44.241 - pfnOrderStatusCallback(): END
время работы: 0.3866
16:23:44.241 - pfnOrderStatusCallback(): START
1|1925034015996323418
16:23:44.242 - pfnOrderStatusCallback(): END
время работы: 0.3299
16:23:44.242 - pfnOrderStatusCallback(): START
"C:\Program Files (x86)\AutoIt3\Include\WinAPIGdiInternals.au3" (458) : ==> Variable used without being declared.:
Local $aResult = DllCall("user32.dll", "bool", "RedrawWindow", "hwnd", $hWnd, "struct*", $tRECT, "handle", $hRegion, "uint", $iFlags)
Local $aResult^ ERROR
16:23:44.242 - pfnOrderStatusCallback(): END
!>16:23:44 AutoIt3.exe ended.rc:-1073741819
+>16:23:44 AutoIt3Wrapper Finished.
>Exit code: 3221225477    Time: 2.809

Почему программа падает?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
С Callback'ами всегда были проблемы...
Попробуй убрать Opt("MustDeclareVars", 1), или добавить Global $aResult в начало скрипта.
И скорее всего у тебя ещё проблема с рекурсией, из Callback функции зацикливается функция которая её же и вызывает (по AdlibRegister).
Это баг AutoIt'а однозначно, нужно бы выявить более лаконичный пример чтобы показать разработчикам.
 
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
Вообще странная хрень происходит при работе колбеков.. Ошибки то одна то другая в разных местах на то что не объявленная переменная, хотя они объявлены все везде у меня. А если я закомментирую регистрацию колбек функции то прога работает нормально без ошибок. Вопрос как забороть чтобы с колбеками и без ошибок ?
Сообщение автоматически объединено:

Попробуй убрать Opt("MustDeclareVars", 1), или добавить Global $aResult в начало скрипта.
Не помогло ((
Может быть можно как то больше памяти выделить чтобы оно не глючило ? Если ошибки с разных местах проявляются это ведь получается проблема на уровне винды возникает, а не приложения, или нет?
 
Последнее редактирование:

Tempo

AutoIT Гуру
Сообщения
616
Репутация
205
Попробуйте уделить больше внимания типизации в Dll функциях.
Если вы используете библиотеку из этого сообщения. Колбеки из trans2quik_api.h
C++:
typedef void (__stdcall *TRANS2QUIK_CONNECTION_STATUS_CALLBACK) (
                            long nConnectionEvent
                            , long nExtendedErrorCode
                            , LPCSTR lpcstrInfoMessage);

typedef unsigned __int64 EntityNumber;
typedef __int64 Quantity;
typedef intptr_t TradeDescriptor;
typedef void (__stdcall *TRANS2QUIK_TRADE_STATUS_CALLBACK)      (
                            long nMode
                            , EntityNumber dNumber
                            , EntityNumber dOrderNumber
                            , LPCSTR ClassCode
                            , LPCSTR SecCode
                            , double dPrice
                            , Quantity nQty
                            , double dValue
                            , long nIsSell
                            , TradeDescriptor tradeDescriptor);

И intptr_t из vcruntime.h
C++:
#ifdef _WIN64
    typedef __int64          intptr_t;
#else
    typedef int              intptr_t;
#endif

Как минимум колбеки должны выглядеть так
Код:
DllCallbackRegister(..., 'none', 'long;long;str')
DllCallbackRegister(..., 'none', 'long;uint64;uint64;str;str;double;int64;double;long;int_ptr')
 
Последнее редактирование:
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
Если вы используете библиотеку из этого сообщения сообщения. Колбеки из trans2quik_api.h
Да, именно её использую.
Колбеки должны выглядеть так
Код:
DllCallbackRegister(..., 'none', 'long;long;str')
DllCallbackRegister(..., 'none', 'long;int64;int64;str;str;double;int64;double;long;int_ptr')
Ну у меня в принципе также только вместо none было ptr, ну а int_ptr или int64 по-моему нет разницы. Но я поправил как вы рекомендовали.
Все равно падает. Причем запускаю несколько раз.. 1-2 раза из 10 запустится и работает без ошибок, а разов 8 падает на колбеке.
 

Tempo

AutoIT Гуру
Сообщения
616
Репутация
205
Да, именно её использую.

Ну у меня в принципе также только вместо none было ptr, ну а int_ptr или int64 по-моему нет разницы. Но я поправил как вы рекомендовали.
Все равно падает. Причем запускаю несколько раз.. 1-2 раза из 10 запустится и работает без ошибок, а разов 8 падает на колбеке.
Я отредактировал сообщение. Посмотрите как минимум на то что у вас не хватало 1 параметра.
 
Последнее редактирование:
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
Посмотрите как минимум на то что у вас не хватало 1 параметра.
Вот сейчас не понял. Где чего не хватает? сверил вроде все 1 в 1.
Код:
Local $CallbackStatusConnect = DllCallbackRegister("pfConnectionStatusCallback", "none", "long;long;str")
Local $CallbackStatusOrder = DllCallbackRegister("pfnOrderStatusCallback", "none", "long;int64;int64;str;str;double;int64;double;long;int_ptr")
 

Tempo

AutoIT Гуру
Сообщения
616
Репутация
205
Вот сейчас не понял. Где чего не хватает? сверил вроде все 1 в 1.
Не на тот колбек посмотрел...

Пересмотрите другие Dll функции. Особенно указатели intptr_t размер которых зависит от x86/x64.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
странная хрень происходит
Скорее всего всё из за рекурсии. Избавься от AdlibRegister("_ConnectToQuik", 5000) и всё должно стать на свои места...
Код:
...

Global $iConnect_Timer = 0
;_ConnectToQuik()

;Sleep(5000)
;Exit

While 1
    If $iConnect_Timer And TimerDiff($iConnect_Timer) >= 5000 Then
        $iConnect_Timer = 0
        _ConnectToQuik()
    EndIf
    
    Sleep(10)
WEnd

;-- Функция подключения к Quik
Func _ConnectToQuik()
    ...
        $iConnect_Timer = TimerInit()
        ;AdlibRegister("_ConnectToQuik", 5000)
    ...
EndFunc
 
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
К сожалению проблема сохраняется.
Мне кажется это из-за того что программа одномоментно вынуждена работать по своим функциями и плюс в любой момент прилетают колбеки, а так как все работает в одном потоке, возникает когнитивный диссонанс и следовательно сносит крышу... Надо попробовать вынести работу колбеков в отдельный скрыто работающий exe файл.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
В новых версиях есть Volatile, хоть и экспериментальный, но можно попробовать использовать для Callback функции (Volatile Func pfnOrderStatusCallback(...)).
 
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
В общем и так падает и сяк падает... Сделал отдельный файлик, который не делает ничего кроме как получает колбеки и сует данные из них в sqlite базу которая в памяти находится. Минимум кода и то падает и даже при том что я для колбеков прописал Volatile. И чистенько так падает, без ошибок:
Код:
pfnOrderStatusCallback(): START
pfnOrderStatusCallback(): END
pfnOrderStatusCallback(): START
pfnOrderStatusCallback(): END
pfnOrderStatusCallback(): START
pfnOrderStatusCallback(): END
pfnOrderStatusCallback(): START
+>22:10:49 AutoIt3.exe ended.rc:0
+>22:10:49 AutoIt3Wrapper Finished.
>Exit code: 0    Time: 28.29

Не знаю что с этим всем делать (( А проблема в том что колбеки сыпятся каждый раз с начала до конца весь список, если бы можно было получать частями, можно было бы отрабатывать, а они если есть 100 записей, они каждый раз от 1 начинают сыпаться.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Ещё предположение... у тебя в скрипте нет случайно запуска этой функции по #OnAutoItStartRegister?
 
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
В общем вывод к которому я пришел следующий... Autoit для автоматизации неплох, но не смотря на обширные возможности все же софт на нем писать не вариант...
Перешел на Qt5...
 
Последнее редактирование:
Верх