😽
MQL5Discord
MQL5成功
//+------------------------------------------------------------------+
//| Discord Notification EA.mq5 |
//| Copyright 2025 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025"
#property link ""
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| WinINet.mqh |
//| Copyright 2023-2024, Geraked |
//| https://github.com/geraked |
//+------------------------------------------------------------------+
#define WININET_TIMEOUT_SECS 300
#define WININET_BUFF_SIZE 16384
#define WININET_KERNEL_ERRORS true
#define INTERNET_FLAG_PRAGMA_NOCACHE 0x00000100
#define INTERNET_FLAG_KEEP_CONNECTION 0x00400000
#define INTERNET_FLAG_SECURE 0x00800000
#define INTERNET_FLAG_RELOAD 0x80000000
#define INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP 0x00008000
#define INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS 0x00004000
#define INTERNET_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000
#define INTERNET_FLAG_IGNORE_CERT_CN_INVALID 0x00001000
#define INTERNET_FLAG_NO_AUTO_REDIRECT 0x00200000
#define INTERNET_OPTION_HTTP_DECODING 65
#define INTERNET_OPTION_SEND_TIMEOUT 5
#define INTERNET_OPTION_RECEIVE_TIMEOUT 6
#define HTTP_QUERY_CONTENT_LENGTH 5
#define HTTP_QUERY_STATUS_CODE 19
#define HTTP_QUERY_STATUS_TEXT 20
#define HTTP_QUERY_RAW_HEADERS 21
#define HTTP_QUERY_RAW_HEADERS_CRLF 22
#import "kernel32.dll"
uint GetLastError(void);
#import
#import "wininet.dll"
long InternetOpenW(const ushort &lpszAgent[], int dwAccessType, const ushort &lpszProxyName[], const ushort &lpszProxyBypass[], uint dwFlags);
long InternetConnectW(long hInternet, const ushort &lpszServerName[], int nServerPort, const ushort &lpszUsername[], const ushort &lpszPassword[], int dwService, uint dwFlags, int dwContext);
long HttpOpenRequestW(long hConnect, const ushort &lpszVerb[], const ushort &lpszObjectName[], const ushort &lpszVersion[], const ushort &lpszReferer[], const ushort &lplpszAcceptTypes[][], uint dwFlags, int dwContext);
int InternetCloseHandle(long hInternet);
int InternetSetOptionW(long hInternet, int dwOption, long &lpBuffer, int dwBufferLength);
int HttpAddRequestHeadersW(long hRequest, const ushort &lpszHeaders[], int dwHeadersLength, uint dwModifiers);
int HttpSendRequestW(long hRequest, const ushort &lpszHeaders[], int dwHeadersLength, const uchar &lpOptional[], int dwOptionalLength);
int HttpSendRequestExW(long hRequest, long lpBuffersIn, long lpBuffersOut, uint dwFlags, int dwContext);
int HttpEndRequestW(long hRequest, long lpBuffersOut, uint dwFlags, int dwContext);
int HttpQueryInfoW(long hRequest, int dwInfoLevel, uchar &lpvBuffer[], int &lpdwBufferLength, int &lpdwIndex);
int InternetWriteFile(long hFile, const uchar &lpBuffer[], int dwNumberOfBytesToWrite, int &lpdwNumberOfBytesWritten);
int InternetReadFile(long hFile, uchar &lpBuffer[], int dwNumberOfBytesToRead, int &lpdwNumberOfBytesRead);
#import
struct WininetRequest {
string method;
string host;
int port;
string path;
string headers;
uchar data[];
string data_str;
void WininetRequest() {
method = "GET";
port = 443;
path = "/";
headers = "";
}
};
struct WininetResponse {
int status;
string headers;
uchar data[];
string GetDataStr() {
return UnicodeUnescape(data);
}
};
//+------------------------------------------------------------------+
//| HTTP request using wininet.dll |
//+------------------------------------------------------------------+
int WebReq(
const string method, // HTTP method
const string host, // host name
const string path, // URL path
int port, // port number
bool secure, // use HTTPS
const string headers, // HTTP request headers
const uchar &data[], // HTTP request body
uchar &result[], // server response data
string &result_headers // headers of server response
) {
//- Declare the variables.
ushort buff[WININET_BUFF_SIZE / 2], buff2[WININET_BUFF_SIZE / 2];
uchar cbuff[WININET_BUFF_SIZE];
int n, bLen, bLen2, bIdx;
long lval;
long session, connection, request;
int status;
uint flags;
string head;
//- Create the NULL string.
ushort nill[2] = {0, 0};
ushort nill2[2][2] = {{0, 0}, {0, 0}};
//- Create a session.
StringToShortArray(GetUserAgent(), buff);
session = InternetOpenW(buff, 0, nill, nill, 0);
if (session <= 0)
return _wininetErr("InternetOpen");
//- Enable automatically decoding from gzip and deflate.
lval = 1;
if (!InternetSetOptionW(session, INTERNET_OPTION_HTTP_DECODING, lval, sizeof(int)))
return _wininetErr("InternetSetOption, DECODING", session);
//- Set timeouts.
lval = WININET_TIMEOUT_SECS * 1000;
if (!InternetSetOptionW(session, INTERNET_OPTION_SEND_TIMEOUT, lval, sizeof(int)))
return _wininetErr("InternetSetOption, SEND_TIMEOUT", session);
lval = WININET_TIMEOUT_SECS * 1000;
if (!InternetSetOptionW(session, INTERNET_OPTION_RECEIVE_TIMEOUT, lval, sizeof(int)))
return _wininetErr("InternetSetOption, RECEIVE_TIMEOUT", session);
//- Create a connection.
StringToShortArray(host, buff);
connection = InternetConnectW(session, buff, port, nill, nill, 3, 0, 0);
if (connection <= 0)
return _wininetErr("InternetConnect", session);
//- Open a request.
StringToShortArray(method, buff);
StringToShortArray(path, buff2);
flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE;
flags |= INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
if (port == 443 || (secure && port != 80)) flags |= INTERNET_FLAG_SECURE;
if (method == "GET") flags |= INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS;
if (method != "GET") flags |= INTERNET_FLAG_NO_AUTO_REDIRECT;
request = HttpOpenRequestW(connection, buff, buff2, nill, nill, nill2, flags, 0);
if (request <= 0)
return _wininetErr("HttpOpenRequest", session, connection);
//- Add request headers.
n = ArraySize(data);
if (n > 0 && data[n - 1] == 0) n--;
head = StringFormat("Accept-Encoding: gzip, deflate\r\n"
"Content-Length: %d\r\n", n);
bLen = StringToShortArray(head + headers, buff);
if (bLen > 0 && buff[bLen - 1] == 0) bLen--;
if (!HttpAddRequestHeadersW(request, buff, bLen, 0x80000000))
return _wininetErr("HttpAddRequestHeaders", session, connection, request);
//- Send the request.
int cnt = 1;
while (!HttpSendRequestExW(request, 0, 0, 0, 0)) {
if (cnt == 5)
return _wininetErr("HttpSendRequestEx", session, connection, request);
Sleep(1000);
cnt++;
}
bIdx = 0;
bLen2 = 0;
while (true) {
bLen = MathMin(WININET_BUFF_SIZE, n - bIdx);
if (bLen <= 0) break;
ArrayCopy(cbuff, data, 0, bIdx, bLen);
if (!InternetWriteFile(request, cbuff, bLen, bLen2))
return _wininetErr("InternetWriteFile", session, connection, request);
bIdx += bLen2;
}
if (!HttpEndRequestW(request, 0, 0, 0))
return _wininetErr("HttpEndRequest", session, connection, request);
//- Fetch the status code from the response header.
bLen = WININET_BUFF_SIZE;
bIdx = 0;
if (!HttpQueryInfoW(request, HTTP_QUERY_STATUS_CODE, cbuff, bLen, bIdx))
return _wininetErr("HttpQueryInfo, STATUS_CODE", session, connection, request);
status = (int) UnicodeUnescape(cbuff, bLen);
//- Fetch the entire response header.
bLen = WININET_BUFF_SIZE;
bIdx = 0;
if (!HttpQueryInfoW(request, HTTP_QUERY_RAW_HEADERS_CRLF, cbuff, bLen, bIdx))
return _wininetErr("HttpQueryInfo, HEADER", session, connection, request);
result_headers = UnicodeUnescape(cbuff, bLen);
//- Fetch the response body.
bLen = 0;
while (true) {
if (!InternetReadFile(request, cbuff, WININET_BUFF_SIZE, bLen))
return _wininetErr("InternetReadFile", session, connection, request);
if (bLen <= 0) break;
ArrayCopy(result, cbuff, ArraySize(result), 0, bLen);
}
//- Close the request, connection, and session.
if (!InternetCloseHandle(request))
_wininetErr("InternetCloseRequest");
if (!InternetCloseHandle(connection))
_wininetErr("InternetCloseConnection");
if (!InternetCloseHandle(session))
_wininetErr("InternetCloseSession");
return status;
}
//+------------------------------------------------------------------+
//| Overload |
//+------------------------------------------------------------------+
bool WebReq(WininetRequest &req, WininetResponse &res) {
if (req.method == NULL || req.method == "") req.method = "GET";
if (req.path == NULL || req.path == "") req.path = "/";
if (req.headers == NULL) req.headers = "";
if (req.port == 0) req.port = 443;
if (ArraySize(req.data) > 0 || req.data_str == NULL)
res.status = WebReq(req.method, req.host, req.path, req.port, false, req.headers, req.data, res.data, res.headers);
else {
uchar data_arr[];
StringToCharArray(req.data_str, data_arr, 0, WHOLE_ARRAY, CP_UTF8);
res.status = WebReq(req.method, req.host, req.path, req.port, false, req.headers, data_arr, res.data, res.headers);
}
if (res.status == -1) return false;
return true;
}
//+------------------------------------------------------------------+
//| Generate User-Agent for the HTTP request header. |
//+------------------------------------------------------------------+
string GetUserAgent() {
return StringFormat(
"%s/%d (%s; %s; %s %d Cores; %dMB RAM) WinINet/1.6",
TerminalInfoString(TERMINAL_NAME),
TerminalInfoInteger(TERMINAL_BUILD),
TerminalInfoString(TERMINAL_OS_VERSION),
TerminalInfoInteger(TERMINAL_X64) ? "x64" : "x32",
TerminalInfoString(TERMINAL_CPU_NAME),
TerminalInfoInteger(TERMINAL_CPU_CORES),
TerminalInfoInteger(TERMINAL_MEMORY_PHYSICAL)
);
}
//+------------------------------------------------------------------+
//| Remove 0 characters from the fixed size array. |
//+------------------------------------------------------------------+
template<typename T>
int ArrayRemoveGaps(T &arr[], int n) {
int i, j, k;
T c;
k = 0;
for (i = 0; i < n; i++) {
if (arr[i] != 0) {
k++;
continue;
}
c = 0;
for (j = i + 1; j < n; j++) {
if (arr[j] != 0) {
c = arr[j];
arr[j] = 0;
break;
}
}
if (c == 0) break;
arr[i] = c;
k++;
}
if (k < n)
arr[k] = 0;
return k;
}
//+------------------------------------------------------------------+
//| Unescape Unicode characters from the string. |
//+------------------------------------------------------------------+
string UnicodeUnescape(string str) {
ushort s[];
ushort c1, c2, c, x;
int n, i, j, k;
n = StringLen(str);
ArrayResize(s, n);
i = 0;
j = 0;
while (i < n) {
c1 = str[i];
c2 = i + 1 < n ? str[i + 1] : 0;
if (c1 == '\\' && (c2 == 'u' || c2 == 'U')) {
if (i + 5 < n) {
c = 0;
for (k = i + 2; k < i + 6; k++) {
x = str[k];
if (x >= '0' && x <= '9') x = x - '0';
else if (x >= 'a' && x <= 'f') x = x - 'a' + 10;
else if (x >= 'A' && x <= 'F') x = x - 'A' + 10;
else break;
c = (c << 4) | (x & 0xF);
}
if (k == i + 6) {
if (c != 0) s[j++] = c;
i += 6;
} else {
s[j++] = c1;
i++;
}
} else {
s[j++] = c1;
i++;
}
} else {
s[j++] = c1;
i++;
}
}
return ShortArrayToString(s, 0, j);
}
//+------------------------------------------------------------------+
//| Overload |
//+------------------------------------------------------------------+
string UnicodeUnescape(ushort &arr[], int n = 0) {
if (n == 0) n = ArraySize(arr);
n = ArrayRemoveGaps(arr, n);
return UnicodeUnescape(ShortArrayToString(arr, 0, n));
}
//+------------------------------------------------------------------+
//| Overload |
//+------------------------------------------------------------------+
string UnicodeUnescape(uchar &arr[], int n = 0) {
if (n == 0) n = ArraySize(arr);
n = ArrayRemoveGaps(arr, n);
return UnicodeUnescape(CharArrayToString(arr, 0, n, CP_UTF8));
}
//+------------------------------------------------------------------+
//| Handle WinINet errors. |
//+------------------------------------------------------------------+
int _wininetErr(string title = "", long session = 0, long connection = 0, long request = 0) {
uint err = kernel32::GetLastError();
if (WININET_KERNEL_ERRORS)
PrintFormat("Error (%s, %s): #%d", "WinINet", title, err);
if (request > 0) InternetCloseHandle(request);
if (connection > 0) InternetCloseHandle(connection);
if (session > 0) InternetCloseHandle(session);
return -1;
}
//+------------------------------------------------------------------+
//| 日本語/Unicode文字に対応した強化JSON文字列エスケープ関数 |
//+------------------------------------------------------------------+
string EnhancedEscapeJSON(string text)
{
// 空の文字列チェック
if(text == "" || text == NULL)
{
Print("警告: EnhancedEscapeJSONに空の文字列が渡されました");
return "MT5からの自動メッセージ"; // 空文字列を返さずデフォルト値を返す
}
Print("EnhancedEscapeJSON入力: ", text);
string escaped = text;
// JSONのための特殊文字をエスケープ
StringReplace(escaped, "\\", "\\\\"); // バックスラッシュは最初に処理する必要あり
StringReplace(escaped, "\"", "\\\""); // ダブルクォート
StringReplace(escaped, "\n", "\\n"); // 改行
StringReplace(escaped, "\r", "\\r"); // キャリッジリターン
StringReplace(escaped, "\t", "\\t"); // タブ
// バックスペースとフォームフィードはMQL5では非対応
Print("特殊文字エスケープ後: ", escaped);
return escaped; // 文字変換処理を単純化して問題箇所を減らす
}
//+------------------------------------------------------------------+
//| URLからホスト名とパス名を抽出する関数 |
//+------------------------------------------------------------------+
bool ParseURL(string url, string &host, string &path, int &port)
{
host = "";
path = "";
port = 80;
int pos = StringFind(url, "://");
if(pos < 0) return(false);
string protocol = StringSubstr(url, 0, pos);
if(StringCompare(protocol, "https", false) == 0) port = 443;
string temp = StringSubstr(url, pos + 3);
pos = StringFind(temp, "/");
if(pos < 0)
{
host = temp;
path = "/";
}
else
{
host = StringSubstr(temp, 0, pos);
path = StringSubstr(temp, pos);
}
// ポート番号が含まれている場合
int portPos = StringFind(host, ":");
if(portPos >= 0)
{
string portStr = StringSubstr(host, portPos + 1);
host = StringSubstr(host, 0, portPos);
port = (int)StringToInteger(portStr);
}
return(true);
}
//+------------------------------------------------------------------+
//| マルチパートフォームデータの境界文字列を生成する関数 |
//+------------------------------------------------------------------+
string GenerateBoundary()
{
return "----WebKitFormBoundary" + IntegerToString(GetTickCount());
}
//+------------------------------------------------------------------+
//| テキストメッセージのみをDiscordに送信する関数 |
//+------------------------------------------------------------------+
bool SendDiscordTextNotification(string message, string webhookUrl)
{
// URLからホスト名とパス名を抽出
string host, path;
int port;
if(!ParseURL(webhookUrl, host, path, port))
{
Print("URLの解析に失敗しました");
return false;
}
// JSONペイロードを作成
string escapedMessage = EnhancedEscapeJSON(message);
string payloadJson = "{\"content\":\"" + escapedMessage + "\"}";
Print("テキスト送信用JSON: ", payloadJson);
// WinINet.mqhライブラリを使用してHTTPリクエスト送信
WininetRequest req;
WininetResponse res;
req.method = "POST";
req.host = host;
req.port = port;
req.path = path;
// ヘッダーを設定
req.headers = "Content-Type: application/json\r\n";
req.headers += "User-Agent: MT5/Discord-Integration\r\n";
// UTF-8エンコーディングを使用するために、data_str経由でJSONを送信
req.data_str = payloadJson;
// リクエスト送信
Print("テキストメッセージを送信中...");
bool result = WebReq(req, res);
if(!result)
{
Print("WebReq関数の実行に失敗しました");
return false;
}
// レスポンスをチェック
string response = res.GetDataStr();
Print("Discord応答: ", response);
Print("ステータスコード: ", res.status);
// 成功の判定
if((res.status >= 200 && res.status < 300) || StringFind(response, "\"id\"") >= 0)
{
Print("Discordへのテキスト送信成功");
return true;
}
Print("Discordへのテキスト送信失敗");
return false;
}
//+------------------------------------------------------------------+
//| 画像のみをDiscordに送信する関数 |
//+------------------------------------------------------------------+
bool SendDiscordImageNotification(string filename, string webhookUrl)
{
// ファイルが存在するか確認
if(!FileIsExist(filename))
{
Print("ファイルが存在しません: ", filename);
return false;
}
// ファイルを開く - 共有モードを使用
int filehandle = FileOpen(filename, FILE_READ|FILE_BIN|FILE_SHARE_READ);
if(filehandle == INVALID_HANDLE)
{
Print("ファイルを開けませんでした: ", GetLastError());
return false;
}
// ファイルサイズを取得
ulong filesize = FileSize(filehandle);
if(filesize == 0)
{
FileClose(filehandle);
Print("ファイルサイズが0です");
return false;
}
// ファイルの内容を読み込む
uchar filedata[];
ArrayResize(filedata, (int)filesize);
FileReadArray(filehandle, filedata, 0, (int)filesize);
FileClose(filehandle);
// URLからホスト名とパス名を抽出
string host, path;
int port;
if(!ParseURL(webhookUrl, host, path, port))
{
Print("URLの解析に失敗しました");
return false;
}
// 境界文字列を生成
string boundary = GenerateBoundary();
// 空のJSONペイロード(メッセージなし)
string payloadJson = "{\"content\":\"\"}";
// マルチパートフォームデータを構築
string formData = "";
// パート1: JSON ペイロード
formData += "--" + boundary + "\r\n";
formData += "Content-Disposition: form-data; name=\"payload_json\"\r\n";
formData += "Content-Type: application/json\r\n\r\n";
formData += payloadJson + "\r\n";
// パート2: ファイル
formData += "--" + boundary + "\r\n";
formData += "Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"\r\n";
formData += "Content-Type: image/png\r\n\r\n";
// 終了境界
string endBoundary = "\r\n--" + boundary + "--\r\n";
// マルチパートデータを直接コンストラクト
uchar requestData[];
// ファイルサイズを考慮して十分な配列サイズを確保
int totalSize = StringLen(formData) * 3 + (int)filesize + StringLen(endBoundary) * 3;
ArrayResize(requestData, totalSize);
int pos = 0;
// ヘッダー部分
uchar temp[];
StringToCharArray(formData, temp, 0, StringLen(formData), CP_UTF8);
for(int i = 0; i < ArraySize(temp); i++)
requestData[pos++] = temp[i];
// ファイルデータ
for(int i = 0; i < (int)filesize; i++)
requestData[pos++] = filedata[i];
// フッター部分
ArrayFree(temp);
StringToCharArray(endBoundary, temp, 0, StringLen(endBoundary), CP_UTF8);
for(int i = 0; i < ArraySize(temp); i++)
requestData[pos++] = temp[i];
// 実際のデータサイズに配列を再調整
ArrayResize(requestData, pos);
Print("画像データを送信中... サイズ: ", pos, " バイト");
// WinINet.mqhライブラリを使用してHTTPリクエスト送信
WininetRequest req;
WininetResponse res;
req.method = "POST";
req.host = host;
req.port = port;
req.path = path;
// ヘッダーを設定
req.headers = "Content-Type: multipart/form-data; boundary=" + boundary + "; charset=utf-8\r\n";
req.headers += "User-Agent: MT5/Discord-Integration\r\n";
req.headers += "Connection: close\r\n";
// バイナリデータをセット
ArrayResize(req.data, ArraySize(requestData));
ArrayCopy(req.data, requestData, 0, 0, ArraySize(requestData));
// リクエスト送信
bool result = WebReq(req, res);
if(!result)
{
Print("WebReq関数の実行に失敗しました");
return false;
}
// レスポンスをチェック
string response = res.GetDataStr();
Print("Discord応答: ", response);
Print("ステータスコード: ", res.status);
// 成功の判定
if((res.status >= 200 && res.status < 300) || StringFind(response, "\"id\"") >= 0)
{
Print("Discordへの画像送信成功");
return true;
}
Print("Discordへの画像送信失敗");
return false;
}
//+------------------------------------------------------------------+
//| テキストと画像の両方をDiscordに送信する関数 |
//+------------------------------------------------------------------+
bool SendImageToDiscord(string filename, string webhookUrl, string message)
{
// まずテキストメッセージを送信
bool textSuccess = SendDiscordTextNotification(message, webhookUrl);
// 次に画像を送信
bool imageSuccess = SendDiscordImageNotification(filename, webhookUrl);
// 両方成功した場合にtrueを返す
return textSuccess && imageSuccess;
}
// 外部パラメータ
input string DiscordWebhookURL = "https://discord.com/api/webhooks/your-webhook-id/your-webhook-token"; // Discord Webhook URL
input int ScreenshotInterval = 300; // スクリーンショット間隔(秒)
input string MessageText = "MT5からの画像です"; // 送信メッセージ
// グローバル変数
int lastScreenshotTime = 0;
string terminalDataPath = "";
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// 初期化時に時間をリセット
lastScreenshotTime = 0;
// ターミナルデータパスを取得
terminalDataPath = TerminalInfoString(TERMINAL_DATA_PATH);
Print("Discord Image Sender EA 初期化完了");
Print("データパス: ", terminalDataPath);
Print("設定メッセージ: ", MessageText);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("Discord Image Sender EA 停止");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 現在の時間を取得
int currentTime = (int)TimeLocal();
// スクリーンショット間隔を確認
if(currentTime - lastScreenshotTime >= ScreenshotInterval)
{
// スクリーンショットを撮影して送信
TakeAndSendScreenshot();
// 最後のスクリーンショット時間を更新
lastScreenshotTime = currentTime;
}
}
//+------------------------------------------------------------------+
//| スクリーンショットを撮影して送信する関数 |
//+------------------------------------------------------------------+
void TakeAndSendScreenshot()
{
// 現在の日時を取得してファイル名に使用
string timestamp = TimeToString(TimeLocal(), TIME_DATE|TIME_SECONDS);
StringReplace(timestamp, ":", "-");
StringReplace(timestamp, " ", "_");
// スクリーンショットのファイル名を作成(ファイル名のみ指定)
string filename = "MT5_Screenshot_" + timestamp + ".png";
Print("保存ファイル: ", filename);
// スクリーンショットを撮影 - MT5ではChartScreenShotを使用
if(!ChartScreenShot(0, filename, 1024, 768, ALIGN_RIGHT))
{
Print("スクリーンショット撮影エラー: ", GetLastError());
return;
}
Print("スクリーンショット保存成功");
// メッセージテキストを確認(空の場合はデフォルト値を使用)
string messageToSend = MessageText;
if(messageToSend == "" || messageToSend == NULL)
{
messageToSend = "MT5からの画像です(自動メッセージ)";
Print("警告: MessageTextが空のため、デフォルトメッセージを使用します");
}
Print("送信メッセージ: ", messageToSend);
// Discordに送信
if(DiscordWebhookURL != "")
{
if(SendImageToDiscord(filename, DiscordWebhookURL, messageToSend))
Print("Discordへの送信成功");
else
Print("Discordへの送信失敗");
}
}
Discussion