gryps2/EA-code/handy_systems/EXPERIMENTAL/HS-E-004-MAGIC-NUMBER-DUPLICATE-CHECKER/MagicNumberDuplicateChecker.mq4
super.admin ae3f0ebf03 convert
2025-05-30 14:58:21 +02:00

280 lines
No EOL
10 KiB
MQL4

//+------------------------------------------------------------------+
//| MagicNumberDuplicateChecker.mq4 |
//| Copyright (c) 2024, HANDY SYSTEMS |
//+------------------------------------------------------------------+
/*
The MIT License
Copyright (c) 2024, HANDY SYSTEMS
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#property copyright "Copyright (c) 2024, HANDY SYSTEMS"
#property version "1.0"
#property description "Magic Number Duplicate Checker"
#property strict
//+------------------------------------------------------------------+
//| Debug mode |
//+------------------------------------------------------------------+
#define DEBUG_MODE false
//+------------------------------------------------------------------+
//| Win32 API functions |
//+------------------------------------------------------------------+
#import "kernel32.dll"
int CreateFileW(string lpFileName, int dwDesiredAccess, int dwShareMode,
int lpSecurityAttributes, int dwCreationDisposition,
int dwFlagsAndAttributes, int hTemplateFile);
bool CloseHandle(int hObject);
int GetTempPathW(int nBufferLength, string& lpBuffer);
int GetCurrentProcessId();
#import
#import "ntdll.dll"
int RtlGetLastWin32Error();
#import
//+------------------------------------------------------------------+
//| Win32 API constants |
//+------------------------------------------------------------------+
#define GENERIC_WRITE 0x40000000
#define GENERIC_READ 0x80000000
#define FILE_SHARE_DELETE 0x00000004
#define CREATE_NEW 1
#define CREATE_ALWAYS 2
#define OPEN_EXISTING 3
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
#define INVALID_HANDLE_VALUE -1
#define ERROR_FILE_EXISTS 80
//+------------------------------------------------------------------+
//| Message constants |
//+------------------------------------------------------------------+
#define MSG_DUPLICATE_WARNING "WARNING: Magic number %d is already in use.\n\n" + \
"There may already be an EA running with the\n" + \
"same magic number for the same currency pair.\n\n" + \
"Do you want to continue running it?"
#define MSG_SYSTEM_ERROR "System error occurred: %d"
#define MSG_TEMP_PATH_ERROR "Failed to get temporary path"
//+------------------------------------------------------------------+
//| Input parameters |
//+------------------------------------------------------------------+
input int MagicNumber = 12345; // Magic Number: Unique identifier for EA
input bool CheckDuplicate = true; // Check Duplicate: Enable/disable duplicate checking
input int CheckInterval = 300; // Check Interval: Time between checks (seconds)
//+------------------------------------------------------------------+
//| Global variables |
//+------------------------------------------------------------------+
datetime lastCheckTime = 0; // Last check timestamp
int lockFileHandle = INVALID_HANDLE_VALUE; // Lock file handle
string tempPath = ""; // Temporary file path
//+------------------------------------------------------------------+
//| Custom logging function |
//+------------------------------------------------------------------+
void LogDebug(const string message)
{
if (DEBUG_MODE) Print("[DEBUG] ", message);
}
//+------------------------------------------------------------------+
//| Get Windows temporary path |
//+------------------------------------------------------------------+
bool GetTempPath()
{
string buffer = " "; // 50 chars buffer
int result = GetTempPathW(StringLen(buffer), buffer);
if (result > 0)
{
tempPath = StringSubstr(buffer, 0, result);
LogDebug("Temp path: " + tempPath);
return true;
}
Print(MSG_TEMP_PATH_ERROR);
return false;
}
//+------------------------------------------------------------------+
//| Generate lock file name |
//+------------------------------------------------------------------+
string GetLockFileName()
{
string fileName = StringFormat("MT4_Magic_%d_%s_%d.lock",
MagicNumber,
Symbol(),
GetCurrentProcessId()
);
LogDebug("Lock file name: " + fileName);
return tempPath + fileName;
}
//+------------------------------------------------------------------+
//| Check for magic number duplication |
//+------------------------------------------------------------------+
bool CheckDuplicateMagicNumber()
{
string fileName = GetLockFileName();
int fileHandle = CreateFileW(
fileName,
(int)GENERIC_READ,
0,
0,
OPEN_EXISTING,
0,
0
);
if (fileHandle != INVALID_HANDLE_VALUE)
{
if (fileHandle != lockFileHandle)
{
CloseHandle(fileHandle);
return true; // Duplicate found
}
CloseHandle(fileHandle);
}
return false; // No duplicate
}
//+------------------------------------------------------------------+
//| Register magic number |
//+------------------------------------------------------------------+
bool RegisterMagicNumber()
{
string fileName = GetLockFileName();
LogDebug("Attempting to register magic number: " + IntegerToString(MagicNumber));
lockFileHandle = CreateFileW(
fileName,
(int)GENERIC_WRITE,
0,
0,
CREATE_NEW,
(int)(FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE),
0
);
if (lockFileHandle == INVALID_HANDLE_VALUE)
{
int error = RtlGetLastWin32Error();
if (error == ERROR_FILE_EXISTS)
{
// Show warning and ask user whether to continue
string message = StringFormat(MSG_DUPLICATE_WARNING, MagicNumber);
int response = MessageBox(
message,
"Magic Number Duplicate Warning",
MB_ICONWARNING | MB_OKCANCEL
);
if (response == IDCANCEL)
{
LogDebug("User canceled operation");
return false;
}
LogDebug("User chose to continue despite duplicate");
return true; // User accepted the risk
}
else
{
// Handle other system errors
string errorMsg = StringFormat(MSG_SYSTEM_ERROR, error);
MessageBox(
errorMsg,
"System Error",
MB_ICONERROR | MB_OK
);
Print(errorMsg);
return false;
}
}
LogDebug("Successfully registered magic number");
return true;
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Get temporary path
if (!GetTempPath())
{
return INIT_FAILED;
}
// Perform duplicate checking if enabled
if (CheckDuplicate)
{
if (!RegisterMagicNumber())
{
return INIT_FAILED;
}
}
lastCheckTime = TimeCurrent();
LogDebug("Initialization completed successfully");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if (lockFileHandle != INVALID_HANDLE_VALUE)
{
LogDebug("Closing lock file handle");
if (!CloseHandle(lockFileHandle))
{
int error = RtlGetLastWin32Error();
Print("Failed to close handle: ", error);
}
lockFileHandle = INVALID_HANDLE_VALUE;
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if (!CheckDuplicate) return;
// Perform periodic checks
if (TimeCurrent() - lastCheckTime >= CheckInterval)
{
if (CheckDuplicateMagicNumber())
{
Print("Warning: Duplicate magic number detected during runtime check");
Alert("Warning: Duplicate magic number detected\nMagic Number: ", MagicNumber);
}
lastCheckTime = TimeCurrent();
}
}
//+------------------------------------------------------------------+