Проблема при HTTP-запросе к бирже криптовалют с использованием wininet.dll

 

Здравствуйте!

Делаю HTTP-запросы к API криптовалютной бирже. В связи с невозможностью использования в штатной функции WebRequest  HTTP-метода DELETE, пришлось использовать библиотеку wininet.dll. Но до метода DELETE даже не дошло, проблемы начались уже при использования http-метода GET.

В API биржи есть публичная (не требует аутентификации на биржи) функция time. Для доступа к ней нужно отправить HTTP-запрос с методом GET. Функция возвращает текущее время биржи в виде JSON-объекта: 

{"serverTime": 1499827319559}

Вот мой код.

#property link      "https://www.mql5.com" 
#property version   "1.00" 
#property strict 

//+------------------------------------------------------------------+
#import "wininet.dll"
   int InternetAttemptConnect(int x);
   int InternetOpenW(string &sAgent, int lAccessType, string &sProxyName, string &sProxyBypass, int lFlags);
   int InternetConnectW(int hInternet, string &szServerName, int nServerPort, string &lpszUsername, string &lpszPassword, int dwService, int dwFlags, int dwContext);
   int HttpOpenRequestW(int hConnect, string &Verb, string &ObjectName, string &Version, string &Referer, string &AcceptTypes, uint dwFlags, int dwContext);
   int HttpSendRequestW(int hRequest, string &lpszHeaders, int dwHeadersLength, uchar &lpOptional[], int dwOptionalLength);
   int HttpQueryInfoW(int hRequest, int dwInfoLevel, int &lpvBuffer[], int &lpdwBufferLength, int &lpdwIndex);
   int InternetReadFile(int hFile, uchar &sBuffer[], int lNumBytesToRead, int &lNumberOfBytesRead);
   int InternetCloseHandle(int hInet);
#import
#import "kernel32.dll"
   int GetLastError(void);
#import

//+------------------------------------------------------------------+
#define INTERNET_FLAG_CACHE_IF_NET_FAIL         0x00010000
#define INTERNET_FLAG_IGNORE_CERT_CN_INVALID    0x00001000
#define INTERNET_FLAG_IGNORE_CERT_DATE_INVALID  0x00002000
#define INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP   0x00008000
#define INTERNET_FLAG_KEEP_CONNECTION           0x00400000
#define INTERNET_FLAG_PRAGMA_NOCACHE            0x00000100
#define INTERNET_FLAG_RELOAD                    0x80000000
#define INTERNET_FLAG_SECURE                    0x00800000

//+------------------------------------------------------------------+
int OnInit()
{
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}

//+------------------------------------------------------------------+
void OnTick()
{
}

//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{  
   if (lparam == 'T') TestBinanceApi();
}

//+------------------------------------------------------------------+
void TestBinanceApi()
{
   //Open session
   int sessionHandle = 0; string sAgent = "MQL"; string sProxyName = ""; string sProxyBypass = "";
   sessionHandle = InternetOpenW(sAgent, 0, sProxyName, sProxyBypass, 0);
   Print("sessionHandle = ", sessionHandle, " errorKernel = ", kernel32::GetLastError(), " errorMql = ", GetLastError());
   //Connect to host
   int connectionHandle = 0; string szServerName = "api.binance.com"; string lpszUsername = ""; string lpszPassword = ""; 
   connectionHandle = InternetConnectW(sessionHandle, szServerName, 443, lpszUsername, lpszPassword, 3, 0, 0);
   Print("connectionHandle = ", sessionHandle, " errorKernel = ", kernel32::GetLastError(), " errorMql = ", GetLastError());   
   //Open request
   int requestHandle = 0; string Verb = "GET"; string ObjectName = "/api/v1/time"; string Version = "HTTP/1.1"; string Referer = ""; string AcceptTypes = "";   
   requestHandle = HttpOpenRequestW(connectionHandle, Verb, ObjectName, Version, Referer, AcceptTypes, INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_SECURE, 0);
   Print("requestHandle = ", requestHandle, sessionHandle, " errorKernel = ", kernel32::GetLastError(), " errorMql = ", GetLastError());
   //Send request
   bool isSentRequest = false; string lpszHeaders = ""; uchar lpOptional[];
   isSentRequest = HttpSendRequestW(requestHandle, lpszHeaders, StringLen(lpszHeaders), lpOptional, ArraySize(lpOptional) - 1);
   //Read request
   bool isReadRequest = true; uchar sBuffer[100]; int lNumberOfBytesRead; string readString = "";
   while (true && !IsStopped()) 
   {
      isReadRequest = InternetReadFile(requestHandle, sBuffer, 100, lNumberOfBytesRead); 
      if (isReadRequest == false || lNumberOfBytesRead <= 0) break; 
      readString += CharArrayToString(sBuffer, 0, lNumberOfBytesRead);
   }
   Print("readString = ", readString);
   //Close handles
   bool idClosedRequest = false; if(requestHandle > 0) idClosedRequest = InternetCloseHandle(requestHandle); 
   Print("idClosedRequest = ", idClosedRequest, sessionHandle, " errorKernel = ", kernel32::GetLastError(), " errorMql = ", GetLastError());
   bool isClosedConnection = false; if(connectionHandle > 0) isClosedConnection = InternetCloseHandle(connectionHandle);
   Print("isClosedConnection = ", isClosedConnection, sessionHandle, " errorKernel = ", kernel32::GetLastError(), " errorMql = ", GetLastError()); 
   bool isClosedSession = false; if(sessionHandle > 0) isClosedSession = InternetCloseHandle(sessionHandle);
   Print("isClosedSession = ", isClosedSession, sessionHandle, " errorKernel = ", kernel32::GetLastError(), " errorMql = ", GetLastError());
}

