1

I am trying for two weeks to create a DLL to which I can pass strings and get back strings. But still no success.

I tried this on Dev-C++(TDM-GCC 4.9.2) and visual studio community 2015. I searched a lot about this and tried almost every sample code I found but I have no success.

I have to use this DLL with MetaTrader Terminal 4.
Here is a one sample code, which I used. This code compiles successfully but when I send a string to this, from MT4, I get an access violation error.

#ifndef MYLIB_HPP
#define MYLIB_HPP

#include <string>

#ifdef MYLIB_EXPORTS
#define MYLIB_API __declspec(dllimport) 
#else
#define MYLIB_API __declspec(dllexport) 
#endif
bool MYLIB_API test(const std::string& str);
#endif

bool MYLIB_API MyTest(const std::string& str)
{
    return (str == "Hi There");
}
user3666197
  • 1
  • 6
  • 50
  • 92

3 Answers3

2

If you do share a C++ string between a DLL and another executable, both need to have been compiled with the same tool-chain. This is because std::string is defined in header only. So, if the DLL and executable use different string headers, they may well be binary incompatible.

If you want to make sure that things do work with different tool-chains, stick to NULL terminated C strings.

user3666197
  • 1
  • 6
  • 50
  • 92
doron
  • 27,972
  • 12
  • 65
  • 103
  • You might have already realised the issue comes from the fact the `MQL4` is not C language and the MetaTrader Terminal 4 MetaLanguage compiler + the code-execution environment does not represent `string` as **`string`**, but **rather as a `struct`**. Here we go and collide. All the rest just rolls forward from this fact. **Enjoy the day, doron.** – user3666197 Dec 13 '16 at 04:58
1

You have just experienced one of the MQL4 tricks,
the MQL4 string is not a string but a struct thus #import on MQL4 side will make MT4 to inject that, not matching your DLL C-side expectations and the access-violation error is straightforward, as your C-side code tried to access the MQL4 territories...


First rule to design API/DLL: READ the documentation very carefully.

Yes, one may object, that the MQL4 doc is somewhat tricky to follow, but thus more double the Rule#1, read the documentation very, very, very carefully as some important design facts are noted almost hidden in some not very predictable chapters or somewhere in explanations of ENUM tables, compiler directives, pragma-s side-notes et al.


Second rule: design API/DLL interface so as to allow smooth integration

MQL4 has changed the rules somewhere about Build 670+. Good news is, the MetaQuotes has announced, that there will be no further investment on their side into MT4 further developlments, so the MT4-side of the DLL/API integration will hopefully stop from further creeping.

Given your statement, that you design the DLL/API, try to design future-proof specification -- use block of uchar[]-s instead of "interpretations"-sensitive string, pass both inputs and outputs by-reference and return just some form of int aReturnCODE = myDLL_FUNC( byRefParA, byRefParB, byRefRESULT ); and your efforts will result in clean code, better portability among 3rd party language-wrappers and will also minimise your further maintenance costs.

user3666197
  • 1
  • 6
  • 50
  • 92
0

Most likely, your code and the one you're linking against have been compiled with a different ABI for std::string, i.e. the string used by the library has a different memory layout (and sizeof) than the one you're compiling with.

I once ran into this problem when linking against the hdf5 library and using gcc. In this case, the problem could be solved by reverting to a previous ABI, as explained here.

However, the problem also occurred with clang, when such a solution was not available. Thus, to make this all working I had to avoid using std::string in any calls to the library (hdf5 in my case) that was compiled with the different ABI, and instead make do with the hdf5 interface using const char*.

Walter
  • 44,150
  • 20
  • 113
  • 196
  • *it did not work* In which way? If it didn't compile, then you merely failed to adhere to the API. – Walter Dec 10 '16 at 11:30
  • @Walter Nice idea about the DLL-side dual ABI, however, `MQL4` is not C language and the MetaTrader Terminal 4 MetaLanguage compiler + the code-execution environment does not represent `string` as **`string`**, but **rather as a `struct`**. This is the root-cause of the problem. All the rest just rolls forward from this fact. **Enjoy the day, Walter.** – user3666197 Dec 13 '16 at 05:02
  • @user3666197 Isn't this exactly what I say? The library uses a different ABI (not a `std::string`, but some `struct` with memory layout different from that used in `std::string` of the caller). – Walter Dec 13 '16 at 09:34
  • Got your view, Walter, tho, I would dare agree on this idea. Best **neutral** mode is to pass pure-containers ( unstructured buf-blocks ) by-ref as ( uchar[] ) + an int scalar for efficient length of valid data inside the buffer-block ( both on the way "there" and "back" ). One never knows, when that internal secret will get silently changed next time. – user3666197 Dec 13 '16 at 13:21
  • You might have heard the bloody part of the story -- the whole Global MQL4 Community has realised such move to *New*-MQL4 just by headbang accident without a prior warning -- Sunday night crash of all API/DLL-interfaces world-wide, simply stopped working and exploded all the distributed infrastructures waiting for the first FX-Market tick. **Indeed a good lesson** -- reminds me the golden ASSEMBLER directive "**ASSUME NOTHING**" :o) – user3666197 Dec 13 '16 at 13:22
  • 1
    @user3666197 No I haven't heard the bloody part. sounds like a serious cock-up. – Walter Dec 14 '16 at 11:01