Calling a DLL from MQL
There are times when we want access to additional data structures and function libraries than the ones provided by MetaTrader’s MQL. Besides native open-source MQL options, we can create our own Dynamic Link Library (DLL) in C# or C++ and link it to our programs.
In this article, we research how to connect to DLLs created with these languages. We must keep in mind that the code generated by C# is managed code running on the .NET framework, while C++'s code is native. We are going to use Visual Studio 2022 for this exercise.
Creating a DLL with C#
To create a DLL with C#, we need the Unmanaged Exports library by Robert Giesecke or RGiesecke library for short. This library gives our functions the ability to interact with native (unmanaged) executables.
Start by installing Microsoft Build Tools 2015 and .NET 3.5 as recommended in this StackOverflow article. They are necessary to use the RGiesecke library. Restart Visual Studio and create a new C# Class Library (.NET Framework) project. Right-click on the project and select Properties. Make sure to do it on the project, not on the solution. Click on Build and select x86 for Platform target. MQL can only interact with 32-bit DLLs, hence the need to do this change.
On the top bar, look for Configuration Manager,
and click on it and add a new x86 Project context.
Add the RGiesecke library reference to the project by right-clicking on References and selecting Manage Nuget Packages. Look for unmanaged exports and click the Install button.
Add the following functions to the Class1.cs file.
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace MyDll
{
public class Class1
{
[DllExport("Add", CallingConvention = CallingConvention.StdCall)]
public static int Add(int a, int b)
{
return a + b;
}
[DllExport("AddDouble", CallingConvention = CallingConvention.StdCall)]
public static double AddDouble(double a, double b)
{
return a + b;
}
}
}
Original version from How To MT4 Call C# DLL Function
The DllExport
annotation is provided by the RGiesecke library. It defines the name of the exported function, or in other words, the name that an external program will use to call it. We are exporting two functions in this example.
Build the solution. This process, if successful, will generate a DLL file in the Debug folder of the solution. The full path to it is displayed by the build process. Copy the resulting DLL to MetaTrader’s Data folder > MQL4 > Libraries directory.
We will now create the MetaTrader code that will call the functions in our DLL.
On MetaTrader, open the MetaQuotes Language Editor. Create a new Indicator and add the following code to it.
#property copyright "Copyright 2022, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#import "MyDll.dll"
int Add(int, int);
double AddDouble(double, double);
#import
int OnInit() {
Print("Add: " + IntegerToString(Add(1, 2)));
Print("Add Double: " + DoubleToString(AddDouble(1.5, 1.5)));
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) { }
void OnTick() { }
The #import
code section tells MetaTrader the name of the DLL that we will use and the function declarations as defined in the DLL. And then, we simply call them, in this example, on the OnInit
function.
Compile the indicator and add it to a MetaTrader chart. During the configuration, make sure to select the Allow DLL imports box.
If everything goes ok, the result of these operations will be displayed in MetaTrader’s Experts tab.
Our last step is to install the corresponding .NET framework on the production computer and our Indicator and DLL files to the MetaTrader Data folder. Make sure the .NET version matches the one used for development.
See Exposing c# code to mql5 using unmanaged exports for additional examples, including passing strings as parameters and return values.
Creating a DLL with C++
It is simpler to create a C++ library because we do not need any external libraries.
Check that Visual Studio has the Desktop Development with C++ component installed by running the Visual Studio Installer application and selecting Modify.
Create a new C++ Dynamic-Link Library (DLL) project. Use the Configuration Manager to create a new 32-bit configuration. This is required by MQL.
Add the 32-bit configuration:
Add a new header file called myfunctions.h with the following content:
#pragma once
#define EXPORT __declspec(dllexport)
extern "C" EXPORT int add(int a, int b);
extern "C" EXPORT double addDouble(double a, double b);
extern "C" EXPORT void greet(char* name, char* response, unsigned int size);
We have to prepend extern "C"
to function declarations to avoid name mangling when using C++.
Add a new source file called myfunctions.cpp with the following content:
#include "pch.h"
#include "myfunctions.h"
#include <string>
int add(int a, int b)
{
return a + b;
}
double addDouble(double a, double b)
{
return a + b;
}
/*
* Sample function to receive and return a string.
* `response` is an initialized char array provided by MQL.
*/
void greet(char* name, char* buffer, unsigned int size)
{
std::string str(name);
std::string result = "hello " + str;
strcpy_s(buffer, size, result.c_str());
}
We are creating an additional function for our C++ example. This function receives and returns a char array. Note that we convert the provided char array into a std::string
for internal manipulation and then turn it back into a char array to return it to MQL. The size
parameter contains the buffer size to avoid overflows.
Build the solution. This process will generate a DLL file in the directory displayed by the build phase. Copy the resulting file into the MetaTrader’s Data folder > MQL4 > Libraries directory.
On MetaTrader, open the MetaQuotes Language Editor. Create a new Indicator and add the following code to it.
#property copyright "Copyright 2022, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#import "c-test.dll"
int add(int, int);
double addDouble(double, double);
void greet(char& [], char& [], unsigned int size);
#import
int OnInit()
{
//---
Print("Add: " + IntegerToString(add(1, 2)));
Print("Add Double: " + DoubleToString(addDouble(1.5, 1.5)));
char buffer1[1024]; // to store name
StringToCharArray("joe doe", buffer1);
char buffer2[1024]; // to store result
greet(buffer1, buffer2, ArraySize(buffer2));
string result = CharArrayToString(buffer2);
Print("Greet: " + result);
//---
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason) { }
void OnTick() { }
As we can see, passing simple values like ints and doubles is similar to our C# example. However, passing a string involves some additional steps:
char buffer1[1024];
reserves a buffer to store the input string, in this case a name.StringToCharArray("joe doe", buffer1);
converts an MQL string into a char array.char buffer2[1024];
reserves a buffer to store the resulting string.greet(buffer1, buffer2, ArraySize(buffer2));
calls the DLL function.string result = CharArrayToString(buffer2);
converts the char array stored in the resulting buffer to an MQL string.Print("Greet: " + result);
we use the string.
All char buffers will be automatically removed once we leave the function scope (unless we create them with new
).
Compile the indicator and add it to a MetaTrader chart. During the configuration, make sure to select the Allow DLL imports box.
If everything goes ok, the result of these operations will be displayed in MetaTrader’s Experts tab.
Unlike our C# example, we do not need to install any .NET library on the production computer when we are ready to deploy.
Additional resources
The following resources contain libraries that may be useful for C++ development:
- Awesome C/C++ - a great collection of libraries.
- JSON library - this library is included in the previous collection, but it looks so good we think it deserves its own bullet on our list.
- Notes on smart pointers - notes on
unique_ptr
andshared_ptr
. - Notes on unordered_map - C++'s hash tables.
Additional references
- Adam H. (2017, October 25). Building and using DLLs in C. Codementor. https://www.codementor.io/@a_hathon/building-and-using-dlls-in-c-d7rrd4caz
- Walkthrough: Create and use your own Dynamic Link Library (C++). (2021, October 12). Microsoft. https://docs.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170
- Van, Thach. (2017, April 1). Passing strings between MQL and C++ DLL. VNDeveloper. https://www.vndeveloper.com/passing-strings-between-mql-and-c-dll/
Bonus: Creating a shared library for macOS
- Ngo, Tommy. (2017, July 8). C++ Creating Shared Library on macOS. YouTube. https://www.youtube.com/watch?v=PRUR_bN3r-E
This is a quick tutorial to create C++ Shared Library on macOS. Not a file we can use from MQL, but still somewhat related to what we do in this article.
PostgreSQL resources
An additional benefit of connecting a DLL is that we have access to any database. These are some valuable resources for Postgres:
- PostgreSQL C - a list of full examples for the most essential Postgres operations.
- C++ PostgreSQL Example - configure Postgres libraries in Visual Studio.
- PostgreSQL Upsert Using INSERT ON CONFLICT statement
- Connection Status Functions - relevant information for checking connection status and the functions we have to close or reset a connection.
- Using PostgreSQL in .NET
MySQL resources
- How to access the mysql database from MQL5 (MQL4) - this is a useful resource to avoid creating an external DLL and calling MySQL directly from MQL.