在C#中调用外部DLL文件是一种常见的编程实践,它具有以下几个重要意义:1.代码重用;2.模块化;3.性能优化;4.安全性;5.跨平台兼容性;6.方便更新和维护;7.利用特定技术或框架;8.减少编译时间;9.保护知识产权;10.动态加载等。
调用外部DLL时,需要注意DLL的兼容性、版本控制以及依赖管理等问题,确保程序的稳定性和可靠性。
本节通过调用c++编写的dll文件显示带有噪声的正弦信号和脉冲信号。
1.1 生成动态链接库
1)打开VS2022,创建新项目
填写项目名称,选择路径,点击创建
解决方案处的结构如图所示
2)因为本人c#程序版本是32位,所以DLL也必须是32位的
3)打开pch.h文件
添加内容
#ifndef PCH_H
#define PCH_H
// 添加要在此处预编译的标头
#include "framework.h"
extern "C" int __declspec(dllexport) Add(int a, int b);
extern "C" __declspec(dllexport) void SinSignal(double amplitude, int T, double phase, int num, double noise, double result[]);
extern "C" __declspec(dllexport) void PulseSignal(double amplitude, int T, int start, int num, double noise, double result[]);
#endif //PCH_H
4)打开pch.cpp
添加内容
// pch.cpp: 与预编译标头对应的源文件
#include "pch.h"
// 当使用预编译的头时,需要使用此源文件,编译才能成功。
#include <cstdlib>
#include <ctime>
int Add(int a, int b)
{
return a + b;
}
///********************* 正弦信号输出 **************//
//amplitude :幅值
// T :一个周期个数
//phase :相位
//num :输出个数
//noise :噪声幅值
//result :结果
void SinSignal(double amplitude, int T, double phase, int num, double noise, double result[])
{
std::srand(std::time(0));
double pi_value = acos(-1.0); // 利用反余弦函数acos特性计算π
for (int i = 0; i < num;i++)
{
double noise1 = noise * rand() / 32768;
result[i] = amplitude * sin(phase * pi_value / 180 + pi_value * i * 2 / T) + noise1;
}
}
///********************* 脉冲信号 **************//
//amplitude :幅值
// T :一个周期个数
//start :开始位置
//num :输出个数
//noise :噪声幅值
//result :结果
void PulseSignal(double amplitude, int T, int start, int num, double noise, double result[])
{
std::srand(std::time(0));
for (int i = 0; i < num;i++)
{
double noise1 = noise * rand() / 32768;
if (((i + start) / (T / 2)) % 2 == 0)
result[i] = noise1;
else
result[i] = amplitude + noise1;
}
}
5)编译
菜单栏->生成->重新生成解决方案
看输出窗口中显示生成成功
去项目文件的Debug文件夹中可以看到CppDllTest.dll文件,将其拷贝在Labview文件夹中。
1.2 调用DLL
1)新建一个项目UseCppDll_example
将CppDllTest.dll文件拷贝到UseCppDll_example\bin\x86\Debug文件夹下。
同时在VS的配置管理器中将编译平台选择成x86(因为dll文件是32位的)。
在Form1中添加一个Chart控件(chart1),一个ComboBox控件(combobox1)。
2)编写代码
导入函数部分代码
using System.Runtime.InteropServices;
[DllImport("CppDllTest.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);
[DllImport("CppDllTest.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SinSignal(double amplitude, int T, double phase, int num, double noise, double[] result);
[DllImport("CppDllTest.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void PulseSignal(double amplitude, int T, int start, int num, double noise, double[] result);
整体程序
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Windows.Forms.DataVisualization.Charting;
namespace UseCppDll_example
{
public partial class Form1 : Form
{
[DllImport("CppDllTest.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);
[DllImport("CppDllTest.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SinSignal(double amplitude, int T, double phase, int num, double noise, double[] result);
[DllImport("CppDllTest.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void PulseSignal(double amplitude, int T, int start, int num, double noise, double[] result);
public Form1()
{
InitializeComponent();
Chartinit();
comboBox1.Items.AddRange(new string[] { "正弦信号", "脉冲信号" });
comboBox1.SelectedIndex = 0;
comboBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 10,FontStyle.Bold);
times = 0;
Timer timer1 = new Timer();
timer1.Interval = 20;
timer1.Tick += timer1_Tick;
timer1.Start();
}
void Chartinit()
{
#region chart1
chart1.Titles.Add("波形图");
chart1.Titles[0].Font = new Font("Arial", 12, FontStyle.Bold);
chart1.Series.Clear();
//chart1.ChartAreas.Clear();
//chart1.Legends.Clear();
//chart1.BackColor = Color.Transparent;
chart1.ChartAreas[0].BackColor = Color.Transparent;
chart1.ChartAreas[0].Position = new ElementPosition(0, 8, 99, 90);
//chart1.ChartAreas[0].AxisX.MajorGrid.Interval = 1;
//chart1.ChartAreas[0].AxisY.MajorGrid.Interval = 1;
//chart1.ChartAreas[0].AxisX.MajorGrid.LineDashStyle = ChartDashStyle.NotSet;
chart1.ChartAreas[0].AxisX.MajorGrid.LineDashStyle = ChartDashStyle.Dash;
chart1.ChartAreas[0].AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dash;
chart1.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.LightGray;
chart1.ChartAreas[0].AxisX.MajorGrid.LineColor = Color.LightGray;
chart1.ChartAreas[0].AxisX.LineWidth = 2;
chart1.ChartAreas[0].AxisY.LineWidth = 2;
chart1.Legends[0].BackColor = Color.Transparent;
//chart1.Legends[0].Position = new ElementPosition(chart1.ChartAreas[0].Position.Width+ 1, 10, 23, 23);
Series series = new Series();
series.ChartType = SeriesChartType.Line; // 设置为折线图
series.Name = "Data1";
chart1.Series.Add(series);
#endregion
}
private double times;
void timer1_Tick(object sender, EventArgs e)
{
double[] result = new double[500];
if (comboBox1.SelectedItem.ToString() == "正弦信号")
SinSignal(2, 500, times, 500, 0.1, result);
if (comboBox1.SelectedItem.ToString() == "脉冲信号")
PulseSignal(2, 100, (int)times, 500, 0.1, result);
chart1.Series["Data1"].Points.Clear();//清空点
foreach (var value1 in result)
chart1.Series["Data1"].Points.AddY(value1);//添加单个点
times++;
}
}
}