2011-01-03 30 views
6

Bien chicos, esto me está volviendo loco. Estoy creando un puerto para una biblioteca C en C# pero tengo un problema al usar un mapa de bits (generado con gdi) con una matriz de bytes (requerida de la lib)Contenedor C# .net para c dll, específicamente lglcd (g19 sdk)

Aquí está el código, (pastie) dividido en ficheros:

  1. Lglcd.dll: http://pastie.org/1424596 (compilado)
  2. G19dotNet.dll: http://pastie.org/1424600 (compilado, este es el lib de interoperabilidad para C#)
  3. TestProject: http://pastie.org/1424603 (compilar, pero emite una excepción)

El problema está en el último archivo (los otros dos son bastante sencillo), la línea 116

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

Este emite una excepción para un acceso a memoria no válida a la memoria administrada.

La firma de la función es la siguiente:

/// 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); 

Como se puede ver el segundo parámetro es un puntero a lgLcdBitmapHeader, pero supongo (porque he visto una versión más antigua de la lib) que este puntero es fundido a un puntero lgLcdBitmapQVGAx32 (que es una estructura de diferente tamaño)

creo que el problema está ahí, sin embargo no puedo manejar para resolver esto, realmente

aquí es la firma de la estructura :

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

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

y

[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; } } 
    } 

espero que alguien me puede ayudar, estoy viendo por toda la web y he encontrado un puerto .NET de este lib pero es muy viejo, y no lo hace tengo el problema que tengo porque no usa mapas de bits coloreados (con 4 bytes para cada color) y no usa lgLcdBitmapHeader struct (usa uno más simple). También su código fuente es muy similar al mío.

Cualquier ayuda será apreciada

Enlaces:

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

Actualizar 1:

hice algunos progresos en base a un teory.

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

Esta firma tiene "un significado" en C, porque el puntero al primer elemento de una estructura es también el puntero a la estructura. De hecho, lgLcdBitmapQVGAx32 tiene un primer elemento de tipo lgLcdBitmapHeader. Dicho esto, están utilizando la posibilidad de que C diseñe todo para crear un "método genérico", porque lgLcdBitmapHeader puede ser lgLcdBitmap160x43x1 (el primer elemento es lgLcdBitmapHeader) o lgLcdBitmapQVGAx32.

Esto es un problema porque en C# no puedo emular esta capacidad, así que creé algunas funciones de "ayuda" que aceptan lgLcdBitmap160x43x1 y lgLcdBitmapQVGAx32 que se utilizan internamente como punteros a lgLcdBitmapHeader.

Este hecho, sin embargo, me dio otro error:

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: 

versión en Inglés de System.Runtime.InteropServices.MarshalDirectiveException non è stata gestita Mensaje = Impossibile effettuare il de clasificación di 'parámetro # 2': Limitazione interna: la struttura è troppo complessa o troppo grande.:

System.Runtime.InteropServices.MarshalDirectiveException no se manejan Mensaje = Imposible hacer el guiado de la 'parámetro # 2': Limitación interna: la estructura es demasiado grande o demasiado compleja

Tiene una gran variedad de 307200 bytes, ¿qué debo hacer?

Actualización 2:

logré mostrar una imagen en la pantalla, significa que mi teory era correcta, tuve que usar este tipo de "cosa" para que sea funciona: http://bytes.com/topic/c-sharp/answers/272048-internal-limitation-structure-too-complex-too-large Sin embargo la imagen se muestra "roto", quiero decir que tiene la forma de la imagen original, pero un poco confusa y sin color, tal vez porque la forma en que paso el mapa de bits?

Update 3 y SOLUCIÓN:

He resuelto el problema por mi cuenta, el código es realmente feo y lo voy a publicar aquí dentro pastie, es de esperar que alguien le resultará útil. La parte más importante del código es la siguiente:

/// <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); 

} 

y esto:

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

Tal vez usted tiene que reunir algo en un tipo administrado un-antes de pasarlo? – Machinarius

+0

Eso es seguro, sin embargo, no sé cómo organizar de esta manera, no soy bueno con los servicios de Interop, me estoy volviendo loco –

+0

No estoy muy seguro, pero ¿puedes echar un vistazo a http: // msdn .microsoft.com/en-us/library/23acw07k.aspx –

Respuesta

1

Se necesita el uso de la asignación no administrada como se explica directamente en la pregunta.

Código ejemplo:

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); 

también tenía que cambiar el método extern firma:

[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

Ya que tienes el código fuente de C DLL, se debe considerar escribir el envoltorio con el proyecto de Visual C++ CLR . Common Language Runtime le permite escribir códigos administrados y no administrados juntos. Entonces no necesitarás pasar variables, sino usarlas directamente.

Y cuando quiera usarlo desde C# simplemente haga referencia a la biblioteca C++ Clr desde su aplicación C#. Lo usé de esta manera antes y funciona perfectamente.

+0

Creo que es mejor, pero nunca lo usé C++ clr Sin embargo, logré mostrar algo, el problema ahora es mostrar el mapa de bits correctamente –

+0

@Fire: Ok, entonces supongo que deberías verifica el formato de píxel. Tenemos pf 32bppARGB, pf 32bppRGBA ... ¿es posible que vea el valor alfa en lugar del verde? – honibis

+0

Mh Pude hacer que funcionara de manera diferente, invoqué GetBitmapBits, que funciona bien con un HBITMAP, lo puedo obtener fácilmente de mi mapa de bits ... así que todo está bien, creo que está bien de esta manera también. Por cierto, el formato es RGBA –