GrabWeb não funciona no MT4 Build 600

 

Este código funcionou sem falhas para mim até testá-lo no MT4 build 600, onde não verifica mais as contas do meu servidor.



bool bWinInetDebug = false;

string errorMsg;
 
int hSession_IEType;
int hSession_Direct;
int Internet_Open_Type_Preconfig = 0;
int Internet_Open_Type_Direct = 1;
int Internet_Open_Type_Proxy = 3;
int Buffer_LEN = 250;
string answer;

#import "wininet.dll"
 
#define  INTERNET_FLAG_PRAGMA_NOCACHE    0x00000100 // Forces the request to be resolved by the origin server, even if a cached copy exists on the proxy.
#define  INTERNET_FLAG_NO_CACHE_WRITE    0x04000000 // Does not add the returned entity to the cache. 
#define  INTERNET_FLAG_RELOAD            0x80000000 // Forces a download of the requested file, object, or directory listing from the origin server, not from the cache.
#define  INTERNET_FLAG_KEEP_CONNECTION   0x00400000  // use keep-alive semantics
#define  INTERNET_OPEN_TYPE_PRECONFIG                    0   // use registry configuration
#define  INTERNET_SERVICE_HTTP   3
#define  HTTP_ADDREQ_FLAG_ADD            0x20000000
#define  HTTP_ADDREQ_FLAG_REPLACE        0x80000000
int InternetOpenA(
    string     sAgent,
    int        lAccessType,
    string     sProxyName="",
    string     sProxyBypass="",
    int     lFlags=0
);
 
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
);

int HttpOpenRequestA(
    int hConnect,
    string lpszVerb,
    string lpszObjectName,
    string lpszVersion,
    string lpszReferrer,
    string lplpszAcceptTypes,
    int  dwFlags,
    int  dwContext);
    
int  InternetOpenA(
    string lpszAgent,
    int dwAccessType,
    string lpszProxy,
    string lpszProxyBypass,
    int dwFlags
    );    
    
int InternetConnectA(
    int hInternet,
    string lpszServerName,
    int nServerPort,
    string lpszUserName,
    string lpszPassword,
    int dwService,
    int dwFlags,
    int dwContext
    );

bool HttpSendRequestA(
    int hRequest,
    string lpszHeaders,
    int dwHeadersLength,
    string lpOptional,
    int dwOptionalLength
    );  
    
bool HttpAddRequestHeadersA(
    int hRequest,
    string lpszHeaders,
    int dwHeadersLength,
    int  dwModifiers
    );          
#import



int logId;
void Log(string st)
{
   if(logId>=0)
   {
      
      FileWrite(logId, TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS) + ": " + st);
   }
}



int init() 
{ 
GrabWeb("http://www.website.com/query.php?accountnumber="+AccountNumber()+"&login="+User, answer);
}



int hSession(bool Direct)
{
    string InternetAgent;
    if (hSession_IEType == 0)
    {
        InternetAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Q312461)";
        hSession_IEType = InternetOpenA(InternetAgent, Internet_Open_Type_Preconfig, "0", "0", 0);
        hSession_Direct = InternetOpenA(InternetAgent, Internet_Open_Type_Direct, "0", "0", 0);
    }
    if (Direct) 
    { 
        return(hSession_Direct); 
    }
    else 
    {
        return(hSession_IEType); 
    }
}

bool GrabWeb(string strUrl, string& strWebPage)
{
    int     hInternet;
    int        iResult;
    int     lReturn[]={1};
    string     sBuffer="x";
    int     bytes;
    
    hInternet = InternetOpenUrlA(hSession(FALSE), strUrl, "0", 0, 
                                INTERNET_FLAG_NO_CACHE_WRITE | 
                                INTERNET_FLAG_PRAGMA_NOCACHE | 
                                INTERNET_FLAG_RELOAD, 0);
                                
 
    if (hInternet == 0) 
        return(false);
         
    iResult = InternetReadFile(hInternet, sBuffer, Buffer_LEN, lReturn);     

    if (iResult == 0) 
        return(false);
    bytes = lReturn[0];

    strWebPage = StringSubstr(sBuffer, 0, lReturn[0]);    
    // If there's more data then keep reading it into the buffer
    while (lReturn[0] != 0)
    {
        iResult = InternetReadFile(hInternet, sBuffer, Buffer_LEN, lReturn);
        if (lReturn[0]==0) 
            break;
        bytes = bytes + lReturn[0];
       
        strWebPage = strWebPage + StringSubstr(sBuffer, 0, lReturn[0]);
    }
    
  
   
      
    iResult = InternetCloseHandle(hInternet);
    if (iResult == 0) 
        return(false);
   
    return(true);
}

int deinit() {
   FileClose(logId);
   return (0);
}
 
thili55:

Este código funcionou sem falhas para mim até testá-lo no MT4 build 600, onde não verifica mais as contas do meu servidor.


