C#调用C++写的Dll的问题,尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

仙剑 2012-01-17 03:49:47
DLL中有回调函数,还有结构体

DLL中结构体,回调函数和函数的原型如下:

typedef struct _VOCLINK_PARAM {
TCHAR sVocIp[16];
UINT nPort;
} VOCLINK_PARAM, *PVOCLINK_PARAM;

typedef struct _VMCCB_EVT {
UINT EvtCode;
UINT RetCode;
UINT Channel;
UINT uBufferLen; // pBuffer 's length
void* pBuffer; // Buffer for holding extra info
} VMCCB_EVT, *PVMCCB_EVT;

typedef void (*VLVMC_CB)( long VocHandle, const PVMCCB_EVT pVmcEvt, LPARAM lpData );

_DLLIMP long CALL_CONVENT
VLVmcOpen( const VLVMC_CB pVmcCB, LPARAM lpData, long *pVmcHandle );

_DLLIMP long CALL_CONVENT
VLVmcConnectVoc( long VmcHandle, const PVOCLINK_PARAM pVocSrv, long *pVocHandle );

C#中对应类型定义如下:

public static class VMCOperator
{
/// Return Type: int
///pVmcCB: VLVMC_CB
///lpData: LPARAM->LONG_PTR->int
///pVmcHandle: int*
[DllImportAttribute("VLVmc.dll", EntryPoint = "VLVmcOpen", CallingConvention = CallingConvention.StdCall)]
//public static extern int VLVmcOpen(VLVMC_CB pVmcCB, [MarshalAsAttribute(UnmanagedType.SysInt)] int lpData, ref int pVmcHandle);
public static extern int VLVmcOpen(VLVMC_CB pVmcCB, int lpData, ref int pVmcHandle);

/// Return Type: int
///VmcHandle: int
[DllImportAttribute("VLVmc.dll", EntryPoint = "VLVmcClose", CallingConvention = CallingConvention.StdCall)]
public static extern int VLVmcClose(int VmcHandle);

/// Return Type: int
///VmcHandle: int
///pVocSrv: PVOCLINK_PARAM->_VOCLINK_PARAM*
///pVocHandle: int*
[DllImportAttribute("VLVmc.dll", EntryPoint = "VLVmcConnectVoc", CallingConvention = CallingConvention.StdCall)]
public static extern int VLVmcConnectVoc(int VmcHandle, ref VOCLINK_PARAM pVocSrv, ref int pVocHandle);

/// Return Type: int
///VocHandle: int
[DllImportAttribute("VLVmc.dll", EntryPoint = "VLVmcDisconnectVoc", CallingConvention = CallingConvention.StdCall)]
public static extern int VLVmcDisconnectVoc(int VocHandle);

}
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
public struct VOCLINK_PARAM
{

/// TCHAR[16]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 16)]
public string sVocIp;
//public char* sVocIp;

/// UINT->unsigned int
public uint nPort;
}

[StructLayoutAttribute(LayoutKind.Sequential)]
public struct VMCCB_EVT
{

/// UINT->unsigned int
public uint EvtCode;

/// UINT->unsigned int
public uint RetCode;

/// UINT->unsigned int
public uint Channel;

/// UINT->unsigned int
public uint uBufferLen;

/// void*
public IntPtr pBuffer;
}

/// Return Type: void
///VocHandle: int
///pVmcEvt: PVMCCB_EVT->_VMCCB_EVT*
///lpData: LPARAM->LONG_PTR->int
//[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void VLVMC_CB(int VocHandle, ref VMCCB_EVT pVmcEvt, int lpData);

调用函数的代码:

private void btnOpenVMC_Click(object sender, RoutedEventArgs e)
{
vmc_handler = 0;
int lpdata = 0;

if (VMCOperator.VLVmcOpen(vmc_cb, lpdata, ref vmc_handler) == VLVMC_ERR_SUCCESS)
{
MessageBox.Show("VMC Opened");
voc_link_param.sVocIp = "192.168.4.44";
voc_link_param.nPort = 3000;
voc_handler = 0;
if (VMCOperator.VLVmcConnectVoc(vmc_handler,ref voc_link_param, ref voc_handler) == VLVMC_ERR_SUCCESS)
{
MessageBox.Show("Voice Connected");
}
}
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
vmc_cb = new VLVMC_CB(OnVLVMC_CB);
voc_link_param = new VOCLINK_PARAM();
vmccb_evt = new VMCCB_EVT();
}
private void OnVLVMC_CB(int voc_handler, ref VMCCB_EVT vmccb_evt, int lpdata)
{
MessageBox.Show(vmccb_evt.EvtCode.ToString());
}

在调用VLVmcConnectVoc函数时就报错:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
看了网上有人加上了委托的属性 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
可是这样做虽然不报错了,但结果不对,不知道是不是封送 sVocIp 出错造成的,请高手指点迷津。。。在线等,谢谢!
...全文
485 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
wenbin 2012-02-13
  • 打赏
  • 举报
回复
TChar不一定是对应byte
根据你的C++ DLL编译条件
若是使用了Unicode则TCHAR是WCHAR,双字节了
仙剑 2012-02-13
  • 打赏
  • 举报
回复
TChar类型应对应于C#中得byte数组类型

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
public struct VOCLINK_PARAM
{
/// TCHAR[16]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] sVocIp;

/// UINT->unsigned int
public uint nPort;
}

string类型与byte类型转换

string vocip = “192.168.4.44”;
byte[] bytevocip = new byte[16];
Encoding.Default.GetBytes(vocip).CopyTo(bytevocip, 0);
  • 打赏
  • 举报
回复
读取 了不安全的地址一般都是传到C++ DLL的指针访问越界或指向错误了,
C++里的数据类型和C#里的有驱动,比如根据编译格式不同,有的占一个字节有的占两个字节
仙剑 2012-02-13
  • 打赏
  • 举报
回复
但是有两个问题
1、我不知道在定义结构体时到底指定ANSI还是Unicode
2、传入一个IP,程序会报错,说是读取了不安全的地址
WAN 2012-02-13
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 wodegege10 的回复:]
TChar不一定是对应byte
根据你的C++ DLL编译条件
若是使用了Unicode则TCHAR是WCHAR,双字节了
[/Quote]
确实。
因此,一般不是使用CharSet.Auto,而是指定CharSet.ANSI或CharSet.Unicode
然后:
/// TCHAR[16]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public String sVocIp;

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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