1.编译环境及版本信息
- 金字塔版本
金字塔决策交易系统(x86)2020(v5.21) - IDE
Visual Studio Community 2019 版本 16.4.6 - 完整测试代码在附件中
2. 问题描述
- 在金字塔软件中,在公式里序列模式下调用DLL扩展函数时,使用了类,在调用该函数时在全局区定义了一个全局变量并置为空,然后在调用的函数处,通过new的方式创建一个对象,并把全局指针变量指向该对象;通过打印文件方式查看到当在金字塔软件里公式调用该DLL函数时,当改变品种或者周期时并没有调用析构函数,但是却新调用了构造函数创建了新的类对象,这里是金字塔通过DLL管理这一块堆上的内存还是用户自己要在DLL里自己进行管理,是否会存在内存泄露的问题?
- 在上诉函数之后,再调用其他函数,该全局指针并未指向上一个函数所产生的对象?要在其他函数里使用其中一个函数中创建的类对象,要进行怎样的定义才行?
3. 想要实现的目的
想要实现的目的:比如在 MYMACLOSE_TEST1
中创建了一个类,怎样才能在 MYMACLOSE_TEST2
函数中调用上面 MYMACLOSE_TEST1
中创建的对象,这样就可以调用返回对象的多个属性而不用多次创建,因为用 pData->m_pResultBuf[]
返回值时只能返回一组计算值,当想要返回其他组的计算值是要另外返回 pData->m_pResultBuf[]
才能再公式里获得!
4. 打印的记录信息



