2014-12-15 4 views
5

i p verwenden/ruft eine Reihe von "DN_OPstruct" s von meinem nicht verwalteten Code zurück:P/Invoke Zurückgeben Array von Strukturen mit String-Feldern

struct DN_OPstruct { 
    const char* TargetNode_Identifier; 
    const char* Name; 
    int TargetNode_NamespaceIndex; 
    ... 
}; 


EXTERN_C UA_EXPORT_WRAPPER_IMPORT int getOpToArr(const char* _rootGuid, DN_OPstruct ** array, int * arraySizeInElements){   
    std::list<UA_Ref_and_TargetNode> uaList; 
    uaList = getLisT(...) 
    *arraySizeInElements = uaList.size(); 
    int bytesToAlloc = sizeof(DN_OPstruct) * (*arraySizeInElements); 
    DN_OPstruct * a = static_cast<DN_OPstruct*>(CoTaskMemAlloc(bytesToAlloc)); 
    *array = a; 

    for (UA_Ref_and_TargetNode &i: uaList){    
      DN_OPstruct iterOp;  
      iterOp = getOp(...);    
     opList.push_back(iterOp); 

    } 
    return 1; 
} 

Mein Managed-Code wie folgt aussieht:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct DN_OPstruct 
    { 
     private IntPtr TargetNode_Identifier; 
     private IntPtr NamePtr; 

     public string Guid 
     { 
      get { return Marshal.PtrToStringAnsi(TargetNode_Identifier); } 
      set { TargetNode_Identifier = Marshal.StringToHGlobalAnsi(value); } 
     } 

     public string Name 
     { 
      get { return Marshal.PtrToStringAnsi(NamePtr); } 
      set { NamePtr = Marshal.StringToHGlobalAnsi(value); } 
     } 

     public int TargetNode_NamespaceIndex; 
     ... 

    }; 


[DllImport(@"...", CallingConvention = CallingConvention.Cdecl, 
      EntryPoint = "getOpToArr", 
      ExactSpelling = true, CharSet = CharSet.Ansi)] 
     public static extern int getOpToArr([MarshalAs(UnmanagedType.LPStr)]string myNodeGuid, 
      [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] out DN_OPstruct[] array, out int arraySizeInElements); 

Wenn ich versuche, die Methode aufzurufen, werde ich in den nicht verwalteten Code springen und kann es erfolgreich debuggen und ich bekomme ein Array mit meinem DN_OPstructs zurück. Allerdings, wenn ich seine Felder ausgelesen wie .Name oder .Guid, bekomme ich diesen Fehler:

First-chance exception at 0x000007fefd921757 in (...).exe: 0xC0000005: Access violation reading location 0xffffffffffffffff.

If there is a handler for this exception, the program may be safely continued.

Ich habe versucht, „ArraySubType = UnmanagedType.LPStruct“ zu meiner Methode Erklärung hinzuzufügen; Es hat nicht geholfen.

+0

Ich habe gerade Stunden damit verbracht, P/Invoke in einem ähnlichen Szenario arbeiten zu lassen. Ich habe am Ende eine C++/CLR-Wrapper-Bibliothek geschrieben. Ich fand es viel einfacher, mit verwaltetem/nicht verwaltetem Code aus C++ umzugehen. Ich habe einfach alles in ein paar CLR-Klassen abgebildet, und wenn Sie ref zu diesem Projekt hinzufügen, können Sie diese Klassen verwenden, als wären sie C# (weil sie .NET-kompatibel geschrieben sind). – AlexanderBrevig

Antwort

1
public static extern int getOpToArr(
    [MarshalAs(UnmanagedType.LPStr)] 
    string myNodeGuid, 
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] 
    out DN_OPstruct[] array, 
    out int arraySizeInElements 
); 

Das Problem ist der zweite Parameter. Der nicht verwaltete Code kann kein verwaltetes .net-Array synthetisieren. Sie müssen die p/aufrufen wie folgt erklären:

public static extern int getOpToArr(
    string myNodeGuid, 
    out IntPtr arrayPtr, 
    out int arrayLen 
); 

Dann Sie die Elemente des Arrays zu einer verwalteten Array Marschall müssen Marshal.PtrToStructure verwenden.

IntPtr arrayPtr; 
int arrayLen; 
int retval = getOpToArr(nodeGuid, out arrayPtr, out arrayLen); 
// check retval 

IntPtr ptr = arrayPtr; 
DN_OPstruct[] arr = new DN_OPstruct[arrayLen]; 
for (int i = 0; i < arrayLen; i++) 
{ 
    arr[i] = (DN_OPstruct)Marshal.PtrToStructure(ptr, typeof(DN_OPstruct)); 
    ptr += Marshal.SizeOf(typeof(DN_OPstruct)); 
} 

Ich bin auch ein wenig skeptisch gegenüber den Eigenschaften in Ihrer Struktur. Warum hast du sowohl Setter als auch Getter? Es sieht nicht so aus, als würden die Daten in diese Richtung fließen. Und der nicht verwaltete Code, den Sie verwenden, zeigt die Zuordnung mit CoTaskMemAlloc, die nicht StringToHGlobalAnsi entspricht. Auch wenn ich bezweifle, dass Sie Einstellungen schreiben sollten und daher vielleicht die Anrufe zu StringToHGlobalAnsi entfernen sollten, vermute ich auch, dass es Verwirrung über den Zuordner gibt, den Sie verwenden.

Beachten Sie, dass der Code in Ihrer Frage keinen Hinweis darauf gibt, wie Sie das Array zugewiesen haben, das an den Aufrufer zurückgegeben wird. Nach allem, was wir wissen, könnte es in diesem Teil des Codes ein Problem geben.

+0

Ich benutze die Setter in einem anderen Kontext, in was ich die Eigenschaften von meinem verwalteten zu unm geben. Code. Leider bekomme ich den gleichen Fehler mit Ihrem Code-Vorschlag ... – Pepelee

+0

Ich schlage vor, dass Sie ein Debuggen tun. Sie haben nicht den gesamten Code angezeigt, sodass wir nicht wissen können, ob Sie einen Fehler gemacht haben oder nicht. Zum Beispiel kann ich nur davon ausgehen, dass Sie das Array von Strukturen korrekt im nicht verwalteten Code gefüllt haben. Aber es gibt keinen Beweis dafür, dass du irgendetwas davon getan hast. Sie haben es auch versäumt zu zeigen, wie Sie die Funktion aufrufen. Viel Glück. –

+0

Ich würde gerne alle relevanten Details veröffentlichen, aber es würde die Form eines SO-Threads brechen. Aber danke für deinen Codevorschlag, ich kann jetzt ruhig nach anderen möglichen Fehlern suchen – Pepelee