解决方案 »
- 怎么能将c# winform的Treeview控件的图片与checkbox位置换一下?
- 字典中一个key能对应2个或2个以上value吗?
- 如何用C#或者别的语言来检测硬件的型号?
- 如何通过选择A页面的下拉菜单实现B页面datagrid的显示和跳转?
- 如何查找并得到一個已運行的窗體實例?
- 关于remoting的宿主程序
- 求一个:两个时间之差的函数 ,帮忙写一下参数的意义,多谢各位大哥
- 获取传递给打印机的打印内容
- 问一个关于调用线程是如何传递参数的问题
- 我想下载用C#写的系统,哪里有得下载?
- InternetSetCookie 设置cookie后 访问js不发送
- 64位系统远程访问IIS部署的32位exe程序提示程序集不可用
class CNative
{
public:
int NativeFunction(int a) {}
}
C++/CLI
public ref class CNativeWrapper
{
private:
CNative *m_pNative;
public:
CNativeWrapper() { m_pNative = new CNative; }
int ManagedMethod(int a) { return m_pNative->NativeFunction(a); }
~CNativeWrapper() { delete m_pNative; }
protected:
!CNativeWrapper() { delete m_pNative; }
}
C#
class Program
{
int Main()
{
var nativeWrapper = new CNativeWrapper();
nativeWrapper.ManagedMethod();
return 0;
}
}
另外2楼说:“成员函数只不过包含一个隐型的this指针参数。你声明原型的时候加上,并且用cdelc方式调用即可。”我也去试试!
另外关于2楼,我发现只要我的成员函数定义中,没有操作数据成员的话(例如给某成员赋值),就可以在C#中被成功调用。也就是C++中那个隐含的this参数,自动被C#去掉了....C#这么智能啊。当然,如果此类成员函数中有对成员变量赋值的操作,那么自然会出错,因为C#中根本没有实例化过此C++类的实例。那么看来对于这种类成员函数,只能用托管C++封装了,PInvoke无能为力。剩下的问题就是:
①:2楼所说“成员函数只不过包含一个隐型的this指针参数。你声明原型的时候加上”,这事儿办不到....声明一个指向c++的某个类的指针,这怎么可能在C#中做到呢?C++中的struct倒可以在C#中重写个struct,再作为参数声明。C++中的class不可能在C#中重写啊........
②:网上某些人说C++导出函数必须声明为extern "c",我认为这是错误的,extern c只是告诉链接器“我这个函数在编译时是按C编译的”,编译后生成的目标文件中的函数符号是C编译器编译的结果。其实只是和C++编译器生成的函数符号不一样而已。不管按哪个编译,我们只要在PInvoke时正确将入口点指明为此函数符号即可。所以不管C编译器或C++编译器规则都无所谓,入口点指明正确,就能在链接时正确找到此函数位置。 对吧?
class CFORCS_API CCForCS
{
public:
CCForCS(void);
CCForCS(int nValue);
~CCForCS(void);
public:
void Print(LPCWSTR pszMessage);
int GetValue(void);
protected:
virtual int VFunctionBefore(LPCWSTR pszMessage, int *pnValue);
virtual void VFunctionAfter(LPCWSTR pszMessage, int nValue);
private:
int _nValue;
};
{
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(IntPtr @this)
{
IntPtr old = Marshal.ReadIntPtr(@this, 0 * Marshal.SizeOf(typeof(IntPtr)));
Marshal.WriteIntPtr(@this, 0 * Marshal.SizeOf(typeof(IntPtr)), _vtable);
return old;
}
public void ReleaseVTable(IntPtr @this, IntPtr vtable)
{
Marshal.WriteIntPtr(@this, 0 * Marshal.SizeOf(typeof(IntPtr)), vtable);
}
}
partial class CSForC : IDisposable
{
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
_Dispose();
disposed = true;
}
} ~CSForC()
{
Dispose(false);
}
} [StructLayout(LayoutKind.Sequential)]
public struct _CForCS
{
public IntPtr _vtable;
public int _nValue;
} partial class CSForC
{
private IntPtr _basecpp;
private const string dllname = "..\\..\\..\\Debug\\CForCS.dll";
[DllImport(dllname, EntryPoint = "??0CCForCS@@QAE@XZ", CallingConvention = CallingConvention.ThisCall)]
private static extern void _Constructor([In] IntPtr @this);
[DllImport(dllname, EntryPoint = "??0CCForCS@@QAE@H@Z", CallingConvention = CallingConvention.ThisCall)]
private static extern void _Constructor([In] IntPtr @this, [In, MarshalAs(UnmanagedType.I4)] int value);
[DllImport(dllname, EntryPoint = "??1CCForCS@@QAE@XZ", CallingConvention = CallingConvention.ThisCall)]
private static extern void _Destructor([In] IntPtr @this); [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);
[DllImport(dllname, EntryPoint = "?GetValue@CCForCS@@QAEHXZ", CallingConvention = CallingConvention.ThisCall)]
[return: MarshalAs(UnmanagedType.I4)]
private static extern int _GetValue([In] IntPtr @this); public CSForC()
{
_basecpp = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(_CForCS)));
_Constructor(_basecpp);
CreateVtable();
} public CSForC(int value)
{
_basecpp = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(_CForCS)));
_Constructor(_basecpp, value);
CreateVtable();
} private void _Dispose()
{
if (_basecpp != IntPtr.Zero)
{
ReleaseVtable();
_Destructor(_basecpp);
Marshal.FreeCoTaskMem(_basecpp);
_basecpp = IntPtr.Zero;
}
} public void Print(string message)
{
_Print(_basecpp, message);
}
public int GetValue()
{
return _GetValue(_basecpp);
} IntPtr _basecppvtable;
CVTable vtable;
private void CreateVtable()
{
vtable = new CVTable(new _VFunctionBeforeHandler(VFunctionBefore), new _VFunctionAfterHandler(VFunctionAfter));
_basecppvtable = vtable.CreateVTable(_basecpp);
}
private void ReleaseVtable()
{
if (_basecppvtable != IntPtr.Zero)
{
vtable.ReleaseVTable(_basecpp, _basecppvtable);
((IDisposable)vtable).Dispose();
}
} [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);
[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);
private delegate int _VFunctionBeforeHandler([In, MarshalAs(UnmanagedType.LPWStr)]string message, [Out, MarshalAs(UnmanagedType.I4)]out int value);
private delegate void _VFunctionAfterHandler([In, MarshalAs(UnmanagedType.LPWStr)]string message, [In, MarshalAs(UnmanagedType.I4)]int value);
protected virtual int VFunctionBefore(string message, out int value)
{
int n = _VFunctionBefore(_basecpp, message, out value);
value = 100;
return n;
}
protected virtual void VFunctionAfter(string message, int value)
{
System.Diagnostics.Debug.WriteLine(string.Format("{0}, {1}.", message, value));
}
}
class Program
{
static void Main(string[] args)
{
var v = new CSForC(123456789);
v.Print("CSMessage ");
System.Diagnostics.Debug.WriteLine(string.Format("GetValue() = {0}", v.GetValue())); ((IDisposable)v).Dispose();
}
}