5. 测试代码
- 金字塔公式
目的就是想用 MYMACLOSE_TEST2
调用 MYMACLOSE_TEST1
中创建的对象,这样就不用重复再计算了,因为如果对象中有多个属性需要返回时,好像只能通过多次函数调用返回!
- DLL中的代码:
-- 测试类的代码:以下内容为程序代码:
1 #pragma once
2 #include<vector>
3 #include <iostream>
4 #include<fstream>
5 #include<time.h>
6 #include "StockFunc.h"
7
8 #define MyClassTestDeBug
9
10 using namespace std;
11
12 //测试在DLL中运用类对象
13 class MyClassTest
14 {
15 public:
16 MyClassTest(CALCINFO* pData);
17 ~MyClassTest();
18 void MyCalMa(int _nPeriod); //计算均线
19 vector<float> c_MaData; //结果值
20
21 private:
22 CALCINFO* c_pData_test;
23
24 };
25
26 MyClassTest::MyClassTest(CALCINFO* pData)
27 {
28 c_pData_test = pData;
29 #ifdef MyClassTestDeBug
30 ofstream outfile;
31 //outfile.imbue(locale(locale(), "", LC_CTYPE)); // ①
32
outfile.open("./Document/ctestdomedebug.txt",
ios::app); //"D:/Program Files (x86)/Weisoft
Stock(x86)/Document/clcdebug.txt"
33 if (outfile.is_open())
34 {
35 outfile.imbue(locale("", locale::all ^ locale::numeric));
36 time_t time_seconds = time(NULL); struct tm now_time; localtime_s(&now_time, &time_seconds);
37 char str[26]; strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &now_time);
38
outfile << __FUNCTION__ << " ; c_pData_test->m_nNumData: " <<
c_pData_test->m_nNumData << " ; c_MaData.size: " << c_MaData.size() << "
";
39 outfile << " name: " << c_pData_test->m_strStkName
<< "; label:" << (string)c_pData_test->m_strStkLabel << " ; run_time: "
<< str << endl;
40 outfile << "--------------------------------------------------------------" << endl;
41 }
42 outfile.close();
43 #endif // MyClassTestDeBug 输出类属性StockFunc.h中的结构、均线计算的结果值
44
45 }
46
47 MyClassTest::~MyClassTest()
48 {
49 #ifdef MyClassTestDeBug
50 ofstream outfile;
51
outfile.open("./Document/ctestdomedebug.txt",
ios::app); //"D:/Program Files (x86)/Weisoft
Stock(x86)/Document/clcdebug.txt"
52 if (outfile.is_open())
53 {
54 time_t time_seconds = time(NULL); struct tm now_time; localtime_s(&now_time, &time_seconds);
55 char str[26]; strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &now_time);
56 outfile << __FUNCTION__ << " ; c_MaData.size: " << c_MaData.size() << " " << str << endl;
57 outfile << "--------------------------------------------------------------" << endl;
58 }
59 outfile.close();
60 #endif // MyClassTestDeBug
61 }
62
63 inline void MyClassTest::MyCalMa(int _nPeriod)
64 {
65 if (_nPeriod > 0)
66 {
67 float fTotal;
68 float fCal;
69 int i(0), j(0);
70 for (i = 0; i < c_pData_test->m_nNumData; i++)//计算_nPeriod周期的均线,数据从_nPeriod-1开始有效
71 {
72 fTotal = 0.0f;
73 fCal = 0.0f;
74 if (i >= _nPeriod - 1)
75 {
76 for (j = 0; j < _nPeriod; j++) //累加
77 {
78 fTotal += c_pData_test->m_pData[i - j].m_fClose;
79 }
80 }
81 fCal = fTotal / _nPeriod; //平均
82 c_MaData.push_back(fCal);
83 }
84
85 }
86 #ifdef MyClassTestDeBug
87 ofstream outfile;
88
outfile.open("./Document/ctestdomedebug.txt",
ios::app); //"D:/Program Files (x86)/Weisoft
Stock(x86)/Document/clcdebug.txt"
89 if (outfile.is_open())
90 {
91 time_t time_seconds = time(NULL); struct tm now_time; localtime_s(&now_time, &time_seconds);
92 char str[26]; strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &now_time);
93
outfile << __FUNCTION__ << " ; c_pData_test->m_nNumData: " <<
c_pData_test->m_nNumData << " ; c_MaData.size: " << c_MaData.size() << "
" << str << endl;
94 outfile << "--------------------------------------------------------------" << endl;
95 }
96 outfile.close();
97 #endif // MyClassTestDeBug
98 }
99
- 返回调用部分代码:
以下内容为程序代码:
1 // StockFunc.cpp : Defines the entry point for the DLL application.
2 //
3
4 #include "pch.h" //#include "stdafx.h"
5 #include "StockFunc.h"
6 #include "CTestDemo.h"
7 #include "stdio.h"
8 #include "vector"
9
10 #define Test_Interface_DeBug
11
12 BOOL APIENTRY DllMain( HANDLE hModule,
13 DWORD ul_reason_for_call,
14 LPVOID lpReserved
15 )
16 {
17 switch (ul_reason_for_call)
18 {
19 case DLL_PROCESS_ATTACH:
20 case DLL_THREAD_ATTACH:
21 case DLL_THREAD_DETACH:
22 case DLL_PROCESS_DETACH:
23 break;
24 }
25 return TRUE;
26 }
27
28 //DLL公式的运行模式,系统系统调用该DLL时,告知公式系统该DLL公式运行在何种模式下
29 //返回值: 0本DLL运行序列模式 1本DLL运行逐周期模式
30 __declspec(dllexport) int WINAPI RUNMODE()
31 {
32 //本DLL运行序列模式,如果运行逐K线模式将此函数返回1,此时每执行一个K线都是调用本接口一次。
33 // return 1;
34 return 0;
35 }
36
37
38 //测试对象函数部分
39 MyClassTest* instance = nullptr; //定义一个类指针的全局变量,目的是为了下面的MYMACLOSE_TEST2也能够通过这个指针获得类属性
40 __declspec(dllexport) int WINAPI MYMACLOSE_TEST1(CALCINFO* pData)
41 {
42 if (pData->m_pfParam1 && //参数1有效
43 pData->m_nParam1Start < 0 && //参数1为常数
44 pData->m_pfParam2 == NULL) //仅有一个参数
45 {
46 float fParam = *pData->m_pfParam1;
47 int nPeriod = (int)fParam; //参数1
48 instance = new MyClassTest(pData); //类的实例化
49 instance->MyCalMa(nPeriod); //计算均线值
50 const std::vector<float>& maData = instance->c_MaData; //获得类属性(均线值)
51 for (int i = nPeriod - 1; i < (int)maData.size(); i++)//计算nPeriod周期的均线,数据从nPeriod-1开始有效
52 {
53 pData->m_pResultBuf[i] = maData[i]; //平均
54 }
55 #ifdef Test_Interface_DeBug
56 ofstream outfile;
57
outfile.open("./Document/ctestdomedebug.txt",
ios::app); //"D:/Program Files (x86)/Weisoft
Stock(x86)/Document/clcdebug.txt"
58 if (outfile.is_open())
59 {
60 time_t time_seconds = time(NULL); struct tm now_time; localtime_s(&now_time, &time_seconds);
61 char str[26]; strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &now_time);
62 outfile << __FUNCTION__ << " ; maData.size: " << maData.size() << " " << str << endl;
63 outfile << "instance指向的地址:" << instance <<" ; 获得的类属性(返回的均线值)的地址:"<< &maData<< endl;
64 outfile << "--------------------------------------------------------------" << endl;
65 }
66 outfile.close();
67 #endif // Test_Interface_DeBug
68 return nPeriod - 1;
69 }
70 return -1;
71 }
72
73 //该函数测试上面全局变量instance是否可用?
74 __declspec(dllexport) int WINAPI MYMACLOSE_TEST2(CALCINFO* pData)
75 {
76 if (pData->m_pfParam1 && //参数1有效
77 pData->m_nParam1Start < 0 && //参数1为常数
78 pData->m_pfParam2 == NULL) //仅有一个参数
79 {
80 #ifdef Test_Interface_DeBug
81 ofstream outfile;
82
outfile.open("./Document/ctestdomedebug.txt",
ios::app); //"D:/Program Files (x86)/Weisoft
Stock(x86)/Document/clcdebug.txt"
83 if (outfile.is_open())
84 {
85 time_t time_seconds = time(NULL); struct tm now_time; localtime_s(&now_time, &time_seconds);
86 char str[26]; strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &now_time);
87 outfile << __FUNCTION__ << " ; pData->m_nNumData: " << pData->m_nNumData << " " << str << endl;
88 outfile << "instance指向的地址:" << instance << endl;
89 outfile << "--------------------------------------------------------------" << endl;
90 }
91 outfile.close();
92 #endif // Test_Interface_DeBug
93 float fParam = *pData->m_pfParam1;
94 int nPeriod = (int)fParam; //参数1
95 //instance = new MyClassTest(pData); //类的实例化
96 //instance->MyCalMa(nPeriod); //计算均线值
97
98 if (instance == nullptr)
99 {
100 #ifdef Test_Interface_DeBug
101 ofstream outfile1;
102
outfile1.open("./Document/ctestdomedebug.txt",
ios::app); //"D:/Program Files (x86)/Weisoft
Stock(x86)/Document/clcdebug.txt"
103 if (outfile1.is_open())
104 {
105 time_t time_seconds = time(NULL); struct tm now_time; localtime_s(&now_time, &time_seconds);
106 char str[26]; strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &now_time);
107 outfile1 << __FUNCTION__ << " 类对象指针指向的均线属性是否为空:" << instance->c_MaData.empty() << " " << str << endl;
108 outfile1 << "--------------------------------------------------------------" << endl;
109 }
110 outfile1.close();
111 #endif // Test_Interface_DeBug
112 return -1;
113 }
114
115 const std::vector<float>& maData = instance->c_MaData; //获得类属性(均线值)
116
117 for (int i = nPeriod - 1; i < (int)maData.size(); i++)//计算nPeriod周期的均线,数据从nPeriod-1开始有效
118 {
119 pData->m_pResultBuf[i] = maData[i] * 1.01f; //平均
120 }
121 #ifdef Test_Interface_DeBug
122 ofstream outfile2;
123
outfile2.open("./Document/ctestdomedebug.txt",
ios::app); //"D:/Program Files (x86)/Weisoft
Stock(x86)/Document/clcdebug.txt"
124 if (outfile2.is_open())
125 {
126 time_t time_seconds = time(NULL); struct tm now_time; localtime_s(&now_time, &time_seconds);
127 char str[26]; strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", &now_time);
128 outfile2 << __FUNCTION__ << " ; maData.size: " << maData.size() << " " << str << endl;
129 outfile2 << "--------------------------------------------------------------" << endl;
130 }
131 outfile2.close();
132 #endif // Test_Interface_DeBug
133 return nPeriod - 1;
134 }
135 return -1;
136 }
加我QQ406720655我询问一件事情,或者你在这里回答我的问题,我告诉你实现方法:我用VS2019测试了你这个代码,没有发现任何错误,并且我可以正常编译;而去年51VS2019升级以后,几个月时间,我VS2019无法正常编辑金字塔接口程序,是可以正常打开,但是光标无法下拉到下面编辑的行,咨询了很多人都无法解决,而你这个接口解决了,不知道是金字塔接口文件更新了还是你经过了特殊处理?先谢谢你啊
![图片点击可在新窗口打开查看]()
我发图给你看看,你有一个空指针,当然没有多大问题,我编译正常,编辑正常

