How to pass arrays to C++, found C# DLL tutorial

 

What I want to do ultimately is pass the History array to my C# DLL where I can do lots of cool things :)

I found this C# and metatrader tutorial to work great with MT4 (not MT5 64 bit)

http://www.codeguru.com/csharp/.net/cpp_managed/windowsservices/article.php/c14735/

The tutorial passes a string and gets a string back.


What I want to do is pass a double[]

Can someone assist with some sample code on how to pass a double to a c++ CLL? Also if you know how to wrap that for a C# dll that would be great too.

 

pass the array by reference:


#import "mydll.dll"

int somefunction(double &some_array[], int array_size);

#import


and in your dll you will receive a pointer to an array of double that you can read and write. You can also pass indicator buffers into which the DLL can write this way. Note that inside the DLL the indexing of indicator buffers starts with 0 being the oldest bar and Bars-1 being the current bar. All other arrays work normally and start with 0 just as in mql4.

You will also have to pass the length of the arrays to the DLL or the total bars number if you work with indicator buffers. The DLL has no way to find out on its own how big the arrays are. If you read or write beyond the array boundaries you will immediately crash metatrader with an access violation, make sure to catch all access violations inside the DLL to not crash MT4 all the time during development until it works correctly because this can be very frustrating.


The calling convention for your exported functions must be stdcall, not cdecl or anything else.

If you test your EA in the strategy tester then you will observe that due to a bug in MT4 it will not unload your DLL anymore (this is not the case in normal operation). This is very annoying since you will have to restart MT4 every time you make a new built of your DLL. You might want to make yourself a batch script to automate this.


You should not use global variables in your DLL unless you intentionally want to share data between multiple EA instances. Your DLL should be made thread safe, all standard recommendations about thread safety apply.



And finally you should do yourself a big favor and not use C++ for this (let this ancient dinosaur rest in peace) but something more modern, powerful and user friendly like Object Pascal (Free Pascal) for example. This would give you much more fine grained and easier control over your data structures and it will give you strong compile time type safety which helps to avoid many errors and boost your productivity by a factor of roughly 2.5

 

Thanks for the info. I am not a C++ guy so forgive this stupid question, but I have been following the ExpertSample EA that comes with MT4. There is a function in the ExpertSample.dll which is imported


#import "ExpertSample.dll"

double GetArrayItemValue(double arr[],int,int);

This simple function reads the first element of the array and returns it;

So here they are doing a read on the array but they do not use double &arr[], and it seems to work. Why?

My main question is that I want to pass in the arrays like High, Low, Open, Close. These do not seem to work. With the ExpertSample EA, I keep getting value of 0 back.


Thanks for the Pascal advice. I write all my classes in C# and just use C++ as a wrapper so that they can be utilized from MQ4

 

I don't know why they are so inconsequential and sometimes pass it by reference and sometimes pass it by value, the DLL always seems to receive a pointer to an array. Maybe "by value" will pass a pointer to a copy of the array to somehow enforce write protection which would be much more expensive than simply passing a pointer to the original data, maybe there is no difference at all, I don't know.


In all other examples and tutorials I have seen so far it is common practice to simply pass arrays "by reference". Therefore I regard "by reference" as the way to do it and "by value" as something that also seems to work but its not clearly documented how it is implemented. Therefore I simply ignore it to keep my code more consistent.


I suggest you simply fire up your IDE and do some experiments.

If you are "not a C++ guy" then this is even one more reason to NOT start torturing yourself with C++ for no reason when there are so much better and more productive tools around to do the same job: http://www.forexfactory.com/showthread.php?t=219576

 

hi 7bit

thanks again for your help. do you know why in either case, reference or value, when i try to pass in an array I populated with ArrayCopySeries, copying in values from High, Open, Low, or Close?

I would use Lazarus and Pascal, except all my code is already written in C#. I simply need a wrapper class so that MT4 can utilize these C# classes. If you can show me how to load a C# dll via Pascal I would be interested. I see in your forum example you are doing the exact stuff I am lookng for so it is a shame!

 
clam61:

do you know why in either case, reference or value, when i try to pass in an array I populated with ArrayCopySeries, copying in values from High, Open, Low, or Close?


this sentence is not complete. Although it has a question mark you left out the actual question.


clam61:

If you can show me how to load a C# dll via Pascal I would be interested. I see in your forum example you are doing the exact stuff I am lookng for so it is a shame!


C# "DLL"s (.NET assemblies) can be made so that you can use them as COM objects. FPC can load and use COM objects on windows but I currently don't have an example here. I always tried to steer clear of anything that has to do with unportable MS-only technology and therefore I don't have an example.


If you have a C++ example already then all the other things in the above mentioned Pascal thread about writing DLLs for MT4 should still be 1:1 translatable into C++, the way how it works (regarding MT4 and DLL) is not different from how it works in C++, only the language to express it is more elegant (readable, expressive) in Pascal. For almost every Pascal construct there is an equivalent C++ construct (only string handling will always be more problematic in C++), both languages play on the same level of abstraction and Pascal can be intuitively read by any C++ developer.

 
7bit:

