Не могу отправить данные через Wininet.dll POST

 

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

Пытаюсь отправить данные методом POST, и на стадии HttpSendRequestW получаю 0.

Вот мой код.

#define INTERNET_OPEN_TYPE_DIRECT       0
#define INTERNET_OPEN_TYPE_PRECONFIG    1
#define INTERNET_OPEN_TYPE_PROXY        3

 
#define _IGNORE_REDIRECT_TO_HTTP        0x00008000
#define _IGNORE_REDIRECT_TO_HTTPS       0x00004000
 
#define INTERNET_FLAG_KEEP_CONNECTION   0x00400000
#define INTERNET_FLAG_NO_AUTO_REDIRECT  0x00200000
#define INTERNET_FLAG_NO_COOKIES        0x00080000
#define INTERNET_FLAG_RELOAD            0x80000000
#define INTERNET_FLAG_NO_CACHE_WRITE    0x04000000
#define INTERNET_FLAG_DONT_CACHE        0x04000000
#define INTERNET_FLAG_PRAGMA_NOCACHE    0x00000100
#define INTERNET_FLAG_NO_UI             0x00000200
 
#define HTTP_ADDREQ_FLAG_ADD            0x20000000
#define HTTP_ADDREQ_FLAG_REPLACE        0x80000000
 
#define INTERNET_SERVICE_HTTP           3
#define INTERNET_DEFAULT_HTTP_PORT      80
 
#define ICU_ESCAPE                      0x80000000
#define ICU_USERNAME                    0x40000000
#define ICU_NO_ENCODE                   0x20000000
#define ICU_DECODE                      0x10000000
#define ICU_NO_META                     0x08000000
#define ICU_ENCODE_PERCENT              0x00001000
#define ICU_ENCODE_SPACES_ONLY          0x04000000
#define ICU_BROWSER_MODE                0x02000000

#import  "Wininet.dll"
   int InternetOpenW(string userAgent, uint AccessType, string proxyName, string proxyBypass, uint flags);
   int InternetConnectW(uint ioHandler, string host, uint port, string userName, string userPassword, uint service, uint flags, uint context); 
   int HttpOpenRequestW(uint icHandler, string method, string uri, uint httpVersion, string referer, uint acceptTypes, string flags, uint context); 
   int HttpSendRequestW(uint horHandler, string headers, uint headersLength, string data, uint dataLength);
   int HttpSendRequestA(uint horHandler, string headers, uint headersLength, string data, uint dataLength);
   int InternetReadFile(uint horHandle, string response, uint responseLength, uint offset);
   
   //bool InternetGetLastResponseInfo();
   //int HttpQueryInfoW(uint hor);
   int InternetOpenUrlW(int, string, string, int, int, int);
   int InternetCloseHandle(uint ioHandler); 
#import


int init()
{
   Print("START!");
   int io = InternetOpenW("MetaTrader 4", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL);
   Print("InternetOpenW: " + io);
   int ic = InternetConnectW(io, "test.example.com", 80, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, NULL);
   Print("InternetConnectW: " + ic);
   int hor = HttpOpenRequestW(ic, "POST", "/index.php", NULL, NULL, NULL, 
                                                                           INTERNET_FLAG_NO_CACHE_WRITE|
                                                                           INTERNET_FLAG_PRAGMA_NOCACHE|
                                                                           INTERNET_FLAG_RELOAD, 
                                                                           NULL);
   Print("HttpOpenRequestW: " + hor);
   string headers = "Content-Type: application/x-www-form-urlencoded";
   string data = "TESTDATA";
   
   int hsr = HttpSendRequestW(hor, headers, StringLen(headers), data, StringLen(data));
   Print("HttpSendRequest: " + hsr);
   
   string buffer;
   
   bool irf = InternetReadFile(hor, buffer, 128, NULL);
   Print("Buffer: " + buffer);
   
   InternetCloseHandle(io);
   InternetCloseHandle(ic);
   InternetCloseHandle(hor);
   return(0);
}

Домен изменен.

Подскажите пожалуйста, где я ошибаюсь?

 
А что возвращает GetLastError?
 
RickD:
А что возвращает GetLastError?

Который стандартный MQL4-шный - 0.
 
Так в чем может быть проблема? Никто не знает?
 
Ну подскажите же кто нибудь???
 
gaaarfild:
Ну подскажите же кто нибудь???


У вас там ошибки на каждом шагу. Трудно даже комментировать.

Вот вам рабочий пример чтения страницы сайта, разберитесь с этим примером,

а потом исправьте все в своем коде, сделайте аналогично примеру.

