Что нового

Падает приложение на 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 552
Репутация
2 429
С Callback'ами всегда были проблемы...
Попробуй убрать Opt("MustDeclareVars", 1), или добавить Global $aResult в начало скрипта.
И скорее всего у тебя ещё проблема с рекурсией, из Callback функции зацикливается функция которая её же и вызывает (по AdlibRegister).
Это баг AutoIt'а однозначно, нужно бы выявить более лаконичный пример чтобы показать разработчикам.
 
Автор
kodges

kodges

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

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

Tempo

Скриптер
Сообщения
597
Репутация
190
Попробуйте уделить больше внимания типизации в 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

Скриптер
Сообщения
597
Репутация
190
Да, именно её использую.

Ну у меня в принципе также только вместо 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

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

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

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 552
Репутация
2 429
странная хрень происходит
Скорее всего всё из за рекурсии. Избавься от 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 552
Репутация
2 429
В новых версиях есть 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 552
Репутация
2 429
Ещё предположение... у тебя в скрипте нет случайно запуска этой функции по #OnAutoItStartRegister?
 
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
Ещё предположение... у тебя в скрипте нет случайно запуска этой функции по #OnAutoItStartRegister?
Нет. До этого момента я даже и не знал о такой фишке...

Вот тестовый стенд так сказать, ничего лишнего. Просто получаем колбеки и пихаем в базу которая в памяти. И все идеально работает если колбеков немного ну штук 10 плюс минус... если их несколько десятков тогда где-то в районе обработки 15-20 колбека программа вываливается.
Код:
#include <Json.au3>
#include <SQLite.au3>
#include <SQLite.dll.au3>


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


Global $DEBUG_INFO = True
Local _
$FolderName = "Proga1", _                                ; Название программы
$DataDir = @AppDataDir & "\" & $FolderName & "\", _          ; Папка с данными
$FileConf = $DataDir & "config.dat", _                    ; Файл конфигурации
$FileDB = $DataDir & "database.db", _                        ; Файл базы данных
$GConf, _                                                 ; Переменная глобального конфига
$ErrMessage = DllStructCreate("char[1024]"), _            ; Создаем структуру для обработки ошибок с trans2quik.dll
$hDll = DllOpen(@ScriptDir & "\trans2quik.dll"), _        ; Открываем дескриптор для работы с trans2quik.dll
$ErrMessage, $hDll, $QuikConnectStatus, $DLLResult, _
$hdb, $mdb, $sql_query, $sql_query_hash, $sql_result, $sql_row, _
$i, $j, $k, $n, $m, $Item


__DEBUG__("PROGRAMM", "START")
;-------------------------------------------------------------------------------
; Получаем конфигурацию
;-------------------------------------------------------------------------------
If FileExists($FileConf) Then
    $GConf = Json_Decode(FileReadLine($FileConf))
EndIf


;-------------------------------------------------------------------------------
; Проверяем есть ли база данных, елси нет, то создаем
;-------------------------------------------------------------------------------
_SQLite_Startup()
If @error Then
    ConsoleWrite("Не удалось загрузить библиотеку SQLite3")
    Exit -1
EndIf
ConsoleWrite("Version SQLite3 = " & _SQLite_LibVersion() & @CRLF)
#cs
$hdb = _SQLite_Open($FileDB)
If @error Then
    ConsoleWrite("Не удалось открыть базу данных!")
    Exit -1
EndIf

_SQLite_Exec($hdb, "PRAGMA journal_mode = WAL2;")
_SQLite_SetTimeout($hdb, 1000*60*5)
#ce
;-- Создаем временную базу в памяти для уникальных номеров сделок
$mdb = _SQLite_Open()
If @error Then
    ConsoleWrite("Не удалось открыть базу данных в памяти!")
    Exit -1
EndIf
; создает таблицу для временного хранения
_SQLite_Exec($mdb, "CREATE TABLE IF NOT EXISTS trades (id INTEGER PRIMARY KEY AUTOINCREMENT, opendate TEXT DEFAULT '', number INTEGER NOT NULL UNIQUE, account TEXT DEFAULT '', class TEXT DEFAULT '', ticker TEXT DEFAULT '', operation INTEGER DEFAULT 0, count INTEGER DEFAULT 0, price REAL DEFAULT 0.00, volume REAL DEFAULT 0.00, ticprice REAL DEFAULT 0.00, comis REAL DEFAULT 0.00, comment TEXT DEFAULT '', currency TEXT DEFAULT '');")
_SQLite_Exec($mdb, "CREATE INDEX IF NOT EXISTS i_id ON trades (id);")                                    ; Создаем индекс для колонки id
_SQLite_Exec($mdb, "CREATE INDEX IF NOT EXISTS i_number ON trades (number);")                         ; Создаем индекс для колонки number


