PR

WinAPIを使用した画像付きLINE通知のやり方【WebRequestの問題解決】

オリジナル関数

MQL4やMQL5でのHTTP通信は、既存のWebRequest関数によって可能になっています。
しかし、この関数にはいくつかの制限があります。

これを解決するため、GETとPOSTリクエストに対応し、開発の利便性を大幅に向上させる新しい関数、WebRequest2を作成しました。この関数はWinAPIを活用し、従来の制限を打破します。

サンプルとして、画像付きLINE通知のソースコードを紹介します。

3行でわかる本記事の内容

  • WebRequest関数のデメリットを解消
  • オリジナル関数「WebRequest2」の紹介
  • 画像付きLINE通知のソースコードをプレゼント

WebRequest関数のデメリットと対策

MQL言語は、ニッチなプログラミング言語です。そのため、ChatGPTのようなAIにおいても、MQL言語の正確なコードを提供するのは困難です。

この言語で、HTTPリクエストを実行しようとする際に多くの場合、標準的なWebRequest関数に基づいたコードの提案が行われます。

しかし、WebRequest関数は利用にあたっていくつかのデメリットがあり、多くの開発者はその使用を避けているのが現状です。

2段階のプロセスを踏む必要がある

これらの問題に直面し、WinAPIを利用してHTTPリクエストを行うコードを作成するものの、通常はWebRequest関数を用いた標準的なコードから始めます。
そこから、WinAPIを使ってHTTPリクエストを実行する、という2段階のプロセスを踏むことになります。

このプロセスは非効率的で時間を要するため、よりシンプルな方法の必要性が明らかでした。

そもそもHTTP通信(リクエスト)とは?
特定のWebサイト、Webアプリにアクセスして情報を送受信することです。
簡単に言うと受信がGET、送信がPOSTです。
GET(受信)の代表例としては経済指標の取得。
POST(送信)の代表例としてはLINE通知があります。

デメリットの対策

この問題に対処するため、下記の【オリジナル関数】WebRequest2 の開発に至りました。

【オリジナル関数】WebRequest2

  • WebRequest関数と同じ引数を持つ
  • 関数名の末尾に「2」を付けるだけで、WinAPIを使用したHTTPリクエストを実行できる

このアプローチにより、開発者はChatGPTなどのAIを利用してWebRequest関数に基づくコードを簡単に取得し、そのコードを微調整するだけでWinAPIを活用したHTTPリクエストに変換できるようになりました。
この革新的な解決策により、MQLプログラミングにおけるHTTP通信のプロセスが、大幅に簡略化されました。

従来のWebRequest関数とメリット・デメリット

従来のWebRequestのバージョンは以下の2パターンがあります。

パターン1

int  WebRequest( 
   const string     method,          // HTTP メソッド  
   const string     url,             // URL 
   const string     cookie,          // クッキー 
   const string     referer,         // リファラ 
   int              timeout,         // 時間切れ 
   const char       &data[],         // HTTPメッセージ本文の配列 
   int              data_size,       // data[] 配列のバイトサイズ 
   char             &result[],       // サーバ応答データを含む配列 
   string           &result_headers  // サーバ応答ヘッダ 
  );

パターン2

int  WebRequest( 
   const string     method,          // HTTP メソッド 
   const string     url,             // URL 
   const string     headers,         // ヘッダ  
   int              timeout,         // 時間切れ 
   const char       &data[],         // HTTPメッセージ本文の配列 
   char             &result[],       // サーバ応答データを含む配列 
   string           &result_headers  // サーバ応答ヘッダ 
  );

メリットとデメリット

メリット
  • HTTP通信を行う、MQL唯一の関数
  • 引数を指定するだけで、簡単にHTTP通信が行える
  • セキュリティ面で安全※

※「WebRequestを許可するURLリスト」によって、許可したURLにのみ接続を行う。

デメリット
  • 事前に「WebRequestを許可するURLリスト」を指定する必要があり設定が面倒。またこれによりユーザー側に認証などで使用しているURLが知られてしまう。
  • テスターで使用不可
  • インジケーターから使用不可

これらの問題により、多くの開発者はWebRequestを使用しない手段を模索してきました。

オリジナル関数のWebRequest2を作成する

WebRequest2関数の使い方

WebRequest2関数は、以下の構造でHTTPリクエストを行います。

