使用自定义指标和 C++ DLL 时访问冲突读取错误和 MT4 崩溃

Access violation read error and MT4 crash when using custom indicator and C++ DLL

我正在编写一个从 C++ DLL 调用函数的指示器。我只需要将收盘价传递给 DLL 和 return 来自 DLL 的字符串。

MQL4 代码:

#import "PythonZones.dll"
void CalculateZones(double &data[], double quantile, int arraySize,char&[]);
#import

#property indicator_chart_window
char buffer[4096];
input color M5color = clrTurquoise;

input int WINDOW = 446;
input double PARAM_SHIFT = 0.14;

int start()
  {
    if (IsNewBar()){
         double data[];
         ArrayResize(data,WINDOW);
         Rate(data,WINDOW);
         Print(data[0]);
         CalculateZones(data,PARAM_SHIFT ,WINDOW,buffer);
         string zones = CharArrayToString(buffer);
         Print(zones);
  }
   return(0);
}

void Rate(double &out[],int len){
        for(int i=(len - 1);i>-1;i--){
         double close = iClose(NULL,0,i+1);
         out[i] = close;
      }   
 }

和 C++ DLL 代码:

#define WIN32_LEAN_AND_MEAN  // Exclude rarely-used stuff from Windows headers
//#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include <windows.h>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include "Python.h"
#include "numpy/arrayobject.h"
//----
#define MT4_EXPFUNC __declspec(dllexport)

PyObject *Amanda;
PyObject *AmandaZones;


BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
  {
//----
   switch(ul_reason_for_call)
     {
      case DLL_PROCESS_ATTACH:
          Py_Initialize();
          import_array1(-1);
          PyObject *pName;
          pName = PyString_FromString("Amanda");
                  Amanda = PyImport_Import(pName);
          Py_DECREF(pName);
                  if (Amanda != NULL){
                          AmandaZones = PyObject_GetAttrString(Amanda, "CalculateZones");
                          if (AmandaZones == NULL){
                 OutputDebugString("Failed to get desired func.");
             }
          }else{
              OutputDebugString("Failed to load Amanda.");
          }
          OutputDebugString("Attached.");
          break;
      case DLL_THREAD_ATTACH:
          break;
      case DLL_THREAD_DETACH:

          break;
      case DLL_PROCESS_DETACH:
                  Py_DECREF(Amanda);
                  Py_DECREF(AmandaZones);
          Py_Finalize();
          break;
     }
//----
   return(TRUE);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MT4_EXPFUNC void __stdcall CalculateZones(double *data, double quantile, int arraySize,char *buffer)
  {

        if (arraySize < 0) return;


        npy_intp npy_arraysize;

        npy_arraysize = arraySize;
        PyObject *q = PyFloat_FromDouble(quantile);
        PyObject *np_value = PyArray_SimpleNewFromData(1, &npy_arraysize, NPY_DOUBLE, data);
        Py_INCREF(np_value);;
        Py_INCREF(q);;
        PyObject *pArgs = PyTuple_New(2);
        PyTuple_SetItem(pArgs, 0, np_value);
        PyTuple_SetItem(pArgs, 1, q);


        PyObject *pResult = PyObject_CallObject(AmandaZones, pArgs);
   Py_DECREF(pArgs);
   Py_DECREF(np_value);
   Py_DECREF(q);

   char* res = PyString_AsString(pResult);

   Py_DECREF(pResult);


   strcpy(buffer,res);


  }

指标完美运行,但是当我从图表中删除指标并再次添加时,它不再工作并且 return 出现错误 "Access violation read"。

而且当我将它与 Strategy Tester 一起使用时,MetaTrader 崩溃但没有记录任何错误。

我认为问题出在数组引用上。我尝试使用 struct 而不是数组来尝试它,但我无法以任何方式编译它,因为我不太了解 MQL4 或 C++。

我该如何解决这个问题?

Q: How can I solve the problem?

使用 string-s 的 MQL4 / DLL 集成是一个疯狂的旅程...

然而,第一步应该是修复 #import 调用签名,其中提供了供 MQL4 编译器使用的接口详细信息:

#import "PythonZones.dll"
void CalculateZones( double &data[],
                     double  quantile,
                     int     arraySize,
                     char   &buffer[]   // this line is a suspect for mystifying compiler
                     );
#import

如果修复调用签名以满足 DLL 发布的调用接口没有帮助(如果没有 DLL-Under-Test 的副本我们无法测试),您需要专家对于这样的双系统集成(具有双域专业知识,C++ 不足以使 MQL4 编排工作)。

我祈祷你用修复的 #import 呼号就能解决问题。数十人 * 年的双域故障排除告诉我这样祈祷的原因。

问题出在 numpy 包上。在C++中使用时不应初始化两次。 Py_finilize() 无法正常工作并且不会删除 numpy 模块对象。我从这里解决https://github.com/numpy/numpy/issues/8097