Ok, to doprowadza mnie do szału. Tworzę port dla biblioteki C w języku C#, ale mam problem z użyciem bitmapy (generowanej z gdi) z tablicą bajtów (wymagane od biblioteki c)C# .net wrapper dla c dll, konkretnie lglcd (g19 sdk)
Oto kod, (Pastie) podzielona w plikach:
- Lglcd.dll: http://pastie.org/1424596 (zestawiane)
- G19dotNet.dll: http://pastie.org/1424600 (skompilowany jest lib współdziałanie C#)
- TestProject: http://pastie.org/1424603 (kompilacji ale zgłasza wyjątek)
Problem jest w ostatnim pliku (dwa pozostałe są dość proste), linia 116
res = LgLcd.NativeMethods.lgLcdUpdateBitmap(openContext.device, ref bmp.hdr, LgLcd.NativeConstants.LGLCD_SYNC_UPDATE(LgLcd.NativeConstants.LGLCD_PRIORITY_NORMAL));
ta zgłasza wyjątek dla nieprawidłowym dostępem do pamięci do zarządzanej pamięci.
Podpis funkcji jest taka:
/// 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);
Jak widać drugi param jest wskaźnikiem do lgLcdBitmapHeader, ale przypuszczam (bo widziałem starszą wersję lib), które ten wskaźnik jest lanego do wskaźnika lgLcdBitmapQVGAx32 (który jest struct różnej wielkości)
Myślę, że problem istnieje, jednak nie uda się rozwiązać ten problem, naprawdę
tu jest podpis struct :
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct lgLcdBitmapHeader
{
/// DWORD->unsigned int
public uint Format;
}
i
[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; } }
}
Mam nadzieję, że ktoś może mi pomóc, patrzę w całej sieci i znalazłem port .net tego lib, ale jest to bardzo stary, a nie Mam problem, który mam, ponieważ nie używa kolorowych map bitowych (z 4 bajtami dla każdego koloru) i nie używa struktury lgLcdBitmapHeader (używa prostszej). Również jego kod źródłowy jest bardzo podobny do mojego.
Każda pomoc będzie mile widziane
Przydatne linki:
http://lglcdnet.codeplex.com/SourceControl/changeset/changes/5538
Update 1:
zrobiłem pewne postępy w oparciu o teory.
DWORD WINAPI lgLcdUpdateBitmap(IN int device,
IN const lgLcdBitmapHeader *bitmap,
IN DWORD priority);
Podpis ten ma "znaczenie" w c, ponieważ wskaźnik do pierwszego elementu struktury jest również wskaźnikiem do tej struktury. W rzeczywistości lgLcdBitmapQVGAx32 ma pierwszy element typu lgLcdBitmapHeader. To powiedziawszy, używają one możliwości, że C rzuca wszystko na wszystko, aby stworzyć "ogólną metodę", ponieważ lgLcdBitmapHeader może być zarówno lgLcdBitmap160x43x1 (pierwszym elem jest lgLcdBitmapHeader) lub lgLcdBitmapQVGAx32.
To jest problem, ponieważ w C# nie mogę emulować tej pojemności, więc stworzyłem pewne funkcje "pomocnicze", które akceptują lgLcdBitmap160x43x1 i lgLcdBitmapQVGAx32, które są wewnętrznie używane jako wskaźniki dla lgLcdBitmapHeader.
to zrobić jednak, dali mi inny błąd:
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:
angielska wersja System.Runtime.InteropServices.MarshalDirectiveException non è stata gestita Message = Impossibile effettuare il marshalling di 'parametr # 2': Limitazione interna: la struttura è troppo complessa o troppo grande.:
System.Runtime.InteropServices.MarshalDirectiveException nie obsługiwane Message = Niemożliwe zrobić zestawiania z „parametr # 2”: ograniczenie wewnętrzne: struktura jest zbyt duży lub zbyt skomplikowane
Posiada tablicę 307200 bajtów, co powinienem zrobić?
Aktualizacja 2:
udało mi się pokazać obraz na ekranie, oznacza to, że mój teory była prawidłowa, musiałem korzystać z tego typu „coś” zrobić to działa: http://bytes.com/topic/c-sharp/answers/272048-internal-limitation-structure-too-complex-too-large jednak obraz pokazano "jest zepsuty", mam na myśli, że ma kształt oryginalnego obrazu, ale nieco zdezorientowany i bezbarwny, może z powodu sposobu, w jaki przekazuję bitmapę?
Update 3 i ROZWIĄZANIE:
I rozwiązać problem sam kod jest naprawdę brzydka, a ja go tu zamieścić wewnątrz Pastie, mam nadzieję, że ktoś znajdzie to użyteczne. Najważniejszą część kodu jest taka:
/// <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);
}
a to:
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);
Może trzeba zebrać coś w un-zarządzanym typu przed przekazaniem go? – Machinarius
To na pewno, ale nie wiem, jak marszałkować w ten sposób, nie jestem dobry z usługami Interop, oszaleję –
Nie jestem pewien, ale można spojrzeć na http: // msdn .microsoft.com/en-us/library/23acw07k.aspx –