C++ Access violation write to 0x00000000 in dll in mql4

2.6k views Asked by At

First, I am new to C++ (nearly a week into it), so forgive me if this is obvious. Also, I have hunted through many posts with similar issues. Either my understanding is just not developed enough, or none had relevant info to help me understand this issue.

In Metatrader 4, I am trying to figure out how to pass a structure variable to a dll, and modify variables stored in said structure. So far, I have had great success, even when dealing with structure arrays. Then I encountered an issue.

I have narrowed the problem down to the use of strings. If you will, please have a look at the following code, which I have used to focus on solving this problem, and help me understand why I keep getting this 'Access violation write to 0x00000000' error whenever I try and run the script in mt4.

The mql4 code:

struct Naming
{
  string word;
} name;

#import  "SampleDLLtest.dll"
bool     NameTest(Naming &name);
#import

int init() { return(0); }

int start()
{
   Print("original name: ", name.word);
   if( NameTest( name ) )
   {
     Print("new name: ", name.word);
   }

   //---
   return(0);
}

This is the relevant dll code:

#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

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);
}

struct Naming
{
   std::string n_name;
};

bool __stdcall NameTest(Naming *name)
{
   name->n_name = "Captain Success";

   return true;
}
2

There are 2 answers

2
Hauke S On BEST ANSWER

From the documentation of mql4: http://docs.mql4.com/basis/preprosessor/import

The following can't be used for parameters in imported functions:

  • pointers (*);
  • links to objects that contain dynamic arrays and/or pointers.

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.

The imported function takes a pointer and that is apparently not supported by mql4.

You should probably use a fixed size array of characters to pass data to and from the dll:

like:

struct Naming {
  char m_name[255];
}

The function would need to accept a reference to this struct (but this is probably not supported either) or accept the struct directly and return the struct.

Naming NameTest(Naming name) {

  strncpy(name.m_name, "New Content", sizeof(name.m_name) -1);
  if (sizeof(name.m_name) > 0) {
      name.m_name[sizeof(name)-1] = 0;
  }
  return name;
}

Calling it would then look like this:

name = NameTest(name);
0
MehZhure On

I know this is a bit odd, but I am answering my own question because I figured out what was going on....mostly at least.

So, here is the deal. Technically speaking, you can pass a structure that contains a string. What you cannot do is edit the string. There is no automatic conversion of a string to a char[] in the structure. So, when the dll attempts to edit the string, it throws up the access violation because a string is not really a string in C++, but is a char array disguised as a string.

That said, I did resolve how to pass a structure containing a string, and modify the value in the dll. Here is how I did it.

---Starting with the mql4 code--- First, I declared the struct with a char[] instead of a string.

struct Naming
{
  char word[65];
} name;

Then I initialized the char[] with null value, checked it, passed the struct, and checked to see if the value was set correctly.

ArrayInitialize(name.word, '\0');
Print("original name: ", CharArrayToString(name.word));
if( NameTest( name ) )
{
   Print("new name: ", CharArrayToString(name.word));
}

---now to the C++ code--- I declared the same struct.

struct Naming
{
    char n_name[65];
};

Then the function. I first had to capture the string literal in a temporary char[]. The I cycled a for loop to distribute the elements to the char[] in the struct. The problem is, the char[] from the struct is not a const, and the char temp[] is. I got around this by capturing each char to a char variable, and then storing that variable value in the struct char[].

bool __stdcall NameTest(Naming *name)
{
    char temp[] = "Captain Success";

    for (int i = 0; temp[i] != '\0'; i++)
    {
        char t = temp[i];
        name->n_name[i] = t;
    }

    return true;
}

This code works beautifully.