既存のWebRequest関数(前章の②)の引数をそのままに、従来のWebRequest関数を使用せずにWinAPIを利用してHTTPリクエストを行います

int WebRequest2(
   const string       method,          // HTTPメソッド
   const string       url,             // URL
   const string       headers,         // ヘッダ
   int                timeout,         // タイムアウト
   char               &data[],         // HTTPメッセージ本文の配列
   char               &result[],       // サーバ応答データを含む配列
   string             &result_headers  // サーバ応答ヘッダ
);
WebRequest2関数の注意点
  • 全体的なコードがやや長くなる。
  • GETとPOSTメソッドにのみ対応しており、他のHTTPメソッドには対応していない。
WAN
WAN

オタクのみんなは長いコードにも慣れてると思うから平気だよねっ(‘Д’)
サクッとコピペしちゃおー♪

WebRequest2関数のソースコード

今回のコードは長くなっているので、下記のソースコードを開くからご覧ください。

//+------------------------------------------------------------------+
//| GETまたはPOSTリクエストを実行し、データを取得  ワンダフルFXライフ
//+------------------------------------------------------------------+
#define INTERNET_DEFAULT_HTTPS_PORT 443
#define INTERNET_DEFAULT_HTTP_PORT 80
#define INTERNET_SERVICE_HTTP 3
#define HTTP_QUERY_STATUS_CODE 19
#define HTTP_QUERY_RAW_HEADERS_CRLF 21
#define INTERNET_FLAG_SECURE 0x00800000
#define INTERNET_FLAG_PRAGMA_NOCACHE 0x00000100
#define INTERNET_FLAG_KEEP_CONNECTION 0x00400000
#define INTERNET_FLAG_RELOAD 0x80000000
#define INTERNET_OPTION_CONNECT_TIMEOUT 2
#define INTERNET_OPTION_SEND_TIMEOUT 5
#define INTERNET_OPTION_RECEIVE_TIMEOUT 6
#import "wininet.dll"
int InternetOpenW(string userAgent, int accessType, string proxyServer, string bypassProxyFor, int flags);
int InternetOpenUrlW(int internetSession, string url, string header, int headerLength, int flags, int context);
int InternetConnectW(int sessionHandle, string serverUrl, int serverPort, string userCredentials, string userPassword, int serviceType, int connectionFlags, int context);
int HttpOpenRequestW(int connectionHandle, string httpVerb, string objectUrl, string httpVersion, string referrer, string acceptTypes, uint requestFlags, int context);
bool HttpSendRequestW(int hRequest, string lpszHeaders, int dwHeadersLength, uchar &lpOptional[], int dwOptionalLength);
bool InternetReadFile(int hFile, uchar &lpBuffer[], int dwNumberOfBytesToRead, int &lpdwNumberOfBytesRead);
bool InternetCloseHandle(int hInternet);
bool HttpQueryInfoA(int hRequest, int dwInfoLevel, uchar &lpBuffer[], int &lpdwBufferLength, int &lpdwIndex);
bool InternetSetOptionW(int hInternet, int dwOption, string lpBuffer, int dwBufferLength);
#import
int WebRequest2(const string method, const string url,const string headers, int timeout, char & data[], char & result[], string & result_headers)
  {
   int secure = 0;
   int port = INTERNET_DEFAULT_HTTP_PORT;
   if(StringFind(url, "https") >= 0)
     {
      secure = INTERNET_FLAG_SECURE;
      port = INTERNET_DEFAULT_HTTPS_PORT;
     }
//URLからホストとエンドポイントの抽出
   string host = "", endpoint = "";
   int response = -1;
   int http_pos = StringFind(url, "//");
   if(http_pos >= 0)
     {
      int next_slash = StringFind(url, "/", http_pos + 2);
      if(next_slash < 0)
         next_slash = StringLen(url);
      host = StringSubstr(url, http_pos + 2, next_slash - http_pos - 2);
      endpoint = StringSubstr(url, next_slash);
     }
// インターネットセッションを開始
   int session = InternetOpenW("Mozilla/5.0", 0, "", "", 0);
   if(!session)
     {
      string error = "エラー:インターネットセッションを開けません";
      StringToCharArray(error, result);
      return(response);
     }

// タイムアウトの設定
   string timeoutStr = IntegerToString(timeout);
   bool timeout_res = InternetSetOptionW(session, INTERNET_OPTION_CONNECT_TIMEOUT, timeoutStr, sizeof(timeout));
   timeout_res = InternetSetOptionW(session, INTERNET_OPTION_SEND_TIMEOUT, timeoutStr, sizeof(timeout));
   timeout_res = InternetSetOptionW(session, INTERNET_OPTION_RECEIVE_TIMEOUT, timeoutStr, sizeof(timeout));

   if(method == "GET")
     {
      // URLを開く
      int connect = InternetOpenUrlW(session, url, headers, StringLen(headers), secure, 0);
      if(!connect)
        {
         InternetCloseHandle(session);
         string error = "エラー:URLを開けません";
         StringToCharArray(error, result);
         return(response);
        }

      //レスポンス確認
        {
         int bufferLength = 1024;
         uchar result_array[];
         string result_str = "";
         ArrayResize(result_array, bufferLength);
         int index = 0;
         // HTTPステータスコードを取得
         if(HttpQueryInfoA(connect, HTTP_QUERY_STATUS_CODE, result_array, bufferLength, index))
           {
            for(int i = 0; i < bufferLength; i++)
              {
               uchar ch[1];
               ch[0] = result_array[i];
               if(ch[0] != NULL)
                  result_str += CharArrayToString(ch);
               else
                  result_str += "\n";
              }
           }
         response = (int)result_str;
        }

      char receive[1024];
      int byteSize = 0;
      int totalBytesRead = 0;
      // レスポンスデータを読み取る
      while(InternetReadFile(connect, receive, 1024, byteSize))
        {
         if(byteSize <= 0)
            break;
         ArrayResize(result, totalBytesRead + byteSize);
         for(int i = 0; i < byteSize; ++i)
           {
            result[totalBytesRead + i] = receive[i];
           }
         totalBytesRead += byteSize;
        }

      InternetCloseHandle(connect);
     }
   else
      if(method == "POST")
        {
         // ホストに接続
         int connect = InternetConnectW(session, host, port, "", "", INTERNET_SERVICE_HTTP, 0, 0);
         if(!connect)
           {
            InternetCloseHandle(session);
            string error = "エラー:接続できません";
            StringToCharArray(error, result);
            return(response);
           }

         // HTTPリクエストを開く
         int hRequest = HttpOpenRequestW(connect, method, endpoint, "HTTP/1.1", "", NULL, secure | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE, 0);
         if(!hRequest)
           {
            InternetCloseHandle(connect);
            InternetCloseHandle(session);
            string error = "エラー:HTTPリクエストを開けません";
            StringToCharArray(error, result);
            return(response);
           }

         if(!HttpSendRequestW(hRequest, headers, StringLen(headers), data, ArraySize(data)))
           {
            InternetCloseHandle(hRequest);
            InternetCloseHandle(connect);
            InternetCloseHandle(session);
            string error = "エラー:HTTPリクエストの送信に失敗しました。";
            StringToCharArray(error, result);
            return(response);
           }

         //レスポンス確認
           {
            int bufferLength = 1024;
            uchar result_array[];
            string result_str = "";
            int index = 0;
            ArrayResize(result_array, bufferLength);
            // HTTPステータスコードを取得
            if(HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE, result_array, bufferLength, index))
              {
               for(int i = 0; i < bufferLength; i++)
                 {
                  uchar ch[1];
                  ch[0] = result_array[i];
                  if(ch[0] != NULL)
                     result_str += CharArrayToString(ch);
                  else
                     result_str += "\n";
                 }
              }
            response = (int)result_str;
           }
         //リクエストヘッダー取得
           {
            int bufferLength = 1024;
            uchar result_array[];
            string result_str = "";
            ArrayResize(result_array, bufferLength);
            int index = 0;
            // HTTPステータスコードを取得
            if(HttpQueryInfoA(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, result_array, bufferLength, index))
              {
               for(int i = 0; i < bufferLength; i++)
                 {
                  uchar ch[1];
                  ch[0] = result_array[i];
                  if(ch[0] != NULL)
                     result_str += CharArrayToString(ch);
                  else
                     result_str += "\n";
                 }
              }
            result_headers = result_str;
           }

         char receive[1024];
         int byteSize = 0;
         int totalBytesRead = 0;
         // レスポンスデータを読み取る
         while(InternetReadFile(hRequest, receive, 1024, byteSize))
           {
            if(byteSize <= 0)
               break;
            ArrayResize(result, totalBytesRead + byteSize);
            for(int i = 0; i < byteSize; ++i)
              {
               result[totalBytesRead + i] = receive[i];
              }
            totalBytesRead += byteSize;
           }

         InternetCloseHandle(hRequest);
         InternetCloseHandle(connect);
        }
