如何从对象获取IntPtr指针

时间:2011-05-03 20:04:56

标签: .net c++ fingerprint intptr

我正在使用指纹设备,制造商(Upek)给了我一个c ++ BSAPI.dll,所以我需要使用包装器才能在.net中使用它。

我可以从内存中使用它,我可以抓住并匹配指纹。

现在我不得不尝试将数据输出到文件中,然后将其重新加载到内存中并获取IntPtr。

Here有关于如何从文件导出和导入的c ++示例。但我不知道怎么读。

感谢所有帮助


这就是我的所作所为并且效果很好: enter image description here

现在我需要两件事  1.将bufBIR保存到数据库中。  2.获取我保存的数据并将其传递给abs_verify。

如何做到这一点?

3 个答案:

答案 0 :(得分:4)

我不知道问题的主体意味着什么,但要回答标题:

  

如何从对象获取IntPtr?

故意这需要一点点工作,这是有充分理由的。垃圾收集器通常可以在内存中重新定位对象,因此可以通过“固定”它来完成。为此,您必须使用GCHandle'固定'创建GCHandleType,然后拨打GCHandle.AddrOfPinnedObject。如果没有固定,这将抛出异常。

另外,您应该注意GCHandle.ToIntPtr返回句柄的值而不是对象的地址。这基本上用于具有单个整数值,可以在重构GCHandle之前轻松传递。

答案 1 :(得分:3)

这是我很久以前与BioAPI接口的C#代码(我想从BIOAPI示例代码中得到)。 DoMarshall方法返回一个IntPtr,指向分配的内存足够大以容纳数组。

我没有使用Managed C ++,所以我不确定需要做哪些更改,但也许它会指向正确的方向。我当时正在和UPEK合作。我希望这有帮助...

    [Serializable]
[StructLayout(LayoutKind.Sequential)]
public class BioAPI_DATA 
{
    public uint Length = 0;
    public byte[] Data = null;
    public BioAPI_DATA() {}
    public BioAPI_DATA(uint length, byte[] data) { Length = length; Data = data; }

    public IntPtr DoMarshal(ref int size)
    {
        IntPtr ptr;
        IntPtr ptrData = IntPtr.Zero;
        int ofs = 0;

        size = Marshal.SizeOf(Type.GetType("System.Int32")) + 
               Marshal.SizeOf(Type.GetType("System.IntPtr"));

        ptr = Marshal.AllocCoTaskMem( size );
        Marshal.WriteInt32(ptr, ofs, (int) Length);
        ofs += Marshal.SizeOf(Type.GetType("System.Int32"));
        if (Data != null) 
        {
            ptrData = Marshal.AllocCoTaskMem( Data.Length );
            Marshal.Copy(Data, 0, ptrData, Data.Length);
        }
        Marshal.WriteIntPtr(ptr, ofs, ptrData);
        return ptr;
    }

    public void DoUnmarshal(IntPtr ptr, ref int size, bool fDeleteOld)
    {
        int ofs = 0;
        size = Marshal.SizeOf(Type.GetType("System.Int32")) + 
               Marshal.SizeOf(Type.GetType("System.IntPtr"));
        Length =  (uint) Marshal.ReadInt32( ptr, ofs );
        ofs += Marshal.SizeOf(Type.GetType("System.Int32"));

        if (Length == 0) 
        {
            if (Data != null) Data = null;
            return;
        }

        IntPtr ptr2 = Marshal.ReadIntPtr(ptr, ofs);

        if (Data == null || Data.Length != Length) Data = new byte[Length];
        Marshal.Copy(ptr2, Data, 0, (int) Length);
        if (fDeleteOld)  { if (ptr != IntPtr.Zero) Marshal.FreeCoTaskMem( ptr ); }
    }
}

答案 2 :(得分:2)

IntPtr只是void*的.NET类型。它本身并不意味着任何意义。您需要知道内存包含的内容,并确保.NET和C端使用相同的内存布局。

有两种主要方法可以在托管代码和非托管代码之间进行接口。

一个是C ++ / CLI(IJW)。如果您固定托管对象或数组,则可以将其传递给非托管函数。但是,对于复杂类型,您可能遇到麻烦,因为.NET的内存布局不一定与C库所期望的相同。查看pin_ptr了解详情。

第二种流行的方法是使用p/invoke,您可以将C#struct(C ++ / CLI value struct)编组为C struct,甚至是数组那些。您可以指定内存布局,是否应将string编组为MBCS或UTF-16,如何对齐结构,等等。通过这种方式直接从C#调用C函数很容易。