I worked up a simple sample C# DLL that is properly exported for use with Metatrader. I made use of the template that can be downloaded from C# Project Template for Unmanaged Exports.
C# Code for "testUMD.dll" below using R. Giesecke's template:
Code:
using System; using System.Text; using RGiesecke.DllExport; using System.Runtime.InteropServices; using System.Windows.Forms; namespace testUnmanagedDLL { class Test { [DllExport("AddInteger", CallingConvention = CallingConvention.StdCall)] public static int AddInteger(int Value1, int Value2) { MessageBox.Show("Add Integers: " + Value1.ToString() + " " + Value2.ToString()); return (Value1 + Value2); } [DllExport("AddDouble", CallingConvention = CallingConvention.StdCall)] public static double AddDouble(double Value1, double Value2) { MessageBox.Show("AddDouble: " + Value1.ToString() + " " + Value2.ToString()); double Value3 = Value1 + Value2; return (Value3); } [DllExport("AddDoubleString", CallingConvention = CallingConvention.StdCall)] public static string AddDoubleString(double Value1, double Value2) { MessageBox.Show("AddDoubleString: " + Value1.ToString() + " " + Value2.ToString()); double Value3 = Value1 + Value2; return (Value3.ToString() ); } [DllExport("returnString", CallingConvention = CallingConvention.StdCall)] public static string returnString(string Input) { MessageBox.Show("Received: " + Input); return ("SEND to MT4"); } // many thanks to anonymous for the code sample below! [DllExport("ReturnDouble2", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)] static double ReturnDouble2() { return 4.5; } }
MT4 Script 'testDLL' code below: File testUMD.dll added to experts/libraries folder
Code:
#import "testUMD.dll" int AddInteger(int Value1, int Value2); double AddDouble(double Value1, double Value2); string AddDoubleString(double Value1, double Value2); string returnString(string Input); double ReturnDouble2(); #import //+------------------------------------------------------------------+ //| script program start function | //+------------------------------------------------------------------+ int start() { //---- Print("AddInteger: " + AddInteger(250, 750)); double a = AddDouble(250,750); Print("AddDouble: " + NormalizeDouble(a,4)); double d = StrToDouble(AddDoubleString(250, 750)); Print("AddDoubleString: " + NormalizeDouble(d,4)); string temp = "Send to DLL"; string recv = returnString(temp); Print(recv); double dd = ReturnDouble2(); Print("Returning Double from C#: " + NormalizeDouble(dd, 4)); //---- return(0); }
Cursory Summary: Integer passing = success, double passing MT4 to C# = success, double passing from C# to MT4 = fail, string passing = success. I haven't experimented with arrays. Sample code written with VS 10 .NET 4.0.
If anyone knows how to successfully get doubles to pass from C# to MT4 without conversion to a string, please leave a comment!
------------
Edit: thanks for the feedback from anonymous! The code has been updated to reflect passing a double from C# to Metatrader.
By the way, you must use the 32 bit version of the DLL. The 64 bit version and the "Any CPU" version both failed with error #127 in Metatrader. This is understandable considering MT4 is a 32 bit program.
As per g3ro's suggestion I have made available for download both the testUnamanagedDLL Visual Studio solution and the testDLL MT4 script. Download testUnmanagedDLL VS solution
71 comments:
nice job.. you should write posts more often :)
and i can receive a double in metatrader from c#.. . maybe you should try to change the name of DllExport , exemple:
[DllExport("ReturnDouble2", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
static double ReturnDouble( )
{
return 4.5;
}
it works for me...
hi, this code doeasn't work for me.
can you post the visual studio solution?
thnak you
Thanks for the feedback! The samples have been updated based on your code.
I should have more time to post in August.
Thanks for your comment and question. I have updated the post above with a link to download the visual studio solution as well as the MT4 sample script.
yeah!!! many thanks!!!! :-)
yeah!!!! many thanks!!!!
You're welcome! Let me know if you have any problems with the code or comments/suggestions.
ok, thank you.
I want use this project to create a dll to send emails with attachments.
I'll post it, if i succeed :-)
Sounds interesting g3ro! Keep us updated on your progress!
Very interesting stuff Patrick. Thanks for sharing.
You're welcome, John and thanks for the comment!
Yes I think this concept opens up the possibility for a C# developer to write powerful DLLs for Metatrader, expanding the capabilities of the MQL4 scripting language substantially.
hello patrick
can u help me to protect my indicator ...
please contact :
klidu09@gmail.com
Hi Indocopaz,
I'm not familiar with indicator protection methods.
Any method I create that instantiates a new object, fails on call. Any idea on how to get around this?
[DllExport("InsertTick", CallingConvention = CallingConvention.StdCall)]
public static bool InsertTick(string symbol)
{
Tick newTick = new Tick(){Symbol=symbol};
return true;
}
Not sure exactly why you would have problems with your object instantiation. Did you try putting a try/catch block inside the InsertTick method to trap the error. My understanding is that whenever you call a dll, all errors must be caught and handled within the dll or they cause problems for the calling application.
{
try {
Tick newTick = new Tick(){Symbol=symbol};
} catch (Exception ex) {
Messagebox.Show("Error in InsertTick " + ex.ToString());
}
return true;
}
Turns out the issues has to do with the object being referenced in another project. I just moved all the code to the same project and all seems to be working. Thanks for the quick reply.
Thanks Patrick for posting the sample. I was able to get your sample to work as is with MT4, however, if I try to just compile it unchanged in C# I keep getting a compile error of "Cannot find lib.exe in 'c:\Program Files (x86)", which is stopping the compiler from creating the 32Bit version, which I read is what I need.
I'm reading that MS changed lib.exe to link.exe from this page.
http://stackoverflow.com/questions/4345052/why-is-lib-exe-removed-from-recent-wdk-releases
If anyone has any ideas I would appreciate it. Thanks!
After some digging I found the lib.exe is part of the 32 bit C++ compiler. I loaded Visual C++ Express and it solved the issues.
Thanks again for sharing the example code Patrick.
Thanks for the tip Drew, I'll have to look into that.
This article is excellent.
This dll sample can read data and send data to mt4. This itself is very useful. My question is, can you provide more samples of what you can do with this DLL, specifically regarding trading functions (send order, send pending order, Close open order etc.). That would be great thanks
I've thought about that but am currently not doing that much with Metatrader. However I may at some point. I'm keeping an eye on the work done by another developer. He is actively creating a project that may be of great interest to you as it has order sending / reporting capability. Take a look:
http://beathespread.com/blog/view/14096/mt4-c-mongodb-encog-ea#blog-comments
I have a problem with Visual C# 2010.
When I save my DLL, the compiler saves only the 64bit version.
The 64bit version don't works on MT4 (error 127).
How can I save the DLL in the 32 bit version?
Thanks.
Find your menu at the top:
Project > Properties > Build (tab on left) > Platform Target (x86)
Thanks.
I will prove this way.
When I run the script, there is this error in the journal for each function:
function 'AddInteger' call from dll 'testUMD.dll' critical error e06d7363 at 769AB727.
Why the MT4 gives me these error?
Not sure what would cause the error. Double check that you have DLLs enabled in MT4, and that the dll is in the right place (see instructions on download page), and the right version (sounds like you're now using x86). Is your code exactly as shown above? If not, try to get the default code working first.
Is your MT4 installation in a folder you own (preferred) or in the default location? Strange things sometimes happen with installations in the default location due to Windows craziness.
I solved the problem with your script...
I changed the platform.
But now I have the same problem with my DLL.
Also if I change platform.
There's an alternative approach.
You could create your MetaTrader expert directly in C# and so use your C# DLL directly with http://www.nquotes.net/ - a library which brings the whole MetaTrader API to .NET.
Hi Ken,
My first suggestion is to put a try/catch block around your return value within each method so you can possibly get a more precise error description from the compiler.
Let me know if still need help and I'll dig into the code to see if I can make a more concrete suggestion.
Dear Patrick,
Thanks for your advise, I found that the error is due to I forgot to initialize the object. Now it has been solved.
By the way, to take care about the string input and output, I found there is an easier way to just declare the variable in String (not string) type, which we can freely communicate with the MT4.
Best wishes.
Dear Patrick,
I'd like to create DLL for Metatrader4 in VS2010 C# with Unmanaged Exports Package (NuGet). My code compiling successfully with target configuration option AnyCPU.
But I have got error with target configuration option x86 or x64:
"Error 3 rror -- Undeclared identifier dpar
rror -- Undeclared identifier dpar
C:\Applications\DLLSampleNET\DLLSampleNET\Class1.cs(153) : error : syntax error at token '{' in: {
DLLSampleNET"
or simply text of error:
"C:\Users\"
If I have compiled my project with one method in class:
"using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
//using System.Windows.Forms;
using RGiesecke.DllExport;
namespace DLLSampleNET
{
public class Class1
{
[DllExport]
public static int GetIntValue(int ipar)
{
Console.WriteLine("GetIntValue takes " + ipar.ToString() "\n");
return(ipar);
}
}
}"
I do not understand, why?
There are a couple of questions in your comment. I don't see "dpar" so maybe that variable name exists but is not shown. Maybe search for "dpar" in your project in case you changed names and there is a lingering name somewhere in the project that is undeclared.
Also, try replacing [DllExport] with the full definition for your method name. Such as (MT4 requires StdCall):
[DllExport("GetIntValue", CallingConvention = CallingConvention.StdCall)]
If you get an error message when referencing the dll in MT4, I'd also suggest putting a try/catch block around the contents of the the GetIntValue method to see if you can get a more precise error message.
Thanks Patrick give the article
I got error following i am using VS2010 as follows
A Project with an output type of class library cannot be started directly
In order to debug this project and an excuetable project to this solution which referance the library project. Set the executable project as the startup project
What i do? I new baby to c#
thanks
suman
Dear Patrick,
I have tried to make a C# DLL for MT4 in VS2010 with NuGet package as shown below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RGiesecke;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace DllTest2
{
public class Class1
{
[DllExport("Add", CallingConvention = CallingConvention.StdCall)] // <- Error Occured
public static int Add(int left, int right)
{
return left + right;
}
}
}
When target configuration option is AnyCPU, there is no problem on build.
But, I have got an syntax error on the line of 'DllExport' and the syntax error is the same one with the above article written by 'Anonymous'.
After I put '//' in front of the line of 'Dllexport', the result of build has no error. So, the syntax error comes from the Dllexport line.
I read another article says that Metatrader4 doesn't recognize the function of C# DLL made in AnyCPU mode or x64 mode, I need to make DLL in x86 mode, but x86 mode generates such systax error on the Dllexport line.
How can I fix that syntax error?
Hope to have your kind reply eagerly~
Thanks in advance~
Thanks Patrick for the great article. Your code works for me for the most part. However, when I pass a string to the dll and back, MT4 only sends (DLL receives?) a single character and prints back a single character and the rest is question marks.
With your code specifically, "Send to DLL" only returns the first character "S" (so "Returned: S" is what the MessageBox shows).
"SEND to MT4" gets printed back to the MT4 terminal as "2014.03.22 01:05:16.411 testDLL AUDUSD,M30: ?????4."
Are you seeing this? Do you think the latest versions of MT4 are causing that? Do you know how to fix it?
I've been going round and round with this. I'm leaning towards MT4 as the culprit, but don't really know how to effectively troubleshoot it. Any help is much appreciated.
P.S. One other thing I noticed is that the AddDoubleString gets sent to the DLL correctly (MessageBox shows "AddDoubleString: 250 750"). However, when it goes back to MT4 it prints 0 instead of 1000:
2014.03.22 01:26:35.306 testDLL AUDUSD,M30: AddDoubleString: 0
Thanks again.
Hi Patrick, it's me again. Looks like the new 600 version of MT4 definitely broke it. Here are a couple articles with the solution:
http://forum.mql4.com/61595
which references this:
http://forum.mql4.com/60905
It looks like the immediate solution is to use MarshalAs:
[DllExport("returnString", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static string returnString([MarshalAs(UnmanagedType.LPWStr)] string Input)
{
MessageBox.Show("Received: " + Input);
return ("SEND to MT4");
}
After reading... the better solution appears to be, don't use strings for this? Please feel free to consolidate my comments. Thanks again.
Sorry for the late reply, suman. Basically that just means you need to compile your dll and then link to it from another project (such as MT4) in order to test it. DLL files are not directly executable.
Hello,
thanks Patrick for this post but I'm having issue.
I'm using Visual Studio 2013 and I installed using Nuget UnmanagedExports trhough PM> Install-Package UnmanagedExports
I compiled dll and add it to Metatrader 4 (build 625 so build >= 600).
I put dll file and also pdb file into C:\Program Files (x86)\MT4Folder\MQL4\Libraries
but I get an error:
2014.04.13 15:27:44.189 Cannot find 'AddInteger' in 'MT4SampleLib.dll'
2014.04.13 15:27:44.189 unresolved import function call
Did you try it with build >= 600 because MetaQuotes changed a lot of things.
I also get your solution
https://sites.google.com/site/marketformula/vb6-to-c/vb6-to-c-downloads/code-to-export-c-dll-to-metatrader
and I get exactly the same error.
Any idea ?
Thanks
Femto
I succesfully run this MT4 script which call DotNet DLL.
But there is a problem with MT4 build >= 600 about string see http://forum.mql4.com/60708
I hope you can fix that.
You will have to act on both part:
Passing array of char instead of string
uchar acTemp[];
StringToCharArray(strTemp, acTemp);
and you will also have to fix returned string
Please also add some sample with C# decimal type as it is very common in financial calculations to avoid floating issue.
Maybe you also add this into a SVN or GIT repository ?
Here is my fix (on MQL side) for sending string parameter to a DLL
//+------------------------------------------------------------------+
//| testDLL.mq4 |
//| Copyright © 2011, Patrick M. White |
//| https://sites.google.com/site/marketformula/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, Patrick M. White"
#property link "https://sites.google.com/site/marketformula/"
#import "testUMD.dll"
int AddInteger(int Value1, int Value2);
double AddDouble(double Value1, double Value2);
string AddDoubleString(double Value1, double Value2);
string returnString(char Input[]);
double ReturnDouble2();
#import
//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
//----
Print("AddInteger: " + AddInteger(250, 750));
double a = AddDouble(250,750);
Print("AddDouble: " + NormalizeDouble(a,4));
double d = StrToDouble(AddDoubleString(250, 750));
Print("AddDoubleString: " + NormalizeDouble(d,4));
string temp = "Send to DLL";
uchar arrcharTemp[];
StringToCharArray(temp, arrcharTemp);
string recv = returnString(arrcharTemp);
Print(recv);
double dd = ReturnDouble2();
Print("Returning Double from C#: " + NormalizeDouble(dd, 4));
//----
return(0);
}
but I don't know how to fix returned string
That's maybe possible to fix code on C# side and keep MQL code with strings.
Hi Femto,
I am still using VS 2010. I have recently compiled a dll for use with MT4 build 600. There are a few gotchas such as for strings you must use UnmanagedType.LPWStr, but in this case I think you should take care to use the dll compiled for x86 as the function call could not be found because MT4 is a 32 bit program.
Hi, Patrick. Help me, please. when I use your example mql4 says "unresolved import function call". dll was compiled correctly (x86) but with warning "Cannot find lib.exe"
Hi Patrick,
I made it work - see my example here http://worldwide-invest.org/threads/34585-Messaging-queue-AMQP-(RabbitMQ-ZeroMQ)-and-MT4.
I have changed code on MT4 side converting new MT4 (build>=600) strings to array of uchar but it seems not the good way to do this.
I still don't find a way for a DLL function to output a string that way.
It will be nice if you could produce a solution which works with Metatrader 4 build >= 600.
In your example, you should also try to pass decimal data (C# type with fixed precision) and also datetime. Because these 2 kinds of data type are very useful.
Hi Femto,
Here is passing and returning a string in C# from MT4 build 600+. I haven't experimented with datetime.
[DllExport("returnString", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static string returnString ([MarshalAs(UnmanagedType.LPWStr)] string Input) {
MessageBox.Show("Received: " + Input);
return ("SEND to MT4");
}
Also see this re: strings:
http://forum.mql4.com/60905
The MT4 side of string passing doesn't change - just pass to dll as a string.
Ok thanks Patrick for your quick reply
Had the same problem. Solution - change the system language to English. For Windows 7: Start -> Control Panel -> Clock, Language, and Region.
I think I've had that same error. But I didn't figure out why it occurred. This is why I saved a template to use for other projects.
Hi Matt, It looks like you figured out the string mystery. I've included updated code in the build 600+ version of this blog post (link at top). I agree that passing numeric values as numeric values makes more sense than converting to strings.
It doesn't look like MT4 supports the decimal type:
book.mql4.com/basics/types
Yes, I think you figured it out but for those just arriving and reading the comments, C# needs to be adjusted in the case of strings:
http://forum.mql4.com/60905
Drew previously wrote:
"After some digging I found the lib.exe is part of the 32 bit C++ compiler. I loaded Visual C++ Express and it solved the issues. "
Hope that helps!
Hay , Patrick ,nce work here ,actually I want a suggestion . I am familiar with analytical language called R , so I had made an dll in C# which calls R codes inside it . So now I want to write down a strategy in R language and made the dll in C# which could run in MQL5 , is it possible for 3 compilers to run parallel ,need ur suggestions .
PS:- ashis
Hi Ashis Deb,
It sounds like based on the architecture that you suggest, that C# would handle the R connection and then the C# dll would be accessed from MT5? I see no reason why this wouldn't work if you can get C# to talk with R successfully and MT5 to talk with C# via the DLL. The other linked post at the top of this blog post (build 600+ link at top and posted in 2014) might be a more complete and less error prone example for C# to MT5 and the new MT4 than the one linked from this article.
Patrick
Hi Patrick,
Thanks a lot for writing this great information. I have some questions:
1) I am using windows7 64 bit at the moment. If i compile the DLL using 64bit system, but i set the compiled DLL should be 32 bit (x86) as output. Will it work at my 64 bit computer ?
2) I compiled the c# code without error. But as i call it from MT4 (not MT5), i got error message "AddInteger" not found .... Does it mean that the MT4 has found the DLL, but can not call the function "AddInteger" ? How to solve this ?
Thanks in advance.
-jackprobe
Hi Patrick,
I forgot to tell that i used the example file for build 600+ (I am using MT4 build 6xx), and nuget package (UnmanagedExport) is installed via PM without problem. The DLL is compiled using VS2012 express.
Thanks
Hi JackProbe,
1) Yes a 32 bit compiled dll will work on 64 bit windows 7 - this is my setup actually too! You must compile using 32 bit due to Metatrader being a 32 bit application so that it can read/use the dll. This may be causing your problem in #2. On the menus, go to Build, Configuration Manager - make sure that your configuration is set to x86. Then go into Project/Properties and note the location of the DLL. Make sure you're not copying an old (64 bit) dll to MT4\MQL4\Libraries\
2) Yes it means that MT4 has found the dll but has not found that function within the dll (see #1 above). Please check to make sure that DLLs are enabled within MT4 (check box) for the script/indicator/EA you are running. Also, sometimes if your MT4 is in a folder that you don't own, strange things can happen. If this is the case, try copying out the whole folder to another location, creating a startup shortcut with the portable switch, such as: "...\terminal.exe" /portable
anyone had used ref array in c# dll pass back to mq4 code?
Thanks;
Bob G
Bob G:
Regarding an example of passing by reference an array to/from MT4, see the updated example here: (latest post)
http://vb6-to-csharp.blogspot.com/2014/05/code-to-export-c-dll-to-metatrader.html
See sample methods: PassDoubleArray and PassDoubleArrayByref.
Patrick,
Thank you very much. The array passing value works for me.
Another issue is that when using 2013 Visual Studio, it can't build the project. The error message is that it can't find lib.exe, in target file RGiesecke.DllExport.target as LibToolPath="$(DevEnvDir)\..\..\VC\bin"
did anyone has been with any ideals for this?
Thank you all!
Bob G
Bob G,
Drew previously wrote:
"After some digging I found the lib.exe is part of the 32 bit C++ compiler. I loaded Visual C++ Express and it solved the issues. "
Hope that helps!
I download the DLL and script , put into MT4 (libraries and script folder) and execute the script,got following error message:
2015.06.05 11:54:00.958 Cannot call 'mt4UMD600.dll::AddInteger', 'mt4UMD600.dll' is not loaded
2015.06.05 11:44:37.709 unresolved import function call
my host is windows 7 x64 and use Tickmill MT4 4.00 Build 830
am I doing something wrong?
tried download the DLL and script ,then execute in MT4, got following error message:
2015.06.05 12:10:37.490 Cannot load 'mt4UMD600.dll' [126]
2015.06.05 12:10:37.490 Cannot call 'mt4UMD600.dll::AddInteger', 'mt4UMD600.dll' is not loaded
2015.06.05 12:10:37.490 unresolved import function call
using Tickmill MT4 4.00 Build 830 on Windows 7 x64
what's the possible problem?
Eddy, if it is error 126 then:
Error 126 in MQL4 is The specified module could not be found. ERROR_MOD_NOT_FOUND. Check to be sure your dll is in the directory MT4 expects it to be located: ...\MQL4\Libraries\ and make sure your startup shortcut for MT4 has the /portable flag at the end so it will look in that directory, such as:
Presumably your MT4 version is 600+? Make sure you are using that version of the code. This is the pre 600 version blog post. See: vb6-to-csharp.blogspot.com/2014/05/code-to-export-c-dll-to-metatrader.html
Portable such as...:
"...\MetaTrader\terminal.exe" /portable
Hi,
Many thanks, learn a lot on this project.
Question:
I recompile the testUnmanagedDLL project in visual studio 2013, but it does not work.
error meassage:
1>C:\Users\hanse\Desktop\UnManaged\testUnmanagedDLL\testUnmanagedDLL\DllExport\RGiesecke.DllExport.targets(8,5): error :
Would you tell me to solve it.
Thanks!
Hanse
Hi Hanse,
I believe that error (8,5) is: "The system cannot find the file specified" and relates to the reference being missing for Giesecke's project as I responded to Dai on the 600+ blog post (in the comments):
http://vb6-to-csharp.blogspot.com/2014/05/code-to-export-c-dll-to-metatrader.html
I'll repeat here my recommendation if that is indeed your error:
In VS 2013, go Project/Manage NuGet packages, then search for 'Giesecke' and install it. It now compiles without error. Also change target build under Project/Properties/Build platform target to x86 instead of any CPU for MT4 compatibility. Good Luck!
Hi Sir,
Thanks for your information.
I got it.
Bests
Hanse
Excellent
I delight in, cause I found exactly what I was having a look for.
You have ended my 4 day lengthy hunt! God Bless
you man. Have a great day. Bye
Post a Comment