GrabWeb在MT4 Build 600上不工作

 

这段代码对我来说是完美无缺的,直到在MT4 build 600中测试时,它不再能从我的服务器上验证账户。



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:

这段代码对我来说是完美无缺的,直到在MT4 build 600中测试,它不再从我的服务器上验证账户。


字符串现在以Unicode格式呈现,尽管它们之前是ANSI格式(单字节的)。如果程序使用DLLs并向其传递字符串变量,就应该考虑到这一点。当调用Windows API函数时,应使用这些函数的Unicode版本。

你必须调整你的代码。使用InternetOpenW而不是InternetOpenA,对于其他以'a'结尾的DLL函数 也是如此(对于ANSI)。
 
谢谢你的建议,但我试着把所有的 "A "换成 "W",但仍然没有结果。
 
thili55:
谢谢你的建议,但我试着把所有的Ansi'A'换成W,但还是没有结果。

你的问题将与InternetReadFile()有关。关于如何在新的MQL4中使用WinInet函数的例子,请参见EasyXml.mqh,网址是https://www.mql5.com/en/code/1998- 该代码在MQL4和MQL5中都可以使用。

实质上,你将一个ucar[]数组传递给InternetReadFile(),然后使用CharArrayToString()将该数组转换为一个字符串。在MQL4中,你现在实际上可以做的是分配任意长度的托管内存缓冲区,将它们传递给DLL,然后根据情况将数据从Ansi或Unicode转换。

 
gchrmt4:

从本质上讲,你把一个ucar[]数组传给InternetReadFile(),然后用CharArrayToString()把数组转换为一个字符串。在MQL4中,你现在实际上可以做的是分配任意长度的托管内存缓冲区,将它们传递给DLL,然后根据情况将数据从Ansi或Unicode转换。

稍微扩大一下话题和答案......在新的MQL4中,有可能调用许多函数 的A或W版本。例如,下面的脚本同时使用GetTempPathA和GetTempPathW调用来获取Windows临时目录。

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

因此,在新的MQL4中可以继续使用许多只用Ansi的DLL调用:不一定需要同时更新MQL4代码 DLL。

 
gchrmt4:

因此,有可能继续使用新的MQL4中的许多纯Ansi的DLL调用:不一定需要同时更新MQL4代码 DLL。


......另一个例子:从新的MQL4中向 Ansi DLL调用传递字符串值。(在现实生活中,你显然会直接调用MessageBoxW,而不是使用这种变通方法来调用MessageBoxA,但一般的观点是有用的)

#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);
}
 
谢谢gchrmt4的详细解释,不幸的是,我不是什么程序员,所以我似乎无法自己解决这个问题。我正在看我的代码和你发布的例子,不知道该怎么做,所以看起来我可能要找人帮我做这个。
 
我已经玩了几个小时了,还是没有收获。所以,我想请人帮我做这件事;)
 
thili55:
我已经玩了几个小时了,还是没有收获。所以,我想请人帮我做这件事;)
https://www.mql5.com/en/job
 
thili55:
我已经玩了几个小时了,还是没有收获。所以,我想请人帮我做这件事;)
https://www.mql5.com/en/forum/149360- 我正准备把这个作为答案贴在这里,但后来发现了一个问题......
 
gchrmt4:
https://www.mql5.com/en/forum/149360- 我本来想把这个作为答案贴在这里,但后来发现了一个问题...
...然而,该脚本对于检索短的服务器响应,如许可查询的结果,应该仍然有效。只有当服务器的响应大小超过1KB左右时才会有问题。