#import "wininet.dll"
  int InternetOpenW( string sAgent, int lAccessType, string sProxyName, string sProxyBypass, int lFlags );
  int InternetOpenUrlW( int hInternetSession, string sUrl, string sHeaders, int lHeadersLength, int lFlags, int lContext );
  int InternetReadFile( int hFile, uchar& lpvBuffer[], int lNumBytesToRead, int& lNumberOfBytesRead[] );
  int InternetCloseHandle( int hInet );
  int InternetQueryDataAvailable( int hFile, int& lpdwNumberOfBytesAvailable[], int dwFlags, int dwContext );
  int HttpQueryInfoW(int hRequest, int dwInfoLevel, int& lpvBuffer[], int& lpdwBufferLength[], int& lpdwReserved[] );
#import

#import "Kernel32.dll"
   uint GetLastError(void);
#import

#define HTTP_QUERY_CONTENT_LENGTH 0x00000005
#define HTTP_QUERY_FLAG_NUMBER    0x20000000

#define INTERNET_OPEN_TYPE_PRECONFIG    0x00000000   // use registry configuration
#define INTERNET_FLAG_RELOAD            0x80000000
#define INTERNET_FLAG_NO_CACHE_WRITE    0x04000000
#define INTERNET_FLAG_PRAGMA_NOCACHE    0x00000100


//+---------------------------------------------------------------------------+

int ReadSitePage(string ps_FileName)  // out : gs_HtmlString is fille
{
        if (!gs_UrlPage)
        {
                return ERROR_INVALID_PARAMETER;
        }
        
  gs_HtmlString = "";
  
  int hSession = InternetOpenW(AGENT, INTERNET_OPEN_TYPE_PRECONFIG, "", "", 0);

  if (hSession <= 0)
    return(Kernel32::GetLastError()); // INTERNET_OPENW_ERROR

  int    lReturn[1];
  uchar  Buffer[];
  int    AvailableData;
  int    handle;
  int    Error = 0;
  bool   Result;
  
  int hReq = InternetOpenUrlW(hSession, gs_UrlPage, "", 0, INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD, 0);
//  uint ui_Flag = 0x04000000 | 0x00000100 | 0x80000000;

  if (hReq == 0)
  {
    Error = Kernel32::GetLastError(); 
    InternetCloseHandle(hSession); 
      return(Error); // INTERNET_OPENURLW_ERROR
  }
  
  while (true)
  {
    AvailableData = GetDataAvailable(hReq, Result);
    
    if (!Result)
    {
      Error = AvailableData; // INTERNET_QUERYDATAAVAILABLE_ERROR
      break;
    }
    
    if (AvailableData == 0)
      break;

    ArrayResize(Buffer, AvailableData);
    
    Result = InternetReadFile(hReq, Buffer, AvailableData, lReturn);
    
    if (!Result)
    {
      Error = Kernel32::GetLastError(); // INTERNET_READFILE_ERROR;
      break;
    }
    
    if (lReturn[0] == 0)
      break;

   StringAdd(gs_HtmlString, CharArrayToString(Buffer, 0, lReturn[0]));

   Comment("HTML Page Read = " ,StringLen(gs_HtmlString));
  }
  
  InternetCloseHandle(hSession); 
  InternetCloseHandle(hReq);
 
  if (ps_FileName)
  {
    int i_TotalLen = StringLen(gs_HtmlString);
    
    ArrayResize(Buffer, i_TotalLen);
    
    StringToCharArray(gs_HtmlString, Buffer, 0, i_TotalLen); 
    
    handle = FileOpen(ps_FileName, FILE_BIN|FILE_WRITE);
    
    FileWriteArray(handle, Buffer, 0, i_TotalLen);
    
    FileClose(handle);
  }
  
  return(Error);
}    
//+--------------------------------------------------------------------------------------+


int GetDataAvailable(int hRequest, bool& Res )
{
   int  Buffer[1];

   Res = InternetQueryDataAvailable(hRequest, Buffer, 0, 0);
   
   if (Res)
      return(Buffer[0]);
   
   return(Kernel32::GetLastError());  // INTERNET_QUERYDATAAVAILABLE_ERROR
}

string    gs_UrlPage = "https://forum.mql4.com/ru/36699/page2";     
string    gs_HtmlString;

int init()
{
    int i_Error = ReadSitePage("Page.html")
    Print("ReadSitePage(...) return = ", i_Error);
}

Если код возврата равен 0, в папке Files терминала появится файл Page.html, который вы сможете посмотреть.


 
more:


У вас там ошибки на каждом шагу. Трудно даже комментировать.

Вот вам рабочий пример чтения страницы сайта, разберитесь с этим примером,

а потом исправьте все в своем коде, сделайте аналогично примеру.

Если код возврата равен 0, в папке Files терминала появится файл Page.html, который вы сможете посмотреть.



