GrabWeb ne fonctionne pas sur MT4 Build 600

 

Ce code a fonctionné parfaitement pour moi jusqu'à ce que je le teste dans MT4 build 600, où il ne vérifie plus les comptes de mon serveur.



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:

Ce code a fonctionné parfaitement pour moi jusqu'à ce que je le teste dans MT4 build 600, où il ne vérifie plus les comptes de mon serveur.


Les chaînes de caractères sont maintenant présentées au format Unicode, alors qu'elles étaient auparavant au format ANSI (octets simples). Il faut en tenir compte si le programme utilise des DLL et leur transmet des variables de type chaîne. Lorsque vous appelez des fonctions de l'API Windows, les versions Unicode de ces fonctions doivent être utilisées.

Vous devez adapter votre code. Utilisez InternetOpenW au lieu de InternetOpenA, de même pour les autres fonctions DLL qui se terminent par 'a' (pour ANSI).
 
Merci pour votre suggestion angevoyageur, mais j'ai essayé de changer tous les ansi 'A' en W mais toujours pas de résultat.
 
thili55:
Merci pour votre suggestion angevoyageur, mais j'ai essayé de changer tous les ansi 'A' en W mais toujours pas de résultat.

Votre problème se situe au niveau de InternetReadFile(). Voir EasyXml.mqh à l'adresse https://www.mql5.com/en/code/1998 pour un exemple d'utilisation des fonctions WinInet dans le nouveau MQL4 - le code fonctionne à la fois dans MQL4 et MQL5.

En substance, vous passez un tableau uchar[] à InternetReadFile(), puis vous convertissez le tableau en une chaîne de caractères à l'aide de CharArrayToString(). Ce que vous pouvez en fait faire maintenant dans MQL4 est d'allouer des tampons de mémoire gérés de longueur arbitraire, de les passer à une DLL, et ensuite de convertir les données d'Ansi ou d'Unicode selon le cas.

 
gchrmt4:

En substance, vous passez un tableau uchar[] à InternetReadFile(), puis vous convertissez le tableau en chaîne de caractères à l'aide de CharArrayToString(). Ce que vous pouvez en fait faire maintenant dans MQL4 est d'allouer des tampons de mémoire gérés de longueur arbitraire, de les passer à une DLL, puis de convertir les données d'Ansi ou d'Unicode selon le cas.

En élargissant légèrement le sujet et la réponse... dans le nouveau MQL4, il est possible d'appeler les versions A ou W de nombreuses fonctions. Par exemple, le script suivant obtient le répertoire temporaire de Windows en utilisant à la fois les appels GetTempPathA et 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);
}

Par conséquent, il est possible de continuer à utiliser de nombreux appels DLL uniquement en Ansi à partir du nouveau MQL4 : il n'est pas nécessairement nécessaire de mettre à jour le code MQL4 et la DLL.

 
gchrmt4:

Par conséquent, il est possible de continuer à utiliser de nombreux appels DLL Ansi uniquement à partir du nouveau MQL4 : il n'est pas nécessairement nécessaire de mettre à jour à la fois le code MQL4 et la DLL.


... Un autre exemple : passer des valeurs de chaîne dans un appel DLL Ansi à partir du nouveau MQL4. (Dans la vie réelle, il est évident que vous appelleriez MessageBoxW plutôt que d'utiliser cette solution de contournement pour appeler MessageBoxA, mais le point général est 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);
}
 
Merci gchrmt4 pour l'explication détaillée, malheureusement je ne suis pas un grand programmeur donc il ne semble pas que je puisse m'attaquer à cela moi-même. Je regarde mon code, et les exemples que vous avez postés et je ne suis pas sûr de ce qu'il faut faire donc il semble que je vais devoir trouver quelqu'un pour le faire pour moi.
 
J'ai joué avec cela pendant quelques heures maintenant, toujours pas de chance. Donc oui, je cherche à engager quelqu'un pour faire ça pour moi ;)
 
thili55:
J'ai joué avec cela pendant quelques heures maintenant, toujours pas de chance. Donc oui, je cherche à engager quelqu'un pour faire ça pour moi ;)
https://www.mql5.com/en/job
 
thili55:
J'ai joué avec cela pendant quelques heures maintenant, toujours pas de chance. Donc oui, je cherche à engager quelqu'un pour faire ça pour moi ;)
Voir https://www.mql5.com/en/forum/149360 - J'étais sur le point de poster ceci comme réponse ici, mais j'ai trouvé un problème...
 
gchrmt4:
Voir https://www.mql5.com/en/forum/149360 - J'étais sur le point de poster ceci comme réponse ici, mais j'ai trouvé un problème...
...Cependant, ce script devrait toujours fonctionner pour récupérer des réponses courtes du serveur, comme les résultats d'une requête de licence. Il ne pose problème que si la taille de la réponse du serveur dépasse 1KB-ish.