How can I return an array of string values from a DLL?

 

Hi,


This question, or variants on the theme, seem to keep coming up but I can't find a comprehensive (or correct?) answer.


I've looked through the example in the experts\samples directory, but it doesn't really address my specific question. I can see an array of strings being sorted, but I can't see any example where the string value itself is set by the DLL.


What I want to do is define a function in my DLL that when called, will return 4 string values. Preferably, I'd like these to be in a structure but I can't see any evidence that MQL4 supports user-defined structures...(perhaps I'm wrong and someone can point out how this is done).


What I've tried so far is the following.


In my MQL4
----------
string orderDets[4]={ "XXXXXXXXXXXXXXXXXXXXXX",
                      "yyyyyyyyyyyyyyyyyyyyyy",
                      "zzzzzzzzzzzzzzzzzzzzzz",
                      "aaaaaaaaaaaaaaaaaaaaaa" };

int rc = TD_GetStringDetails(Symbol(), orderDets);


In my dll.mqh file
------------------
int TD_GetStringDetails(string, string& []);


In my dll
---------
int MT4_EXPFUNC __stdcall TD_GetStringDetails(char *sCurrency, char **orderDetails) {
....
}


This gives the following error...

2009.08.22 22:52:05 TradeDirector NZDUSD,H1: cannot call function 'TD_GetStringDetails' from dll 'TradeDirector.dll' (error 127)


Any suggestions on how I might be able to update the contents of the 4 strings in the orderDets array would be most appreciated.

 
mjbrady:

This question, or variants on the theme, seem to keep coming up but I can't find a comprehensive (or correct?) answer.

I've looked through the example in the experts\samples directory, but it doesn't really address my specific question. I can see an array of strings being sorted, but I can't see any example where the string value itself is set by the DLL.

The following isn't necessarily "correct", but it does seem to work. The critical things are (a) the array dimensions must be initialised before passing the array to the DLL, and (b) arrays of strings get passed to a DLL as MqlStr*, not as char**.


This code takes a string array with (at least) two slots in it, and stores a new string in each one. It allocates a block of memory to hold each string, on the assumption that MT4 eventually tries to free the memory associated with strings. (If the array you pass in already contains values, then there will probably be a minor memory leak because the strings get replaced without ever being released.)


struct MqlStr {
	int	len;
	char    *string;
};


int __stdcall MyFunction(MqlStr * stringarray)
{
	const char * value1 = "Now is the winter of ";
	const char * value2 = "our discontent";

	int szString1 = lstrlenA(value1);
	char * string1 = (char*)malloc(szString1 + 1);
	lstrcpyA(string1, value1);

	int szString2 = lstrlenA(value2);
	char * string2 = (char*)malloc(szString2 + 1);
	lstrcpyA(string2, value2);

	stringarray[0].string = string1;
	stringarray[0].len = szString1;

	stringarray[1].string = string2;
	stringarray[1].len = szString2;

	return 0;
}
 
jjc:

The following isn't necessarily "correct", but it does seem to work. The critical things are (a) the array dimensions must be initialised before passing the array to the DLL, and (b) arrays of strings get passed to a DLL as MqlStr*, not as char**.


This code takes a string array with (at least) two slots in it, and stores a new string in each one. It allocates a block of memory to hold each string, on the assumption that MT4 eventually tries to free the memory associated with strings. (If the array you pass in already contains values, then there will probably be a minor memory leak because the strings get replaced without ever being released.)



Thanks for the tips jjc. I have managed to get this working cleanly, and w/o any leaks :-) by passing an array of strings by reference, and just making sure that each string is already initialised to a value which is at least the same size as the largest string value I wish to return from the DLL. In the DLL itself, the code is very similar to yours, except that it simply uses strcpy to overwrite the original string variable of MqlStr. Works like a charm.

 

I know this is an old topic - but can you post the code on how you did it? I am curious as to how to initialize the array prior to passing it to the dll and then what you refer to the variables as.


Thanks!

 

I know this is an old topic, but is now current for me.

Solution of jcc doesn't work. I'm out of ideas :-(

I've tried this:

C++:

vector<string> array1;
array1.push_back("text 1");
array1.push_back("text 2");
array1.push_back("text 3");
...

static char* convert(const std::string &s)
{
   char* pc=new char[s.size()+1];
   std::strcpy(pc,s.c_str());
   return pc; 
}
...
MT4_EXPFUNC BOOL __stdcall getArray(MqlStr* arr)
{
        try
        {       for(int i=0;i<static_cast<int>(array1.size());i++)
                {       
                        const char* value=convert(array1[i]);

                        strcpy(arr[i].string,value);
                        arr[i].len=strlen(value);

                        delete[] value;
                }
        }
        catch (...){return(FALSE);}
        return(TRUE);
}

MQL4:

   #import "test.dll"
   bool getArray(string& array1[]);
   #import
   ...
   string array1[];
   if(getArray(array1))
   {
      if(ArraySize(array1)>0)
      {  
         for(int i=0;i<ArraySize(array1);i++)Print(array1[i]);
         ArrayResize(array1,0);
      }
   }
 

again , I am trying the same thing in C# dll , and no success passing value from and to the dll , 

please any active user help  me in passing array of string ! 

 thanks in advance

 
hijeenu:

again , I am trying the same thing in C# dll , and no success passing value from and to the dll , 

please any active user help  me in passing array of string ! 

 thanks in advance


Please do not double post . . .  especially to old threads.
 
jjc:

The following isn't necessarily "correct", but it does seem to work. The critical things are (a) the array dimensions must be initialised before passing the array to the DLL, and (b) arrays of strings get passed to a DLL as MqlStr*, not as char**.


This code takes a string array with (at least) two slots in it, and stores a new string in each one. It allocates a block of memory to hold each string, on the assumption that MT4 eventually tries to free the memory associated with strings. (If the array you pass in already contains values, then there will probably be a minor memory leak because the strings get replaced without ever being released.)




any possible way we could see the Mql4 side of this scenario, thanks :) 

 

i am writing some dll now,it seems that dll not support char very well,it use wchar_t instead.

i have an alternative solution: 

to return string array,another way is return wchar_t* in dll,which direct transfer to string in mql4

In dll:

__declspec(dllexport) wchar_t* Func(void) ;

 

 In mql4:

#import "xxx.dll" 

string Func(void); 

#import

 string strTemp =  Func();

 

you can construct the string with special separator in dll,such as "one;two;three",then split it in mql4 to get the string "one","two","three"

 

hope that be helpful