Дело в том, что GET запрос я и сам могу сделать. Мне нужна именно отправка данных через POST и получение ответа. С этим-то и есть проблема.
 
gaaarfild:

Дело в том, что GET запрос я и сам могу сделать. Мне нужна именно отправка данных через POST и получение ответа. С этим-то и есть проблема.

Ладно, пусть так. Вот здесь https://www.mql5.com/ru/articles/276 статья нашего модератора Sergeeva, все разложено по полочкам, но только там классы и все такое...
 
more:

Ладно, пусть так. Вот здесь https://www.mql5.com/ru/articles/276 статья нашего модератора Sergeeva, все разложено по полочкам, но только там классы и все такое...

Да. Я читал эту статью. С классами я работать умею. А MQL4 это может использовать?

И насчет моего кода. Укажите хотя бы на одну ошибку пожалуйста. Я вот не вижу.

 
gaaarfild:

Да. Я читал эту статью. С классами я работать умею. А MQL4 это может использовать?

И насчет моего кода. Укажите хотя бы на одну ошибку пожалуйста. Я вот не вижу.


c 600 билда и выше, можно. по ошибкам, к примеру функция InternetReadFile(...)







Вот у меня

int InternetReadFile (int hFile, uchar& lpvBuffer[], int lNumBytesToRead, int& lNumberOfBytesRead[] );

вот у вас

int InternetReadFile (uint horHandle, string response, uint responseLength, uint offset);

Второй параметр - адрес, по которому функция будет писаться данные. для билда 509 и ниже у вас все правильно,

для билда 600 и выше вы получите в строковой переменной Response все прочитанные данные, но чтобы ими воспользоваться

нужно еще потрудиться, поскольку в новом билде один символ строки - это два байта.

А вот вы читаете:

string buffer;

   
   bool irf = InternetReadFile(hor, buffer, 128, NULL);

Третий параметр говорит функции сколько байт надо прочитать - 128 у вас, а откуда вы знаете, что вообще есть данные для чтения ?

Четвертый параметр - это адрес DWORD куда функция пишет количество реально прочитанных байт, у вас там вообще стоит NULL !

Вот полное описание этой функции:

C++

BOOL InternetReadFile(
  _In_   HINTERNET hFile,
  _Out_  LPVOID lpBuffer,
  _In_   DWORD dwNumberOfBytesToRead,
  _Out_  LPDWORD lpdwNumberOfBytesRead
);

Parameters

hFile [in]

Handle returned from a previous call to InternetOpenUrl, FtpOpenFile, or HttpOpenRequest.

lpBuffer [out]

Pointer to a buffer that receives the data.

dwNumberOfBytesToRead [in]

Number of bytes to be read.

lpdwNumberOfBytesRead [out]

Pointer to a variable that receives the number of bytes read. InternetReadFile sets this value to zero before doing any work or error checking.

А вот ссылка, как она работает:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa385103(v=vs.85).aspx

 
more:


c 600 билда и выше, можно. по ошибкам, к примеру функция InternetReadFile(...)

Вот у меня

int InternetReadFile (int hFile, uchar& lpvBuffer[], int lNumBytesToRead, int& lNumberOfBytesRead[] );

вот у вас

int InternetReadFile (uint horHandle, string response, uint responseLength, uint offset);

Второй параметр - адрес, по которому функция будет писаться данные. для билда 509 и ниже у вас все правильно,

для билда 600 и выше вы получите в строковой переменной Response все прочитанные данные, но чтобы ими воспользоваться

нужно еще потрудиться, поскольку в новом билде один символ строки - это два байта.

А вот вы читаете:

string buffer;

Третий параметр говорит функции сколько байт надо прочитать - 128 у вас, а откуда вы знаете, что вообще есть данные для чтения ?

Четвертый параметр - это адрес DWORD куда функция пишет количество реально прочитанных байт, у вас там вообще стоит NULL !

Вот полное описание этой функции:

C++

Parameters

hFile [in]

Handle returned from a previous call to InternetOpenUrl, FtpOpenFile, or HttpOpenRequest.

lpBuffer [out]

Pointer to a buffer that receives the data.

dwNumberOfBytesToRead [in]

Number of bytes to be read.

lpdwNumberOfBytesRead [out]

Pointer to a variable that receives the number of bytes read. InternetReadFile sets this value to zero before doing any work or error checking.

А вот ссылка, как она работает:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa385103(v=vs.85).aspx

Спасибо за описание ошибок этой функции. Но вы наверно заметили, что до этой функции мы еще даже не добираемся. Ошибка возникает на стадии HttpSendRequest. Она возвращает в хандлер 0.

А GetLastError говорит что ошибка номер 2, что означает COMMON_ERROR. Совершенно неинформативно.

Причина обращения: