Marshal.PtrToStructure访问冲突

问题描述:

任何人都可以看到它为什么失败?如果我用“ref BITMAP lpvObject”替换“out IntPtr lpvObject”,我可以用它来工作。但我只是看不出代码的任何问题。Marshal.PtrToStructure访问冲突

using System; 
using System.Runtime.InteropServices; 
using System.Drawing; 

namespace Program 
{ 
    class Core 
    { 
    [StructLayout(LayoutKind.Sequential)]  
    public struct BITMAP 
    { 
     public Int32 bmType; 
     public Int32 bmWidth; 
     public Int32 bmHeight; 
     public Int32 bmWidthBytes; 
     public UInt16 bmPlanes; 
     public UInt16 bmBitsPixel; 
     public IntPtr bmBits; 
    } 


    [DllImport("gdi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
     public static extern int GetObject (IntPtr hgdiobj, int cbBuffer, out IntPtr lpvObject); 


    static void Main(string[] args) 
    { 
     Bitmap TestBmp = new Bitmap (10, 10); 
     BITMAP BitmapStruct = new BITMAP(); 
     IntPtr pBitmapStruct, pBitmapStructSave; 
     int Status; 

     pBitmapStructSave = pBitmapStruct = Marshal.AllocHGlobal (Marshal.SizeOf(BitmapStruct)); 

     Status = GetObject (TestBmp.GetHbitmap(), Marshal.SizeOf (BitmapStruct), out pBitmapStruct); 

     Console.WriteLine ("\nBytes returned is " + Status + ", buffer address = " + pBitmapStruct); 

     try 
     { 
     BitmapStruct = (BITMAP) Marshal.PtrToStructure (pBitmapStruct, typeof(BITMAP)); 
     } 
     catch (Exception Ex) 
     { 
     Console.WriteLine (Ex.Message); 
     } 

     Marshal.FreeHGlobal(pBitmapStructSave); 
    } 
    } 
} 

的输出是:

字节返回为32,缓冲器地址= 42949672960

未处理的异常:System.AccessViolationException:尝试读取或写入受保护存储器。这通常表明其他内存已损坏。

在System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr的PTR,类型structureType)

在Program.Core.Main(字串[] args)在d:\数据\项目\测试\测试\程序.cs:line 41

+1

'out IntPtr lpvObject' - >'IntPtr lpvObject' – PetSerAl

+0

使用int GetObject(IntPtr hgdiobj,int cbBuffer,out BITMAP lpobj)。十分简单。 –

+0

是的,它也适用于参考BITMAP,如我所述。这样做的麻烦是当函数返回一个空的第三个参数时需要额外的处理。最简单的解决方案仍然是将指针作为输出。无论如何,我需要知道IntPtr类型是一个隐式输出。我不会在一千年内猜出它。我也不会从搜索中找到它。 – user118708

难道是因为您使用了错误的签名吗?

[DllImport(“gdi32.dll”)] static extern int GetObject(IntPtr hgdiobj,int cbBuffer,IntPtr lpvObject);

http://www.pinvoke.net/default.aspx/gdi32/GetObject.html

此外,意味着,值需要在方法中被初始化,并且很可能不会发生,因为你已经有了lpvObject定义。

+0

API规范声明了输出第三个参数:_Out_ LPVOID lpvObject。所以签名很好。程序输出表明out参数按照预期返回一个指针值。 – user118708

+0

好的,谢谢。我删除了“出”,现在它正在工作。我必须重新阅读out关键字的使用方式。 – user118708

+0

@ user118708看[示例用法](https://msdn.microsoft.com/en-us/library/windows/desktop/dd145119(v = vs.85).aspx),您需要传入地址有效的缓冲区。我不知道它为什么在文档中标记为OUT,但它肯定需要一个通过的有效对象 –