Why You Need a Custom DLL for Your MQL5 EA
Every serious algo trader eventually hits a wall in MQL5. Maybe you need to call a Windows API function that isn't exposed through MQL5's built-in libraries. Perhaps you're doing heavy mathematical calculations — like a Monte Carlo simulation or a custom risk model — that would run ten times faster in native C++. Or you might need to access a USB hardware device, read from a proprietary data feed, or integrate with a C++ library you already own.
MQL5 lets you import external functions from DLLs using the #import directive. But there's a big difference between importing a system DLL like kernel32.dll and building your own resource DLL from scratch. A resource DLL is a DLL that you compile specifically for your EA, bundle as a resource, and deploy alongside your .ex5 file. This gives you full control over the code and avoids dependency on third-party binaries.
In this guide, I'll walk you through the entire process: setting up Visual Studio for MQL5-compatible DLLs, writing a C++ function that MQL5 can call, compiling it with the right calling convention and export settings, importing it into your EA, and handling the common pitfalls that trip up most developers. By the end, you'll have a working MQL5 resource DLL that you can extend for your own projects.
One thing I want to emphasize upfront: don't let the C++ part scare you. You don't need to be a systems programmer. If you can write a basic function in C++ and compile a project, you're qualified. The hard part is getting the calling convention and export names right — and I'll show you exactly how to do that.
Prerequisites
Before we start, make sure you have the following ready. I'm assuming you already use MetaTrader 5 and have some basic familiarity with the MetaEditor.
- MetaTrader 5 — build 2000 or newer (check Help > About). The 64-bit version is required; MQL5 does not support 32-bit DLLs on modern builds. You can verify your build by going to Help > About in the terminal.
- Visual Studio 2022 Community Edition (free) — or any edition with the Desktop development with C++ workload installed. You can also use MinGW-w64 if you prefer, but I'll show Visual Studio because it's the most straightforward for Windows DLLs. When installing, make sure you select the "Desktop development with C++" workload — otherwise you won't have the compiler or linker.
- A demo or live MT5 account — you'll need to enable DLL imports in the EA properties to test. I'll cover that in the troubleshooting section.
- Basic C++ knowledge — you should know how to write a simple function, use pointers, and compile a project. You don't need to be an expert. If you've written a "Hello World" in C++, you're fine.
- MetaEditor — comes with MT5, located in the
MetaEditorfolder inside your MT5 installation directory. You can launch it from MT5 by pressing F4.
One more thing: you'll need to run Visual Studio and MetaTrader 5 as Administrator the first time you test the DLL, because Windows may block unsigned DLLs. We'll handle code signing later if you want to distribute your EA. For personal use, just running as admin is enough.
Step-by-Step: Creating Your First MQL5 Resource DLL
I'll break this into five clear steps. Follow them in order — skipping around usually leads to cryptic linker errors. I've done this process dozens of times, and the order matters.
Step 1: Create a New C++ DLL Project in Visual Studio
Open Visual Studio and select Create a new project. Search for "Dynamic-Link Library (DLL)" and pick the one with the C++ tag. Name your project MQL5MathLib (or whatever you like) and choose a folder. Click Create.
Visual Studio generates a template with dllmain.cpp and framework.h. You don't need to touch dllmain.cpp — it's the entry point for the DLL itself. We'll add our own source file.
Right-click your project in Solution Explorer, choose Add > New Item, select C++ File (.cpp), and name it exports.cpp. This is where we'll write the functions that MQL5 will call.
I prefer to keep the project structure clean: put all your export functions in one .cpp file, and put any internal helper functions in separate files. That way it's easy to see what's exposed to MQL5 and what's internal.
Step 2: Write a C++ Function That MQL5 Can Call
Here's the critical part: MQL5 expects functions in a DLL to use the stdcall calling convention (though MQL5 can also handle cdecl with the right attribute). For simplicity, I'll use __stdcall and extern "C" to prevent C++ name mangling, which would make the function invisible to MQL5.
Open exports.cpp and paste this code:
#include <windows.h>
extern "C" __declspec(dllexport) double __stdcall AddNumbers(double a, double b)
{
return a + b;
}
extern "C" __declspec(dllexport) int __stdcall Factorial(int n)
{
if (n < 0) return -1;
int result = 1;
for (int i = 2; i <= n; ++i)
result *= i;
return result;
}
extern "C" __declspec(dllexport) void __stdcall FillArray(int* arr, int size, int value)
{
for (int i = 0; i < size; ++i)
arr[i] = value;
}
Let me explain what this does. extern "C" tells the compiler not to mangle the function names, so MQL5 can find them by the exact name you specify. __declspec(dllexport) makes the function visible outside the DLL. __stdcall matches the calling convention MQL5 uses by default when you don't specify otherwise. The three functions give us a simple arithmetic, a recursive-style calculation, and an array operation — common patterns you'll reuse.
Note the FillArray function: it takes a pointer to an integer array. MQL5 passes arrays by reference, and we'll need to handle that carefully on the MQL side. I'll show you how.
A quick note on the #include <windows.h> — this is needed for Windows types like DWORD and BOOL if you use them, but even for basic functions it's a safe include. Some compilers will complain without it when using __stdcall.
Step 3: Configure the Project for 64-Bit Release Build
MQL5 is 64-bit only. You must compile your DLL for x64. In Visual Studio, find the Solution Platforms dropdown (it usually says "x86" or "Any CPU"). Change it to x64. If x64 isn't listed, open Configuration Manager (Build > Configuration Manager), click the Active solution platform dropdown, select <New...>, choose x64, and copy settings from Win32.
Next, set the build configuration to Release (not Debug). Debug DLLs link against debug runtime libraries that may not be present on a user's machine, causing crashes. Right-click your project, choose Properties, go to C/C++ > Code Generation, and set Runtime Library to /MT (Multi-threaded) instead of /MD. This statically links the C++ runtime into your DLL, so you don't need to ship extra msvcp*.dll files.
There's one more property to check: under Linker > Advanced, make sure Target Machine is set to MachineX64 (/MACHINE:X64). If you copied settings from Win32, this might still say X86, which will produce a 32-bit DLL. I've wasted an hour on this before.
Now build: press Ctrl+Shift+B. If everything compiles, you'll find MQL5MathLib.dll in YourProject\x64\Release\.
Step 4: Import the DLL in MQL5
Open MetaEditor (F4 in MT5) and create a new Expert Advisor or script. At the top of your code, add the #import directive. You have two choices for where to place the DLL:
- In the MT5 installation folder —
...\MetaTrader 5\(next to terminal64.exe). I don't recommend this because it mixes your custom DLLs with system files, and it makes deployment messy. - In the
...\MQL5\Libraries\folder — this is the standard location for MQL5 resource DLLs. Copy your.dllfile there. The full path is usuallyC:\Users\YourName\AppData\Roaming\MetaQuotes\Terminal\InstanceID\MQL5\Libraries\— but you can find it quickly by going to File > Open Data Folder in MT5, then navigating toMQL5\Libraries.
Assuming you copied the DLL to Libraries, here's the MQL5 import:
//+------------------------------------------------------------------+
//| Import our custom DLL |
//+------------------------------------------------------------------+
#import "MQL5MathLib.dll"
double AddNumbers(double a, double b);
int Factorial(int n);
void FillArray(int &arr[], int size, int value);
#import
Notice the & in int &arr[] — that's how MQL5 passes an array by reference to a DLL. The DLL receives a pointer to the array's data. Also note that the function names must match exactly (case-sensitive) what you exported. If you used __stdcall in C++, MQL5 will assume stdcall by default. If you used __cdecl, you'd need to add #import "MQL5MathLib.dll" cdecl — but stick with stdcall for simplicity.
One subtlety: MQL5 expects the DLL to be in the Libraries folder, but it also searches the terminal's root directory. If you put it in both places, MT5 will load the one from the root first. Don't do that — it's confusing.
Step 5: Call the DLL Functions from Your EA
Now you can use these functions as if they were native MQL5. Here's a simple test EA that calls each function:
//+------------------------------------------------------------------+
//| TestDLL.mq5 |
//+------------------------------------------------------------------+
#property copyright "Your Name"
#property version "1.00"
#import "MQL5MathLib.dll"
double AddNumbers(double a, double b);
int Factorial(int n);
void FillArray(int &arr[], int size, int value);
#import
int OnInit()
{
// Test AddNumbers
double sum = AddNumbers(12.5, 7.3);
Print("12.5 + 7.3 = ", sum); // Should print 19.8
// Test Factorial
int fact = Factorial(5);
Print("5! = ", fact); // Should print 120
// Test FillArray
int myArray[10];
FillArray(myArray, 10, 42);
for(int i = 0; i < 10; i++)
Print("myArray[", i, "] = ", myArray[i]); // All 42
return(INIT_SUCCEEDED);
}
// ... (empty OnTick and OnDeinit for this test)
Compile the EA (F7 in MetaEditor). If you get an "import function not found" error, double-check the function names in the DLL. You can use Dependency Walker (depends.com) or the dumpbin /exports MQL5MathLib.dll command to list exported functions. Open a command prompt in your DLL's folder and run dumpbin /exports MQL5MathLib.dll — you should see exactly the names you exported.
I always test with a simple script first. Attach the EA to a chart, open the Experts tab in the Toolbox, and watch for the print statements. If you see them, your DLL is working.
Tips and Best Practices from Experience
After building dozens of MQL5 resource DLLs, here's what I've learned the hard way. Some of these cost me hours of debugging.
Use a .def File for Clean Exports
Instead of __declspec(dllexport) on every function, you can create a Module Definition File (.def) that lists the exported names explicitly. This gives you more control and sometimes avoids ordinal export issues. Add a .def file to your Visual Studio project, write:
LIBRARY MQL5MathLib
EXPORTS
AddNumbers
Factorial
FillArray
Then in your C++ code, remove __declspec(dllexport) and just use extern "C" __stdcall. The linker will use the .def file to export only those names. This is especially helpful if you have internal functions you don't want exposed. I use .def files for all my production DLLs because it gives me precise control over the export table.
To add the .def file to your project: right-click your project, choose Add > New Item, select Module-Definition File (.def), and name it exports.def. Then in project properties under Linker > Input > Module Definition File, set it to exports.def.
Always Test with a Simple Script First
Don't embed DLL calls deep inside a complex EA. Write a tiny .mq5 script that calls each function and prints the result. Run it on a chart. This isolates any DLL issues from your EA logic. I keep a TestDLL.mq5 script in my Scripts folder for exactly this purpose. It takes 30 seconds to write and saves hours of debugging.
Handle Memory Carefully
MQL5 manages its own memory. When you pass an array to a DLL, the DLL gets a pointer to the internal data. Never call free() or delete on that pointer from C++ — it will corrupt the MQL5 memory manager. If your DLL needs to allocate memory, do it on the MQL5 side and pass a pre-allocated array, or have the DLL return a simple value. For complex data, consider using struct parameters with fixed-size arrays.
Another memory pitfall: if your DLL creates a thread or uses asynchronous callbacks, make sure you handle synchronization properly. MQL5's threading model is single-threaded, so your DLL callbacks can't call back into MQL5 functions directly. I've seen crashes from this.
Enable DLL Imports in the EA Settings
This trips up everyone. Even if your code is perfect, MT5 blocks DLL calls by default. Go to the EA's properties in the Navigator window (right-click the EA, choose Modify), or after attaching it to a chart, open its Inputs tab and check Allow DLL imports. On the Common tab, also check Allow external imports. Without both, your EA






