2016-08-01 3 views
1

может ли кто-нибудь понять, почему он не работает? Если я заменил «out Intptr lpvObject» на «ref BITMAP 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 (String [] арг) в D: \ Data \ Projects \ Test \ Test \ Program .cs: ​​строка 41

+1

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

+0

Использовать int GetObject (IntPtr hgdiobj, int cbBuffer, вне BITMAP lpobj). Очень просто. –

+0

Да, он также работает с ref BITMAP, как я уже говорил. Проблема в том, что это требует дополнительной обработки, когда функция возвращает нулевой третий параметр. Простейшим решением остается вывод указателя в качестве вывода. В любом случае мне нужно было знать, что тип IntPtr является неявным. Я бы не догадался об этом за тысячу лет. И я не нашел бы это от поиска. – user118708

ответ

1

Не может быть, потому что вы используете неправильную подпись?

[DllImport ("gdi32.dll")] статические ехЬегп 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 в документации, но он определенно нуждается в действительном объекте, прошедшем в –

Смежные вопросы