Нарушение на достъпа на 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:

като:

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[] от структурата не е const, а char temp[] е. Заобиколих това, като заснех всеки char в променлива char и след това запаметих стойността на тази променлива в 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;
}

Този код работи прекрасно.

person MehZhure    schedule 09.06.2015