GrabWeb non funziona su MT4 Build 600

 

Questo codice ha funzionato perfettamente per me fino a quando l'ho provato in MT4 build 600, dove non verifica più i conti dal mio server.



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:

Questo codice ha funzionato perfettamente per me fino a quando l'ho provato in MT4 build 600, dove non verifica più i conti dal mio server.


Le stringhe sono ora presentate in formato Unicode, anche se prima erano in formato ANSI (single byte). Questo dovrebbe essere considerato se il programma usa le DLL e passa loro variabili di stringa. Quando si chiamano le funzioni API di Windows, si dovrebbero usare le versioni Unicode di queste funzioni.

Dovete adattare il vostro codice. Usate InternetOpenW invece di InternetOpenA, lo stesso per altre funzioni DLL che terminano con 'a' (per ANSI).
 
Grazie per il tuo suggerimento angevoyageur, ma ho provato a cambiare tutti gli ansi 'A' in W ma ancora niente da fare.
 
thili55:
Grazie per il tuo suggerimento angevoyageur, ma ho provato a cambiare tutte le 'A' ansi in W ma ancora niente da fare.

Il tuo problema sarà con InternetReadFile(). Vedere EasyXml.mqh su https://www.mql5.com/en/code/1998 per un esempio di come usare le funzioni WinInet nel nuovo MQL4 - il codice funziona sia in MQL4 che in MQL5.

In sostanza, si passa un array uchar[] a InternetReadFile(), e poi si converte l'array in una stringa usando CharArrayToString(). Quello che si può fare in effetti ora in MQL4 è allocare buffer di memoria gestita di lunghezza arbitraria, passarli ad una DLL, e poi convertire i dati da Ansi o Unicode a seconda dei casi.

 
gchrmt4:

In sostanza, si passa un array uchar[] a InternetReadFile(), e poi si converte l'array in una stringa usando CharArrayToString(). Quello che si può fare in effetti ora in MQL4 è allocare buffer di memoria gestita di lunghezza arbitraria, passarli a una DLL, e poi convertire i dati da Ansi o Unicode a seconda dei casi.

Allargando leggermente l'argomento e la risposta... nel nuovo MQL4 è possibile chiamare le versioni A o W di molte funzioni. Per esempio, il seguente script ottiene la directory temporanea di Windows usando entrambe le chiamate GetTempPathA e 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);
}

Pertanto, è possibile continuare ad usare molte chiamate alla DLL solo Ansi dal nuovo MQL4: non c'è necessariamente bisogno di aggiornare sia il codice MQL4 che la DLL.

 
gchrmt4:

Pertanto, è possibile continuare ad usare molte chiamate alla DLL solo Ansi dal nuovo MQL4: non è necessariamente necessario aggiornare sia il codice MQL4 che la DLL.


... Un altro esempio: passare valori di stringa in una chiamata DLL Ansi dal nuovo MQL4. (Nella vita reale si dovrebbe ovviamente chiamare MessageBoxW piuttosto che usare questo workaround per chiamare MessageBoxA, ma il punto generale è utile)

#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);
}
 
Grazie gchrmt4 per la spiegazione dettagliata, purtroppo non sono un gran programmatore quindi non sembra che sarò in grado di affrontare questo da solo. Sto guardando il mio codice e gli esempi che hai postato e non sono sicuro di cosa fare, quindi sembra che dovrò trovare qualcuno che lo faccia per me.
 
Ho giocato con questo per un paio d'ore, ancora nessuna fortuna. Quindi sì, sto cercando di assumere qualcuno che lo faccia per me ;)
 
thili55:
Ho giocato con questo per un paio d'ore, ancora nessuna fortuna. Quindi sì, sto cercando di assumere qualcuno che lo faccia per me ;)
https://www.mql5.com/en/job
 
thili55:
Ho giocato con questo per un paio d'ore, ancora nessuna fortuna. Quindi sì, sto cercando di assumere qualcuno che lo faccia per me ;)
Vedi https://www.mql5.com/en/forum/149360 - Stavo per postare questo come risposta qui, ma poi ho trovato un problema...
 
gchrmt4:
Vedi https://www.mql5.com/en/forum/149360 - Stavo per postarlo come risposta qui, ma poi ho trovato un problema...
...Tuttavia, quello script dovrebbe ancora funzionare per recuperare brevi risposte del server come i risultati di una query di licenza. Ha solo problemi se la dimensione della risposta del server supera 1KB-ish.