DLLSample.cpp not working

 

Dear friends, looking and searching around quite a lot did not find a solution, so here I am.


Contex:

  • I am running the examples in MT4 (mql4)
  • I am running it on Windows 10 64-bit
  • I am running it with VisualStudio 2019

The problem is that the standard distributed DLLSample.cpp (.sln) and the standard script DLLTester.mq4 do not work. Here is the problem.

Code of the GetArrayItemValue function

MT4_EXPFUNC double __stdcall GetArrayItemValue(const double *arr,const int arraysize,const int nitem)
  {
//---
   if(arr==NULL)
     {
      printf("GetArrayItemValue: NULL array\n");
      return(0.0);
     }
   if(arraysize<=0)
     {
      printf("GetArrayItemValue: wrong arraysize (%d)\n", arraysize);
      return(0.0);
     }
   if(nitem<0 || nitem>=arraysize)
     {
      printf("GetArrayItemValue: wrong item number (%d)\n", nitem);
      return(0.0);
     }
//---
   return(arr[nitem]);
  }

Code of the import statement and use:

#import "DLLSample.dll"
int    GetIntValue(int);
double GetDoubleValue(double);
string GetStringValue(string);
double GetArrayItemValue(double &arr[],int,int);
bool   SetArrayItemValue(double &arr[],int,int,double);
double GetRatesItemValue(MqlRates &rates[],int,int,int);
#import

...

int start()
  {
   double   price;
   double   arr[5]={1.5,2.6,3.7,4.8,5.9 };
   MqlRates rates[];
//--- get first item from passed array
   price=GetArrayItemValue(arr,5,0);
   Print("Returned from arr[0] ",price);
//--- change second item in the passed array

....


When compiling everything and running the script the obtained error is: 

2020.06.09 13:59:59.405 Cannot find 'GetArrayItemValue' in 'DLLSample.dll'



Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
  • www.mql5.com
//| Expert initialization function                                   | //| Expert deinitialization function                                 | //| Expert tick function                                             | //| test1                                                            |...
 

Because 


GetArrayItemValue(const double *arr,const int arraysize,const int nitem)
GetArrayItemValue(double &arr[],int,int);


are different.

 
Mahrukh Aleem:

are different.

No, they're not. They're the same.

Incompatible parameters would cause stack corruption or a crash on use, not a failure to find/load the function in the DLL.

The problem looks like the functions are not being exported in the DLL. May be missing a .def file which explicitly exports the functions. 

 
JC:

No, they're not. They're the same.

Incompatible parameters would cause stack corruption or a crash on use, not a failure to find/load the function in the DLL.

The problem looks like the functions are not being exported in the DLL. May be missing a .def file which explicitly exports the functions. 

What is a .def file? How do I generate one?

Is it possible that the error is generated because of different architecture (is MT4 64 bits?).

Please note that, when running the script, the functions imported before, e.g. GetIntValue, GetDoubleValue, and GetStringValue (surprising, because String is actually a w_chart* array pointer) work fine! Execution is stopped with the reported error just when GetArrayItemValue is called.

 
Fab:

What is a .def file? How do I generate one?

The TL;DR answer:

1. In VS2019, choose Project / Add New Item / Code / Module-definition file (.def)

2. Enter the following text for the .def file:

EXPORTS
  GetArrayItemValue
The combination of the C++ sample code and the MQL4 sample code will then work - despite the fact that the parameter is declared as double&[] in MQL4 and double* in C++.
 
JC:

The TL;DR answer [...]

... The full answer involves slightly retracting my earlier statement that it's not to do with the parameter types. I hadn't seen the DLLSample, and wasn't aware of what it was doing.

In MSVC there are two ways of exporting functions from a DLL, so that another program can use them:

A. Declare them as __declspec(dllexport). This is what DLLSample.cpp does via its MT4_EXPFUNC macro.

B. Use a .def file with an EXPORTS section

The problem with (A) is that MSVC doesn't export the bare function names. It packs parameter information into them, leading to exported names such as ?GetDoubleValue@@YGNN@Z instead of GetDoubleValue. You can then only use the DLL from languages which know MSVC's naming process, and know how to reproduce the function names which it generates. For example, you couldn't use the DLLSample DLL from VBA in Microsoft Excel. The Excel VBA can only look for a function called GetDoubleValue. It can't look at the parameters for the function and work out that it needs to be searching for ?GetDoubleValue@@YGNN@Z.

MT4 does have some understanding of the MSVC naming process, and can search either for bare function names or for the MSVC names which include parameter information. Hence the fact that a #import in MQL4 of GetDoubleValue works. But it's not perfect. It breaks down in the case of GetArrayItemValue because the MQL compiler doesn't correctly translate the MQL4 double&[] to the C++ double*. 

So, in this case, it's necessary to help out MQL4 by exporting GetArrayItemValue as a bare function name, using a .def file, rather than as a parameterised function name, using dllexport.

It's always generally preferable to do B rather than A because it means that your DLL can be used with a much wider range of programming languages - VBA in Microsoft Excel again being one of the prime examples.

 
JC:

[...]

Because the error messages in MT4 and MT5 don't adequately distinguish between failure to load a DLL (LoadLibrary) versus failure to bind to a specific function (GetProcAddress), the Dependency Walker is a useful tool for verifying whether your DLL is exporting specific functions, and exactly what names it is exporting.

 
JC:

Because the error messages in MT4 and MT5 don't adequately distinguish between failure to load a DLL (LoadLibrary) versus failure to bind to a specific function (GetProcAddress), the Dependency Walker is a useful tool for verifying whether your DLL is exporting specific functions, and exactly what names it is exporting.

JC, YOU DEFINITELY ROCK! Thank you so much my dear computer science professor! (I am just a self-thaught.... understand how to code in C++ and object oriented design, but very very few about architectures, and windows infrastructure). I was reading those days, while learning how to code .dll's (first time for me...) about DECORATED NAMES, and now you enlighten me! Thank you so much!


BTW... I plan to make a .dll for importing into mql4 some of the Boost-Date-Time functions like to convert a timestamp from a timezone to another timezone (very useful for intraday seasonality trading, for instance)... in case you have further suggestions I will be all-ears!

Thank you so much!

 
And, my dear, IT WORKS PERFECTLY!
Reason: