MT4 Build 600でGrabWebが動作しない。

 

このコードは、MT4ビルド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ビルド600でテストするまでは完璧に動作していましたが、私のサーバーからアカウントを検証しなくなりました。


文字列は、以前はANSIフォーマット(シングルバイト)であったが、現在はユニコードで表示される。プログラムがDLLを使用し、それらに文字列変数を渡す場合、それを考慮する必要があります。Windows API関数を呼び出す場合、これらの関数のUnicodeバージョンを使用する必要があります。

あなたのコードを適応させる必要があります。InternetOpenA の代わりに InternetOpenW を使用し、他の DLL関数も 同様に 'a' で終端するようにしてください(ANSI 用)。
 
angevoyageurさん、ご指摘ありがとうございます!しかし、ansiの'A'を全てWに変えてみましたが、やはりダメでした。
 
thili55:
angevoyageurさん、ご指摘ありがとうございます。

あなたの問題はInternetReadFile()にあります。新しいMQL4でWinInet関数を使用する方法の例として、https://www.mql5.com/en/code/1998 のEasyXml.mqhを参照してください(このコードはMQL4とMQL5の両方で動作します)。

要するに、InternetReadFile()にuchar[]配列を渡し、CharArrayToString()を使ってその配列を文字列に変換しているのです。MQL4で実質的にできることは、任意の長さのマネージド・メモリ・バッファを割り当て、それをDLLに渡し、必要に応じてデータをAnsiまたはUnicodeから変換することです。

 
gchrmt4:

要するに、InternetReadFile()にuchar[]配列を渡し、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コールを使用し続けることが可能です。

 
gchrmt4:

したがって、新しいMQL4から多くのAnsiのみのDLLコールを使用し続けることが可能です:必ずしもMQL4のコードと DLLの両方を更新する必要はありません。


... 他の例として、新しいMQL4からAnsiのDLLコールに 文字列値を渡すことができます。(実際の使用では、この回避策を使用してMessageBoxAを呼び出すのではなく、単にMessageBoxWを呼び出す ことになりますが、一般的なポイントは有用です。)

#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程度を超える場合にのみ問題が発生します。
理由: