Странности с получением интернет странички!

 

Вот текст программы, которая читает главную страничку mql4.com и записывает результат чтения в файл Page.htm

Но, если поменять местами первые 2 строчки в программе start (т.е. сначала получить страницу, а потом открыть файл), то файл не открывается и в закладке Эксперты МТ4 пишется ошибка с именем файла, в котором полная билеберда!

Видимо, после вызова функции чтения страницы GetWebPage каким-то странным образом изменяется код основной программы.

Кто знает: что за чудеса? :)

#import "wininet.dll"
int InternetOpenA (string lpszAgent, int dwAccessType, string lpszProxyName, string lpszProxyBypass, int dwFlags);
int InternetOpenUrlA (int hInternetSession, string sUrl, string sHeaders="", int lHeadersLength=0, int lFlags=0, int lContext=0);
int InternetReadFile (int hFile, string sBuffer, int lNumBytesToRead, int& lNumberOfBytesRead[]);
int InternetCloseHandle (int hInet);
#import

#define INTERNET_FLAG_RELOAD            0x80000000
#define INTERNET_FLAG_NO_CACHE_WRITE    0x04000000
#define INTERNET_FLAG_PRAGMA_NOCACHE    0x00000100

string      NameAgent = "Mozilla"; // имя IE
string      MainPage;   // переменная для сохранения считанной страницы
string      MainAdress = "https://www.mql4.com/ru/"; // адрес считываемой страницы
string      FileName = "Page.htm";
int         h;

int start() {
      h = FileOpen (FileName, FILE_BIN|FILE_WRITE); // открытие файла
      GetWebPage (MainAdress,MainPage);   // получение страницы: https://www.mql4.com/ru/ в переменную: MainPage
      FileWriteString  (h, MainPage, StringLen(MainPage)); // запись страницы в файл
      FileClose (h); // закрытие дескриптора файла
      return (0);
}

bool GetWebPage (string Url, string& WebPage) {

      int     Len[]  = {1};
      string  Buf    = "";

      // открытие сессии и получение дескриптора считанной страницы
      int h1 = InternetOpenA (NameAgent, 0, "0", "0", 0);
      int h2 = InternetOpenUrlA (h1, Url, "0", 0, INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_RELOAD, 0);
      if (h2 == 0) return(false);
      
      // чтение страницы в переменную MainPage
      while (true) {
            if (InternetReadFile (h2, Buf, 128, Len) <= 0 || Len[0] == 0) break;
            WebPage = StringConcatenate (WebPage, StringSubstr(Buf, 0, Len[0]));
      }
      
      // закрытие всех дескрипторов
      InternetCloseHandle (h2); 
      InternetCloseHandle (h1);
      return (true);
}

 

видать с памятью играетесь неправильно.

происходит сбой.


по строчно раскоментаривайте код функции

GetWebPage 
и смотрите момент когда собьет
 

нельзя делать

InternetReadFile 

в строковый буфер, либо его заранее надо инициализировать длиной в 128 символов минимум, например, 128 пробелов.

string  Buf    = "здесь надо написать 128 пробелов";

Еще не стоит

if (InternetReadFile (h2, Buf, 128, Len) <= 0 || Len[0] == 0) break;

так как MQL не содержит стандарта, в каком порядке обрабатываются логические выражения. Поэтому этот порядок лучше задать явно:

if (InternetReadFile (h2, Buf, 128, Len) <= 0) break;
if (Len[0] == 0) break;
 

Спасибо! Все нашел, исправил. Все работает!

Вот рабочий вариант:


#property copyright "Copyright © 2013 ЛЕО"
#property   show_inputs

//    функции
#import "wininet.dll"
int InternetAttemptConnect    (int x);
int InternetOpenA             (string lpszAgent, int dwAccessType, string lpszProxyName, string lpszProxyBypass, int dwFlags);
int InternetOpenUrlA          (int hInternetSession, string sUrl, string sHeaders="", int lHeadersLength=0, int lFlags=0, int lContext=0);
int InternetReadFile          (int hFile, int& sBuffer[], int lNumBytesToRead, int& lNumberOfBytesRead[]);
int InternetCloseHandle       (int hInet);
#import

//    флажки
#define INTERNET_FLAG_RELOAD            0x80000000
#define INTERNET_FLAG_NO_CACHE_WRITE    0x04000000
#define INTERNET_FLAG_PRAGMA_NOCACHE    0x00000100

extern      string      MainAdress = "https://www.mql4.com/ru/";   // адрес считываемой страницы
extern      string      FileName   = "Page.txt";                  // имя файла, куда будет записана наша считанная страничка
extern      string      NameAgent  = "Mozilla";                   // имя IE

string      MainPage;   // переменная для сохранения считанной страницы
int         h, h1, h2;  // дескрипторы

int start() {
      GetWebPage (MainAdress,MainPage);   // получение страницы: https://www.mql4.com/ru/ в переменную: MainPage
      h = FileOpen (FileName, FILE_BIN|FILE_WRITE); // открытие файла
      FileWriteString  (h, MainPage, StringLen(MainPage)); // запись страницы в файл
      FileClose (h); // закрытие дескриптора файла
      Print ("Сайт: ", MainAdress, " Считано: ", StringLen(MainPage), " байт!");
      return (0);
}