Agora as strings são apresentadas no formato Unicode, embora antes estivessem no formato ANSI (single byte ones). Isso deve ser considerado se o programa utiliza DLLs e passa variáveis de string para elas. Ao chamar funções API do Windows, devem ser usadas versões Unicode destas funções.

Você tem que adaptar seu código. Use InternetOpenW ao invés de InternetOpenA, o mesmo para outras funções DLL que terminam por 'a' (para ANSI).
 
Obrigado por sua sugestão angevoyageur, mas eu tentei trocar todo o ansi 'A' para W mas ainda sem dados.
 
thili55:
Obrigado por sua sugestão angevoyageur, mas eu tentei trocar todo o ansi 'A' para W mas ainda sem dados.

Seu problema vai ser com o InternetReadFile(). Veja EasyXml.mqh em https://www.mql5.com/en/code/1998 para um exemplo de como usar as funções WinInet no novo MQL4 - o código funciona tanto no MQL4 quanto no MQL5.

Em essência, você passa um array uchar[] para InternetReadFile(), e então converte o array para uma string usando CharArrayToString(). O que você pode fazer agora em efeito na MQL4 é alocar buffers de memória gerenciada de comprimento arbitrário, passá-los para uma DLL, e então converter os dados de Ansi ou Unicode, conforme aplicável.

 
gchrmt4:

Em essência, você passa um array[] uchar[] para InternetReadFile(), e então converte o array para um string usando CharArrayToString(). O que você pode fazer agora em efeito na MQL4 é alocar buffers de memória gerenciada de comprimento arbitrário, passá-los para uma DLL, e então converter os dados de Ansi ou Unicode, conforme aplicável.

Ampliando o tópico e respondendo ligeiramente... na nova MQL4 é possível chamar as versões A ou W de muitas funções. Por exemplo, o seguinte script obtém o diretório temporário do Windows usando tanto as chamadas GetTempPathA como GetTempPathW:

#import "kernel32.dll"
   int GetTempPathA(int,uchar & arr[]);
   int GetTempPathW(int,short & arr[]);
#import

void OnStart()
{
   uchar AnsiStringBuffer[256];
   GetTempPathA(255, AnsiStringBuffer);
   string strTempPathFromA = CharArrayToString(AnsiStringBuffer);

   short UnicodeStringBuffer[256];
   GetTempPathW(255, UnicodeStringBuffer);
   string strTempPathFromW = ShortArrayToString(UnicodeStringBuffer);

   Print("Temp path via GetTempPathA(): ", strTempPathFromA);
   Print("Temp path via GetTempPathW(): ", strTempPathFromW);
}

Portanto, é possível continuar usando muitas chamadas DLL somente Ansi do novo MQL4: não necessariamente uma necessidade de atualizar tanto o código MQL4 quanto a DLL.

 
gchrmt4:

Portanto, é possível continuar usando muitas chamadas DLL somente da Ansi da nova MQL4: não necessariamente uma necessidade de atualizar tanto o código MQL4 quanto a DLL.


... Outro exemplo: passando valores de string para uma chamada Ansi DLL a partir da nova MQL4. (Na vida real, você obviamente chamaria MessageBoxW em vez de usar esta alternativa para chamar MessageBoxA, mas o ponto geral é útil)

#import "user32.dll"
   // Declare the Ansi function as taking uchar[] input parameters instead of strings
   int MessageBoxA(int,uchar & arr1[],uchar & arr2[],int);
#import

void OnStart()
{
   string strMessage = "Hello";
   string strTitle = "Hi!";
   
   // Convert the strings to uchar[] arrays
   uchar ucMessage[], ucTitle[];
   StringToCharArray(strMessage, ucMessage);
   StringToCharArray(strTitle, ucTitle);
   
   MessageBoxA(0, ucMessage, ucTitle, 64);
}
 
Obrigado gchrmt4 pela explicação detalhada, infelizmente eu não sou muito de programador, então não parece que eu mesmo seja capaz de lidar com isso. Estou olhando meu código, e os exemplos que você postou e não sabe o que fazer, parece que talvez eu tenha que encontrar alguém para fazer isso por mim.
 
Já há algumas horas que brinco com isto, ainda sem sorte. Então, sim, procurando contratar alguém para fazer isso por mim ;)
 
thili55:
Já há algumas horas que brinco com isto, ainda sem sorte. Então, sim, procurando contratar alguém para fazer isso por mim ;)
https://www.mql5.com/en/job
 
thili55:
Já há algumas horas que brinco com isto, ainda sem sorte. Então, sim, procurando contratar alguém para fazer isso por mim ;)
Veja https://www.mql5.com/en/forum/149360 - Eu estava prestes a postar isto como resposta aqui, mas depois encontrei um problema...
 
gchrmt4:
Veja https://www.mql5.com/en/forum/149360 - Eu estava prestes a postar isto como resposta aqui, mas depois encontrei um problema...
...Entretanto, esse script ainda deve funcionar para recuperar respostas curtas do servidor, tais como os resultados de uma consulta de licenciamento. Ele só tem problemas se o tamanho da resposta do servidor exceder 1KB-ish.