结构c#
//[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] public struct UserInfo { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 19)] public byte[] Id; //[MarshalAs(UnmanagedType.I4)] public int dwUsedFlag; //[MarshalAs(UnmanagedType.I4)] public int byUseGroupTZ; //[MarshalAs(UnmanagedType.I4)] public int byUseGroupVM; //[MarshalAs(UnmanagedType.I4)] public int byMgr; //[MarshalAs(UnmanagedType.I4)] public int bEnable; }
vb的结构是
Type USERINFO64_FLAG_TYPE ID(19) As Byte dwUsedFlag As Long byUseGroupTZ As Long byUseGroupVM As Long byMgr As Long bEnable As Long End Type
‘关键代码
Private Sub cmdGetEnrollInfo_Click()
Dim nRet As Long
Dim i As Long, j As Long, k As Long, n As Long
Dim szTemp As String, szTemp1 As String
Dim UInfoOne As USERINFO64_FLAG_TYPE
Dim UInfoArray(41/4+1) As Long
Dim tempbuf(21) As Byte
lstEnrollInfo.Clear
nRet = frmMain.SB_APC1.ReadAllUserIDEXT64()
lblMessage = pubGetErrorString
If nRet >= 0 Then
lstEnrollInfo.AddItem ("No. ID Priv Ena (FP1 ~ ~ ~ FP10) PW CD GT GV")
i = 0
While frmMain.SB_APC1.GetAllUserIDEXT64(UInfoArray(0)) > 0
i = i + 1
CopyMemory UInfoOne, UInfoArray(0), 38
szTemp = ""
For n = 0 To 19
If UInfoOne.ID(n) = 0 Then
.....
调用ocx控件中的获得用户ID 的方法
int info = 0; if (axSB100PCX1.GetAllUserIDEXT64(ref info) != 0) { //CopyMemory(uinfo,p,41); //Marshal.PtrToStructure(p, uinfo); UserInfo uinfo =(UserInfo)Marshal.PtrToStructure(new IntPtr(info), typeof(UserInfo)); //Marshal.Copy(p, uinfo, 0, 40); listBox1.Items.Add(uinfo.Id); }
总是报:尝试读取或写入受保护的内存。这通常指内存损坏;
但是看VB 的测试程序中
Dim UInfoOne As USERINFO64_FLAG_TYPE Dim UInfoArray(41 / 4 + 1) As Long frmMain.SB_APC1.GetAllUserIDEXT64(UInfoArray(0)) CopyMemory UInfoOne, UInfoArray(0), 41
就能获得到值。不知道问题怎么解决
你这个 GetAllUserIDEXT64 方法中的参数类型是什么?
是int类型的!
@咲丶: 按道理你通过导入 OCX 的话,应该生成 IntPtr 类型,你这样吧:
IntPtr ptr = Marshal.AllocHGlobal 先分配一个 Marshal.Sizeof(typeof(UserInfo)) 大小的内存区,
然后这样调用:axSB100PCX1.GetAllUserIDEXT64(ptr.ToInt32())
@Launcher: 好的 我先试试看!
按照你的方法,但是axSB100PCX1.GetAllUserIDEXT64(ref ptr.ToInt32()) 要求传入的参数必须是可以赋值的!
@咲丶: axSB100PCX1.GetAllUserIDEXT64(ref ptr) 也不行吗?
GetAllUserIDEXT64 是自动生成的吗?能贴下接口定义吗?
@咲丶: 观看高人答疑啊!(什么内存的我一点都不知道!!!)
参数ptr.ToInt32() 改为 int temp =ptr.ToInt32();再传值temp
@滴答的雨: 你这个方法,我看行。
@Launcher:
接口功能 |
获取一条用户ID信息
|
|||||||||||||||||||||
功能详细说明 |
从内存中获取一条用户注册信息。 |
|||||||||||||||||||||
函数声明 |
function GetAllUserID_EXT(var pAllIDInfo: Integer): Integer; |
|||||||||||||||||||||
参数说明 |
pAllIDInfo 要获取的注册信息 |
|||||||||||||||||||||
函数返回值 |
0 结束,已无记录 >0 获取成功 |
|||||||||||||||||||||
参数返回值 |
Long型(4字节)数组 数据长度6个long型数据 数据结构
|
|||||||||||||||||||||
备注 |
(1) 与GetAllUserID_EXT结合使用先用,先用 ReadAllUserID_EXT把全部用户注册信息读到计算机内存中,再循环调用GetAllUserID_EXT将用户注册信息一条条从内存中获取出来。 (2) 当GetAllUserID_EXT返回TRUE时表示记录获取成功,可以继续获取。当返回False表示记录获取完毕。
|
@滴答的雨: 那和直接穿一个int变量 没区别
@咲丶: 报一样的错吗?我认识中他们的区别是:
1、ptr.ToInt32() 会产生一个临时Int32变量,此临时变量不可赋值。
2、Int32 temp =ptr.ToInt32(); temp是实际变量,可以被赋值,ref要求一个可以赋值的变量
@Launcher: axSB100PCX1.GetAllUserIDEXT64(ref int pAllIDinfo) 这是vs 的方法提示!
@滴答的雨: 结果是回到最初那个 说内存受保护的错误!
@咲丶: 恩,你原始的问题我是不懂啦,我是来看Launcher回答,学习的。
我刚回答的只是ref的问题。
@咲丶: 你检查下 axSB100PCX1.GetAllUserIDEXT64(ref info) 是否 >= 0 ?
是否在调用 GetAllUserIDEXT64 之前调用了 ReadAllUserID_EXT ?
@Launcher: 是的
if (axSB100PCX1.ReadAllUserIDEXT64() != -1) { UserInfo uinfo = new UserInfo(); int size = Marshal.SizeOf(uinfo); IntPtr Ptr = Marshal.AllocHGlobal(size); Int32 info = Ptr.ToInt32(); for (int i = 0; i < length; i++) { if (axSB100PCX1.GetAllUserIDEXT64(ref info) != 0) { //CopyMemory(uinfo,p,41); //Marshal.PtrToStructure(p, uinfo); UserInfo uinfo = (UserInfo)Marshal.PtrToStructure(new IntPtr(info), typeof(UserInfo)); //Marshal.Copy(p, uinfo, 0, 40); listBox1.Items.Add(uinfo.Id); } } }
axSB100PCX1.GetAllUserIDEXT64(ref info) 运行之后 info=825241908
@咲丶: 会不会是结构体构建的有问题?我看你vb都是long。。c#中都是int
@滴答的雨: VB中的long类型对应c# 中的 int 网上有对照表的!
@咲丶:
Dim UInfoOne As USERINFO64_FLAG_TYPE
Dim UInfoArray(41 / 4 + 1) As Long
frmMain.SB_APC1.GetAllUserIDEXT64(UInfoArray(0))
CopyMemory UInfoOne, UInfoArray(0), 41
等价于:
USERINFO64_FLAG_TYPE UInfoOne;
int UInfoArray[41/4+1];
IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(UInfoArray,0);
int AllIDinfo = ptr.ToInt32();
axSB100PCX1.GetAllUserIDEXT64(ref AllIDinfo);
你定个断点,当上面这句调用成功后,你看下 UInfoArray 中是否有值了。
Marshal.PtrToStructure(new IntPtr(AllIDinfo),UInfoOne);
@Launcher: 是一个空的长度为11的数组! 没有值! 两厢对比 结构体的定义没有问题吧!VB 里边那个41是怎么来的? VB 是自带的测速程序!
@咲丶: 很遗憾,我没有你的OCX,我没法进行我的测试,但从它的VBA代码来看,写的太糟糕,无法看清它内部如何维护内存的,所以你自己琢磨吧。
CopyMemory UInfoOne, UInfoArray(0), 41
从 UInfoArray 拷贝 41 个字节 到 UInfoOne.
可实际是,UInfoOne 只有 39 个字节的大小。
@Launcher: 就算把ocx 发给你 你也没有硬件配合测试! 我再琢磨琢磨吧! 问一个问题!尝试读取或写入受保护的内存。这通常指内存损坏; 这种问题,应该从那里着手! 谢谢了!
@咲丶: 就是你要使用的内存大小超出实际分配给你的内存大小。一般像这种API,我在C++中会这样定义:
void GetAllUserIDEXT64(USERINFO64_FLAG_TYPE* pAllIDinfo);
如果按照它写的文档的话,我会这样定义接口:
void GetAllUserIDEXT64(int* pArray,int size);
@Launcher: 嗯 谢谢了! 我再试试想想吧!
@咲丶:
IntPtr ptr = Marshal.AllocHGlobal(100);
IntPtr ptr = Marshal.AllocCoTaskMem(100);
这两种分配方式都测试下。
int AllIDinfo = ptr.ToInt32();
axSB100PCX1.GetAllUserIDEXT64(ref AllIDinfo);
观察下 AllIDinfo 的值在调用后有没有改变。
IntPtr newPtr = new IntPtr(AllIDinfo);
byte buff[50];
Marshal.Copy(newPtr,buff,0,50);
Marshal.Copy(ptr,buff,0,50);
两种 Copy 方式都测试下,看看 buff 是否有值。
@Launcher:1.AllIDinfo在调用好发生变化
2 .按照第一种copy,还是报错!第二种buff 有值,但是这些值是随机出的吧!!
@咲丶: 你可以多做一点测试,比如 Marshal.Copy(newPtr,buff,0,10); 变小点,或者新分配一个:
IntPtr ptrDest = Marshal.AllocHGlobal(100);
Marshal.Copy(newPtr,ptrDest,0,40);
如果 AllIDinfo 的值发生了改变,那就说明 GetAllUserIDEXT64 函数在内部做了内存分配,也就是说,如果你这样调用也是成功的:
int AllIDinfo = 0;
axSB100PCX1.GetAllUserIDEXT64(ref AllIDinfo);
因为你有调用成功的 VB 代码,那么你可以观察下 Dim UInfoArray(41 / 4 + 1) As Long 中的数组 UInfoArray 中的值是如何改变的,UInfoArray[0] 的值是如何改变的。
如果你能用C++来写一个调用此 OCX 控件的方法,会有助于我分析此问题。
@Launcher: 你好! 今天又测试了 ,发现在VB 里边frmMain.SB_APC1.GetAllUserIDEXT64(UInfoArray(0)) 只是穿了数组的第一个值,但是运行过后整个数组里边都有了值! 但是同样的方法 在C# 里边只是数组第一个有值!
@咲丶: 我看你新帖的代码里是这样的:
While frmMain.SB_APC1.GetAllUserIDEXT64(UInfoArray) > 0
i = i + 1
//---------------------------------------------------
也就是说你是否应该使用这种循环调用的方式。
while(axSB100PCX1.GetAllUserIDEXT64(ref AllIDinfo) > 0)
@咲丶: 最好你能用C++写一个调用的代码。