此主题相关图片如下:捕获.png
给你2个解决方案你尝试一下:
1 工具-》选项-》其他,勾选DLL公式内存加载驻留模式
2 使用文件保存的方式来实现2个不同的项目之间的数据共享
首先编译问题肯定是编译器的问题,其次金字塔里的FmlDevelope.zip里的文件来看数据交互头文件确实更新了,但是时间是2018/4/5号,如果你上述问题,可以查看你软件里的这个文件,这是官方给我接口文件!有空多多交流,这一块交流的人确实不多!
谢谢你的回复,我的问题不是编译的问题,请看文字描述部分,简单说就是,我想创建一个类,计算什么的在该类里实现,然后再金字塔软件里实现多次调用该类的属性,这里是软件与DLL数据交互机制的问题!
谢谢管理大大的回复,我看了下逐K模式的官方Demo里面用的静态局部变量的vector来存储数据,是不是意味着在逐K模式下,就可以创建一个类对象,然后在多个返回函数里调用该对象?内存驻留模式字面理解确实是这个理,管理大大,软件在与DLL交互时,是不是只管内存申请?当在k线图表界面换品种或周期时又另外再次调用了DLL,而之前的调用确不是软件来管理这样的内存的?即便是DLL里使用的单例模式?
如果你选择了DLL驻留模式,就等于说这个DLL就会一直加载的内存中,理论是可以实现你的多个函数的数据共享的,但是如果我们要做类似项目的时候,可能这不是优选的解决方案,因为这种模式不利于排查错误,逻辑复杂也非常容易出错,所以我们会优选文件记录的方式来解决你的项目需求
是这个理,如果多个地方调用的话,对于整个工程项目确实不好定位错误位置,而且管理也比较容易混乱,我用你说内存DLL驻留的方法,测试成功,管理,还有个问题想请教下,当我在开盘时间里,调用了DLL的公式,如果中途断了连接一段时间,然后又恢复好了,恢复后,公式在K线图表上加载他又是重起始位置重新全部遍历吗?
要看你的运行模式是什么,对于逐K线而言,即便你勾选了仅刷最后K线,那么再出现新的K线时也会从头刷一遍的。你也可以多尝试进行日志记录,依此来多了解金字塔PEL的工作机理