2016-08-01 5 views
1

누구나 실패 이유를 확인할 수 있습니까? 내가 "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 버퍼 주소

42,949,672,960되지 않은 예외 System.AccessViolationException : 보호 된 메모리를 읽거나 쓰기 시도. 이것은 종종 다른 메모리가 손상되었다는 표시입니다.

D에 System.Runtime.InteropServices.Marshal.PtrToStructure (PTR을 IntPtr에, 입력 structureType) Program.Core.Main에서

(문자열 [] 인수)에서 : 프로젝트 \ 테스트 \ 테스트 \ 프로그램 \ \ 데이터 .cs : line 41

+1

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

+0

int GetObject (intPtr hgdiobj, int cbBuffer, out BITMAP lpobj)를 사용하십시오. 쉬워요. –

+0

예, 명시된대로 ref BITMAP에서도 작동합니다. 문제는 함수가 null의 세 번째 매개 변수를 반환 할 때 추가 처리가 필요하다는 것입니다. 가장 간단한 해결책은 포인터를 출력으로 사용하는 것입니다. 어쨌든 IntPtr 형식이 암시 적 (implicit out)이라는 것을 알아야했습니다. 나는 천 년 동안 그것을 짐작하지 못했을 것이다. 나는 그것을 찾지도 못했다. – user118708

답변

1

잘못된 서명을 사용하고 있기 때문일 수 있습니까?

[같이 DllImport ("gdi32.dll에")] 정적 통근 용 GetObject를 INT (HGDIOBJ을 IntPtr은 cbBuffer, lpvObject을 IntPtr를 INT); 또한

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으로 표시되는 이유를 모르지만 유효한 객체가 전달되어야합니다. –