Download MetaTrader 5
To add comments, please log in or register
Move from theory to practice. Code Base will help you!
micclly
187
micclly 2014.02.24 15:12 

On build 509 or earlier, MqlStr struct, which is for passing mql string array to DLL, is as follows.

// for build 509 or earliear
struct MqlStr509
{
    int len;
    char* str;
};


From build 600, MqlStr might be changed as follows.

// for build 600 or later
struct MqlStr600
{
    int len;
    wchar_t* str;
    int dummy; // for padding
};


Is this fixed specification? or might be changed on the future builds?

The verifcation code is as follows.

DLL:

#define STRINGARRAYTEST_API extern "C" __declspec(dllexport)

STRINGARRAYTEST_API int func509(MqlStr509 *strArray, int arrayCount)
{
    std::stringstream msg;

    for (int i = 0; i < arrayCount; i++) {
        msg.str("");
        msg << "func509: strArray[" << i << "] = " << strArray[i].str
            << ", strArray[" << i << "].len = " << strArray[i].len;
        OutputDebugStringA(msg.str().c_str());
    }

    return 0;
}

STRINGARRAYTEST_API int func600(MqlStr600 *strArray, int arrayCount)
{
    std::wstringstream msg;

    for (int i = 0; i < arrayCount; i++) {
        msg.str(L"");
        msg << "func600: strArray[" << i << "] = " << strArray[i].str
            << ", strArray[" << i << "].len = " << strArray[i].len;
        OutputDebugStringW(msg.str().c_str());
    }

    return 0;
}


MQL for build 509 or earlier:

#import "StringArrayTest.dll"
    int func509(string& strArray[], int arrayCount);
#import

int start()
{
    string strArray[] = { "Hello", "World", "Goodnight" };
    func509(strArray, ArraySize(strArray));

    return(0);
}


MQL for build 600 or later:

#property strict

#import "StringArrayTest.dll"
    int func600(string& strArray[], int arrayCount);
#import

void OnStart()
{
    string strArray[] = { "Hello", "World", "Goodbye" };

    func600(strArray, ArraySize(strArray));
}


Result of build 509:

[6448] func509: strArray[0] = Hello, strArray[0].len = 0
[6448] func509: strArray[1] = World, strArray[1].len = 0
[6448] func509: strArray[2] = Goodnight, strArray[2].len = 0


Result of build 610:

[6916] func600: strArray[0] = Hello, strArray[0].len = 123
[6916] func600: strArray[1] = World, strArray[1].len = 0
[6916] func600: strArray[2] = Goodbye, strArray[2].len = 0


My built DLL is attached.

Files:
micclly
187
micclly 2014.02.25 09:17  

In addition about this, old MqlStr is still defined in a sample.

With the build 610 installation, the sample is located at <MT4_INSTALL_DIR>\MQL4\Scripts\Examples\DLL\DLLSample.cpp .

//+------------------------------------------------------------------+
//|                                              Sample DLL for MQL4 |
//|                   Copyright 2001-2014, MetaQuotes Software Corp. |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+
#define WIN32_LEAN_AND_MEAN  // Exclude rarely-used stuff from Windows headers
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
//---
#define MT4_EXPFUNC __declspec(dllexport)
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#pragma pack(push,1)
struct RateInfo
  {
   __int64           ctm;
   double            open;
   double            low;
   double            high;
   double            close;
   unsigned __int64  vol_tick;
   int               spread;
   unsigned __int64  vol_real;
  };
#pragma pack(pop)
//---
struct MqlStr
  {
   int               len;
   char             *string;
  };
