It’s a Meta Trader 5 ‘wrappsody’
MetaTrader 5 (MT5) is a widely used online trading platform that empowers traders with advanced tools and features. Meta Trader 5 API is written in C++, and if you are looking to integrate it using Java, wrapping it with a C-wrapper is a good choice — here’s how it’s done.

The “mt5apimanager64.dll” file is associated with MetaTrader 5 (MT5), which is a popular trading platform used for online trading in financial markets, including Forex and stock markets. The “mt5apimanager64.dll” file is a dynamic link library (DLL) that plays a significant role in providing an Application Programming Interface (API) for interacting with the MetaTrader 5 platform.
Using a C wrapper with MetaTrader 5 enhances language interoperability, enabling integration with various programming languages. It allows you to facilitate algorithmic trading and seamless integration with existing systems.
The full solution can be found here.
While testing one of the DLLs, mt5apimanager64.dll, we found that the below function names were exported:
1 0 00184BA0 MTAdminCreate
2 1 00184BC0 MTAdminCreateExt
3 2 00184BB0 MTManagerCreate
4 3 00184D60 MTManagerCreateExt
5 4 00184F20 MTManagerVersion
We still need to use the defined function name, for example, MTAdminCreate_t, and then dynamically load mt5apimanager64.dll via LoadLibrary() and then fill these function pointers with valid function
addresses, using GetProcAddress().
We have done that using a combination of using DumpBin and the Lib command from the Visual Studio command prompt.
The result was as shown bellow:
Microsoft (R) COFF/PE Dumper Version 14.36.32534.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file MT5APIManager64.dll
File Type: DLL
Section contains the following exports for MT5APIManager64.dll
00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
5 number of functions
5 number of names
ordinal hint RVA name
1 0 00184BA0 MTAdminCreate
2 1 00184BC0 MTAdminCreateExt
3 2 00184BB0 MTManagerCreate
4 3 00184D60 MTManagerCreateExt
5 4 00184F20 MTManagerVersion
Summary
330000 .cod0
3C000 .data
18000 .pdata
A1000 .rdata
7000 .reloc
12000 .rsrc
29F000 .text
1000 _RDATA
To do so, we need to define, a set of functions that will do that and that should be called before using anything else from the DLL. We don’t recommend calling LoadLibrary() in DllMain.
According to the Microsoft documentation, it can cause crashes and is therefore not recommended.
A typical entry point for a DLL, would look like this:
/* A typical entry point into a dynamic-link library (Dll).
* When the system starts or terminates a process or thread,
* it calls the entry-point function for each loaded DLL using
* the first thread of the process.
* The system also calls the entry-point function for a Dll,
* when it is loaded or unloaded using the LoadLibrary and FreeLibrary functions.
*
* hinstDll - handle to DLL module
* fdwReason - reason for calling function
* lpvReserved - reserved
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
{
// Perform actions based on the reason for calling.
switch(fdwReason)
{
// Initialize once for each new process. Return FALSE to fail DLL load.
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH: // Do thread-specific initialization.
break;
case DLL_THREAD_DETACH: // Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
if(lpvReserved != nullptr)
{
break; // do not do cleanup if process termination scenario
}
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
For the reasons explained, we will use a different approach in our DLL:
extern "C"
{
#include <mt5flat.h>
HMODULE g_hDll = NULL;
MTAdminCreate_t AdminCreate = NULL;
MTAdminCreateExt_t AdminCreateExt = NULL;
MTManagerCreate_t ManagerCreate = NULL;
MTManagerCreateExt_t ManagerCreateExt = NULL;
MTManagerVersion_t ManagerVersion = NULL;
// 1 - success, 0 - fail.
UINT_PTR MtWrapperInitialize()
{
std::wstring MT5APIMANAGER64DLL = GetExecutableDirectory();
MT5APIMANAGER64DLL += L"mt5apimanager64.dll";
g_hDll = LoadLibraryW(MT5APIMANAGER64DLL.c_str());
if (!g_hDll)
return 0;
return(g_hDll = LoadLibraryW(MT5APIMANAGER64DLL.c_str()))
&& (AdminCreate = (MTAdminCreate_t)GetProcAddress(g_hDll, (LPCSTR)1)) // you can use name instead of ordinal
&& (AdminCreateExt = (MTAdminCreateExt_t)GetProcAddress(g_hDll, (LPCSTR)2))
&& (ManagerCreate = (MTManagerCreate_t)GetProcAddress(g_hDll, (LPCSTR)3))
&& (ManagerCreateExt = (MTManagerCreateExt_t)GetProcAddress(g_hDll, (LPCSTR)4))
&& (ManagerVersion = (MTManagerVersion_t)GetProcAddress(g_hDll, (LPCSTR)5));
}
////
UINT MtManagerVersion(UINT* version)
{
UINT v = *version;
return ManagerVersion(v);
}
UINT MtAdminCreate(UINT api_version, void** admin)
{
return AdminCreate(api_version, (IMTAdminAPI**)admin);
}
UINT MtAdminCreateExt(UINT api_version, LPCWSTR datapath, void** admin)
{
return AdminCreateExt(api_version, datapath, (IMTAdminAPI**)admin);
}
UINT MtManagerCreate(UINT api_version, void** manager)
{
return ManagerCreate(api_version, (IMTManagerAPI**)manager);
}
UINT MtManagerCreateExt(UINT api_version, LPCWSTR datapath, void** manager)
{
return ManagerCreateExt(api_version, datapath, (IMTManagerAPI**)manager);
}
////
//// these are Admin variants
void Release(void* admin)
{
return ((IMTAdminAPI*)admin)->Release();
}
int SubscriptionHistoryReserved1(void* admin)
{
return reinterpret_cast<IMTAdminAPI*>(admin)->SubscriptionHistoryReserved1();
}
int SubscriptionHistoryReserved2(void* admin)
{
return reinterpret_cast<IMTAdminAPI*>(admin)->SubscriptionHistoryReserved2();
}
void* SubscriptionHistoryCreate(void* admin)
{
return reinterpret_cast<IMTAdminAPI*>(admin)->SubscriptionHistoryCreate();
}
MTAPIRES SubscriptionHistoryUpdate(void* admin, void* SubscriptionHistoryCreate)
{
return reinterpret_cast<IMTAdminAPI*>(admin)->SubscriptionHistoryUpdate(
(IMTSubscriptionHistory*)SubscriptionHistoryCreate);
}
} // extern "C"
We will also add a function to locate our MT5 DLL. For the purpose of this article, we will assume it is located where our executable resides.
// Helper functions
std::wstring GetExecutableDirectory()
{
wchar_t exePath[MAX_PATH];
GetModuleFileName(NULL, exePath, MAX_PATH);
// Find the position of the last backslash in the path
size_t lastSlashPos = wcslen(exePath);
while (lastSlashPos > 0 && exePath[lastSlashPos - 1] != L'\\')
{
lastSlashPos - ;
}
// Extract the directory path, including the trailing backslash
exePath[lastSlashPos] = L'\0';
return std::wstring(exePath);
}
Our Header File
We went with an identical header file for both our DLL and our C test program. We use a preprocessor directive named _MT5_FLAT_ to distinguish between the use from the DLL and from the test program.
Here is how our header file looks like:
/* this is header, intended to be used both by the C consumers and the wrapper implementation
* itself, so it needs to distinguish the declspecs
*/
#if defined(_MT5_FLAT_)
// this is for the library itself
#define DECLSPEC __declspec(dllexport) // __declspec(dllexport) here or .def file and ordinals
#else // the below is for the consumers
#define DECLSPEC __declspec(dllimport)
#endif
//// this is a wrapped specific function to load MT5APIManager.dll and get addresses of the
// exported functions
DECLSPEC UINT_PTR MtWrapperInitialize();
////
//// these are C wrapper functions for the functions, that are exported from MT5APIManager.dll
//typedef MTAPIRES(*MTManagerVersion_t) (UINT &version);
DECLSPEC UINT MtManagerVersion(UINT *version);
//typedef MTAPIRES(*MTManagerCreate_t) (UINT api_version,IMTManagerAPI **manager);
DECLSPEC UINT MtManagerCreate(UINT api_version, void **manager);
//typedef MTAPIRES(*MTManagerCreateExt_t) (UINT api_version,LPCWSTR datapath,IMTManagerAPI **manager);
DECLSPEC UINT MtManagerCreateExt(UINT api_version, LPCWSTR datapath, void **manager);
//typedef MTAPIRES(*MTAdminCreate_t) (UINT api_version,IMTAdminAPI **admin);
DECLSPEC UINT MtAdminCreate(UINT api_version, void **admin);
//typedef MTAPIRES(*MTAdminCreateExt_t) (UINT api_version,LPCWSTR datapath,IMTAdminAPI **admin);
DECLSPEC UINT MtAdminCreateExt(UINT api_version, LPCWSTR datapath, void **admin);
////
//// and this is just an attempt to use MT5APIManager.dll interfaces via obtained pointers
// and their API
// these are Admin variants
DECLSPEC void Release(void* admin);
DECLSPEC int SubscriptionHistoryReserved1(void* admin);
DECLSPEC int SubscriptionHistoryReserved2(void* admin);
DECLSPEC void* SubscriptionHistoryCreate(void* admin);
DECLSPEC UINT SubscriptionHistoryUpdate(void* admin, void* SubscriptionHistoryCreate);
Our test program
We then wrote a C program to test our new DLL and see if it operates the MT5 API successfully, while our DLL acts as a middleman between our C program and the real MT5 DLL.
#define WIN32_LEAN_AND_MEAN
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#include<windows.h>
#include"stdio.h"
/* this is a test C program, that knows nothing about C++ class dll and imports flat C functions
* from the C wrapper dll (called mt5flat.dll)
*
*/
// the line below instructs compiler to include into .obj a comment, that will help linker
// to find out the import .lib of the wrapper library
#pragma comment(lib, "mt5flat.lib")
// it's our wrapper dll SDK header
#include <mt5flat.h>
int wmain(int argc, wchar_t** wargv)
{
void* admin = NULL; // handle to the IMTAdminAPI
UINT res, ver = 0x0b00b135;
if (!MtWrapperInitialize())
{
wprintf(L"MtWrapperInitialize failed.\r\n");
return 0;
}
wprintf(L"Loaded mt5apimanager64.dll successfully.\r\n");
res = MtManagerVersion(&ver);
wprintf(
L"res = MtManagerVersion(&ver) returned, res: 0x%x, *ver: 0x%x.\r\n"
L"And who knows what this means...\r\n",
res, ver
);
res = MtAdminCreate(0xb7c, &admin);
if (res) // this is our flat C wrapper function call example
{
wprintf(L"MtAdminCreate failed, code: 0x%x.\r\n", res);
return 0;
}
else
{
wprintf(L"MtAdminCreate succeeded.\r\n", res);
}
wprintf(L"SubscriptionHistoryReserved1: %d\r\n", SubscriptionHistoryReserved1(admin)); // call to another function
wprintf(L"SubscriptionHistoryReserved2: %d\r\n", SubscriptionHistoryReserved2(admin)); // yet one
Release(admin); // and this is too
return 0;
}
While the Visual Studio solution (.sln) has the two projects with every setting required, you can always compile the files manually
cl /MD /O2 /c mt5flat.cpp
link /machine:x64 /dll mt5flat.obj
cl /MD /O2 “C Test Program.c”

When running our test program, we can see the MT5 creates its log folder with the log file.

Then the log file confirms that everything went well.

C++ is a serious programming language for important software and has been one of the top programming languages for 30 years — and it is not slowing down. Everywhere you look, C++ fingerprints are all over it. It’s never a bad time to learn it, and my new book, co written with Michael Haephrati and published by Manning Publications, will help you do just that — even if you don’t have any programming or computer science experience.