GrabWeb no funciona en MT4 Build 600

 

Este código me ha funcionado sin problemas hasta que lo he probado en MT4 build 600, donde ya no verifica las cuentas de mi 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 me ha funcionado perfectamente hasta que lo he probado en MT4 build 600, donde ya no verifica las cuentas de mi servidor.


Las cadenas se presentan ahora en formato Unicode, aunque antes estaban en formato ANSI (de un solo byte). Esto debe tenerse en cuenta si el programa utiliza DLLs y les pasa variables de cadena. Al llamar a las funciones de la API de Windows, deben utilizarse las versiones Unicode de estas funciones.

Tiene que adaptar su código. Utilice InternetOpenW en lugar de InternetOpenA, lo mismo para otras funciones de la DLL que terminan con 'a' (para ANSI).
 
Gracias por tu sugerencia angevoyageur, pero he probado a cambiar todos los ansi 'A' por W pero sigue sin haber suerte.
 
thili55:
Gracias por tu sugerencia angevoyageur, pero he intentado cambiar todos los ansi 'A' a W pero todavía no hay dados.

Tu problema será con InternetReadFile(). Mira EasyXml.mqh en https://www.mql5.com/en/code/1998 para un ejemplo de como usar las funciones WinInet en el nuevo MQL4 - el código funciona tanto en MQL4 como en MQL5.

En esencia, pasas un array uchar[] a InternetReadFile(), y luego conviertes el array en una cadena usando CharArrayToString(). Lo que en efecto puedes hacer ahora en MQL4 es asignar buffers de memoria gestionados de longitud arbitraria, pasarlos a una DLL, y luego convertir los datos de Ansi o Unicode según corresponda.

 
gchrmt4:

En esencia, usted pasa una matriz uchar[] a InternetReadFile(), y luego convierte la matriz a una cadena usando CharArrayToString(). Lo que en efecto puedes hacer ahora en MQL4 es asignar buffers de memoria gestionados de longitud arbitraria, pasarlos a una DLL, y luego convertir los datos de Ansi o Unicode según sea el caso.

Ampliando un poco el tema y la respuesta... en el nuevo MQL4 es posible llamar a las versiones A o W de muchas funciones. Por ejemplo, el siguiente script obtiene el directorio temporal de Windows utilizando tanto las llamadas 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);
}

Por lo tanto, es posible seguir usando muchas llamadas a la DLL sólo en versión Ansi desde el nuevo MQL4: no es necesario actualizar tanto el código MQL4 como la DLL.

 
gchrmt4:

Por lo tanto, es posible seguir utilizando muchas llamadas a la DLL de Ansi desde el nuevo MQL4: no es necesario actualizar tanto el código MQL4 como la DLL.


... Otro ejemplo: pasar valores de cadena a una llamada DLL Ansi desde el nuevo MQL4. (En la vida real, obviamente, sólo llamarías a MessageBoxW en lugar de utilizar esta solución para llamar a MessageBoxA, pero el punto general es ú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);
}
 
Gracias gchrmt4 para la explicación detallada, por desgracia no soy mucho de un programador por lo que no parece que voy a ser capaz de hacer frente a esto yo mismo. Estoy mirando mi código, y los ejemplos que has publicado y no estoy seguro de qué hacer, así que parece que voy a tener que encontrar a alguien para hacer esto para mí.
 
He jugado con esto durante unas horas, todavía no hay suerte. Así que sí, buscando contratar a alguien para hacer esto para mí ;)
 
thili55:
He jugado con esto durante unas horas, todavía no hay suerte. Así que sí, buscando contratar a alguien para hacer esto para mí ;)
https://www.mql5.com/en/job
 
thili55:
He jugado con esto durante unas horas, todavía no hay suerte. Así que sí, buscando contratar a alguien para hacer esto para mí ;)
Ver https://www.mql5.com/en/forum/149360 - Estaba a punto de publicar esto como respuesta aquí, pero luego encontró un problema ...
 
gchrmt4:
Ver https://www.mql5.com/en/forum/149360 - Estaba a punto de publicar esto como respuesta aquí, pero luego encontré un problema...
...Sin embargo, ese script debería seguir funcionando para recuperar respuestas cortas del servidor, como los resultados de una consulta sobre licencias. Sólo tiene problemas si el tamaño de la respuesta del servidor es superior a 1KB.