// インターネットセッションを閉じる
   InternetCloseHandle(session);
   return(response);
  }
WAN
WAN

えっwwwwwww
長っwwwwwww
さすがに長いよ(‘Д’)

You
You

やっぱりWebRequest使おう・・・

WAN
WAN

オイラの努力・・・(‘ω’)

サンプルコード【画像付きLINE通知】

以下のコードをスクリプトとして保存するだけで、画像付きLINE通知が可能です。LINEトークンの取得方法はBingで調べてください。

#property copyright "FX WAN."
#property link      "https://twitter.com/wonderfulfxlife"
#property version   "1.00"
#property script_show_inputs
#property strict
// ここでLINEの通知のためのトークンや、保存する画像の名前を設定しています。
input string LineToken = "";
input string FileName = "test.png";


//+------------------------------------------------------------------+
//| このスクリプトが開始すると、この関数が実行されます。                               |
//+------------------------------------------------------------------+
void OnStart()
  {
// DLLの使用許可
   if((bool)MQLInfoInteger(MQL_DLLS_ALLOWED) == false)
     {
      Print("DLLの使用を許可してください");
      return;
     }

// 現在の画面のスクリーンショットを取って、FileNameで指定した名前で保存します。
   ChartScreenShot(0, FileName, 800, 600);

// LINEにメッセージと画像を送るための関数を呼び出します。
   LineNotify(LineToken, "テスト☺", FileName);
  }