bool GetWebPage (string Url, string& WebPage) {

      int cBuffer[256], NumBytes[1]; 
      string TXT = "", TmpString = "", char = "";
      WebPage = "";
      
      if (!IsDllsAllowed())               { Alert ("Необходимо в настройках разрешить использование DLL"); return(0); }
      if (InternetAttemptConnect(0) != 0) { Alert ("Ошибка при вызове InternetAttemptConnect()");          return(0); }
      
      h1 = InternetOpenA    (NameAgent, 0, "0", "0", 0);
      if (h1 <= 0)                        { Alert ("Ошибка при вызове InternetOpenA()");                   return(0); }

      h2 = InternetOpenUrlA (h1, Url, "0", 0, INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_RELOAD, 0);
      if (h2 <= 0)                        { Alert ("Ошибка при вызове InternetOpenUrlA()"); 
                                            InternetCloseHandle (h1);                        return(0); }      
 
      while (!IsStopped()) {
            bool R = InternetReadFile (h2, cBuffer, 1024, NumBytes); if (NumBytes[0] == 0) break;
            TmpString = ""; char = "";
            
            // После считывания очередной порции, необходимо каждое целое число преобразовать в 4 символа
            // Что и делаем в этом цикле до конца сичтывания
            for (int i=0; i<256; i++) {
                   char = CharToStr (cBuffer[i]     & 0x000000FF);
                   if (char != "\r") TmpString = TmpString + char; else NumBytes[0]--;
                   if (StringLen (TmpString) == NumBytes[0]) break;
              
                   char = CharToStr (cBuffer[i]>>8  & 0x000000FF);
                   if (char != "\r") TmpString = TmpString + char; else NumBytes[0]--;
                   if (StringLen (TmpString) == NumBytes[0]) break;
              
                   char = CharToStr (cBuffer[i]>>16 & 0x000000FF);
                   if (char != "\r") TmpString = TmpString + char; else NumBytes[0]--;
                   if (StringLen (TmpString) == NumBytes[0]) break;

                   char = CharToStr (cBuffer[i]>>24 & 0x000000FF);
                   if (char != "\r") TmpString = TmpString + char; else NumBytes[0]--;
                   if (StringLen (TmpString) == NumBytes[0]) break;
              
            }
            
            // после перекодировкаи пополняем нашу строчку!
            WebPage = WebPage + TmpString;
            Sleep(1);
      }
      
      // закрытие всех дескрипторов
      InternetCloseHandle (h2); 
      InternetCloseHandle (h1);
      return (true);
}

 

Есть у кого-нибудь готовый рабочий примерчик с POST под МТ4?

Не хочется опять 3-4 дня терять. :)

 
Видимо нет... :( Жаль!
 
LEOK:
Видимо нет... :( Жаль!
Асинхронный POST не нашёл как сделать средствами mql. Делал в dllке
 
Avals:
Асинхронный POST не нашёл как сделать средствами mql. Делал в dllке


асинхронный, да еще и POST. замудренные слова.  не кажется ли? 

все реализуется аналогично как и GET.

чет вы не там копались

 
sergeev:

асинхронный, да еще и POST. замудренные слова.  не кажется ли? 

все реализуется аналогично как и GET.

чет вы не там копались


Не выходит как get... возомжно раньше работало, но в свежих билдах не. У меня подозрение, что криво параметры стали передаваться в DLL.


Особенное подозрение вызывает

HINTERNET HttpOpenRequest(
  _In_  HINTERNET hConnect,
  _In_  LPCTSTR lpszVerb,
  _In_  LPCTSTR lpszObjectName,
  _In_  LPCTSTR lpszVersion,
  _In_  LPCTSTR lpszReferer,
  _In_  LPCTSTR *lplpszAcceptTypes,
  _In_  DWORD dwFlags,
  _In_  DWORD_PTR dwContext
);

цитата
lplpszAcceptTypes [in]

A pointer to a null-terminated array of strings that indicates media types accepted by the client. Here is an example.

PCTSTR rgpszAcceptTypes[] = {_T(“text/*”), NULL};

Failing to properly terminate the array with a NULL pointer will cause a crash.

т.е. мы должны передать массив строк, на последнем месте в котором нулевой указатель, не совсем представляю себе, как это сделать в MQL.

 
Смотрел HTTPAnalyser'ом, заголовок с POST вообще теряется, хотя остальная часть - сам запрос то бишь, с параметрами формы и файлами, передается нормально. Но так как предложения POST в запросе нет, wininet интерпретирует его как GET, прописывает отсебятину и в таком виде отправляет.
 
alsu:

Не выходит как get... возомжно раньше работало, но в свежих билдах не. У меня подозрение, что криво параметры стали передаваться в DLL.

Особенное подозрение вызывает

т.е. мы должны передать массив строк, на последнем месте в котором нулевой указатель, не совсем представляю себе, как это сделать в MQL.

у меня все работает.

нужно передавать массив байт. ниже int в МТ4 не упадешь.

заголовки такие:

  int HttpOpenRequestA(int hConnect, string lpszVerb, string lpszObjectName, string lpszVersion, string lpszReferer, string lplpszAcceptTypes, int dwFlags, int dwContext);
  int HttpSendRequestA(int hRequest, string lpszHeaders, int dwHeadersLength, int& lpOptional[], int dwOptionalLength);
Причина обращения: