Passing strings to dll files with complete example

 

Does anyone know how to properly return strings from a dll file? Attached is my project, complete with mql4 and Visual C++ source code.  The project is to create a winhttp wrapper that will function on windows 7.  The problem I am facing is per the following message in the log.

07:17:16 VNetSigFeed EURUSD,H4: function 'winhttp_WinHttpQueryOption' call from dll 'mt4_winhttp.dll' critical error c0000005 at 7771E3BE.

I have narrowed down the problem to the code which should be copying the result string back to metatrader.

Files:
mt4_winhttp.zip  1781 kb
 
rritoch:

Does anyone know how to properly return strings from a dll file? Attached is my project, complete with mql4 and Visual C++ source code.  The project is to create a winhttp wrapper that will function on windows 7.  The problem I am facing is per the following message in the log.

07:17:16 VNetSigFeed EURUSD,H4: function 'winhttp_WinHttpQueryOption' call from dll 'mt4_winhttp.dll' critical error c0000005 at 7771E3BE.

I have narrowed down the problem to the code which should be copying the result string back to metatrader.



There *.dll example in experts/samples/ folder

 
phi.nuts:

There *.dll example in experts/samples/ folder

 



Wow, I never would have thought of that *** SARCASM ***

Does anyone know how to pass strings OUT of a dll for MT4? I've done some reworking of the above code but there still isn't any hope. I did try the above solution LONG before posting here, but when passing a string variable the result never arrives as it evaluates to null.  What is even more odd is that the returned data is not null, so there is clearly a communication issue. The dll uses .NET /clr and I'm not sure if that makes a difference but it needs /clr to interface with the winhttp API.

 
rritoch:

Wow, I never would have thought of that *** SARCASM ***
What a great way to encourage other people to try and help you . . .  I'm not sure it's going to work though,  you might want to change your tactics,  perhaps saying thank you when someone posts and tries to help ?  just a suggestion,  it's a little unorthodox I know but you might want to give it a try.
 
RaptorUK:
What a great way to encourage other people to try and help you . . .  I'm not sure it's going to work though,  you might want to change your tactics,  perhaps saying thank you when someone posts and tries to help ?  just a suggestion,  it's a little unorthodox I know but you might want to give it a try.

RaptorUK,

  I find it hard to believe that response was an attempt to help me.  I made this post a long time ago and had received no assistance of any value. I've actually been holding my tongue about this worthless response since it was made but everyone seems to think this issue has been resolved by some magical sample...  I don't expect you or anyone in this forum to assist as there is clearly a problem with the platform itself that no one is willing to acknowledge or deal with. I was able to find other posts regarding this same exact issue but their responses were vague and none of them have functioned on my platform.

 
rritoch:

RaptorUK,

  I find it hard to believe that response was an attempt to help me.  I made this post a long time ago and had received no assistance of any value. I've actually been holding my tongue about this worthless response since it was made but everyone seems to think this issue has been resolved by some magical sample...  I don't expect you or anyone in this forum to assist as there is clearly a problem with the platform itself that no one is willing to acknowledge or deal with. I was able to find other posts regarding this same exact issue but their responses were vague and none of them have functioned on my platform. 

I have never written a DLL let alone a DLL intended top work with MT4,  perhaps  phi.nuts  is in a similar position and was simply trying to offer any help that he could.  If you were expecting an official response from MetaQuotes you will have a long wait,  they very rarely post in this Forum other than stuff about MT5.  So any post you get is going to be from another end user posting unpaid in his/her own time.

If you want help directly from MetaQuotes the only option is to register at the MT5 forum go to your Profile and use the service desk.  It's really intended for MT5 but they may also help with MT4. 

 

