求教C#调用VC++6.0的dll在数据转化方面的问题

Li_Huiyi 2010-09-30 11:16:25
最近在使用视频服务器的SDK开发,要调用一个动态链接库内的函数,卡在了这样的一个结构上:

VC++定义:

typedef struct tagJBNV_SERVER_INFO
{
DWORD dwSize; //结构大小
DWORD dwServerFlag; //服务器类型
DWORD dwServerIp; //服务器IP(整数表示形式)
char szServerIp[16]; //服务器IP(字符串表示形式)
WORD wServerPort; //服务器端口
WORD wChannelNum; //通道数量
DWORD dwVersionNum; //版本
char szServerName[32]; //服务器名称
DWORD dwServerCPUType; //当前CPU类型
BYTE bServerSerial[48]; //服务器序列号,具有唯一标识功能
BYTE byMACAddr[6]; //服务器的物理地址
DWORD dwAlarmInCount; //告警输入个数
DWORD dwAlarmOutCount; //告警输出个数
DWORD dwSysFlags; //系统支持的功能
DWORD dwUserRight; //当前用户权限
DWORD dwNetPriviewRight; //网络观看权限
char csServerDes[64]; //服务器描述
}JBNV_SERVER_INFO,*PJBNV_SERVER_INFO;
//函数是:
DWORD WINAPI JBNV_GetServerInfo(HANDLE hServer,JBNV_SERVER_INFO *lpsi);


我在C#中是这样定义的:

/// <summary>
/// 服务器基本信息结构
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet= CharSet.Ansi)]
public struct JBNV_ServerInfo
{
public uint dwSize; // 结构大小
public uint dwServerFlag; // 服务器类型
public uint dwServerIp; // 服务器IP(整数表示形式)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public char[] szServerIp; // 服务器IP(字符串表示形式)
public UInt16 wServerPort; // 服务器端口
public UInt16 wChannelNum; // 通道数量
public uint dwVersionNum; // 版本
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] szServerName;
public uint dwServerCPUType; // 当前CPU类型
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 48)]
public byte[] bServerSerial;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 6)]
public byte[] byMACAddr;
uint dwAlarmInCount; // 告警输入个数
uint dwAlarmOutCount; // 告警输出个数
uint dwSysFlags; // 系统支持的功能
uint dwUserRight; // 当前用户权限
uint dwNetPriviewRight; // 网络观看权限
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
public char[] csServerDes;
}
/// <summary>
/// 获取视频服务器信息
/// </summary>
/// <param name="hServer">视频服务器句柄</param>
/// <param name="serverInfo">返回的视频服务器基本信息</param>
/// <returns>错误代码</returns>
[DllImport("JBNVSDK.dll", CharSet = CharSet.Ansi)]
public extern static JBNV_ErrorCode JBNV_GetServerInfo(IntPtr hServer, ref IntPtr serverInfo);
// 调用:
IntPtr serverInfo = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(JBNV_ServerInfo)));
re = JBNV_DLLFuction.JBNV_GetServerInfo(hServer, ref serverInfo);
JBNV_ServerInfo info = (JBNV_ServerInfo)Marshal.PtrToStructure(serverInfo, typeof(JBNV_ServerInfo));



请大家帮我看看这其中有什么问题么?调用的结构显示参数不正确。
在线等!

...全文
143 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
mjp1234airen4385 2010-09-30
  • 打赏
  • 举报
回复
实在不行,你就一个一个拷贝吧。
指针已经得到了,只要拷贝制定大小就行了。
int dwSize = ConvertInt(serverInfo);
dwServerFlag = ConvertInt(serverInfo);
兔子-顾问 2010-09-30
  • 打赏
  • 举报
回复
加一个字节对齐试试
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi,Pack=1)]
liuh6 2010-09-30
  • 打赏
  • 举报
回复
老生常谈的问题了..在社区中有N多的便子了!~
yinrongg 2010-09-30
  • 打赏
  • 举报
回复
DWORD 对应 C#的 long 吧
yinrongg 2010-09-30
  • 打赏
  • 举报
回复
又是沙发
Li_Huiyi 2010-09-30
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 jointan 的回复:]
C# code
public extern static Int32 JBNV_GetServerInfo(IntPtr hServer, /*ref*/ IntPtr serverInfo);


调用:


C# code
IntPtr serverInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(JBNV_ServerInfo……
[/Quote]

to :jointan
您的这个方法我试了,确实可以正确传入,但是可能是因为表示结构大小的字段没有赋值,所以传出来的结果有问题。我还不知道怎么给函数Marshal.AllocHGlobal分配的内存写入值,所以没有测试到底正不正确。我会留心以后会了再来测试一下的。

再次谢谢大家。
Li_Huiyi 2010-09-30
  • 打赏
  • 举报
回复
问题解决了,不是类型转换的问题,MSDN上写的那种方式是完全正确的。
我的问题出在了结构里有一个参数表征数据结构大小的字段,这个字段要赋值后才能传入,否则的话就会出现参数不正确的错误。这个也是看MSDN上的例子突然想起来的,在视频服务器的SDK说明上根本没有提要赋值才能传入,我没有这方面的编程经验,属于自己在粗心了...
谢谢大家,结贴!
Li_Huiyi 2010-09-30
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 mjp1234airen4385 的回复:]
实在不行,你就一个一个拷贝吧。
指针已经得到了,只要拷贝制定大小就行了。
int dwSize = ConvertInt(serverInfo);
dwServerFlag = ConvertInt(serverInfo);
[/Quote]

