C#调用C++的函数出现了这个异常,记录之。
public delegate void VOIPREGSTATEPROC(IntPtr hReg, VOIPREG_STATE state, IntPtr msg);
public delegate void VOIPCALLSTATEPROC(IntPtr hCall, VOIPCALL_STATE state, IntPtr msg);
public delegate void VOIPAUTHREQPROC(IntPtr hAuth, VOIPAUTH_METHOD method);
public struct VOIPINITSTRUCT
{
public VOIPREGSTATEPROC pfnRegStateChange; // SIP注册状态回调
public VOIPCALLSTATEPROC pfnCallStateChange; // 通话状态回调
public VOIPAUTHREQPROC pfnAuthRequested; // 认证回调
public IntPtr pszRingFileDirPath; // 默认铃声目录路径(目录下需要有ring.wav和ringback.wav两个文件)
public IntPtr pszLicense; //授权码 6b240c1094a86518738c4bc76a22f609
}
[DllImport("./Voip/VoipDLL/MyVoIp.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int MVoipInitialize(IntPtr pvis);
起初的用法,是在程序窗体的load事件中初始化了一个局部结构体。
VOIPINITSTRUCT m_vis;
m_vis.pfnRegStateChange = VoipRegStateProc;
m_vis.pfnCallStateChange = VoipCallStateProc;
m_vis.pfnAuthRequested = VoipAuthReqProc;
m_vis.pszRingFileDirPath = IntPtr.Zero;
m_vis.pszLicense = IntPtr.Zero;
IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(m_vis));
Marshal.StructureToPtr<VOIPINITSTRUCT>(m_vis, intPtr, false);
VoIP.MVoipInitialize(intPtr);
这样使用,过一段时间就会出现“Invoke类型的已垃圾回收委托进行了回调”异常。
查阅了一下。
关于GC(.NET的垃圾回收)
分配在栈中的空间变量,一旦出了该变量的作用域就会被CLR立即回收;
C# 中的结构体是值类型,分配在栈中。如我上述用法,在窗体load方法执行结束,结构体分配的内存空间就被垃圾回收了,也就导致了异常了。
我的解决方案就是定义一个全局的静态变量(public static VOIPINITSTRUCT m_vis;)。如此,结构体分配的内存空间直到程序退出才会释放内存。