FullMt5McpByLeo/Src/Complex/Pw.mqh
Nique_372 e8527b2815
2026-06-30 10:46:22 -05:00

128 lines
4.3 KiB
MQL5

//+------------------------------------------------------------------+
//| Pw.mqh |
//| Copyright 2026, Niquel Mendoza. |
//| https://www.mql5.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Niquel Mendoza."
#property link "https://www.mql5.com/"
#property strict
#ifndef FULLMT5MCPBYLEO_SRC_COMPLEX_PW_MQH
#define FULLMT5MCPBYLEO_SRC_COMPLEX_PW_MQH
//+------------------------------------------------------------------+
//| Include |
//+------------------------------------------------------------------+
#include "..\\Def\\Def.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
class CMcpFuncRunCommand : public CMcpFunction
{
private:
int m_mode;
CJsonBuilder m_builder;
public:
CMcpFuncRunCommand(int mode)
: CMcpFunction(0, false, "run_command"), m_mode(mode) {}
~CMcpFuncRunCommand(void) {}
void Run(CJsonNode& param, string& res) override final;
};
//+------------------------------------------------------------------+
void CMcpFuncRunCommand::Run(CJsonNode& param, string& res) override final
{
//---
const string command = param["run"].ToStringNoEscape("");
const uint timeout = uint(param["timeout_segundos"].ToInt(1) * 1000);
//---
if(command == "")
{
res = "{\"ok\":false,\"result\":\"Empty command\"}";
return;
}
if(m_mode == 0)
{
res = "{\"ok\":false,\"result\":\"The user has disabled the use of this tool in the EA settings.\"}";
return;
}
//--- Nombre único de archivo temporal, relativo a la carpeta Files (para usarlo con funciones nativas MQL5)
const string rel_file = "McpMt5ByLeo\\temp.txt";
//--- Asegurar que la subcarpeta exista, en el ámbito Common
FolderCreate("McpMt5ByLeo", FILE_COMMON);
//--- Ruta absoluta real en disco: Common + \Files\ + subcarpeta + archivo
const string abs_path = TERMINAL_MT5_COMMON_PATH + "\\Files\\" + rel_file;
//--- Borrar cualquier residuo previo antes de ejecutar
FileDelete(rel_file, FILE_COMMON);
//--- El propio shell redirige su salida (stdout + stderr) al archivo
string ps_args = "-NoProfile -NonInteractive";
if(m_mode == 1)
ps_args += " -ExecutionPolicy AllSigned";
else
if(m_mode == 2)
ps_args += " -ExecutionPolicy Restricted";
string ps_inner =
"$out = & { " + command + " } 2>&1 | Out-String; " +
"[System.IO.File]::WriteAllText('" + abs_path + "', $out, [System.Text.UTF8Encoding]::new($false))";
string full_command = "powershell " + ps_args + " -Command \"" + ps_inner + "\"";
//---
PROCESS_INFORMATION pi;
STARTUPINFOW si;
ZeroMemory(pi);
ZeroMemory(si);
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
//---
const int created = CreateProcessW(NULL, full_command, NULL, NULL, 0, 0x08000000, NULL, NULL, si, pi);
if(created == 0)
{
res = StringFormat("{\"ok\":false,\"result\":\"Failed call CreateProcessW, last error = %u\"}", GetLastError());
return;
}
//--- Esperar a que el proceso termine
const uint wait_result = WaitForSingleObject(pi.hProcess, timeout);
if(wait_result == WAIT_TIMEOUT_VAL)
TerminateProcess(pi.hProcess, 1);
uint exit_code = 0;
GetExitCodeProcess(pi.hProcess, exit_code);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
//--- Leer el contenido del archivo con funciones nativas de MQL5 (ámbito Common)
uchar data[];
const long size = FileLoad(rel_file, data, FILE_COMMON);
//--- Borrar el archivo temporal para no acumular basura
FileDelete(rel_file, FILE_COMMON);
//---
m_builder.Clear();
m_builder.Obj();
m_builder.Key("ok").Val(bool(exit_code == 0));
m_builder.Key("result").Obj();
m_builder.Key("exit_code").Val(int(exit_code));
m_builder.Key("stdout").ValU(data);
m_builder.EndObj();
m_builder.EndObj();
res = m_builder.Build();
}
}
//+------------------------------------------------------------------+
#endif // FULLMT5MCPBYLEO_SRC_COMPLEX_PW_MQH