static int CompareMqlStr(const void *left,const void *right);
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
  {
//---
   switch(ul_reason_for_call)
     {
      case DLL_PROCESS_ATTACH:
      case DLL_THREAD_ATTACH:
      case DLL_THREAD_DETACH:
      case DLL_PROCESS_DETACH:
         break;
     }
//---
   return(TRUE);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall GetIntValue(const int ipar)
  {
   printf("GetIntValue takes %d\n",ipar);
   return(ipar);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MT4_EXPFUNC double __stdcall GetDoubleValue(const double dpar)
  {
   printf("GetDoubleValue takes %.8lf\n",dpar);
   return(dpar);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MT4_EXPFUNC wchar_t* __stdcall GetStringValue(wchar_t *spar)
  {
   wprintf(L"GetStringValue takes \"%s\"\n",spar);
   return(spar);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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]);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MT4_EXPFUNC bool _stdcall SetArrayItemValue(double *arr,const int arraysize,const int nitem,const double value)
  {
//---
   if(arr==NULL)
     {
      printf("GetArrayItemValue: NULL array\n");
      return(FALSE);
     }
   if(arraysize<=0)
     {
      printf("GetArrayItemValue: wrong arraysize (%d)\n", arraysize);
      return(FALSE);
     }
   if(nitem<0 || nitem>=arraysize)
     {
      printf("GetArrayItemValue: wrong item number (%d)\n", nitem);
      return(FALSE);
     }
//---
   arr[nitem]=value;
   return(TRUE);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MT4_EXPFUNC double __stdcall GetRatesItemValue(const RateInfo* rates,const int rates_total,const int shift,const int nrate)
  {
//---
   if(rates==NULL)
     {
      printf("GetRatesItemValue: NULL array\n");
      return(0.0);
     }
//---
   if(rates_total<0)
     {
      printf("GetRatesItemValue: wrong rates_total number (%d)\n", rates_total);
      return(0.0);
     }
//---
   if(shift<0 || shift>=rates_total)
     {
      printf("GetRatesItemValue: wrong shift number (%d)\n", shift);
      return(0.0);
     }
//---
   if(nrate<0 || nrate>5)
     {
      printf("GetRatesItemValue: wrong rate index (%d)\n", nrate);
      return(0.0);
     }
//---
   int nitem=rates_total-1-shift;
   switch(nrate)
     {
      case 0: return double(rates[nitem].ctm);
      case 1: return rates[nitem].open;
      case 2: return rates[nitem].low;
      case 3: return rates[nitem].high;
      case 4: return rates[nitem].close;
      case 5: return double(rates[nitem].vol_tick);
     }
//---
   return(0.0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall SortStringArray(MqlStr *arr,const int arraysize)
  {
//---
   if(arr==NULL)
     {
      printf("SortStringArray: NULL array\n");
      return(-1);
     }
   if(arraysize<=0)
     {
      printf("SortStringArray: wrong arraysize (%d)\n", arraysize);
      return(-1);
     }
//---
   qsort(arr,arraysize,sizeof(MqlStr),CompareMqlStr);
//---
   return(arraysize);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MT4_EXPFUNC int __stdcall ProcessStringArray(MqlStr *arr,const int arraysize)
  {
   int   len1,len2;
//---
   if(arr==NULL)
     {
      printf("ProcessStringArray: NULL array\n");
      return(-1);
     }
   if(arraysize<=0)
     {
      printf("ProcessStringArray: wrong arraysize (%d)\n", arraysize);
      return(-1);
     }
//---
   for(int i=0; i<arraysize-1; i++)
     {
      if(arr[i].string==NULL) len1=0;
      else len1=strlen(arr[i].string);
      if(arr[i+1].string==NULL) len2=0;
      else len2=strlen(arr[i+1].string);
      //--- uninitialized string
      if(arr[i+1].string==NULL) continue;
      //--- destination string is uninitialized and cannot be allocated within dll
      if(arr[i].string==NULL)   continue;
      //--- memory piece is less than needed and cannot be reallocated within dll
      if(arr[i].len<len1+len2)  continue;
      //--- final processing
      strcat(arr[i].string,arr[i+1].string);
     }
//---
   return(arraysize);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CompareMqlStr(const void *left,const void *right)
  {
   MqlStr *leftstr=(MqlStr *)left;
   MqlStr *rightstr=(MqlStr *)right;
//---
   if(leftstr->string==NULL) return(-1);
   if(rightstr->string==NULL) return(1);
//---
   return(strcmp(leftstr->string,rightstr->string));
  }
//+------------------------------------------------------------------+
Ovo Cz
2951
Ovo Cz 2014.02.25 10:00  

I have no idea what MqlStr is for, but I am sure that passing a string array is denied in MQL+:

#import "StringArrayTest.dll"
    int func600(string& strArray[], int arrayCount);
#import
gchrmt4
356
gchrmt4 2014.02.25 10:18  
Ovo:

but I am sure that passing a string array is denied in MQL+:

That was certainly in the advance information about the new version, but I think it was brought back by popular demand: https://www.mql5.com/en/forum/149271/page20#905209
gchrmt4
356
gchrmt4 2014.02.25 10:24  
gchrmt4:
That was certainly in the advance information about the new version, but I think it was brought back by popular demand: https://www.mql5.com/en/forum/149271/page20#905209
... Alternatively, it's possible to continue using the old DLL and the old MqlStr: https://www.mql5.com/en/forum/149412
micclly
187
micclly 2014.02.25 11:07  
Ovo:

I have no idea what MqlStr is for, but I am sure that passing a string array is denied in MQL+:


The verification code is executed on the latest build, 610.


MQL code is as you can see with strict property, so currently passing string array isn't denied. Also works good with additional int field in the MqlStr.

Ovo Cz
2951
Ovo Cz 2014.02.25 11:14  
micclly:

The verification code is executed on the latest build, 610.


MQL code is as you can see with strict property, so currently passing string array isn't denied. Also works good with additional int field in the MqlStr.


I did not try. In that case wording in the Help file is out of date:

Classes, string arrays or complex objects that contain strings and/or dynamic arrays of any types cannot be passed as a parameter to functions imported from DLL.

micclly
187
micclly 2014.02.25 11:18  
gchrmt4:
That was certainly in the advance information about the new version, but I think it was brought back by popular demand: https://www.mql5.com/en/forum/149271/page20#905209


Thank you for nice information.

I've never found posts like that, it's much worth for me!

micclly
187
micclly 2014.02.25 11:22  
gchrmt4:
... Alternatively, it's possible to continue using the old DLL and the old MqlStr: https://www.mql5.com/en/forum/149412


Also good tips, thanks.
micclly
187
micclly 2014.02.25 11:23  
Ovo:


I did not try. In that case wording in the Help file is out of date:

Classes, string arrays or complex objects that contain strings and/or dynamic arrays of any types cannot be passed as a parameter to functions imported from DLL.


I see, thank you for nice information.
/
To add comments, please log in or register