this sentence is not complete. Although it has a question mark you left out the actual question.

oops! sorry, i kept reformatting the sentence i left out the most important part.

i was trying to say that, whenever I use the function ArrayCopySeries to populate a double[] array and then pass that array into the function, MetaTrader crashes! Any idea?

 
clam61:

oops! sorry, i kept reformatting the sentence i left out the most important part.

i was trying to say that, whenever I use the function ArrayCopySeries to populate a double[] array and then pass that array into the function, MetaTrader crashes! Any idea?

Could you post a snippet of code (from both sides)?


Is the DLL function declared as stdcall? (__stdcall in C++) because this is usually (99%) the first thing that goes wrong when you write your first DLL function for MT4 and it will inevitable lead to a crash because a wrong calling convention will totally mess up the stack pointer.

 

Just take the ExportFunctions EA that comes with MT4, and replace the init function with:


int init()
{
double price;
double highs[];
ArrayCopySeries(highs, MODE_HIGH, Symbol(), 0);
// price=GetArrayItemValue(highs,ArraySize(highs),0);
price=GetArrayItemValue(High,ArraySize(High),0);

MessageBox(DoubleToStr(price,4),DoubleToStr(price,4));

return(0);

}


In this case the values will be 0.0000. The same thing happens whether I use the High or highs arrays. When I do the same thing with the custom DLL I wrote, it crashes, probably because my DLL wraps a .NET DLL and there is other stuff going on. However, I bet that if I can make the ExpertSample.dll work properly, I can fix my custom DLL too.

 

First try surrounding the whole body of the DLL function with a try/catch to get rid of any crashes induced by the .NET interface. You can use OutputDebugString() from the windows API and debugview.exe from Microsoft in your catch() block to conveniently log the exception.


If it still crashes (exceptions cannot be caught for some reason) then comment out any .NET related stuff to make sure you can at least create a DLL with your compiler that will not immediately crash and to narrow down and rule out possible reasons for the crash and make the MT4 -> DLL interaction stable and reliable before you continue.


If it still keeps crashing then make sure the function definition really matches the #import statement in metatrader. The dll must be __stdcall. I repeat this again because it is the single one reason for almost all crashes that a beginner will experience. It is almost preprogrammed: the default of the compiler is not stdcall! Some C++ compilers seem to require this definition (along with the export name) in a separate .def file instead of simply declaring it directly in the source code, this is probably a shortcoming of the C++ language itself, it has not enough means to simply express all this in the source code alone, so they need a separate file. I have seen many threads about this here. {Such bizarre things do not exist in sane languages, there you can simply declare all needed things in the function declaration itself. In Pascal for example you simply decorate the function with the word stdcall (or switch the whole unit to stdcall with a compiler directive) and in the exports section you can optionally specify a different export name if needed.}


If you use a series array from MT4 (and also when writing into an indicator buffer from your DLL) then note that the indexing is reversed in mql4. In your DLL you will find the latest (current) bar at [Bars -1] and the oldest bar is [0]. Make sure that under no circumstances you ever access any array element outside these boundaries.


if not annoyed_already then
begin

Finally (if possible) think about porting some of your C# stuff to Object Pascal. It will execute faster (it compiles to native machine code), need MUCH less resources and no runtime environment installed, is easier accessible from other applications (this problem here!) and will be the rescue vessel to leave the (soon sinking¹) Microsoft ship and open up the doors to many other platforms and devices. Although this is also true for C++ the Object Pascal language itself is more powerful than C++ and allows for more things to be done in an easier way and less error prone.

end;


___________

¹) Bill Gates does not rule the company anymore and it is reasonable to assume that without his extreme luck/marketing genius it will not be possible to uphold this unnatural monopoly against all entropy and against all reason for much longer. This was a bizarre and rare one-time event, the universal laws of thermodynamics will soon correct this. The same will happen to Apple as soon as Steve Jobs leaves his company, they will fall into oblivion even faster than MS and you will soon have to go to some historic computer museum to marvel at one of their strange and completely incompatible iSomething devices like if they were relics from a different and already extinct alien species (which they really seem to be).

 

hi 7bit

thanks for the assistance. 1 question and 1 comment:

1. what is the syntax for the try catch block around the dll function? I googled around and when I use catch(...) it compiles, but I want to use catch(Exception *e) so that I can print out the exception stack trace and message. However, when I use catch(Exception *e) it wont compile, I dont know what librar I need to include. MS VC++ is so confusing!


2. my DLL is std_call, but the problem lies even in the sample application ExpertSample. Although the app does not crash, all values are 0 in the array passed to the DLL.

If you compile the given sample app, and change the init function to what I have above, you will see that all values are 0 in the High series array.

Reason: