.net 调用 非托管C++的类

icemelody5316 2014-08-09 11:09:28
背景:安装了一个开发包,通过开发包中的SaperaBasic类(很多类的统称)可以用C++或.net开发控制它们公司硬件的软件,SaperaBasic类包含两种类库:.net调用的和C++调用的(非托管),我需要使用.net开发(CLR,即C++.net),我选择的硬件是由一个叫SaperaRTPro类控制的,它是继承自SaperaBasic中的一两个类生成的,
问题来了:因为我选的硬件不具有代表性,所以这个公司只提供了SaperaRTPro的C++类库(.h文件和DLL文件),我怎么在.net环境下,调用这个库?
注:SaperaRTPro只提供了.h和SYSTEM32下安装的一些DLL,它的实现应该就是在这个DLL中,但这个DLL不是托管集,所以我在.net中不能通过引用直接调用。


我会DLLIMPORT这种引用,但是我想调用整个类,不仅仅是用它的函数,这个局,怎么破?
...全文
1018 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
yinshi2006 2014-08-14
  • 打赏
  • 举报
回复
不需要得到dll源码。 像普通c++程序使用dll就行。 我再其他帖子里的回帖============================ 新建工程》visual c++》CLR》类库,语法什么的自己琢磨吧,基于C++扩展了c#里的概念,比如多了gcnew(对应C#里的new,clr里的new还是c的new)和%(用在变量声明,对应C#里的引用)等。 ============================================= 封装出的类库,和用c#写的类库一样使用 因为clr的语法说明中文的不多,熟悉一下需要4、5天。如果你英文不错,绝对可以更快。 我十分推荐这样做,用它封装过sqlite,这样除了dll,稳定性和可靠性尽在掌握。
icemelody5316 2014-08-14
  • 打赏
  • 举报
回复
引用 8 楼 yinshi2006 的回复:
1、分析一下是不是一定需要这个类,能不用就不用了。 2、你这个需求我认为,用clr把非托管的dll封装为.net的类库是最好的。
你说的方法确实是比较靠谱的,把非托管的DLL封装为.net程序集,但是怎么封装啊?我没有这个DLL的源码
yinshi2006 2014-08-12
  • 打赏
  • 举报
回复
1、分析一下是不是一定需要这个类,能不用就不用了。 2、你这个需求我认为,用clr把非托管的dll封装为.net的类库是最好的。
Saleayas 2014-08-11
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AShura.CSForC
{
	class Program
	{
		static void Main(string[] args)
		{
			var v = new CSForC(123456789);
			v.Print("CSMessage ");
			int value = v.GetValue();
			System.Diagnostics.Debug.WriteLine(string.Format("GetValue() = {0}", value));

			int staticValue = NativeImport.nCForCS;
			System.Diagnostics.Debug.WriteLine(string.Format("StaticValue = {0}", staticValue));
			NativeImport.nCForCS = 987654321;
			staticValue = NativeImport.nCForCS;
			System.Diagnostics.Debug.WriteLine(string.Format("StaticValue = {0}", staticValue));

			string stringValue = v.GetString(1);
			System.Diagnostics.Debug.WriteLine(string.Format("StringValue() = {0}", stringValue));
			stringValue = v.GetString(2);
			System.Diagnostics.Debug.WriteLine(string.Format("StringValue() = {0}", stringValue));

			int memberValue = v.MemberValue;
			System.Diagnostics.Debug.WriteLine(string.Format("MemberValue = {0}", memberValue));
			v.MemberValue = 111111111;
			memberValue = v.MemberValue;
			System.Diagnostics.Debug.WriteLine(string.Format("MemberValue = {0}", memberValue));

			byte[][] data = v.Data;
			for (int i = 0; i < data.Length; ++i)
			{
				if (data[i] != null)
				{
					for (int j = 0; j < data[i].Length; ++j)
					{
						System.Diagnostics.Debug.Write(string.Format("{0}, ", data[i][j]));
					}
					System.Diagnostics.Debug.WriteLine("");
				}
			}

			((IDisposable)v).Dispose();
		}
	}
}
Saleayas 2014-08-11
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Runtime.InteropServices;

