2016-04-10 12 views
0

Wir bekommen ein seltsames Verhalten beim Versuch, read() Methode von Linux/libc mit Mono.PInvoke null Referenz Ausnahme auf Marshal.PtrToStructure <T> (ptr)

 
[16:05:17.258][UNHANDLED EXCEPTION][BEGIN] 
[16:05:18.463]System.NullReferenceException: Object reference not set to an instance of an object 
    at (wrapper unknown) PI.SDK.UI.HW.PAX.ProlinKeyboardManager+InputEvent:PtrToStructure (intptr,object) 
    at (wrapper managed-to-native) System.Runtime.InteropServices.Marshal:PtrToStructure (intptr,System.Type) 
    at System.Runtime.InteropServices.Marshal.PtrToStructure[T] (IntPtr ptr) in :0 
    at PI.SDK.UI.HW.PAX.ProlinKeyboardManager.StartListening() in :0 
    at PI.SDK.PAX.Playground.Program+c.b__37_0() in :0 
    at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) in :0 
    at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, Boolean preserveSyncCtx) in :0 
    at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, Boolean preserveSyncCtx) in :0 
    at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) in :0 
    at System.Threading.ThreadHelper.ThreadStart() in :0 

Das Problem auf Marshal.PtrToStructure<T>(IntPtr) sein aussieht, aber ich kann nicht sehen, wo es ist ...

Das verwaltete/C# Teil des repro Fall ist wie folgt:

[StructLayout(LayoutKind.Sequential)] 
private struct InputEvent 
{ 
    public int Seconds; 
    public int Microseconds; 
    public ushort type; 
    public ushort code; 
    public int value; 
} 

[DllImport(LIBC, EntryPoint = "read", CallingConvention = CallingConvention.Cdecl)] 
private static extern int NativeRead(int fd, ref IntPtr buf, int nbytes); 

public void StartListening() 
{ 
    var kbDeviceName = "/dev/keypad"; 
    int fd = -1; 
    fd = NativeOpen(kbDeviceName, 2); 
    Console.WriteLine($"[KBD] {fd}"); 

    if (fd < 0) 
     throw new InvalidOperationException($"Unable to open Keyboard device {kbDeviceName}. Return code {fd}."); 

    var ev = new InputEvent[64]; 
    var size = Marshal.SizeOf<InputEvent>(); 
    Console.WriteLine($"[EventSize] {size}"); 
    var totalSize = size * 64; 
    Console.WriteLine($"[TotalEventSize] {totalSize}"); 

    var ptr = IntPtr.Zero; 

    while (true) 
    { 
     var rd = NativeRead(fd, ref ptr, totalSize); 
     Console.WriteLine($"[KBD][Read] {rd}"); 
     Console.WriteLine($"[PTR] {ptr}"); 
     if (rd > size) 
     { 
      var eventNum = rd/size; 
      Console.WriteLine($"[Events] {eventNum}"); 
      for (int i = 0; i < eventNum; i++) 
      { 
       var entry = Marshal.PtrToStructure<InputEvent>(ptr); 
       Console.WriteLine($"code: {entry.code} | type: {entry.type} | value: {entry.value}"); 
       ptr = new IntPtr(ptr.ToInt32() + size); 
      } 
     } 
    } 
} 

der Ausgang jener Console.Writeline ist:

[KBD] 5 
[EventSize] 16 
[TotalEventSize] 1024 
[KBD][Read] 32 
[PTR] 1460304317 
[Events] 2 
[16:05:17.258][UNHANDLED EXCEPTION][BEGIN] 
... THE EXCEPTION GOES HERE ... 

Dies ist ein C nativen Probe wir tr ying zu replizieren:

int i; 
int eventNum = 0; 
struct input_event ev[64]; 

int size = sizeof(struct input_event); 
int rd = 0; 

memset(ev, 0, sizeof(ev)); 
rd = read(gfd, ev, sizeof(ev)); 
eventNum = rd/size; 
for (i = 0; i < eventNum; ++i) 
{ 
    /* EV_KEY means type is key (not mouse, etc) */ 
    if (ev[i].type == EV_KEY && ev[i].value == 1) 
    { 
     return ev[i].code; 
    } 
} 

Kann mir jemand zeigen, wo sollte unser Fehler sein?

Danke! Ich schätze jede Hilfe. Gutemberg

+0

wo ist der Code von PI.SDK.UI.HW.PAX.ProlinKeyboardManager? – knocte

+0

der C# -Teil ist es für jetzt. Habe einfach den nicht verwandten Rest der Einfachheit halber entfernt, aber dies betrifft diesen Fall nicht. –

+0

Sie fügen die Klasse nicht hinzu, also haben wir keine Ahnung, wo genau es scheitert – knocte

Antwort

1

zwei Probleme:

1) Der zweite Parameter von NativeRead sollte kein ref Zeiger sein. Stattdessen sollte es der Zeiger selbst sein. Bitte überprüfen Sie die PInvoice-Deklaration und ändern Sie "ref IntPtr" zu "IntPtr". Beispiel:

private static extern int NativeRead(int fd, IntPtr buf, int nbytes); 

2) lesen erwartet, dass der Zeiger auf den Puffer, und dieser Code übergibt 0. Sie sollten die nativen Speicher für den Puffer stattdessen zuweisen. Beispiel:

Und noch ein Problem in der Schleife: der in der Schleife inkrementierte Zeiger ist der gleiche, der für weitere Lesevorgänge verwendet wird. Stattdessen sollten die Lesevorgänge immer mit dem Pufferzeiger erfolgen. Dies sollte es beheben:

var buffer_ptr = Marshal.AllocHGlobal(totalSize); 

    while (true) 
    { 
    var rd = NativeRead(fd, buffer_ptr, totalSize); 
    Console.WriteLine($"[KBD][Read] {rd}"); 
    Console.WriteLine($"[PTR] {buffer_ptr}"); 
    if (rd > size) 
    { 
     var eventNum = rd/size; 
     Console.WriteLine($"[Events] {eventNum}"); 
     var event_ptr = buffer_ptr; 
     for (int i = 0; i < eventNum; i++) 
     { 
     var entry = Marshal.PtrToStructure<InputEvent>(event_ptr); 
     Console.WriteLine($"code: {entry.code} | type: {entry.type} | value: {entry.value}"); 
     event_ptr = IntPtr.Add(event_ptr, size); 
     } 
    } 
    } 

Mit freundlichen Grüßen!

+0

Danke @cmello! Das hat wie ein Zauber funktioniert :) –

Verwandte Themen