我正在Windows CE 6上编写一个C#应用程序来监控3G调制解调器。该应用程序将调用C DLL中的函数来访问调制解调器。
在启动时,C#app将调用此函数来创建新连接:
[DllImport("swmodem.dll", CallingConvention = CallingConvention.Winapi)]
public static extern int CreateDataConnection(EVENT_CALLBACK callback);
EVENT_CALLBACK定义为:
public delegate void EVENT_CALLBACK(int e, IntPtr data);
还定义了数据结构:
[StructLayout(LayoutKind.Sequential)]
public struct ECIO_INFO
{
public UInt32 ecio1; /*!< Primary scramble code */
public UInt32 ecio2; /*!< Received signal code power */
public UInt32 ecio3; /*!< Energy per chip per power density */
}
在C DLL中,函数指针在CreateDataConnection()中传递,用于调制解调器状态更新。
int CreateDataConnection(EVENT_CALLBACK ecb)
{
.
.
fEventCallback = ecb;
// Create a connection
.
.
}
创建连接后,DLL将调用回调函数来更新调制解调器状态,例如EC / IO(接收到的导频能量的比率)。
基本上,当ECIO更改时,调用回调函数将ECIO数据传递给C#app:
在C DLL中:
void ProcessNotification(EVENT_CALLBACK fEventCallback)
{
ECIO_INFO ecio_info;
ecio_info.ecio1 = ecio_info.ecio2 = ecio_info.ecio3 = 0;
if(data.nNumOfCells>0)
ecio_info.ecio1 = data.arCellInfo[0].nEcIo;
if(data.nNumOfCells>1)
ecio_info.ecio2 = data.arCellInfo[1].nEcIo;
if(data.nNumOfCells>2)
ecio_info.ecio3 = data.arCellInfo[2].nEcIo;
if(data.nNumOfCells>0)
fEventCallback(ME_RSCP_ECIO, &ecio_info);
}
在C#app中,回调函数定义为:
private void ModemEventCallback(int e, IntPtr data)
{
.
.
Modem.ECIO_INFO new_reinfo = new Modem.ECIO_INFO();
new_reinfo = (Modem.ECIO_INFO)Marshal.PtrToStructure(
data, typeof(Modem.ECIO_INFO));
.
.
}
现在,问题来了。程序启动时,一切正常,连接创建正常,EC / IO正在更新。但运行几个小时后,EC / IO更新停止。经过测试,我发现在调用回调时它已停止:
fEventCallback(ME_RSCP_ECIO, &ecio_info);
我不知道这里出了什么问题可能在C#DLL中传递一个函数指针调用的方法不正确,或者代码中隐藏了一些错误?
答案 0 :(得分:3)
由于回调函数只是C / C ++的指针,因此必须将callback参数声明为IntPtr。创建EVENT_CALLBACK实例结束,确保它在程序运行时保持活动状态。使用Marshal.GetFunctionPointerForDelegate方法将delecate实例转换为IntPtr,并将生成的IntPtr传递给CreateDataConnection函数。
[DllImport("swmodem.dll", CallingConvention = CallingConvention.Winapi)] public static extern int CreateDataConnection(IntPtr callback); ... EVENT_CALLBACK c; c = new EVENT_CALLBACK( ... ); // keep this alive ! ... CreateDataConnection(Marshal.GetFunctionPointerForDelegate(c));
答案 1 :(得分:3)
试试这个
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void EVENT_CALLBACK(int e, IntPtr data);
它解决了我的问题。
答案 2 :(得分:1)
我认为你必须将GCHandl.Alloc与GCHandleType.Pinned一起使用,这样你就会告诉gc这个对象必须保留在内存中,即使 在引用此对象的应用程序中可能没有“根”,并且无法压缩此对象的内存