C++ Нарушение прав доступа, запись в 0x00000000 в dll в mql4

Во-первых, я новичок в C++ (почти неделю в нем), так что простите меня, если это очевидно. Кроме того, я просмотрел множество сообщений с похожими проблемами. Либо мое понимание недостаточно развито, либо ни у кого не было соответствующей информации, которая помогла бы мне понять эту проблему.

В Metatrader 4 я пытаюсь понять, как передать структурную переменную в dll и изменить переменные, хранящиеся в указанной структуре. До сих пор я добился больших успехов, даже имея дело с массивами структур. Затем я столкнулся с проблемой.

Я сузил проблему до использования строк. Если хотите, взгляните на следующий код, который я использовал, чтобы сосредоточиться на решении этой проблемы, и помогите мне понять, почему я продолжаю получать эту ошибку «Нарушение прав доступа, запись в 0x00000000» всякий раз, когда я пытаюсь запустить скрипт в mt4. .

Код mql4:

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

Это соответствующий код DLL:

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

person MehZhure    schedule 09.06.2015    source источник
comment
Объявление bool NameTest несовместимо. В коде mql4 вы передаете ссылку, а в dll ожидается указатель. вам, вероятно, следует изменить объявление в коде mql4, а затем вызвать NameTest следующим образом: NameTest(&name).   -  person Hauke S    schedule 09.06.2015
comment
Я пробовал. Без изменений.   -  person MehZhure    schedule 09.06.2015


Ответы (2)


Из документации по mql4: http://docs.mql4.com/basis/preprosessor/import

Следующее нельзя использовать в качестве параметров в импортированных функциях:

  • указатели (*);
  • ссылки на объекты, содержащие динамические массивы и/или указатели.

Классы, строковые массивы или сложные объекты, содержащие строки и/или динамические массивы любых типов, не могут передаваться в качестве параметра функциям, импортируемым из DLL.

Импортируемая функция принимает указатель, а это, видимо, не поддерживается mql4.

Вероятно, вам следует использовать массив символов фиксированного размера для передачи данных в dll и из dll:

как:

struct Naming {
  char m_name[255];
}

Функция должна будет принять ссылку на эту структуру (но это, вероятно, тоже не поддерживается) или принять структуру напрямую и вернуть структуру.

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

Тогда вызов будет выглядеть так:

name = NameTest(name);
person Hauke S    schedule 09.06.2015
comment
Я уже провел последние пару дней, многократно передавая структуру, содержащую строку.... успешно. Пока я не пытался редактировать строку в dll, любые другие операции, выполненные с данными структуры, были успешными. Итак, можно ли передать структуру, содержащую строку, в dll? Определенно да. Моя проблема в том, почему нарушение прав доступа при попытке редактирования строки? В любом случае..... Я рассмотрю ваше предложение по коду и посмотрю, смогу ли я найти способ заставить это работать по мере необходимости. Спасибо! - person MehZhure; 09.06.2015
comment
Пожалуйста. Я еще не работал с mql4. Поэтому я не уверен, что на самом деле вызывает проблему. - person Hauke S; 09.06.2015

Я знаю, что это немного странно, но я отвечаю на свой вопрос, потому что я понял, что происходит... по крайней мере, в основном.

Итак, вот в чем дело. С технической точки зрения, вы можете передать структуру, содержащую строку. Чего вы не можете сделать, так это отредактировать строку. В структуре нет автоматического преобразования строки в char[]. Итак, когда dll пытается отредактировать строку, она выдает нарушение доступа, потому что строка на самом деле не является строкой в ​​C++, а представляет собой массив символов, замаскированный под строку.

Тем не менее, я решил, как передать структуру, содержащую строку, и изменить значение в dll. Вот как я это сделал.

---Начнем с кода mql4--- Сначала я объявил структуру с помощью char[] вместо строки.

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

Затем я инициализировал char[] нулевым значением, проверил его, передал структуру и проверил, правильно ли установлено значение.

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

---теперь к коду C++--- Я объявил ту же самую структуру.

struct Naming
{
    char n_name[65];
};

Потом функция. Сначала мне пришлось захватить строковый литерал во временном char[]. Я зациклил цикл for, чтобы распределить элементы по char[] в структуре. Проблема в том, что char[] из структуры не является константой, а char temp[] является константой. Я обошел это, записав каждый char в переменную char, а затем сохранив значение этой переменной в структуре 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;
}

Этот код прекрасно работает.

person MehZhure    schedule 09.06.2015