C#调用C++写的dll
2022/7/27 1:25:01
本文主要是介绍C#调用C++写的dll,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
C#调用C++的DLL搜集整理的所有数据类型转换方式(转) 2011-04-01 13:49:13| 分类: C++,C#|举报|字号 订阅 //C++中的DLL函数原型为 //extern "C" __declspec(dllexport) bool 方法名一(const char* 变量名1, unsigned char* 变量名2) //extern "C" __declspec(dllexport) bool 方法名二(const unsigned char* 变量名1, char* 变量名2) //C#调用C++的DLL搜集整理的所有数据类型转换方式,可能会有重复或者多种方案,自己多测试 //c++:HANDLE(void *) ---- c#:System.IntPtr //c++:Byte(unsigned char) ---- c#:System.Byte //c++:SHORT(short) ---- c#:System.Int16 //c++:WORD(unsigned short) ---- c#:System.UInt16 //c++:INT(int) ---- c#:System.Int16 //c++:INT(int) ---- c#:System.Int32 //c++:UINT(unsigned int) ---- c#:System.UInt16 //c++:UINT(unsigned int) ---- c#:System.UInt32 //c++:LONG(long) ---- c#:System.Int32 //c++:ULONG(unsigned long) ---- c#:System.UInt32 //c++:DWORD(unsigned long) ---- c#:System.UInt32 //c++:DECIMAL ---- c#:System.Decimal //c++:BOOL(long) ---- c#:System.Boolean //c++:CHAR(char) ---- c#:System.Char //c++:LPSTR(char *) ---- c#:System.String //c++:LPWSTR(wchar_t *) ---- c#:System.String //c++:LPCSTR(const char *) ---- c#:System.String //c++:LPCWSTR(const wchar_t *) ---- c#:System.String //c++:PCAHR(char *) ---- c#:System.String //c++:BSTR ---- c#:System.String //c++:FLOAT(float) ---- c#:System.Single //c++:DOUBLE(double) ---- c#:System.Double //c++:VARIANT ---- c#:System.Object //c++:PBYTE(byte *) ---- c#:System.Byte[] //c++:BSTR ---- c#:StringBuilder //c++:LPCTSTR ---- c#:StringBuilder //c++:LPCTSTR ---- c#:string //c++:LPTSTR ---- c#:[MarshalAs(UnmanagedType.LPTStr)] string //c++:LPTSTR 输出变量名 ---- c#:StringBuilder 输出变量名 //c++:LPCWSTR ---- c#:IntPtr //c++:BOOL ---- c#:bool //c++:HMODULE ---- c#:IntPtr //c++:HINSTANCE ---- c#:IntPtr //c++:结构体 ---- c#:public struct 结构体{}; //c++:结构体 **变量名 ---- c#:out 变量名 //C#中提前申明一个结构体实例化后的变量名 //c++:结构体 &变量名 ---- c#:ref 结构体 变量名 //c++:WORD ---- c#:ushort //c++:DWORD ---- c#:uint //c++:DWORD ---- c#:int //c++:UCHAR ---- c#:int //c++:UCHAR ---- c#:byte //c++:UCHAR* ---- c#:string //c++:UCHAR* ---- c#:IntPtr //c++:GUID ---- c#:Guid //c++:Handle ---- c#:IntPtr //c++:HWND ---- c#:IntPtr //c++:DWORD ---- c#:int //c++:COLORREF ---- c#:uint //c++:unsigned char ---- c#:byte //c++:unsigned char * ---- c#:ref byte //c++:unsigned char * ---- c#:[MarshalAs(UnmanagedType.LPArray)] byte[] //c++:unsigned char * ---- c#:[MarshalAs(UnmanagedType.LPArray)] Intptr //c++:unsigned char & ---- c#:ref byte //c++:unsigned char 变量名 ---- c#:byte 变量名 //c++:unsigned short 变量名 ---- c#:ushort 变量名 //c++:unsigned int 变量名 ---- c#:uint 变量名 //c++:unsigned long 变量名 ---- c#:ulong 变量名 //c++:char 变量名 ---- c#:byte 变量名 //C++中一个字符用一个字节表示,C#中一个字符用两个字节表示 //c++:char 数组名[数组大小] ---- c#:MarshalAs(UnmanagedType.ByValTStr, SizeConst = 数组大小)] public string 数组名; ushort //c++:char * ---- c#:string //传入参数 //c++:char * ---- c#:StringBuilder//传出参数 //c++:char *变量名 ---- c#:ref string 变量名 //c++:char *输入变量名 ---- c#:string 输入变量名 //c++:char *输出变量名 ---- c#:[MarshalAs(UnmanagedType.LPStr)] StringBuilder 输出变量名 //c++:char ** ---- c#:string //c++:char **变量名 ---- c#:ref string 变量名 //c++:const char * ---- c#:string //c++:char[] ---- c#:string //c++:char 变量名[数组大小] ---- c#:[MarshalAs(UnmanagedType.ByValTStr,SizeConst=数组大小)] public string 变量名; //c++:struct 结构体名 *变量名 ---- c#:ref 结构体名 变量名 //c++:委托 变量名 ---- c#:委托 变量名 //c++:int ---- c#:int //c++:int ---- c#:ref int //c++:int & ---- c#:ref int //c++:int * ---- c#:ref int //C#中调用前需定义int 变量名 = 0; //c++:*int ---- c#:IntPtr //c++:int32 PIPTR * ---- c#:int32[] //c++:float PIPTR * ---- c#:float[] //c++:double** 数组名 ---- c#:ref double 数组名 //c++:double*[] 数组名 ---- c#:ref double 数组名 //c++:long ---- c#:int //c++:ulong ---- c#:int //c++:UINT8 * ---- c#:ref byte //C#中调用前需定义byte 变量名 = new byte(); //c++:handle ---- c#:IntPtr //c++:hwnd ---- c#:IntPtr //c++:void * ---- c#:IntPtr //c++:void * user_obj_param ---- c#:IntPtr user_obj_param //c++:void * 对象名称 ---- c#:([MarshalAs(UnmanagedType.AsAny)]Object 对象名称 //c++:char, INT8, SBYTE, CHAR ---- c#:System.SByte //c++:short, short int, INT16, SHORT ---- c#:System.Int16 //c++:int, long, long int, INT32, LONG32, BOOL , INT ---- c#:System.Int32 //c++:__int64, INT64, LONGLONG ---- c#:System.Int64 //c++:unsigned char, UINT8, UCHAR , BYTE ---- c#:System.Byte //c++:unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t ---- c#:System.UInt16 //c++:unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT ---- c#:System.UInt32 //c++:unsigned __int64, UINT64, DWORDLONG, ULONGLONG ---- c#:System.UInt64 //c++:float, FLOAT ---- c#:System.Single //c++:double, long double, DOUBLE ---- c#:System.Double //Win32 Types ---- CLR Type //Struct需要在C#里重新定义一个Struct //CallBack回调函数需要封装在一个委托里,delegate static extern int FunCallBack(string str); //unsigned char** ppImage替换成IntPtr ppImage //int& nWidth替换成ref int nWidth //int*, int&, 则都可用 ref int 对应 //双针指类型参数,可以用 ref IntPtr //函数指针使用c++: typedef double (*fun_type1)(double); 对应 c#:public delegate double fun_type1(double); //char* 的操作c++: char*; 对应 c#:StringBuilder; //c#中使用指针:在需要使用指针的地方 加 unsafe //unsigned char对应public byte /* * typedef void (*CALLBACKFUN1W)(wchar_t*, void* pArg); * typedef void (*CALLBACKFUN1A)(char*, void* pArg); * bool BIOPRINT_SENSOR_API dllFun1(CALLBACKFUN1 pCallbackFun1, void* pArg); * 调用方式为 * [UnmanagedFunctionPointer(CallingConvention.Cdecl)] * public delegate void CallbackFunc1([MarshalAs(UnmanagedType.LPWStr)] StringBuilder strName, IntPtr pArg); * * */ 方法有不少,这里记录其中的一个方法。编译、调用通过了的。期间遇到的问题是C#调用时传递string类型的参数和返回值会报错。TargetInvocationException异常,值不在范围内,内存不可访问等等。 解决方法是;在c++的DLL中将string类型的参数返回值改为LPTSTR类型。在C#程序中使用StringBuilder类型来传入参数和接受返回值。 下面是代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; //1. 打开项目“Tzb”,打开类视图,右击“Tzb”,选择“添加”-->“类”,类名设置为“dld”, //即dynamic loading dll 的每个单词的开头字母。 //2. 添加所需的命名空间及声明参数传递方式枚举: using System.Runtime.InteropServices; // 用 DllImport 需用此 命名空间 using System.Reflection; // 使用 Assembly 类需用此 命名空间 using System.Reflection.Emit; // 使用 ILGenerator 需用此 命名空间 namespace WpfApplication1 { //在“public class dld”上面添加如下代码声明参数传递方式枚举: /// /// 参数传递方式枚举 ,ByValue 表示值传递 ,ByRef 表示址传递 /// public enum ModePass { ByValue = 0x0001, ByRef = 0x0002 } public class DLD { //3. 声明LoadLibrary、GetProcAddress、FreeLibrary及私有变量hModule和farProc: /// /// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName); /// /// < param name="lpFileName" / >DLL 文件名 /// 函数库模块的句柄 [DllImport("kernel32.dll")] static extern IntPtr LoadLibrary(string lpFileName); /// /// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName); /// /// < param name="hModule" / > 包含需调用函数的函数库模块的句柄 /// < param name="lpProcName" / > 调用函数的名称 /// 函数指针 [DllImport("kernel32.dll")] static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); /// /// 原型是 : BOOL FreeLibrary(HMODULE hModule); /// /// < param name="hModule" / > 需释放的函数库模块的句柄 /// 是否已释放指定的 Dll [DllImport("kernel32", EntryPoint = "FreeLibrary", SetLastError = true)] static extern bool FreeLibrary(IntPtr hModule); /// /// Loadlibrary 返回的函数库模块的句柄 /// private IntPtr hModule = IntPtr.Zero; /// /// GetProcAddress 返回的函数指针 /// public IntPtr farProc = IntPtr.Zero; //4. 添加LoadDll方法,并为了调用时方便,重载了这个方法: /// /// 装载 Dll /// /// < param name="lpFileName" / >DLL 文件名 public void LoadDll(string lpFileName) { hModule = LoadLibrary(lpFileName); if (hModule == IntPtr.Zero) throw (new Exception(" 没有找到 :" + lpFileName + ".")); } // 若已有已装载Dll的句柄,可以使用LoadDll方法的第二个版本: public void LoadDll(IntPtr HMODULE) { if (HMODULE == IntPtr.Zero) throw (new Exception(" 所传入的函数库模块的句柄 HMODULE 为空 .")); hModule = HMODULE; } //5. 添加LoadFun方法,并为了调用时方便,也重载了这个方法,方法的具体代码及注释如下: /// /// 获得函数指针 /// /// < param name="lpProcName" / > 调用函数的名称 public void LoadFun(string lpProcName) { // 若函数库模块的句柄为空,则抛出异常 if (hModule == IntPtr.Zero) throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !")); // 取得函数指针 farProc = GetProcAddress(hModule, lpProcName); // 若函数指针,则抛出异常 if (farProc == IntPtr.Zero) throw (new Exception(" 没有找到 : " + lpProcName + " 这个函数的入口点 ")); } /// /// 获得函数指针 /// /// < param name="lpFileName" / > 包含需调用函数的 DLL 文件名 /// < param name="lpProcName" / > 调用函数的名称 public void LoadFun(string lpFileName, string lpProcName) { // 取得函数库模块的句柄 hModule = LoadLibrary(lpFileName); // 若函数库模块的句柄为空,则抛出异常 if (hModule == IntPtr.Zero) throw (new Exception(" 没有找到 :" + lpFileName + ".")); // 取得函数指针 farProc = GetProcAddress(hModule, lpProcName); // 若函数指针,则抛出异常 if (farProc == IntPtr.Zero) throw (new Exception(" 没有找到 :" + lpProcName + " 这个函数的入口点 ")); } //6. 添加UnLoadDll及Invoke方法,Invoke方法也进行了重载: /// /// 卸载 Dll /// public void UnLoadDll() { FreeLibrary(hModule); hModule = IntPtr.Zero; farProc = IntPtr.Zero; } /// /// 调用所设定的函数 /// /// < param name="ObjArray_Parameter" / > 实参 /// < param name="TypeArray_ParameterType" / > 实参类型 /// < param name="ModePassArray_Parameter" / > 实参传送方式 /// < param name="Type_Return" / > 返回类型 /// 返回所调用函数的 object public object Invoke(object[] ObjArray_Parameter, Type[] TypeArray_ParameterType, ModePass[] ModePassArray_Parameter, Type Type_Return) { // 下面 3 个 if 是进行安全检查 , 若不能通过 , 则抛出异常 if (hModule == IntPtr.Zero) throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !")); if (farProc == IntPtr.Zero) throw (new Exception(" 函数指针为空 , 请确保已进行 LoadFun 操作 !")); if (ObjArray_Parameter.Length != ModePassArray_Parameter.Length) throw (new Exception(" 参数个数及其传递方式的个数不匹配 .")); // 下面是创建 MyAssemblyName 对象并设置其 Name 属性 AssemblyName MyAssemblyName = new AssemblyName(); MyAssemblyName.Name = "InvokeFun"; // 生成单模块配件 AssemblyBuilder MyAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( MyAssemblyName, AssemblyBuilderAccess.Run); ModuleBuilder MyModuleBuilder = MyAssemblyBuilder.DefineDynamicModule("InvokeDll"); // 定义要调用的方法 , 方法名为“ MyFun ”,返回类型是“ Type_Return ” //参数类型是“ TypeArray_ParameterType ” MethodBuilder MyMethodBuilder = MyModuleBuilder.DefineGlobalMethod( "Init", MethodAttributes.Public | MethodAttributes.Static, Type_Return, TypeArray_ParameterType); // 获取一个 ILGenerator ,用于发送所需的 IL ILGenerator IL = MyMethodBuilder.GetILGenerator(); int i; for (i = 0; i < ObjArray_Parameter.Length; i++) {// 用循环将参数依次压入堆栈 switch (ModePassArray_Parameter[i]) { case ModePass.ByValue: IL.Emit(OpCodes.Ldarg, i); break; case ModePass.ByRef: IL.Emit(OpCodes.Ldarga, i); break; default: throw (new Exception(" 第 " + (i + 1).ToString() + " 个参数没有给定正确的传递方式 .")); } } if (IntPtr.Size == 4) {// 判断处理器类型 IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32()); } else if (IntPtr.Size == 8 ) { IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64()); } else { throw new PlatformNotSupportedException(); } IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, Type_Return, TypeArray_ParameterType); IL.Emit(OpCodes.Ret); // 返回值 MyModuleBuilder.CreateGlobalFunctions(); // 取得方法信息 MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("Init"); return MyMethodInfo.Invoke(null, ObjArray_Parameter);// 调用方法,并返回其值 } //Invoke方法的第二个版本,它是调用了第一个版本的: /// /// 调用所设定的函数 /// /// < param name="IntPtr_Function" / > 函数指针 /// < param name="ObjArray_Parameter" / > 实参 /// < param name="TypeArray_ParameterType" / > 实参类型 /// < param name="ModePassArray_Parameter" / > 实参传送方式 /// < param name="Type_Return" / > 返回类型 /// 返回所调用函数的 object public object Invoke(IntPtr IntPtr_Function, object[] ObjArray_Parameter, Type[] TypeArray_ParameterType, ModePass[] ModePassArray_Parameter, Type Type_Return) { // 下面 2 个 if 是进行安全检查 , 若不能通过 , 则抛出异常 if (hModule == IntPtr.Zero) throw (new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !")); if (IntPtr_Function == IntPtr.Zero) throw (new Exception(" 函数指针 IntPtr_Function 为空 !")); farProc = IntPtr_Function; return Invoke(ObjArray_Parameter, TypeArray_ParameterType, ModePassArray_Parameter, Type_Return); } } } /*******调用方法******/ private void button1_Click(object sender, RoutedEventArgs e) { DLD newDLL = new DLD(); newDLL.LoadFun("E:\\workspaces\\WpfApplication1\\Debug\\DLL.dll", "Init"); StringBuilder MyStringBuilder = new StringBuilder("Hello World!"); object[] obj = new object[] { MyStringBuilder }; Type[] ty = new Type[] { typeof(StringBuilder) }; ModePass[] mode = new ModePass[] { ModePass.ByValue }; Type Type_Return = typeof(StringBuilder); StringBuilder j = (StringBuilder)newDLL.Invoke(obj, ty, mode, Type_Return); } /********c++DLL中的函数*******/ extern "C" __declspec(dllexport) LPTSTR Init(LPTSTR a); LPTSTR Init(LPTSTR a) { strcat((char *)a, "added"); return a; } c#如何调用c++的类 (2009-07-14 03:30:16) 转载▼标签: 杂谈 | 分类: 编程技术 |
- //Mask类头文件mask.h
- #pragma once
- extern "C" class _declspec(dllexport) Mask
- {
- public:
- Mask(char* inputFile,int* maskValue,int maskLength);
- virtual void Run(void);
- ~Mask(void);
- private:
- char* _inputFile;
- int* _maskValue;
- int _maskLength;
- };
- //Mask类实现文件mask.cpp
- Mask::Mask(char* inputFile ,int* maskValue,int maskLength)
- {
- _inputFile=new char[strlen(inputFile)+1];
- strcpy(_inputFile,inputFile);
- _maskValue=new int[maskLength];
- _maskLength=maskLength;
- for(int i=0;i<masklength;i++) < span="">
- _maskValue[i]=maskValue[i];
- }
- void Mask::Run(void)
- {
- }
- Mask::~Mask(void)
- {
- if (_inputFile)
- {
- delete [] _inputFile;
- _inputFile=NULL;
- }
- if (_maskValue)
- {
- delete [] _maskValue;
- _maskValue=NULL;
- }
- }
- //MaskCLR类头文件,用来包装Mask类MaskCLR.h
- #pragma once
- #include " mask.h" //这个就是上面的Mask头文件
- public ref class MaskCLR
- {
- private:
- char* _inputFile;
- int* _maskValue;
- int _maskLength;
- public:
- MaskCLR(String ^ inputFile,int* maskValue,int maskLength);
- virtual void Run(void) override;
- };
- // MaskCLR类内部实现MaskCLR.cpp
- #include "MaskCLR.h"
- MaskCLR::MaskCLR(String ^ inputFile,int* maskValue,int maskLength)
- {
- _inputFile=GlobeFunction::StringToChar(inputFile);
- _maskValue=maskValue;
- _maskLength=maskLength;
- }
- void MaskCLR:: Run(void)
- {
- Mask mask(_inputFile, _maskValue,_maskLength);
- mask.Run();
- }
- char* GlobeFunction::StringToChar(String ^str)
- {
- return (char*)(Marshal::StringToHGlobalAnsi(str)).ToPointer();
- }
- //c#调用托管dll中的MaskCLR类form1.cs
- unsafe
- {
- int* value = stackalloc int[1];
- value[0] = 0;
- MaskCLR mask = new MaskCLR("D:\\临时\\mask8.tif", value, 1);
- mask.Run();
- }
这篇关于C#调用C++写的dll的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-03-01沐雪多租宝商城源码从.NetCore3.1升级到.Net6的步骤
- 2024-12-06使用Microsoft.Extensions.AI在.NET中生成嵌入向量
- 2024-11-18微软研究:RAG系统的四个层次提升理解与回答能力
- 2024-11-15C#中怎么从PEM格式的证书中提取公钥?-icode9专业技术文章分享
- 2024-11-14云架构设计——如何用diagrams.net绘制专业的AWS架构图?
- 2024-05-08首个适配Visual Studio平台的国产智能编程助手CodeGeeX正式上线!C#程序员必备效率神器!
- 2024-03-30C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
- 2024-03-29c# datetime tryparse
- 2024-02-21list find index c#
- 2024-01-24convert toint32 c#