//+------------------------------------------------------------------+
//|  LINEに通知を送るための関数                                            |
//+------------------------------------------------------------------+
void LineNotify(string token, string message, string fileName = "")
  {
// LINEの通知を送るためのURL
   string url = "https://notify-api.line.me/api/notify";

// データの区切りのための文字列
   string boundary = "WanScriptsSample";

// 通知を送るための情報をまとめたもの
   string headers = "Authorization: Bearer " + token + "\r\n" + "Content-Type: multipart/form-data; boundary=" + boundary + "\r\n";

// 送るメッセージを設定
   string body = "--" + boundary + "\r\n";
   body += "Content-Disposition: form-data; name=\"message\"\r\n\r\n";
   body += message + "\r\n";

// ファイル名が指定されていたら画像付きLINE通知、指定されていなかったら文字のみの通知
   int size = 0;
   uchar post_data[];
   if(fileName != "")
     {
      // 画像を送るための情報を追加
      body += "--" + boundary + "\r\n";
      body += "Content-Disposition: form-data; name=\"imageFile\"; filename=\"" + fileName + "\"\r\n";
      body += "Content-Type: image/png\r\n\r\n";
      size = StringToCharArray(body, post_data, 0, WHOLE_ARRAY, CP_UTF8);

      // 画像ファイルを開く
      uchar img[];
      int handle = FileOpen(fileName, FILE_BIN | FILE_READ);
      if(handle != INVALID_HANDLE)
        {
         // 画像のデータを読み込む
         FileReadArray(handle, img);
         FileClose(handle);
        }
      // 画像のデータを追加
      size += ArrayCopy(post_data, img, size - 1);
      // データの終わりを示す
      StringToCharArray("\r\n" + "--" +  boundary + "--\r\n", post_data, size - 1);
     }
   else
     {
      // 文字を送るための情報を追加
      size = StringToCharArray(body, post_data, 0, WHOLE_ARRAY, CP_UTF8);
      // データの終わりを示す
      StringToCharArray("--" + boundary + "--\r\n", post_data, size - 1);
     }

// LINEに通知を送る
   int timeout = 5000;
   char result[];
   string headers_res;
   int res = WebRequest2("POST", url, headers, timeout, post_data, result, headers_res);
   if(res == -1)
      Print("HTTPリクエストエラー");// エラーメッセージを表示
   else
      string res_str = CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);  // レスポンスを取得する
  }

