110,567
社区成员
发帖
与我相关
我的任务
分享
__thiscall
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
__stdcall
[UnmanagedFunctionPointer(CallingConvention.StdCall)] //或者删除这句,因为缺省就是 StdCall。
//而 C 语言的导出函数呼叫约定缺省也应该是 __stdcall 。
我是看你的代码里面没有 __stdcall 约定才明确写上的,在C/C++ 里面定义导出最好使用 __stdcall.
这样在 C# 里面就是缺省的呼叫约定了。
至于 IUnknown 不需要在 C# 里面导出,因为 C# 的 AddRef 和 Release 是由GC 决定的。
你需要自己处理,使用 IDisposed 接口。
至于 QI 在 C# 里面是不存在的,她对应于类型转换。
当你需要 QI 除 IUnknown 之外的接口,你都需要有对应的C# 接口,然后,就可以he 样例中 API 一样,QI 到指定的接口,然后转换为对应的 C# 的接口实例。
当你的接口继承 IUnknwon 时,需要注意 INativeCSForC2 接口布局,有三个 IUnknown 的接口方法委托在前面。
((Action)Marshal.GetDelegateForFunctionPointer((IntPtr)(**(int**)a), typeof(Action)))();
struct ICForCS2
{
virtual int Login(const char* user_name, const char* password, int login_type, LoginInfo *plogin_info, const char* end_point_url, const char* local_ip = NULL) = 0;
virtual int GetUdiskInfo2(s_udiskinfo *a, int max) = 0;
};
C++ 的获取接口的 API。
CFORCS_API void GetICForCS2(ICForCS2 **p);
C# 定义对应的接口
[StructLayout(LayoutKind.Sequential)]
struct INativeCSForC2
{
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int _LoginHandler(IntPtr @this, [In, MarshalAs(UnmanagedType.LPStr)] string user_name, [In, MarshalAs(UnmanagedType.LPStr)] string password, [In, MarshalAs(UnmanagedType.I4)]int login_type, [In, Out] ref LoginInfo plogin_info, [In, MarshalAs(UnmanagedType.LPStr)] string end_point_url, [In, MarshalAs(UnmanagedType.LPStr)] string local_ip);
public _LoginHandler Login;
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int _GetUdiskInfoHandler([In] IntPtr @this, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] s_udiskinfo[] info, int max);
public _GetUdiskInfoHandler GetUdiskInfo;
}
C# 定义这个接口。
interface ICSForC22
{
int Login([In, MarshalAs(UnmanagedType.LPStr)] string user_name, [In, MarshalAs(UnmanagedType.LPStr)] string password, [In, MarshalAs(UnmanagedType.I4)]int login_type, [In, Out] ref LoginInfo plogin_info, [In, MarshalAs(UnmanagedType.LPStr)] string end_point_url, [In, MarshalAs(UnmanagedType.LPStr)] string local_ip);
int GetUdiskInfo(s_udiskinfo[] info);
}
添加一个包装类。
class NativeCSForC2 : ICSForC22
{
public NativeVTable<INativeCSForC2> _native;
int ICSForC22.Login(string user_name, string password, int login_type, ref LoginInfo login_info, string end_point_url, string local_ip)
{
return _native._nativeInterface.Login(_native._ptrInterface, user_name, password, login_type, ref login_info, end_point_url, local_ip);
}
int ICSForC22.GetUdiskInfo(s_udiskinfo[] info)
{
return _native._nativeInterface.GetUdiskInfo(_native._ptrInterface, info, info.Length);
}
}
C# 定义 API 函数对应的方法。
[DllImport(....)]
private static extern void _GetICForCS2([Out] out IntPtr ptrInterface);
public static NativeCSForC2 GetICForCS2()
{
IntPtr ptrInterface;
_GetICForCS2(out ptrInterface);
return new NativeCSForC2
{
_native = new NativeVTable<INativeCSForC2>(ptrInterface),
};
}
如果使用很多的话,定义一个 模板包装
class NativeVTable< I > : IDisposable
{
public IntPtr _ptrInterface;
public I _nativeInterface;
private Action< IntPtr > _release = null;
public NativeVTable(IntPtr ptrInterface)
{
System.Diagnostics.Debug.Assert(ptrInterface != IntPtr.Zero);
_ptrInterface = ptrInterface;
_nativeInterface = (I)Marshal.PtrToStructure(Marshal.ReadIntPtr(ptrInterface, 0), typeof(I));
}
public NativeVTable(IntPtr ptrInterface, Action< IntPtr > release) : this(ptrInterface)
{
_release = release;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (_release != null)
{
_release(_ptrInterface);
}
disposed = true;
}
}
~NativeVTable()
{
Dispose(false);
}
}
最后使用:
var vv = (ICSForC22)NativeImport.GetICForCS2();