首页 新闻 会员 周边 捐助

c# Marshal.copy(),问题求助!==C#中怎么将int数组传递给ref int型参数

1
悬赏园豆:100 [已关闭问题] 关闭于 2013-01-30 11:35

结构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

就能获得到值。不知道问题怎么解决

咲丶的主页 咲丶 | 初学一级 | 园豆:58
提问于:2013-01-25 15:51
< >
分享
所有回答(1)
0

你这个 GetAllUserIDEXT64 方法中的参数类型是什么?

Launcher | 园豆:45050 (高人七级) | 2013-01-25 15:59

是int类型的!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 15:59

@咲丶: 按道理你通过导入 OCX 的话,应该生成 IntPtr 类型,你这样吧:

IntPtr ptr = Marshal.AllocHGlobal  先分配一个 Marshal.Sizeof(typeof(UserInfo)) 大小的内存区,

然后这样调用:axSB100PCX1.GetAllUserIDEXT64(ptr.ToInt32())

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-25 16:04

@Launcher: 好的 我先试试看!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 16:10

按照你的方法,但是axSB100PCX1.GetAllUserIDEXT64(ref ptr.ToInt32()) 要求传入的参数必须是可以赋值的!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 16:17

@咲丶: axSB100PCX1.GetAllUserIDEXT64(ref ptr)  也不行吗?

GetAllUserIDEXT64 是自动生成的吗?能贴下接口定义吗?

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-25 16:26

@咲丶: 观看高人答疑啊!(什么内存的我一点都不知道!!!)

参数ptr.ToInt32()  改为  int temp =ptr.ToInt32();再传值temp

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-01-25 16:26

@滴答的雨: 你这个方法,我看行。

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-25 16:29

@Launcher: 

接口功能

获取一条用户ID信息

 

功能详细说明

从内存中获取一条用户注册信息。

函数声明

function GetAllUserID_EXT(var pAllIDInfo: Integer): Integer;

参数说明

pAllIDInfo 要获取的注册信息

函数返回值

0     结束,已无记录

>0    获取成功 

参数返回值

Long型(4字节)数组 数据长度6个long型数据

数据结构

No.

 

 

1

dwID                  as  long

用户ID

2

dwUsedFlag            as  long

注册状态标致,该参数按位分析(0:否, 1:是):

Bit 0:指纹1是否存在

Bit 1:指纹1是否设置胁迫

Bit 2:指纹2是否存在

Bit 3:指纹2是否设置胁迫

……

Bit 18:指纹10是否存在

Bit 19:指纹10是否设置胁迫

Bit 20:密码是否存在

Bit 21:-

Bit 22:卡是否存在

Bit 23:-

3

byUseGroupTZ          as  long

1:使用时组设置的时区

0:使用个人设置的时区

4

byUseGroupVM          as  long

1:使用时组设置的验证模式

0:使用个人设置的验证模式

5

byMgr                 as  long

用户权限:1-普通用户

6-管理员

7-超级管理员

6

bEnable               as  long

该用户是否可用:0:可用

1:不可用

 

备注

(1)   与GetAllUserID_EXT结合使用先用,先用 ReadAllUserID_EXT把全部用户注册信息读到计算机内存中,再循环调用GetAllUserID_EXT将用户注册信息一条条从内存中获取出来。

(2)   当GetAllUserID_EXT返回TRUE时表示记录获取成功,可以继续获取。当返回False表示记录获取完毕。

 

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 16:34

@滴答的雨: 那和直接穿一个int变量 没区别

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 16:35

@咲丶: 报一样的错吗?我认识中他们的区别是:

1、ptr.ToInt32() 会产生一个临时Int32变量,此临时变量不可赋值。

2、Int32 temp =ptr.ToInt32(); temp是实际变量,可以被赋值,ref要求一个可以赋值的变量

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-01-25 16:38

@Launcher: axSB100PCX1.GetAllUserIDEXT64(ref int pAllIDinfo)  这是vs 的方法提示!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 16:39

@滴答的雨: 结果是回到最初那个  说内存受保护的错误!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 16:40

@咲丶: 恩,你原始的问题我是不懂啦,我是来看Launcher回答,学习的。

 

我刚回答的只是ref的问题。

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-01-25 16:42

@咲丶: 你检查下 axSB100PCX1.GetAllUserIDEXT64(ref info) 是否 >= 0 ?

是否在调用 GetAllUserIDEXT64 之前调用了 ReadAllUserID_EXT ?

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-25 16:46

@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

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 16:52

@咲丶: 会不会是结构体构建的有问题?我看你vb都是long。。c#中都是int

支持(0) 反对(0) 滴答的雨 | 园豆:3660 (老鸟四级) | 2013-01-25 16:56

@滴答的雨: VB中的long类型对应c# 中的 int    网上有对照表的!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 16:57

@咲丶: 

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);

 


 

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-25 17:01

@Launcher: 是一个空的长度为11的数组! 没有值!     两厢对比  结构体的定义没有问题吧!VB 里边那个41是怎么来的? VB 是自带的测速程序!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 17:09

@咲丶: 很遗憾,我没有你的OCX,我没法进行我的测试,但从它的VBA代码来看,写的太糟糕,无法看清它内部如何维护内存的,所以你自己琢磨吧。

CopyMemory UInfoOne, UInfoArray(0), 41

从 UInfoArray 拷贝 41 个字节 到 UInfoOne.

可实际是,UInfoOne 只有 39 个字节的大小。

 

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-25 17:15

@Launcher: 就算把ocx 发给你 你也没有硬件配合测试!  我再琢磨琢磨吧!  问一个问题!尝试读取或写入受保护的内存。这通常指内存损坏; 这种问题,应该从那里着手!  谢谢了!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 17:19

@咲丶: 就是你要使用的内存大小超出实际分配给你的内存大小。一般像这种API,我在C++中会这样定义:

void GetAllUserIDEXT64(USERINFO64_FLAG_TYPE* pAllIDinfo); 

如果按照它写的文档的话,我会这样定义接口:

void GetAllUserIDEXT64(int* pArray,int size);

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-25 17:22

@Launcher: 嗯  谢谢了!  我再试试想想吧! 

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 17:24

@咲丶: 

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 是否有值。

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-25 17:35

@Launcher:1.AllIDinfo在调用好发生变化

2 .按照第一种copy,还是报错!第二种buff 有值,但是这些值是随机出的吧!!

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-25 18:10

@咲丶: 你可以多做一点测试,比如 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 控件的方法,会有助于我分析此问题。

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-28 09:32

@Launcher: 你好!  今天又测试了 ,发现在VB 里边frmMain.SB_APC1.GetAllUserIDEXT64(UInfoArray(0)) 只是穿了数组的第一个值,但是运行过后整个数组里边都有了值!  但是同样的方法 在C# 里边只是数组第一个有值! 

支持(0) 反对(0) 咲丶 | 园豆:58 (初学一级) | 2013-01-28 17:02

@咲丶: 我看你新帖的代码里是这样的:
While frmMain.SB_APC1.GetAllUserIDEXT64(UInfoArray) > 0
       i = i + 1

//---------------------------------------------------

也就是说你是否应该使用这种循环调用的方式。

while(axSB100PCX1.GetAllUserIDEXT64(ref AllIDinfo) > 0)

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-29 09:26

@咲丶: 最好你能用C++写一个调用的代码。

支持(0) 反对(0) Launcher | 园豆:45050 (高人七级) | 2013-01-29 09:54
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册