GrabWeb not working on MT4 Build 600

 

This code has worked flawlessly for me up until testing it in MT4 build 600, where it no longer verifies accounts from my 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:

This code has worked flawlessly for me up until testing it in MT4 build 600, where it no longer verifies accounts from my server.


Strings are now presented in Unicode format, though they were in ANSI format (single byte ones) before. That should be considered if the program uses DLLs and passes string variables to them. When calling Windows API functions, Unicode versions of these functions should be used.

You have to adapt your code. Use InternetOpenW instead od InternetOpenA, same for others DLL functions who terminates by 'a' (for ANSI).
 
Thanks for your suggestion angevoyageur, but I tried switching all the ansi 'A' to W but still no dice.
 
thili55:
Thanks for your suggestion angevoyageur, but I tried switching all the ansi 'A' to W but still no dice.

Your problem is going to be with InternetReadFile(). See EasyXml.mqh at https://www.mql5.com/en/code/1998 for an example of how to use WinInet functions in the new MQL4 - the code works both in MQL4 and MQL5.

In essence, you pass a uchar[] array to InternetReadFile(), and then convert the array to a string using CharArrayToString(). What you can in effect now do in MQL4 is to allocate managed memory buffers of arbitrary length, pass them to a DLL, and then convert the data from Ansi or Unicode as applicable.

 
gchrmt4:

In essence, you pass a uchar[] array to InternetReadFile(), and then convert the array to a string using CharArrayToString(). What you can in effect now do in MQL4 is to allocate managed memory buffers of arbitrary length, pass them to a DLL, and then convert the data from Ansi or Unicode as applicable.

Broadening out the topic and answer slightly... in the new MQL4 it's possible to call either the A or W versions of many functions. For example, the following script gets the Windows temporary directory using both the GetTempPathA and GetTempPathW calls:

#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);
}

Therefore, it's possible to continue using many Ansi-only DLL calls from the new MQL4: not necessarily a need to update both the MQL4 code and the DLL.

 
gchrmt4:

Therefore, it's possible to continue using many Ansi-only DLL calls from the new MQL4: not necessarily a need to update both the MQL4 code and the DLL.


... Another example: passing string values into an Ansi DLL call from the new MQL4. (In real life you would obviously just call MessageBoxW rather than using this workaround to call MessageBoxA, but the general point is useful)

#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);
}
 
Thanks gchrmt4 for the detailed explaination, unfortunately I'm not much of a programmer so it doesn't appear that I will be able to tackle this myself. I'm looking at my code, and the examples you posted and not sure what to do so it looks like I may have to find someone to do this for me.
 
I've played around with this for a few hours now, still no luck. So yea, looking to hire someone to do this for me ;)
 
thili55:
I've played around with this for a few hours now, still no luck. So yea, looking to hire someone to do this for me ;)
https://www.mql5.com/en/job
 
thili55:
I've played around with this for a few hours now, still no luck. So yea, looking to hire someone to do this for me ;)
See https://www.mql5.com/en/forum/149360 - I was about to post this as answer here, but then found a problem...
 
gchrmt4:
See https://www.mql5.com/en/forum/149360 - I was about to post this as answer here, but then found a problem...
...However, that script should still work for retrieving short server responses such as the results of a licensing query. It's only got issues if the size of the server's response exceeds 1KB-ish.