并不是传回来的结构无法读取,而是结构传进去以后可能还没有赋值就出现了错误:参数不正确。
jointan 2010-09-30
  • 打赏
  • 举报
回复
public extern static Int32 JBNV_GetServerInfo(IntPtr hServer, /*ref*/ IntPtr serverInfo);


调用:

IntPtr serverInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(JBNV_ServerInfo)));
re = JBNV_DLLFuction.JBNV_GetServerInfo(hServer, serverInfo);
JBNV_ServerInfo info = (JBNV_ServerInfo)Marshal.PtrToStructure(serverInfo, typeof(JBNV_ServerInfo));
Marshal.FreeHGlobal(serverInfo);
Li_Huiyi 2010-09-30
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 wuyazhe 的回复:]
加一个字节对齐试试
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi,Pack=1)]
[/Quote]

试了,没用。
调用的函数
re = JBNV_DLLFuction.JBNV_GetServerInfo(hServer, ref serverInfo);
两个参数,第一个参数是上一个函数(同一个dll里面的函数)返回的视频服务器句柄,所以这个参数应该不会有问题。函数返回的结果显示参数不正确,我就判断是第二个参数传的不对。
我想可能是对这两个成员的类型转化有问题,到底该怎么转呢?
BYTE bServerSerial[48]; //服务器序列号,具有唯一标识功能
BYTE byMACAddr[6]; //服务器的物理地址

我一开始参照MSDN上这样的一个例子:

// 传递到该函数的初始结构包含以下元素:
typedef struct _OSVERSIONINFO
{
DWORD dwOSVersionInfoSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformId;
TCHAR szCSDVersion[ 128 ];
} OSVERSIONINFO;
// 函数原型:
BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInfo);


// C#中的定义
[ StructLayout( LayoutKind.Sequential )]
public struct OSVersionInfo2
{
public int OSVersionInfoSize;

[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String versionString;
}

public class LibWrap
{
[ DllImport( "kernel32" )]
public static extern bool GetVersionEx( [In, Out] OSVersionInfo osvi );

[ DllImport( "kernel32", EntryPoint="GetVersionEx" )]
public static extern bool GetVersionEx2( ref OSVersionInfo2 osvi );
}
// 函数调用:
public class App
{
public static void Main()
{
Console.WriteLine( "\nPassing OSVersionInfo as class" );

OSVersionInfo osvi = new OSVersionInfo();
osvi.OSVersionInfoSize = Marshal.SizeOf( osvi );

LibWrap.GetVersionEx( osvi );

Console.WriteLine( "Class size: {0}", osvi.OSVersionInfoSize );

Console.WriteLine( "\nPassing OSVersionInfo as struct" );

OSVersionInfo2 osvi2 = new OSVersionInfo2();
osvi2.OSVersionInfoSize = Marshal.SizeOf( osvi2 );

LibWrap.GetVersionEx2( ref osvi2 );
Console.WriteLine( "Struct size: {0}", osvi2.OSVersionInfoSize );

}
}


我参照它的用法这样写:

// 结构定义:
[StructLayout(LayoutKind.Sequential)]
public struct JBNV_ServerInfo
{
public uint dwSize; // 结构大小
public uint dwServerFlag; // 服务器类型
public uint dwServerIp; // 服务器IP(整数表示形式)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string szServerIp; // 服务器IP(字符串表示形式)
public UInt16 wServerPort; // 服务器端口
public UInt16 wChannelNum; // 通道数量
public uint dwVersionNum; // 版本
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string szServerName;
public uint dwServerCPUType; // 当前CPU类型
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 48)]
public byte[] bServerSerial;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 6)]
public byte[] byMACAddr;
uint dwAlarmInCount; // 告警输入个数
uint dwAlarmOutCount; // 告警输出个数
uint dwSysFlags; // 系统支持的功能
uint dwUserRight; // 当前用户权限
uint dwNetPriviewRight; // 网络观看权限
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string csServerDes;
}

// 函数声明:
[DllImport("JBNVSDK.dll", CharSet = CharSet.Ansi)]
public extern static JBNV_ErrorCode JBNV_GetServerInfo(IntPtr hServer, ref JBNV_ServerInfo serverInfo);
// 函数调用:
JBNV_ServerInfo serverInfo = new JBNV_ServerInfo();
re = JBNV_DLLFuction.JBNV_GetServerInfo(hServer, ref serverInfo);


出现一个异常:尝试读取或写入受保护的内存。这通常指示其他内存已损坏。

这很奇怪,如果说是byte[]的问题,但是一楼那种写法并没有出现异常,那么只能是string的错误了。

求解。
Li_Huiyi 2010-09-30
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 ling3wei 的回复:]
又是沙发
[/Quote]

是uint

111,129

社区成员

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

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

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