//+------------------------------------------------------------------+
//| GETまたはPOSTリクエストを実行し、データを取得  ワンダフルFXライフ
//+------------------------------------------------------------------+
#define INTERNET_DEFAULT_HTTPS_PORT 443
#define INTERNET_DEFAULT_HTTP_PORT 80
#define INTERNET_SERVICE_HTTP 3
#define HTTP_QUERY_STATUS_CODE 19
#define HTTP_QUERY_RAW_HEADERS_CRLF 21
#define INTERNET_FLAG_SECURE 0x00800000
#define INTERNET_FLAG_PRAGMA_NOCACHE 0x00000100
#define INTERNET_FLAG_KEEP_CONNECTION 0x00400000
#define INTERNET_FLAG_RELOAD 0x80000000
#define INTERNET_OPTION_CONNECT_TIMEOUT 2
#define INTERNET_OPTION_SEND_TIMEOUT 5
#define INTERNET_OPTION_RECEIVE_TIMEOUT 6
#import "wininet.dll"
int InternetOpenW(string userAgent, int accessType, string proxyServer, string bypassProxyFor, int flags);
int InternetOpenUrlW(int internetSession, string url, string header, int headerLength, int flags, int context);
int InternetConnectW(int sessionHandle, string serverUrl, int serverPort, string userCredentials, string userPassword, int serviceType, int connectionFlags, int context);
int HttpOpenRequestW(int connectionHandle, string httpVerb, string objectUrl, string httpVersion, string referrer, string acceptTypes, uint requestFlags, int context);
bool HttpSendRequestW(int hRequest, string lpszHeaders, int dwHeadersLength, uchar &lpOptional[], int dwOptionalLength);
bool InternetReadFile(int hFile, uchar &lpBuffer[], int dwNumberOfBytesToRead, int &lpdwNumberOfBytesRead);
bool InternetCloseHandle(int hInternet);
bool HttpQueryInfoA(int hRequest, int dwInfoLevel, uchar &lpBuffer[], int &lpdwBufferLength, int &lpdwIndex);
bool InternetSetOptionW(int hInternet, int dwOption, string lpBuffer, int dwBufferLength);
#import
int WebRequest2(const string method, const string url, const string headers, int timeout, char & data[], char & result[], string & result_headers)
  {
   int secure = 0;
   int port = INTERNET_DEFAULT_HTTP_PORT;
   if(StringFind(url, "https") >= 0)
     {
      secure = INTERNET_FLAG_SECURE;
      port = INTERNET_DEFAULT_HTTPS_PORT;
     }
//URLからホストとエンドポイントの抽出
   string host = "", endpoint = "";
   int response = -1;
   int http_pos = StringFind(url, "//");
   if(http_pos >= 0)
     {
      int next_slash = StringFind(url, "/", http_pos + 2);
      if(next_slash < 0)
         next_slash = StringLen(url);
      host = StringSubstr(url, http_pos + 2, next_slash - http_pos - 2);
      endpoint = StringSubstr(url, next_slash);
     }
// インターネットセッションを開始
   int session = InternetOpenW("Mozilla/5.0", 0, "", "", 0);
   if(!session)
     {
      string error = "エラー:インターネットセッションを開けません";
      StringToCharArray(error, result);
      return(response);
     }

// タイムアウトの設定
   string timeoutStr = IntegerToString(timeout);
   bool timeout_res = InternetSetOptionW(session, INTERNET_OPTION_CONNECT_TIMEOUT, timeoutStr, sizeof(timeout));
   timeout_res = InternetSetOptionW(session, INTERNET_OPTION_SEND_TIMEOUT, timeoutStr, sizeof(timeout));
   timeout_res = InternetSetOptionW(session, INTERNET_OPTION_RECEIVE_TIMEOUT, timeoutStr, sizeof(timeout));

   if(method == "GET")
     {
      // URLを開く
      int connect = InternetOpenUrlW(session, url, headers, StringLen(headers), secure, 0);
      if(!connect)
        {
         InternetCloseHandle(session);
         string error = "エラー:URLを開けません";
         StringToCharArray(error, result);
         return(response);
        }

      //レスポンス確認
        {
         int bufferLength = 1024;
         uchar result_array[];
         string result_str = "";
         ArrayResize(result_array, bufferLength);
         int index = 0;
         // HTTPステータスコードを取得
         if(HttpQueryInfoA(connect, HTTP_QUERY_STATUS_CODE, result_array, bufferLength, index))
           {
            for(int i = 0; i < bufferLength; i++)
              {
               uchar ch[1];
               ch[0] = result_array[i];
               if(ch[0] != NULL)
                  result_str += CharArrayToString(ch);
               else
                  result_str += "\n";
              }
           }
         response = (int)result_str;
        }

      char receive[1024];
      int byteSize = 0;
      int totalBytesRead = 0;
      // レスポンスデータを読み取る
      while(InternetReadFile(connect, receive, 1024, byteSize))
        {
         if(byteSize <= 0)
            break;
         ArrayResize(result, totalBytesRead + byteSize);
         for(int i = 0; i < byteSize; ++i)
           {
            result[totalBytesRead + i] = receive[i];
           }
         totalBytesRead += byteSize;
        }

      InternetCloseHandle(connect);
     }
   else
      if(method == "POST")
        {
         // ホストに接続
         int connect = InternetConnectW(session, host, port, "", "", INTERNET_SERVICE_HTTP, 0, 0);
         if(!connect)
           {
            InternetCloseHandle(session);
            string error = "エラー:接続できません";
            StringToCharArray(error, result);
            return(response);
           }

         // HTTPリクエストを開く
         int hRequest = HttpOpenRequestW(connect, method, endpoint, "HTTP/1.1", "", "", secure | INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE, 0);
         if(!hRequest)
           {
            InternetCloseHandle(connect);
            InternetCloseHandle(session);
            string error = "エラー:HTTPリクエストを開けません";
            StringToCharArray(error, result);
            return(response);
           }

         if(!HttpSendRequestW(hRequest, headers, StringLen(headers), data, ArraySize(data)))
           {
            InternetCloseHandle(hRequest);
            InternetCloseHandle(connect);
            InternetCloseHandle(session);
            string error = "エラー:HTTPリクエストの送信に失敗しました。";
            StringToCharArray(error, result);
            return(response);
           }

         //レスポンス確認
           {
            int bufferLength = 1024;
            uchar result_array[];
            string result_str = "";
            int index = 0;
            ArrayResize(result_array, bufferLength);
            // HTTPステータスコードを取得
            if(HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE, result_array, bufferLength, index))
              {
               for(int i = 0; i < bufferLength; i++)
                 {
                  uchar ch[1];
                  ch[0] = result_array[i];
                  if(ch[0] != NULL)
                     result_str += CharArrayToString(ch);
                  else
                     result_str += "\n";
                 }
              }
            response = (int)result_str;
           }
         //リクエストヘッダー取得
           {
            int bufferLength = 1024;
            uchar result_array[];
            string result_str = "";
            ArrayResize(result_array, bufferLength);
            int index = 0;
            // HTTPステータスコードを取得
            if(HttpQueryInfoA(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, result_array, bufferLength, index))
              {
               for(int i = 0; i < bufferLength; i++)
                 {
                  uchar ch[1];
                  ch[0] = result_array[i];
                  if(ch[0] != NULL)
                     result_str += CharArrayToString(ch);
                  else
                     result_str += "\n";
                 }
              }
            result_headers = result_str;
           }

         char receive[1024];
         int byteSize = 0;
         int totalBytesRead = 0;
         // レスポンスデータを読み取る
         while(InternetReadFile(hRequest, receive, 1024, byteSize))
           {
            if(byteSize <= 0)
               break;
            ArrayResize(result, totalBytesRead + byteSize);
            for(int i = 0; i < byteSize; ++i)
              {
               result[totalBytesRead + i] = receive[i];
              }
            totalBytesRead += byteSize;
           }

         InternetCloseHandle(hRequest);
         InternetCloseHandle(connect);
        }
// インターネットセッションを閉じる
   InternetCloseHandle(session);
   return(response);
  }
//+------------------------------------------------------------------+

まとめ

MQL4、およびMQL5でHTTP通信を行うために開発された、改良版のWebRequest2関数について紹介しました。
この関数は、従来のWebRequest関数のデメリットを解消し、GETとPOSTメソッドに対応することで、開発者にとってより簡単なツール作成を実現します。

WebRequest2関数の特徴

メリット
  • URLを事前に許可する必要がなくなる
  • テスターやインジケーターから呼び出し可能
デメリット
  • コードが長くなる
  • GETとPOST以外のメソッドには未対応

開発者はこの関数を利用して、より効率的、かつ効果的なトレーディングツールやインジケーターを作成することが可能になります。

タイトルとURLをコピーしました