namespace AShura.CSForC
{
	static class NativeImport
	{
		class DllImportedField
		{
			[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
			private static extern IntPtr LoadLibrary([In] string lpFileName);
			[DllImport("Kernel32.dll")]
			private static extern void FreeLibrary([In] IntPtr hModule);
			[DllImport("Kernel32.dll", CharSet = CharSet.Ansi)]
			private static extern IntPtr GetProcAddress([In] IntPtr hModule, [In] string lpProcName);

			private IntPtr hModule;
			private IntPtr ptrAddress;
			public DllImportedField(string dllname, string fieldname)
			{
				hModule = LoadLibrary(dllname);
				ptrAddress = GetProcAddress(hModule, fieldname);
			}

			public void Dispose()
			{
				Dispose(true);
				GC.SuppressFinalize(this);
			}

			private bool disposed = false;
			protected virtual void Dispose(bool disposing)
			{
				if (!this.disposed)
				{
					if (hModule != IntPtr.Zero)
					{
						FreeLibrary(hModule);
					}
					disposed = true;
				}
			}

			~DllImportedField()
			{
				Dispose(false);
			}

			public T GetValue<T>()
			{
				return (T)Marshal.PtrToStructure(ptrAddress, typeof(T));
			}
			public void SetValue<T>(T value)
			{
				Marshal.StructureToPtr(value, ptrAddress, false);
			}
		}
		private static DllImportedField _nCForCS = new DllImportedField("..\\..\\..\\Debug\\CForCS.dll", "?nCForCS@@3HA");
		public static int nCForCS
		{
			get
			{
				return _nCForCS.GetValue<int>();
			}
			set
			{
				_nCForCS.SetValue(value);
			}
		}
	}

	class CVTable : IDisposable
	{
		IntPtr _vtable;
		public CVTable(params Delegate[] methods)
		{
			_vtable = Marshal.AllocHGlobal(methods.Length * Marshal.SizeOf(typeof(IntPtr)));
			for (int i = 0; i < methods.Length; ++i)
			{
				Marshal.WriteIntPtr(_vtable, i * Marshal.SizeOf(typeof(IntPtr)), Marshal.GetFunctionPointerForDelegate(methods[i]));
			}
		}
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		private bool disposed = false;
		protected virtual void Dispose(bool disposing)
		{
			if (!this.disposed)
			{
				if (_vtable != IntPtr.Zero)
				{
					Marshal.FreeHGlobal(_vtable);
					_vtable = IntPtr.Zero;
				}
				disposed = true;
			}
		}

		~CVTable()
		{
			Dispose(false);
		}

		public IntPtr CreateVTable(Object @this, IntPtr ptrThis, int index, int offsetOfThis)
		{
			IntPtr old = Marshal.ReadIntPtr(ptrThis, index * Marshal.SizeOf(typeof(IntPtr)));
			Marshal.WriteIntPtr(ptrThis, index * Marshal.SizeOf(typeof(IntPtr)), _vtable);
			Marshal.WriteIntPtr(ptrThis, offsetOfThis, GCHandle.ToIntPtr(GCHandle.Alloc(@this)));
			return old;
		}
		public void ReleaseVTable(IntPtr ptrThis, int index, int offsetOfThis, IntPtr vtable)
		{
			if (ptrThis != IntPtr.Zero)
			{
				GCHandle.FromIntPtr(Marshal.ReadIntPtr(ptrThis, offsetOfThis)).Free();
				Marshal.WriteIntPtr(ptrThis, index * Marshal.SizeOf(typeof(IntPtr)), vtable);
			}
		}
		public Object GetThisObject(IntPtr ptrThis, int offsetOfThis)
		{
			return GCHandle.FromIntPtr(Marshal.ReadIntPtr(ptrThis, offsetOfThis)).Target;
		}
	}

	[StructLayout(LayoutKind.Sequential)]
	public struct _CForCS
	{
		private IntPtr _vtable;
		public int _MemberValue;
		private int _nValue;
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct _READ_DATA
	{
		public int Length;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
		public byte[] Data;
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct _READ_DATA_ARRAY
	{
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
		public _READ_DATA[] Data;
	}

	public class CForCS : IDisposable
	{
		private const string dllname = "..\\..\\..\\Debug\\CForCS.dll";

		private static int _BaseClassSize = Marshal.SizeOf(typeof(_CForCS));
		private IntPtr _basecpp;
		private IntPtr _basecppvtable;
		private static CVTable _vtable = new CVTable(
					new _VFunctionBeforeHandler(_VFunctionBefore_),
					new _VFunctionAfterHandler(_VFunctionAfter_)
			);
		[DllImport(dllname, EntryPoint = "??0CCForCS@@QAE@XZ", CallingConvention = CallingConvention.ThisCall)]
		private static extern void _Constructor([In] IntPtr @this);
		public CForCS()
		{
			_basecpp = Marshal.AllocCoTaskMem(_BaseClassSize + Marshal.SizeOf(typeof(IntPtr)));
			_Constructor(_basecpp);
			_basecppvtable = _vtable.CreateVTable(this, _basecpp, 0, _BaseClassSize);
		}

		[DllImport(dllname, EntryPoint = "??0CCForCS@@QAE@H@Z", CallingConvention = CallingConvention.ThisCall)]
		private static extern void _Constructor([In] IntPtr @this, [In, MarshalAs(UnmanagedType.I4)] int value);
		public CForCS(int value)
		{
			_basecpp = Marshal.AllocCoTaskMem(_BaseClassSize + Marshal.SizeOf(typeof(IntPtr)));
			_Constructor(_basecpp, value);
			_vtable.CreateVTable(this, _basecpp, 0, _BaseClassSize);
		}

		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		private bool disposed = false;
		[DllImport(dllname, EntryPoint = "??1CCForCS@@QAE@XZ", CallingConvention = CallingConvention.ThisCall)]
		private static extern void _Destructor([In] IntPtr @this);
		protected virtual void Dispose(bool disposing)
		{
			if (!this.disposed)
			{
				if (_basecpp != IntPtr.Zero)
				{
					_vtable.ReleaseVTable(_basecpp, 0, _BaseClassSize, _basecppvtable);
					_Destructor(_basecpp);
					Marshal.FreeCoTaskMem(_basecpp);
					_basecpp = IntPtr.Zero;
				}
				disposed = true;
			}
		}

		~CForCS()
		{
			Dispose(false);
		}

		[DllImport(dllname, EntryPoint = "?Print@CCForCS@@QAEXPB_W@Z", CallingConvention = CallingConvention.ThisCall)]
		private static extern void _Print([In] IntPtr @this, [In, MarshalAs(UnmanagedType.LPWStr)]string message);
		public void Print(string message)
		{
			_Print(_basecpp, message);
		}
		[DllImport(dllname, EntryPoint = "?GetValue@CCForCS@@QAEHXZ", CallingConvention = CallingConvention.ThisCall)]
		[return: MarshalAs(UnmanagedType.I4)]
		private static extern int _GetValue([In] IntPtr @this);
		public int GetValue()
		{
			return _GetValue(_basecpp);
		}

		public int MemberValue
		{
			get
			{
				return Marshal.ReadInt32(_basecpp, (int)Marshal.OffsetOf(typeof(_CForCS), "_MemberValue"));
			}
			set
			{
				Marshal.WriteInt32(_basecpp, (int)Marshal.OffsetOf(typeof(_CForCS), "_MemberValue"), value);
			}
		}

		[DllImport(dllname, EntryPoint = "?GetBSTR@CCForCS@@QAEPA_WH@Z", CallingConvention = CallingConvention.ThisCall)]
		[return: MarshalAs(UnmanagedType.BStr)]
		private static extern string _GetGetBSTR([In] IntPtr @this, [In, MarshalAs(UnmanagedType.I4)] int index);

		public string GetString(int index)
		{
			return _GetGetBSTR(_basecpp, index);
		}

		[DllImport(dllname, EntryPoint = "?ReadData@CCForCS@@QAEHPAX@Z", CallingConvention = CallingConvention.ThisCall)]
		[return: MarshalAs(UnmanagedType.Bool)]
		private static extern bool _ReadData([In] IntPtr @this, [In] IntPtr data);
		public byte[][] Data
		{
			get
			{
				int Size = Marshal.SizeOf(typeof(_READ_DATA));
				IntPtr ptrData = Marshal.AllocHGlobal(3 * Size);
				if (_ReadData(_basecpp, ptrData))
				{
					byte[][] d = new byte[3][];
					for (int i = 0; i < d.Length; ++i)
					{
						var data = (_READ_DATA)Marshal.PtrToStructure(ptrData + i * Size, typeof(_READ_DATA));
						d[i] = new byte[data.Length];
						Array.Copy(data.Data, d[i], d[i].Length);
					}
					return d;
				}
				throw new Exception();
			}
		}


		[DllImport(dllname, EntryPoint = "?VFunctionBefore@CCForCS@@MAEHPB_WPAH@Z", CallingConvention = CallingConvention.ThisCall)]
		[return: MarshalAs(UnmanagedType.I4)]
		private static extern int _VFunctionBefore([In] IntPtr @this, [In, MarshalAs(UnmanagedType.LPWStr)]string message, [Out, MarshalAs(UnmanagedType.I4)] out int value);
		[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
		private delegate int _VFunctionBeforeHandler([In] IntPtr @this, [In, MarshalAs(UnmanagedType.LPWStr)]string message, [Out, MarshalAs(UnmanagedType.I4)]out int value);
		private static int _VFunctionBefore_([In] IntPtr @this, string message, out int value)
		{
			return ((CForCS)_vtable.GetThisObject(@this, _BaseClassSize)).VFunctionBefore(message, out value);
		}
		protected virtual int VFunctionBefore(string message, out int value)
		{
			return _VFunctionBefore(_basecpp, message, out value);
		}
		[DllImport(dllname, EntryPoint = "?VFunctionAfter@CCForCS@@MAEXPB_WH@Z", CallingConvention = CallingConvention.ThisCall)]
		private static extern void _VFunctionAfter([In] IntPtr @this, [In, MarshalAs(UnmanagedType.LPWStr)]string message, [In, MarshalAs(UnmanagedType.I4)]int value);
		[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
		private delegate void _VFunctionAfterHandler([In] IntPtr @this, [In, MarshalAs(UnmanagedType.LPWStr)]string message, [In, MarshalAs(UnmanagedType.I4)]int value);
		private static void _VFunctionAfter_([In] IntPtr @this, string message, int value)
		{
			((CForCS)_vtable.GetThisObject(@this, _BaseClassSize)).VFunctionAfter(message, value);
		}
		protected virtual void VFunctionAfter(string message, int value)
		{
			_VFunctionAfter(_basecpp, message, value);
		}
	}

	
	class CSForC : CForCS
	{
		public CSForC()
		{
		}

		public CSForC(int value)
			: base(value)
		{
		}

		protected override int VFunctionBefore(string message, out int value)
		{
			int n = base.VFunctionBefore(message, out value);
			value = 100;
			return n;
		}

		protected override void VFunctionAfter(string message, int value)
		{
			System.Diagnostics.Debug.WriteLine(string.Format("{0}, {1}.", message, value));
		}
	}
}
Saleayas 2014-08-11
  • 打赏
  • 举报
回复
给你一个样例。
// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 CFORCS_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// CFORCS_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef CFORCS_EXPORTS
#define CFORCS_API __declspec(dllexport)
#else
#define CFORCS_API __declspec(dllimport)
#endif

struct READ_DATA
{
	int nLength;
	unsigned char btsData[256];
};

// 此类是从 AShura.CForCS.dll 导出的
class CFORCS_API CCForCS
{
public:
	CCForCS(void);
	CCForCS(int nValue);
	~CCForCS(void);
public:
	void Print(LPCWSTR pszMessage);
	int GetValue(void);
	BSTR GetBSTR(int nIndex);
	BOOL ReadData(void *pOut);
	int MemberValue;
protected:
	virtual int VFunctionBefore(LPCWSTR pszMessage, int *pnValue);
	virtual void VFunctionAfter(LPCWSTR pszMessage, int nValue);
private:
	int _nValue;
};

extern CFORCS_API int nCForCS;

CFORCS_API int fnCForCS(void);
// CForCS.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"

#include "CForCS.h"

// 这是导出变量的一个示例
CFORCS_API int nCForCS=0;

// 这是导出函数的一个示例。
CFORCS_API int fnCForCS(void)
{
	AUTOTRACEX;
	return 42;
}

// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 AShura.CForCS.h
CCForCS::CCForCS()
	: _nValue(0)
	, MemberValue(0)
{
	AUTOTRACEX;
}
CCForCS::~CCForCS()
{
	AUTOTRACEX;
}
CCForCS::CCForCS(int nValue)
	: _nValue(nValue)
	, MemberValue(nValue)
{
	AUTOTRACEX;
}

int CCForCS::GetValue(void)
{
	AUTOTRACEX;
	return _nValue + MemberValue;
}

BSTR CCForCS::GetBSTR(int nIndex)
{
	AUTOTRACEX;
	WCHAR szNumber[32];
	swprintf_s(szNumber, _countof(szNumber), L"BSTR index = %d.", nIndex);
	return SysAllocString(szNumber);
}

BOOL CCForCS::ReadData(void *p)
{
	AUTOTRACEX;
	READ_DATA rd[3];
	for (int i = 0; i < 3; ++i)
	{
		rd[i].nLength = (i + 1) * 10;
		for (int j = 0; j < rd[i].nLength; ++j)
		{
			rd[i].btsData[j] = j;
		}
	}
	memcpy_s(p, sizeof(rd), &rd, sizeof(rd));
	return TRUE;
}


void CCForCS::Print(LPCWSTR pszMessage)
{
	AUTOTRACEX;
	int nValue = 0x12345;
	int n = VFunctionBefore(pszMessage, &nValue);
	TR(L"message = %s, value = %d, CForCS = %d.", pszMessage, n, nValue);
	VFunctionAfter(pszMessage, nValue);
}

int CCForCS::VFunctionBefore(LPCWSTR pszMessage, int *pnValue)
{
	AUTOTRACEX;
	TR(L"Before: message = %s, value = %d, CForCS = %d.", pszMessage, _nValue, nCForCS);
	if (pnValue)
	{
		*pnValue = nCForCS;
	}
	return _nValue;
}
void CCForCS::VFunctionAfter(LPCWSTR pszMessage, int nValue)
{
	AUTOTRACEX;
	nCForCS = nValue;
	TR(L"After: message = %s, value = %d, CForCS = %d.", pszMessage, _nValue, nCForCS);
}
icemelody5316 2014-08-11
  • 打赏
  • 举报
回复
引用 3 楼 caozhy 的回复:
托管程序不能直接访问C++类。 用VC++.NET去访问,并且包装成.NET程序集。
请问怎么把整个类包装成.net程序集?
threenewbee 2014-08-09
  • 打赏
  • 举报
回复
托管程序不能直接访问C++类。 用VC++.NET去访问,并且包装成.NET程序集。
by_封爱 2014-08-09
  • 打赏
  • 举报
回复
非托管的 就用dllimport的方式而不是添加引用.. 另外调用类是什么概念? 最终不都是调用类里面的方法么?
qwertxp 2014-08-09
  • 打赏
  • 举报
回复
?你不使用vc开发么?添加dll依赖,引用头文件啊。

7,540

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 VC.NET
社区管理员
  • VC.NET社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