;-------------------------------------------------------------------------------
; Подключаемся к квику
;-------------------------------------------------------------------------------
;-- Регистрируем колбек функции
Local $CallbackStatusConnect = DllCallbackRegister("pfConnectionStatusCallback", "none", "long;long;str")
Local $CallbackStatusOrder = DllCallbackRegister("pfnOrderStatusCallback", "none", "long;int64;int64;str;str;double;int64;double;long;int_ptr")


_ConnectToQuik()


;-- Функция подключения к Quik
Func _ConnectToQuik()
    __DEBUG__("_ConnectToQuik", "START")
    If $QuikConnectStatus = True Then
        __DEBUG__("_ConnectToQuik", "END")
        Return
    EndIf
    Local $PathQuik = Json_ObjGet($GConf, "ImportQuikPath")
    ;-- Устанавливаем соединение
    __DEBUG__("Устанавливаем соединение с Quik", "")
    $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_CONNECT", "str", $PathQuik, "long*", 0, "ptr", DllStructGetPtr($ErrMessage), "dword", DllStructGetSize($ErrMessage))
    If @error Then
        ConsoleWrite("Res:" & $DLLResult[0] & "; ErrCode:" & $DLLResult[2] & "; ErrMess:" & DllStructGetData($ErrMessage, 1) & @CRLF)
        $QuikConnectStatus = False
        AdlibRegister("_ConnectToQuik", 5000)
        __DEBUG__("Не удалось установить соедиенение с Quik", "")
        __DEBUG__("_ConnectToQuik", "END")
        Return
    Else
        AdlibUnRegister("_ConnectToQuik")
        ;-- Устанавливаем колбек статуса соединения
        $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_SET_CONNECTION_STATUS_CALLBACK", "ptr", DllCallbackGetPtr($CallbackStatusConnect), "long*", 0, "str", DllStructGetPtr($ErrMessage), "dword", DllStructGetSize($ErrMessage))
        If @error 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))
            $QuikConnectStatus = False
            AdlibRegister("_ConnectToQuik", 5000)
            __DEBUG__("_ConnectToQuik", "END")
            Return
        Else
            __DEBUG__("Колбек функция статуса соединения установлена успешно", "")
        EndIf
        ;-- Подписка на трейды
        If Not _subscribe_trades() = 0 Then Return
        $QuikConnectStatus = True
        __DEBUG__("Соединение с Quik установлено", "")
    EndIf
    __DEBUG__("_ConnectToQuik", "END")
EndFunc   ;==>_ConnectToQuik


;-- Подписка на получение трейдов
Func _subscribe_trades()
    ;-- Подписываемся на получение трейдов
    $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_SUBSCRIBE_TRADES", "str", "", "str", "")
    If @error 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))
        $QuikConnectStatus = False
        AdlibRegister("_ConnectToQuik", 5000)
        __DEBUG__("_ConnectToQuik", "END")
        Return 1
    Else
        __DEBUG__("Подписка на получение трейдов прошла успешно", "")
    EndIf
    ;-- Запускаем получение трейдов
    $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_START_TRADES", "ptr", DllCallbackGetPtr($CallbackStatusOrder))
    If @error 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))
        $QuikConnectStatus = False
        AdlibRegister("_ConnectToQuik", 5000)
        __DEBUG__("_ConnectToQuik", "END")
        Return 1
    Else
        __DEBUG__("Колбек функция получения трейдов установлена успешно", "")
    EndIf
    AdlibUnRegister("_subscribe_trades")
    Return 0
EndFunc   ;==>_subscribe_trades