Как вы можете видеть, в коде есть функция для теста запросов. Она вызывается в обработчике событий графика OnChartEvent при нажатии клавиши 'T'. После компиляции и запуска эксперта и после первого нажатия клавиши 'T' все работает и в лог пишет:

PP 0 10:57:01.605 TestBinanceApi (AUDUSD,M1) sessionHandle = 13369356 errorKernel = 0 errorMql = 0

PR 0 10:57:01.605 TestBinanceApi (AUDUSD,M1) connectionHandle = 13369356 errorKernel = 0 errorMql = 0

JK 0 10:57:01.605 TestBinanceApi (AUDUSD,M1) requestHandle = 1336936413369356 errorKernel = 0 errorMql = 0

RK 0 10:57:01.911 TestBinanceApi (AUDUSD,M1) readString = {"serverTime":1525334230666}

LP 0 10:57:01.911 TestBinanceApi (AUDUSD,M1) idClosedRequest = true13369356 errorKernel = 0 errorMql = 0

HL 0 10:57:01.911 TestBinanceApi (AUDUSD,M1) isClosedConnection = true13369356 errorKernel = 0 errorMql = 0

JL 0 10:57:01.911 TestBinanceApi (AUDUSD,M1) isClosedSession = true13369356 errorKernel = 0 errorMql = 0

А вот после второго и всех последующих нажатий клавиши 'T', функция вызывается вот с такой ошибкой в логе:

NJ 0 10:57:05.357 TestBinanceApi (AUDUSD,M1) sessionHandle = 13369356 errorKernel = 0 errorMql = 0

NH 0 10:57:05.357 TestBinanceApi (AUDUSD,M1) connectionHandle = 13369356 errorKernel = 0 errorMql = 0

EE 2 10:57:05.361 TestBinanceApi (AUDUSD,M1) Access violation at 0x00007FFC54FC1830 read to 0xFFFFFFFFFFFFFFFF in 'wininet.dll'

PG 2 10:57:05.370 TestBinanceApi (AUDUSD,M1)               00007FFC54FC1580 48895C2418        mov        [rsp+0x18], rbx

GD 2 10:57:05.370 TestBinanceApi (AUDUSD,M1)               00007FFC54FC1585 48894C2408        mov        [rsp+0x8], rcx

DM 2 10:57:05.370 TestBinanceApi (AUDUSD,M1)               00007FFC54FC158A 55                push       rbp

PO 2 10:57:05.370 TestBinanceApi (AUDUSD,M1)               00007FFC54FC158B 56                push       rsi

...

OE 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC1818 0FB7DE            movzx      ebx, si

EK 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC181B 663BF7            cmp        si, di

FJ 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC181E 737E              jae        0x7ffc54fc189e

NQ 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC1820 0FB7F3            movzx      esi, bx

FP 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC1823 4883C8FF          or         rax, 0xff

JM 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC1827 498B4CF500        mov        rcx, [r13+rsi*8+0x0]

PO 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC182C 0F1F4000          nop        [rax+0x0]

EM 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)    crash -->  00007FFC54FC1830 66837C410200      cmp        word [rcx+rax*2+0x2], 0x0

IO 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC1836 488D4001          lea        rax, [rax+0x1]

ML 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)               00007FFC54FC183A 75F4              jnz        0x7ffc54fc1830

...

RF 2 10:57:05.371 TestBinanceApi (AUDUSD,M1) 00: 0x00007FFC54FC1830

OQ 2 10:57:05.371 TestBinanceApi (AUDUSD,M1) 01: 0x000002A9095E0551

EJ 2 10:57:05.371 TestBinanceApi (AUDUSD,M1) 02: 0x0000000000CC0010

DM 2 10:57:05.371 TestBinanceApi (AUDUSD,M1) 03: 0x000002A96FB20003

ED 2 10:57:05.371 TestBinanceApi (AUDUSD,M1) 04: 0x000002A909CF2834

ES 2 10:57:05.371 TestBinanceApi (AUDUSD,M1) 05: 0x000000B362CFDD88

NI 2 10:57:05.371 TestBinanceApi (AUDUSD,M1)

Как видно из логов, открытия сессии и подключение к хосту проходят успешно (sessionHandle и connectionHandle возвращают ненулевые значения), а проблема возникает при вызове функции HttpOpenRequestW.

Помогите, пожалуйста! Может кто-нибудь сталкивался с данной проблемой?

 
ObjectName - зарезервированное слово. Измените хотя бы на sObjectName.
 
Ihor Herasko:
ObjectName - зарезервированное слово. Измените хотя бы на sObjectName.

Спасибо за замечание! Изменил, но, к сожалению, это проблему не решает.

 
для начала это МТ5 или МТ4? если МТ5 то тип всех хендлов в импорте надо заменить на long
 
Комбинатор:
для начала это МТ5 или МТ4? если МТ5 то тип всех хендлов в импорте надо заменить на long

Это МТ5. Поменял. Ошибка осталась((

 

Немного подшаманил код. Теперь работает.

PS. В принципе, ваш оригинальный код тоже работает.

Просто HttpOpenRequestW любит AcceptTypes = NULL и не любит AcceptTypes = ""

Файлы:
 
. ... Rick D. ... .:

Немного подшаманил код. Теперь работает.

PS. В принципе, ваш оригинальный код тоже работает.

Просто HttpOpenRequestW любит AcceptTypes = NULL и не любит AcceptTypes = ""

Все работает! И на МТ4 тоже. Проблема решена! Большое Вам спасибо!!

 
В WebRequest теперь разрешены все HTTP методы, а также добавились SocketXXX функции для сырых сокетов.