模块化组件化实现独立的功能模块是软件设计的良好习惯,一般用实现为DLL。普通的DLL对外提供接口是采用导出函数接口,如果接口数量不大,只是50个以内,这种方式很适合;如果对外接口有上百个,导出函数接口就完全破坏了软件模块化分层设计的理念,使用接口非常麻烦,此情形采用C++/CLI导出类方式实现比较适合,即核心实现先C++ DLL,然后C++/CLI直接调用C++ DLL导出类,对外第三方工程提供CLI类接口。浮云E绘图以一个最简单的绘图模块为示例,详细介绍此方法的实现过程。
一、C++ DLL实现
本文只是为了介绍调用C++ dll导出类实现C++/CLI dll的完整过程,示例程序尽量简单。先用C++实现一个绘图组件dll。
C++ dll绘图主键设计构思
1. 绘图画布CFyView:CFyView继承自CWnd,是绘图画布窗口,并响应鼠标事件。
2. 绘图数据容器CChart:管理所有业务数据,(如需支持控件内滚轴,容器是虚拟画布)。
3. 曲线CCurve:曲线数据和曲线绘制。
C++ dll程序开发过程
1. 新建工程
选择C++ Windows 的 MFC动态链接库 --> 项目取名FyMfcDll,解决方案取名FyDemo --> Dll类型选 使用共享MFC DLL的常规 DLL
2. 创建绘图窗口类CFyView
新建类CFyView,继承于CWnd --> 添加窗口属性变量int m_crBackColor,重载窗口消息OnPaint、OnLButtonDblClk。
class CFyView : public CWnd
{
public:
CFyView();
virtual ~CFyView();
bool Create(HWND hParentWnd);
DECLARE_MESSAGE_MAP()
afx_msg void OnPaint();
afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
public:
int m_crBackColor;
HWND m_hParentWnd;
CChart m_chart;
};
先创建好绘图窗口,方便调试绘图功能。接着往下实现绘图相关功能,等绘图功能实现后,再在CFyView里声明绘图相关对象,在OnPaint完成绘图呈现。
3. 创建数据管理器类CChart
数据管理类主要定义了曲线Curve对象集合、曲线标题、标题显示位置属性,以及添加、删除曲线,设置标题位置、绘图Draw等函数。
//作者:浮云E绘图,专业付费定制各类CAD/Viso等绘图编辑器、曲线控件等软件
//QQ:316868127
class CChart
{
public:
CChart();
virtual ~CChart();
void AddCurve(CCurve* curve);
void RemoveCurve(CCurve* curve);
void ClearCurves();
void Draw(CDC* dc);
void SetTitlePos(int x, int y);
void GetTitlePos(int& x, int& y);
CString GetTitle();
public:
CString m_sTitle;
CPtrArray m_curves;
int m_iTitleX;
int m_iTitleY;
};
实际商业项目中,数据管理容器管理着大量的业务对象,就曲线控件而言,比如曲线网格、坐标轴、图例等等数据。
4. 创建曲线类CCurve
曲线类主要定义了数据点集合CPoint数组、曲线名称、曲线线条宽度、颜色、线型等属性,主要方法是添加、清空点,以及画点连线函数Draw。
class CCurve
{
public:
CCurve(CString name);
virtual ~CCurve();
virtual bool AddPoint(CPoint* point);
virtual void ClearPoints();
virtual void Draw(CDC* dc);
public:
CString m_sName;
int MAX_POINT_COUNT = 100;
CPoint* m_pts = new CPoint[100]; //实际项目,此处创建的数组个数由外部程序传入
int m_nPointCount;
int m_nLineStyle;
int m_nLineWidth;
int m_crLineColor;
};
以上完成了C++ dll示例定义,完整的解决方案(包含4个工程)源码,在文本底部提供下载链接。在些C++ dll时,为了方便快捷的测试,可以先写一个C#测试工程,直接通过导出函数方式,测试C++ dll的核心流程。具体实现方式可参考 C#和VC++调用dll步骤,接口指针、字符串等类型对应关系。
C++ dll直接导出函数测试接口
1 //作者:浮云E绘图,专业付费定制开发各类绘图软件 2 //QQ:316868127 3 4 extern "C" __declspec(dllexport) CFyView * NewFyChart() 5 { 6 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 7 return new CFyView(); 8 } 9 10 extern "C" __declspec(dllexport) void DeleteFyChart(CFyView* fyView) 11 { 12 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 13 delete fyView; 14 } 15 16 extern "C" __declspec(dllexport) bool CreateFyView(CFyView *fyView, HWND hParentWnd) 17 { 18 AFX_MANAGE_STATE(AfxGetStaticModuleState()); 19 return fyView->Create(hParentWnd); 20 } 21 22 extern "C" __declspec(dllexport) void LoadFyVDate(CFyView * fyView) 23 { 24 CChart* chart = &(fyView->m_chart); 25 26 int offx = 50; 27 CCurve* curve1 = new CCurve(_T("curve 001")); 28 for (int i = 0; i < 20; i++) 29 { 30 curve1->AddPoint(new CPoint(offx, rand()%50)); 31 32 offx += 10; 33 } 34 curve1->m_crLineColor = 0x00FF00; 35 curve1->m_nLineWidth = 2; 36 chart->AddCurve(curve1); 37 38 CCurve* curve2 = new CCurve(_T("curve 001")); 39 for (int i = 0; i < 40; i++) 40 { 41 curve2->AddPoint(new CPoint(offx, 100+rand() % 50)); 42 43 offx += 10; 44 } 45 curve2->m_crLineColor = 0x0; 46 curve2->m_nLineWidth = 1; 47 chart->AddCurve(curve2); 48 49 fyView->RedrawWindow(); 50 } 51 52 extern "C" __declspec(dllexport) void SetFyVBackColor(CFyView * fyView, int color) 53 { 54 fyView->m_crBackColor = color; 55 56 fyView->RedrawWindow(); 57 } 58 59 extern "C" __declspec(dllexport) int GetFyVBackColor(CFyView * fyView) 60 { 61 return fyView->m_crBackColor; 62 }
C#工程直接调用C++ dll测试实例
1 private const string LTDLL_NAME = "FyMfcDll.dll"; 2 [DllImport(LTDLL_NAME, EntryPoint = "NewFyChart", CallingConvention = CallingConvention.Cdecl)] 3 public static extern IntPtr NewFyChart(); 4 [DllImport(LTDLL_NAME, EntryPoint = "DeleteFyChart", CallingConvention = CallingConvention.Cdecl)] 5 public static extern void DeleteFyChart(IntPtr chart); 6 7 [DllImport(LTDLL_NAME, EntryPoint = "CreateFyView", CallingConvention = CallingConvention.Cdecl)] 8 public static extern bool CreateFyView(IntPtr fyView, IntPtr hParentWnd); 9 [DllImport(LTDLL_NAME, EntryPoint = "LoadFyVDate", CallingConvention = CallingConvention.Cdecl)] 10 public static extern void LoadFyVDate(IntPtr chart); 11 12 [DllImport(LTDLL_NAME, EntryPoint = "SetFyVBackColor", CallingConvention = CallingConvention.Cdecl)] 13 public static extern void SetFyVBackColor(IntPtr chart, int color); 14 [DllImport(LTDLL_NAME, EntryPoint = "GetFyVBackColor", CallingConvention = CallingConvention.Cdecl)] 15 public static extern int GetFyVBackColor(IntPtr chart); 16 17 18 IntPtr m_fyChart; 19 20 public Form1() 21 { 22 InitializeComponent(); 23 } 24 25 private void Form1_Load(object sender, EventArgs e) 26 { 27 m_fyChart = NewFyChart(); 28 29 CreateFyView(m_fyChart, this.panel1.Handle); 30 31 LoadFyVDate(m_fyChart); 32 } 33 34 private void btnChangeBk_Click(object sender, EventArgs e) 35 { 36 int bkclr = GetFyVBackColor(m_fyChart); 37 SetFyVBackColor(m_fyChart, 0xADD8E6); 38 }
二、C++/CLI dll、 C++ dll、C#之数据类型的对应关系
3种开发语言常用的数据类型对应关系具体参考上文 CLR组件开发之 基于C++ dll 与C++/CLI dll与C#的数据类型对应关系
三、C++/CLI DLL实现
C++/CLI dll程序开发过程
1. 新建C++/CLI工程
选择 CLR类库(.NET Framework) --> 项目取名 FyClr
2. 添加FView类,作为C++窗口类CFyView的对应
// FView.h文件
using namespace System;
namespace fy_dll
{
public ref class FView : public IDisposable
{
public:
FView();
virtual ~FView();
};
}
// FView.cpp文件
#include "pch.h"
#include "FView.h"
namespace fy_dll
{
FView::FView()
{}
FView::~FView()
{}
}
1> FView是托管类,带ref关键字;
2>FView类继承于IDisposable,作为C++资源对象(窗口)的对应类,请继承于IDisposable
3>请定义一个namespace 命名空间,在C#工程好引用。
C++对象与C#对应
//FView.h
#include "../FyMfcDll/CFyView.h"
public ref class FView : public IDisposable
{
public:
FView();
property Color BackColor {
Color get();
void set(Color value);
}
private:
CFyView* m_cFyView;
......
};
//-----------------------------------------------
//FView.cpp
FView::FView()
{
m_cFyView = new CFyView();
}
Color FView::BackColor::get()
{
return UInt2Color(m_cFyView->m_crBackColor);
}
void FView::BackColor::set(Color value)
{
m_cFyView->m_crBackColor = Color2UInt(value);
}
是在ref class FView类里定义了一个C++对象指针,维系这与C++ dll的关系。
C++/CLI dll封装C++ dll过程和编译选项
1> 回到C++工程,把需要导出的类定义加关键词
class CFyView : public CWnd --> 改成
class __declspec(dllexport) CFyView : public CWnd
2>CLI工程编译选项设置
a> 项目属性 -> 配置属性 -> 高级 -> MFC的使用,设为"在共享DLL中使用MFC";
b> 项目属性 -> 配置属性 -> 高级 -> 字符集,设为"使用多字节字符集;(如果文字乱码)
b> 项目属性 -> 配置属性 -> 调试 -> 命令,可设为调用此dll的应用程序EXE;(非常重要,方便调试代码)
c> 项目属性 -> 配置属性 -> 调试 -> 调试器类型,设为"混合(.NET Framework)";(方便调试代码)
d> 项目属性 -> 链接器 -> 常规 -> 附加库目录,设为"$(SolutionDir)$(Configuration)\";
e> 项目属性 -> 链接器 -> 输入 -> 附加依赖项,设为"$FyMfcDll.lib";(因为本项目CLI工程调用了C++ FyMfcdll工程dll)
f> 项目属性 -> C/C++ -> 代码生成 -> 结构成员对齐,设为"4字节";(如果C++工程与CLI工程对通一结构体内存数据错了,两个工程需设置相同的结构成员对齐方式)
g> 项目属性 -> 配置属性 -> 高级 -> 公共语言运行时支持,设为"公用语言运行时支持(/clr)";(C++工程与CLI工程都要设置)
1 private FView fView = null; 2 private FChart fChart = null; 3 4 public Form1() 5 { 6 InitializeComponent(); 7 8 fView = new FView(); 9 fChart = fView.GetChart(); 10 } 11 12 private void Form1_Load(object sender, EventArgs e) 13 { 14 fView.Create(this.panel1.Handle); 15 fView.BackColor = Color.LightGray; 16 17 18 int x = 100; 19 Random rand = new Random(); 20 FCurve cur1 = new FCurve("cur001"); 21 cur1.LineWidth = 4; 22 for (int i=0; i< 30; i++) 23 { 24 cur1.AddPoint(x, 50+rand.Next(100)); 25 x += 10; 26 } 27 fChart.AddCurve(cur1); 28 29 30 x = 200; 31 FCurve cur2 = new FCurve("cur002"); 32 cur2.LineWidth = 1; 33 for (int i = 0; i < 50; i++) 34 { 35 cur2.AddPoint(x, 200 + rand.Next(50)); 36 x += 10; 37 } 38 fChart.AddCurve(cur2); 39 40 41 fView.ReDraw(); 42 } 43 44 private void btnChangeBk_Click(object sender, EventArgs e) 45 { 46 Random rand = new Random(); 47 fView.BackColor = Color.FromArgb(255, 200+rand.Next(55), 200 + rand.Next(55), 200 + rand.Next(55)); 48 49 fView.ReDraw(); 50 }
3. CLI工程,继续新建托管类FChart对应C++工程的CChart类,新建托管类FCurve对应C++工程导出类CCurve。
C++ 工程类如CChart定义改成class __declspec(dllexport) CChart --> CLI工程FChart类新增有必要对外提供接口访问的属性和成员函数(实现是调用C++指针对象执行)。工程源码底部下载。
四、第三方调用C++/CLI DLL示例
1. 新建项目,选 C# Windows 桌面 --> Windows 窗体应用(.NET Framework) --> 取名“TestClrDllDemo”
2. 引用上文开发的Clr组件。1>添加代码 using yf_dll --> 2> 点击“引用”,右键“添加引用”,浏览clr组件生成目录,选择fyClr.dll。
3. C#工程直接调用CLI DLL里的各种类。
编辑
解决方案可以运行,包含4个工程:(完整源码下载地址)
1. MFC dll工程 FyMfcDll,C++ MFC实现核心业务和绘图。
2. C++/CLI dll工程 fyClr ,封装 MFC dll各功能,以导出类方式对外提供接口,直接C#访问。
3. C# Winform测试MFC dll工程 TestMfcdllDemo
4. C# Winform测试C++/CLI dll工程 TestClrDllDemo
标签:MFC,int,void,FView,C++,dll,源码,public From: https://www.cnblogs.com/fydraw/p/17538413.html