Using code such as the following the log shows that the passed pointer evaluates to 0 so nothing of any value is being passed from the platform when using a char *. I have printed the value of the string (containing all #) in MQL4 before passing it, so the string does have a value, but it is simply not being passed. I'm on a 64 bit AMD system, the DLL and Metatrader are all 32bit. Similar technique works fine for passing integer's in and out of the DLL so the issue is clearly with the MQL4 string passing.

MQL:

string winhttp_WinHttpQueryOption(string retval, int offset, int resource, int option);

C++:

extern "C" __declspec(dllexport) char * winhttp_WinHttpQueryOption(char * retval, int offset, int resource, int option);

char * winhttp_WinHttpQueryOption(char * retval, int offset, int resource, int option)
{
    char * ret;
    Logger::getInstance()->log(LOGGER_DEBUG, "Before winhttp_WinHttpQueryOption");
    mt4_winhttp_client * client = _mt4_winhttp_get_client();
    ret = client->winhttp_WinHttpQueryOption(retval, offset, resource,option);
    Logger::getInstance()->log(LOGGER_DEBUG, "After winhttp_WinHttpQueryOption");
    return ret;
}


    char * mt4_winhttp_client::winhttp_WinHttpQueryOption(char * retval, int offset, int resource, int option)
    {

      int ret,slen;
      char *p;

      HINTERNET hInternet;
      DWORD dwOption;
      LPVOID lpBuffer;
      LPDWORD lpdwBufferLength;
      LPWSTR s_buffer;
      DWORD dwSize = sizeof(DWORD);
      DWORD blen;
      DWORD dwData;

      WinhttpDataType optDataType;

      sprintf_s(buffer,WINHTTP_MAX_STRING_LENGTH,"retval = %d",(int)retval);

      Logger::getInstance()->log(LOGGER_DEBUG, buffer);


//...

 

@RaptorUK,

  Thanks for your assistance. I actually gave up on trying to work with strings directly and started passing arrays of strings. The 255 byte character limit has also been a major failure point in my testing. After switching to using arrays it was a matter of minutes before everything fell together. It seems your first post would have brought me to the solution somewhat faster. This 255 byte limit is going to be a bit of a stressor on this wrapper though, but it is certainly better than going byte by byte which is the direction I was considering if strings couldn't be passed. I've split up the winhttpqueryoption function into 2 calls, one to get the length of the option (integer), and the other to get the value, with an extra integer field for an offset so the returned string can be retrieved in parts. This project still far from being mature, but at least it is possible. Thanks for your assistance.


MQL4: 

   // Header ...

   string winhttp_WinHttpQueryOption(string &retval[], int offset, int resource, int option);

    // Code ...

    string httpResult[1];

     // ...

     httpResult[0] = makeBuffer(200);

    

     // ...
   
     httpResult[0] = winhttp_WinHttpQueryOption(httpResult, 0, hSession, WINHTTP_OPTION_CONNECT_TIMEOUT);

C++:

extern "C" __declspec(dllexport) char * winhttp_WinHttpQueryOption(MqlStr *retval, int offset, int resource, int option);

char * winhttp_WinHttpQueryOption(MqlStr * retval, int offset, int resource, int option)
{
    char * ret;
    Logger::getInstance()->log(LOGGER_DEBUG, "Before winhttp_WinHttpQueryOption");
    mt4_winhttp_client * client = _mt4_winhttp_get_client();
    ret = client->winhttp_WinHttpQueryOption(retval, offset, resource,option);
    Logger::getInstance()->log(LOGGER_DEBUG, "After winhttp_WinHttpQueryOption");
    return ret;

}


    char * mt4_winhttp_client::winhttp_WinHttpQueryOption(MqlStr * retval, int offset, int resource, int option)
    {
      // ...

      char *retstr;

      // ...

      retstr = retval[0].string;

      // ...

      return retval[0].string;

    }

 
As a followup to this I wanted to release my code here so others can benefit from the assistance I received here.  The code is now functional but will require some understanding of the WinHTTP library, and some understanding of C++.  This code was developed using VisualStudio express 2010.  The system uses custom handles (int) and has some minor deviations from normal functionality to better interface with Metatrader.

To avoid wasting time developing a feature that isn't normally needed the winhttp_WinHttpOpenRequest method does not include a parameter for accepted content types and always passes WINHTTP_DEFAULT_ACCEPT_TYPES as the parameter.

Instead of accepting a data parameter to winhttp_WinHttpSendRequest the parameter is intentionally missing.

Data is instead passed using int winhttp_AppendRequestData(int resource,string data); or cleared using int winhttp_FlushRequestData(int resource); prior to calling winhttp_WinHttpSendRequest(int resource, string headers)

While the code is functional it is incomplete. There are many options that are supported by winhttp that are not included.  To allow for maximum support of winhttp options in the future the __winhttp_WinHttpQueryOption method returns a string, such that when a numeric option is requested the number is returned as a numeric string.
Files:
 

Hi,

I'm not a C++ expert and would like to know:

-do not need to deallocate the Loggon class after it has created?

static Logger * Logger::getInstance() 
{
  static Logger * _inst = NULL;
  if (NULL == _inst) {
    _inst = new Logger("winhttp.log");
  }
  return _inst;
}
Reason: