2011-01-03 2 views
6

좋아, 이건 내가 미쳤다. C#에서 C lib 용 포트를 만들고 있지만 바이트 배열 (lib 디렉토리에서 필요함)을 사용하여 비트 맵 (gdi로 생성 됨)을 사용할 때 문제가 발생했습니다.C DLL에 대한. NET 래퍼, 특히 lglcd (g19 sdk)

여기에 코드가 있습니다. pastie) 파일에 나누어 :

  1. Lglcd.dll : http://pastie.org/1424596 (컴파일)
  2. G19dotNet.dll : http://pastie.org/1424600 (컴파일, 이 C#을위한 상호 운용성 LIB)
  3. TestProject입니다 : ,532은 10 (116)

    res = LgLcd.NativeMethods.lgLcdUpdateBitmap(openContext.device, ref bmp.hdr, LgLcd.NativeConstants.LGLCD_SYNC_UPDATE(LgLcd.NativeConstants.LGLCD_PRIORITY_NORMAL)); 
    

    이 잘못된 메모리 액세스에 대해 예외가 발생합니다 라인, 문제는 마지막 파일 (다른 두 꽤 간단합니다)에

( 를 컴파일하지만, 예외를 throw) 관리되는 메모리로.

함수의 서명은 이것이다 : 두 번째 PARAM을 볼 수 있듯이

/// Return Type: DWORD->unsigned int 
      ///device: int 
      ///bitmap: lgLcdBitmapHeader* 
      ///priority: DWORD->unsigned int 
      [System.Runtime.InteropServices.DllImportAttribute("LgLcd", EntryPoint = "lgLcdUpdateBitmap")] 
      public static extern uint lgLcdUpdateBitmap([System.Runtime.InteropServices.In] int device, [System.Runtime.InteropServices.In] ref lgLcdBitmapHeader bitmap, [System.Runtime.InteropServices.In] uint priority); 

가 lgLcdBitmapHeader에 대한 포인터입니다,하지만 (내가 lib 디렉토리의 이전 버전을 본 적이 있기 때문에) 나는 가정이 이 포인터는하지만 정말,이 문제를 해결하기 위해

여기

을 관리 할 수 ​​없습니다,

내가 문제가 있다고 생각 (다른 크기의 구조체 임) lgLcdBitmapQVGAx32 포인터에 주조되어 구조체의 서명입니다 :

012 3,516,
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 
    public struct lgLcdBitmapHeader 
    { 

     /// DWORD->unsigned int 
     public uint Format; 
    } 

나는 누군가가 나를 도울 수 있기를 바랍니다

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 
    public struct lgLcdBitmap160x43x1 
    { 

     /// lgLcdBitmapHeader->Anonymous_5fa96ca7_9cc3_4b33_b5aa_ccff9833813a 
     public lgLcdBitmapHeader hdr; 

     /// BYTE[] 
     //public fixed byte pixels[NativeConstants.LGLCD_BMP_WIDTH * NativeConstants.LGLCD_BMP_HEIGHT * NativeConstants.LGLCD_BMP_BPP]; 
     [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = NativeConstants.LGLCD_BMP_WIDTH * NativeConstants.LGLCD_BMP_HEIGHT * NativeConstants.LGLCD_BMP_BPP)] 
     public byte[] pixels; 
     public static int SizeConst { get { return NativeConstants.LGLCD_BMP_WIDTH * NativeConstants.LGLCD_BMP_HEIGHT * NativeConstants.LGLCD_BMP_BPP; } } 
    } 

, 나는 모든 웹을 통해보고 그리고 난이 LIB의 그물 포트를 찾았지만 아주 오래된, 그리고하지 않습니다 컬러 비트 맵 (각 색마다 4 바이트)을 사용하지 않고 lgLcdBitmapHeader 구조체 (더 간단한 형식을 사용함)를 사용하지 않기 때문에 문제가 발생했습니다. 또한 소스 코드는 내 것과 매우 비슷합니다.

http://lglcdnet.codeplex.com/SourceControl/changeset/changes/5538

업데이트 1 :

어떤 도움을

유용한 링크를 이해할 수있을 것이다

나는 teory에 따라 일부 진전을했다.

DWORD WINAPI lgLcdUpdateBitmap(IN int device, 
          IN const lgLcdBitmapHeader *bitmap, 
          IN DWORD priority); 

이 서명은 구조체의 첫 번째 요소에 대한 포인터도 해당 구조체에 대한 포인터이기 때문에 c에 "의미가 있습니다. 사실 lgLcdBitmapQVGAx32에는 lgLcdBitmapHeader 유형의 첫 번째 요소가 있습니다. 즉, lgLcdBitmapHeader는 lgLcdBitmap160x43x1 (첫 번째 요소는 lgLcdBitmapHeader) 또는 lgLcdBitmapQVGAx32 일 수 있기 때문에 C의 가능성을 사용하여 "일반 메서드"를 만들기 위해 모든 것을 모두 캐스팅 할 수 있습니다.

C#에서는이 용량을 에뮬레이트 할 수 없으므로 문제가됩니다. 그래서 lgLcdBitmapHeader에 대한 포인터로 내부적으로 사용되는 lgLcdBitmap160x43x1 및 lgLcdBitmapQVGAx32를 허용하는 "도우미"함수를 만들었습니다.

수행이

은, 그러나, 나에게 또 다른 오류를 주었다

System.Runtime.InteropServices.MarshalDirectiveException non è stata gestita 
    Message=Impossibile effettuare il marshalling di 'parameter #2': Limitazione interna: la struttura è troppo complessa o troppo grande. 
    Source=G19dotNet 
    StackTrace: 
     in G19dotNet.LgLcd.NativeMethods.lgLcdUpdateBitmapQVGAx32(Int32 device, lgLcdBitmapQVGAx32& bitmap, UInt32 priority) 
     in ConsoleTest2.Program.Main(String[] args) in C:\Documents and Settings\Administrator\documenti\visual studio 2010\Projects\G19dotNet\ConsoleTest2\Program.cs:riga 116 
     in System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
     in System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
     in Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
     in System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
     in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) 
     in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     in System.Threading.ThreadHelper.ThreadStart() 
    InnerException: 
System.Runtime.InteropServices.MarshalDirectiveException 비 è STATA gestita 메시지 = Impossibile effettuare 위원장 마샬링 디 '매개 변수 # 2'의

영어 버전 : 제한된 내부 구조 : 트렁크와 트렁크를 연결하는 그물. :

System.Runtime.InteropServices.MarshalDirectiveException은 처리되지 메시지 = 불가 '파라미터 # 2'마샬링 수행 내부 제한 : 구조는 그것의 배열을 갖는다

너무 크거나 너무 복잡 307200 바이트, 어떻게해야합니까?

업데이트 2 : http://bytes.com/topic/c-sharp/answers/272048-internal-limitation-structure-too-complex-too-large 그러나 이미지를 : 내 화면에 이미지를 표시하는 관리

, 나는 그것이 작동하는지 "일"의이 유형을 사용했다 나의 teory이 올 것을 의미합니다 보이는 "깨진", 그것은 원래 이미지의 모양을 가지고 있지만 비트 혼란과 무색, 비트 맵을 전달하는 방법에 대한 어쩌면 때문에 의미?

업데이트 3 및 해결 방법 :

내가 나 자신에 의해 문제를 해결이 코드는 정말 못생긴 내가 pastie 내부 여기에 게시거야, 희망 누군가는 유용하게 찾을 수 있습니다.

/// <summary> 
/// LONG GetBitmapBits(
/// __in HBITMAP hbmp, 
/// __in LONG cbBuffer, 
/// __out LPVOID lpvBits 
/// ); 
/// </summary> 
/// <param name="hbmp"></param> 
/// <param name="cbBuffer"></param> 
/// <param name="lpvBits"></param> 
/// <returns></returns> 
[DllImport("Gdi32", EntryPoint = "GetBitmapBits")] 
public extern static long GetBitmapBits([In] IntPtr hbmp,[In] int cbBuffer,[Out] byte[] lpvBits); 