;-- Колбек функция получения информации о сделках
Volatile Func pfnOrderStatusCallback($nMode, $dNumber, $dOrderNumber, $ClassCode, $SecCode, $dPrice, $nQty, $dValue, $nIsSell, $tDescriptor)
    __DEBUG__("pfnOrderStatusCallback", "START")
    If Not _SQLite_QuerySingleRow($mdb, "SELECT * FROM trades WHERE number = " & $dNumber & ";", $sql_row) = $SQLITE_OK Then
        If Not _SQLite_Exec($mdb, "INSERT INTO trades (number) VALUES (" & $dNumber & ");") = $SQLITE_OK Then
            ConsoleWrite(@error)
            __DEBUG__("pfnOrderStatusCallback", "END")
            Return
        EndIf
    Else
        __DEBUG__("pfnOrderStatusCallback", "END")
        Return
    EndIf

    AdlibUnRegister("_subscribe_trades")

    Local $date = DllCall($hDll, "long", "TRANS2QUIK_TRADE_DATE", "INT64", $tDescriptor)
    If @error Then
        ConsoleWrite(@error)
        Return
    EndIf
    $date[0] = StringMid($date[0], 1, 4) & "-" & StringMid($date[0], 5, 2) & "-" & StringMid($date[0], 7, 2)

    Local $time = DllCall($hDll, "long", "TRANS2QUIK_TRADE_TIME", "INT64", $tDescriptor)
    If @error Then
        ConsoleWrite(@error)
        Return
    EndIf
    $time[0] = StringMid($time[0], 1, 2) & ":" & StringMid($time[0], 3, 2) & ":" & StringMid($time[0], 5, 2)

    Local $datetime = String($date[0] & " " & $time[0])

    Local $Acc = DllCall($hDll, "str", "TRANS2QUIK_TRADE_ACCOUNT", "INT64", $tDescriptor)
    If @error Then
        ConsoleWrite(@error)
        Return
    EndIf
    Local $account = $Acc[0]

    Local $operation = ($nIsSell == 0) ? 1 : 0
    Local $ticprice = Number($dValue) / (Number($dPrice) * Int($nQty))

    Local $Comis = DllCall($hDll, "double", "TRANS2QUIK_TRADE_TS_COMMISSION", "INT64", $tDescriptor)
    If @error Then
        ConsoleWrite(@error)
        Return
    EndIf
    Local $comision = $Comis[0]

    Local $Coment = DllCall($hDll, "str", "TRANS2QUIK_TRADE_BROKERREF", "INT64", $tDescriptor)
    If @error Then
        ConsoleWrite(@error)
        Return
    EndIf
    Local $commentary = $Coment[0]

    Local $Curr = DllCall($hDll, "str", "TRANS2QUIK_TRADE_CURRENCY", "INT64", $tDescriptor)
    If @error Then
        ConsoleWrite(@error)
        Return
    EndIf
    Local $currency = $Curr[0]

    $sql_query = "UPDATE trades SET opendate=" & _SQLite_Escape($datetime) & ", account=" & _SQLite_Escape($account) & ", class=" & _SQLite_Escape($ClassCode) & ", ticker=" & _SQLite_Escape($SecCode) & _
        ", operation=" & $operation & ", count=" & $nQty & ", price=" & $dPrice & ", volume=" & $dValue & ", ticprice=" & $ticprice & ", comis=" & $comision & ", comment=" & _SQLite_Escape($commentary) & _
        ", currency=" & _SQLite_Escape($currency) & " WHERE number=" & $dNumber & ";"
    If Not _SQLite_Exec($mdb, $sql_query) = $SQLITE_OK Then
        ConsoleWrite("Не удалось выполнить запрос: " & $sql_query)
        _SQLite_Exec($mdb, "DELETE FROM trades WHERE number = " & $dNumber & ";")
        Return
    EndIf

    Local $DLLResult = DllCall($hDll, "long", "TRANS2QUIK_UNSUBSCRIBE_TRADES")
    If @error 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))
        $QuikConnectStatus = False
        AdlibRegister("_ConnectToQuik", 5000)
        __DEBUG__("_ConnectToQuik", "END")
        Return
    Else
        __DEBUG__("Отписка от получения трейдов прошла успешно", "")
        AdlibRegister("_subscribe_trades", 3000)
    EndIf
    __DEBUG__("pfnOrderStatusCallback", "END")
    Return
EndFunc   ;==>pfnOrderStatusCallback


;-- Колбек функция проверки подключения к Quik
Volatile 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)
            $QuikConnectStatus = False
            AdlibRegister("_ConnectToQuik", 5000)
    EndSwitch
    __DEBUG__("pfConnectionStatusCallback", "END")
EndFunc   ;==>pfConnectionStatusCallback


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


Sleep(2147483647) ; 24 дня.

И еще дополню. Если колбек функцию сделать пустой, то любое количество колбеков отрабатывается нормально. То есть проблема явно в том что колбеки занимают время основного потока программы больше разрешенного и после этого прога вылетает. Типо так:
Код:
Volatile Func pfnOrderStatusCallback($nMode, $dNumber, $dOrderNumber, $ClassCode, $SecCode, $dPrice, $nQty, $dValue, $nIsSell, $tDescriptor)
; пусто
EndFunc

Сообщение автоматически объединено:

Хотя нет, вру.. Время выполнения не имеет значения. А имеет значение именно момент запуска колбека наверно. Если он совпадает с каким то действием самой программы то происходит сбой. Для теста сделал вывод чисел каждую секунду 1, 2, 3 и т.д. с нарастанием бесконечно, и колбек объявленный через Volatile все равно блокирует основной вывод программы. Вывод чисел прерывается во время работы колбека. При этом в колбек функцию поставил Sleep(25000) и не падает по времени, но в момент запуска падает если запуск колбека совпадает с чем то еще видимо.
 
Последнее редактирование:
Верх