在 C# 中加载 C++ DLL
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15707859/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Loading a C++ DLL in C#
提问by bkjames
I am trying to use a DLL that was writen in C++ but my application is in C#
我正在尝试使用用 C++ 编写的 DLL,但我的应用程序是用 C# 编写的
The DLL is from another company but they have supplied an SDK for their software.
DLL 来自另一家公司,但他们为他们的软件提供了 SDK。
They give an example of how to load their DLL in C++ but I need to adapt it to C#.
他们给出了如何在 C++ 中加载他们的 DLL 的示例,但我需要将其调整为 C#。
Below is their instructions of how to do it in C++
下面是他们在 C++ 中如何做到这一点的说明
MarkEzd.dll file is Dynamic Link Library.
MarkEzd.dll 文件是动态链接库。
MarkEzdDll.h is header file of the exports function in MarkEzd.dll
MarkEzdDll.h 是 MarkEzd.dll 中导出函数的头文件
The calling way of MarkEzd.dll is explicitly link. Developer needs to load and free MarkEzd.dll by calling Windows API function.
MarkEzd.dll 的调用方式是显式链接。开发者需要通过调用Windows API 函数来加载和释放MarkEzd.dll。
The steps are as follows.
步骤如下。
Call Windows' API function LoadLibrary() to load DLL dynamically;
Call Windows' API function GetProcAddrress() to get the pointer of the functions in the DLL and use the function pointer to finish the work;
Call Windows' API function FreeLibrary() to release library when you do not use DLL or the program ends.
调用Windows的API函数LoadLibrary()动态加载DLL;
调用Windows的API函数GetProcAddrress()获取DLL中函数的指针,并使用函数指针完成工作;
不使用DLL 或程序结束时,调用Windows 的API 函数FreeLibrary() 释放库。
Below is the example they have provided.
以下是他们提供的示例。
Step 2. Program software for calling markezd.dll. a) First step : Dynamic Load MarkEzd.dll
步骤 2. 调用 markezd.dll 的程序软件。a) 第一步:动态加载 MarkEzd.dll
HINSTANCE hEzdDLL = LoadLibrary(_T("MarkEzd.dll"));
b) Second step: get the pointer of the function to be called
b) 第二步:获取被调用函数的指针
lmc1_Initial=(LMC1_INITIAL)GetProcAddress(hEzdDLL, _T("lmc1_Initial"));
lmc1_Close=(LMC1_CLOSE)GetProcAddress(hEzdDLL, _T("lmc1_Close"));
lmc1_LoadEzdFile=(LMC1_LOADEZDFILE)GetProcAddress(hEzdDLL,_T("lmc1_LoadEzdFile"));
lmc1_Mark=(LMC1_MARK)GetProcAddress(hEzdDLL,_T("lmc1_Mark"));
c) Third step: Call the function
c) 第三步:调用函数
1) Initialization lmc1 board: lmc1_Initial()
.
2) Open test.ezd: lmc1_LoadEzdFile(_T(“test.ezd”))
.
3) Call lmc1_Mark() for machining: lmc1_Mark()
.
4) Close lmc1 board: lmc1_Close()
.
1)初始化LMC1板: lmc1_Initial()
。
2) 打开test.ezd: lmc1_LoadEzdFile(_T(“test.ezd”))
.
3) 调用lmc1_Mark()进行加工:lmc1_Mark()
.
4) 关闭 lmc1 板:lmc1_Close()
.
d) Fourth step, Release markezd.dll: FreeLibrary(hEzdDLL)
d) 第四步,释放markezd.dll: FreeLibrary(hEzdDLL)
Bellow is the descriptions of the commands.
下面是命令的说明。
lmc1_Initial
INTENTION: initialize lmc1 control board
DEFINITION: int lmc1_Initial(TCHAR* strEzCadPath, BOOL bTestMode, HWND hOwenWnd)
strEzCadPath: the full path where ezcad2.exe exists
bTestMode Whether in test mode or not
hOwenWnd: The window that has the focus. It is used to check the user's stop messages.
DESCRIPTION: you must first call lmc1?_Initial before other function in program.
RETURN VALUE: common error code
lmc1_Initial
INTENTION: 初始化lmc1 控制板
DEFINITION: int lmc1_Initial(TCHAR* strEzCadPath, BOOL bTestMode, HWND hOwenWnd)
strEzCadPath: ezcad2.exe 所在的完整路径
bTestMode 是否处于测试模式
hOwenWnd: 有焦点的窗口。它用于检查用户的停止消息。说明:必须先调用lmc1?_Initial,然后才能在程序中调用其他函数。
返回值:常见错误代码
lmc1_Close
INTENTION: Close lmc1 board
DEFINITION: int lmc1_Close();
DESCRIPTION: you must call lmc1_Close to close the lmc1 board when exit program.
RETURN VALUE: common error code
lmc1_Close 意图
:关闭 lmc1 板
定义:int lmc1_Close();
描述:退出程序时必须调用 lmc1_Close 来关闭 lmc1 板。
返回值:常见错误代码
lmc1_LoadEzdFile
INTENTION: open the appointed ezd file, and clear all the object in database.
DEFINITION: int lmc1_LoadEzdFile(TCHAR* strFileName);
DESCRIPTION: this function can open an ezd file that was build by user as a template. User need not set process parameters, because they will be loaded in from the template file.
RETURN VALUE: common error code
lmc1_LoadEzdFile 意图
:打开指定的ezd文件,清除数据库中的所有对象。
定义:int lmc1_LoadEzdFile(TCHAR* strFileName);
描述:这个函数可以打开一个由用户构建的作为模板的ezd文件。用户无需设置工艺参数,因为它们将从模板文件中加载。
返回值:常见错误代码
lmc1_Mark
INTENTION: mark all the data in database
DEFINITION: int lmc1_Mark(BOOL bFlyMark);
bFlyMark= TRUE // mark on fly
DISCRIPTION: Begin to mark by calling this function after loading ezd file using lmc1_LoadEzdFile. The function will not return back until marking complete.
RETURN VALUE: common error code
lmc1_Mark 意图
:标记数据库中的所有数据
DEFINITION: int lmc1_Mark(BOOL bFlyMark);
bFlyMark= TRUE // mark on fly
DISCRIPTION:在使用 lmc1_LoadEzdFile 加载 ezd 文件后调用此函数开始标记。该函数在标记完成之前不会返回。
返回值:常见错误代码
They also explain how to set up VS6.0
他们还解释了如何设置 VS6.0
- Choose “Microsoft Visual C++ 6.0” when install visual studio, and click “Change Option”.
- Choose “VC++ MFC and Template Libraries” and click “Change Option”.
- Choose “MS Foundation Class Libraries” and click “change option”.
- Choose the options as following picture, and click “OK”.
- Open the project, choose menu Project->Settings. Choose “C/C++”, add “UNICODE” and delete “MCBS” in “Preprocessor definitions”
- Choose “Link”, select “Output” in Category, and add “wWinMainCRTStartup” in “Entry-point symbol”
- Change all “char” to “TCHAR” in source code.
- Change all character string included by double quotation marks “…” to _T(“…”)
- Compile and link the project again.
- 安装visual studio时选择“Microsoft Visual C++ 6.0”,点击“Change Option”。
- 选择“VC++ MFC 和模板库”,然后单击“更改选项”。
- 选择“MS Foundation Class Libraries”并单击“更改选项”。
- 选择如下图所示的选项,点击“确定”。
- 打开项目,选择菜单项目->设置。选择“C/C++”,在“预处理器定义”中添加“UNICODE”并删除“MCBS”
- 选择“链接”,在类别中选择“输出”,在“入口点符号”中添加“wWinMainCRTStartup”
- 将源代码中的所有“char”更改为“TCHAR”。
- 将双引号“…”包含的所有字符串改为_T(“…”)
- 再次编译并链接项目。
most of the functions return an integer code of 0 for success.
大多数函数返回一个整数代码 0 表示成功。
Would this be correct?
这是正确的吗?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Start_Mark
{
public partial class Form1 : Form
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport("MarkEzd.dll")]
[return: MarshalAs(UnmanagedType.I2)]
public static extern int lmc1_Initial(string strEzCadPath, bool bTestMode, IntPtr hOwenWnd);
[DllImport("MarkEzd.dll")]
[return: MarshalAs(UnmanagedType.I2)]
public static extern int lmc1_Close();
[DllImport("MarkEzd.dll")]
[return: MarshalAs(UnmanagedType.I2)]
public static extern int lmc1_LoadEzdFile(string strFileName);
[DllImport("MarkEzd.dll")]
[return: MarshalAs(UnmanagedType.I2)]
public static extern int lmc1_Mark(bool bFlyMark);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IntPtr hEzdDLL = LoadLibrary("MarkEzd.dll");
IntPtr iplmc1_Initial = GetProcAddress(hEzdDLL, "lmc1_Initial");
IntPtr iplmc1_Close = GetProcAddress(hEzdDLL, "lmc1_Close");
IntPtr iplmc1_LoadEzdFile = GetProcAddress(hEzdDLL, "lmc1_LoadEzdFile");
IntPtr iplmc1_Mark = GetProcAddress(hEzdDLL, "lmc1_Mark");
int intlmc1_Initial=lmc1_Initial("c:\temp", false, hEzdDLL);
if (intlmc1_Initial > 0)
{
return;
}
int intlmc1_LoadEzdFile = lmc1_LoadEzdFile("c:\temp\test.ezd");
if (intlmc1_LoadEzdFile > 0)
{
return;
}
int intlmc1_Mark = lmc1_Mark(true);
if (intlmc1_Mark > 0)
{
return;
}
int intlmc1_Close = lmc1_Close();
if (intlmc1_Close > 0)
{
return;
}
FreeLibrary(hEzdDLL);
}
}
}
采纳答案by bkjames
The correct syntax is as follows.
正确的语法如下。
using System;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Company.Group
{
public class FuncList
{
[DllImport("MarkEzd.dll", EntryPoint = "lmc1_Initial2", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern int Initialize(string PathName, bool TestMode);
}
}
回答by MLeblanc
Use P-Invoke to call native DLL. You might have to marshall some datatype in order to make it work.
使用 P-Invoke 调用本机 DLL。您可能必须编组某些数据类型才能使其工作。