[DllImport("Gdi32", EntryPoint = "GdiFlush")] 
public extern static void GdiFlush(); 

public static void FillPixelArray3(Bitmap bmp, ref byte[] array) 
{ 
    IntPtr hbmp = bmp.GetHbitmap(); 

    GdiFlush(); 
    //Marshal SizeOf is to "ensure" that other people will notice that array.Length 
    //must be multiplied 
    GetBitmapBits(hbmp, array.Length * Marshal.SizeOf(typeof(byte)), array); 

} 

이 : 당신이 C의 DLL의 소스 코드를 가지고 있기 때문에

IntPtr unhandledPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LgLcd.lgLcdBitmapQVGAx32))); 
    Marshal.StructureToPtr(bmp, unhandledPtr, true); 
    res = LgLcd.NativeMethods.lgLcdUpdateBitmap(openContext.device, unhandledPtr, LgLcd.NativeConstants.LGLCD_SYNC_UPDATE(LgLcd.NativeConstants.LGLCD_PRIORITY_NORMAL)); 
    Marshal.FreeHGlobal(unhandledPtr); 
+0

어쩌면 당신이 그것을 통과하기 전에 유엔 관리되는 형식들로 뭔가를 마샬링해야? – Machinarius

+0

물론이 방법으로 마샬링하는 방법을 모르겠다. Interop 서비스가 좋지 않다. 나는 화를 내겠다. –

+0

잘 모르겠지만 http : // msdn을 살펴볼 수있다. .microsoft.com/en/US/ 라이브러리/23acw07k.aspx –

답변

1

관리되지 않는 할당의 사용은 질문에서 직접 설명한대로 필요합니다.

코드 예제 :

IntPtr unhandledPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LgLcd.lgLcdBitmapQVGAx32))); 
Marshal.StructureToPtr(bmp, unhandledPtr, true); 
res = LgLcd.NativeMethods.lgLcdUpdateBitmap(openContext.device, unhandledPtr, LgLcd.NativeConstants.LGLCD_SYNC_UPDATE(LgLcd.NativeConstants.LGLCD_PRIORITY_NORMAL)); 
Marshal.FreeHGlobal(unhandledPtr); 

는 또한 나는 통근 방법 서명을 변경하는 데 필요한 :

[DllImportAttribute("LgLcd", EntryPoint = "lgLcdUpdateBitmap")] 
    public static extern uint lgLcdUpdateBitmap([In] int device, [In] IntPtr bitmap, [In] uint priority); 
    //OLD ONE: 
    public static extern uint lgLcdUpdateBitmap([In] int device, [In] ref lgLcdBitmapHeader bitmap, [In] uint priority); 
0

, 당신은 비주얼 C++ CLR 프로젝트와 래퍼를 작성 고려해야 코드의 가장 중요한 부분은 이것이다 . 공용 언어 런타임을 사용하면 관리 코드와 비 관리 코드를 함께 쓸 수 있습니다. 그렇다면 변수를 전달해야하지만 직접 변수를 사용해야 할 필요는 없습니다.

그리고 C#에서 사용하려면 C# 응용 프로그램에서 C++ Clr 라이브러리를 참조하십시오. 전에이 방법을 사용했는데 완벽하게 작동합니다.

+0

더 좋았지 만 사용하지 않은 것 같아요. 그러나 뭔가를 보여 주면서 문제가 발생했습니다. 비트 맵이 올바르게 표시됩니다. –

+0

@Fire : Ok 픽셀 형식을 확인하십시오. 우리는 pf 32bppARGB, pf 32bppRGBA ... 녹색 대신 알파 값을 볼 수 있습니까? – honibis

+0

나는 다른 방식으로 작동하도록 관리했는데, 나는 HBITMAP에서 잘 작동하는 GetBitmapBits를 PInvoked했다. 나는 비트 맵에서 쉽게 얻을 수있다. 그래서 모든 것이 괜찮다. 나는 이런 식으로도 괜찮다고 생각한다. Btw 형식이 RGBA입니다. –