2015-11-02 9 views
8

diese Frage zurückkommen wird, um die 'neuen' D verweisen: DMD32 Dmit D Schnittstelle richtig ein Array von Struct

für TL v2.068.2 Compiler; DR, wenn Sie Details brauchen nicht überspringen auf die Frage, unter

mit Visual Studio arbeiten (i v2010 verwende), durch eine new project Erstellung ->D ->Dynamic Library

, wenn das Projekt Creartion Prozess abgeschlossen ist, in der Lösung Explorer gibt es zwei Dateien:

  • dllmain.d
  • dll.def

die .def Datei zu verlassen, wie es ist, ich habe es geschaffen, zu verstehen, dass durch Hinzufügen neuer Funktionen zum dllmain.d und prefexing mit:

extern (Windows) export 

exportiert die Funktion und kann von c# aufgerufen werden, nicht mit C oder C++.

Seitennotiz, berühren Sie keinen der vorhandenen Code, wenn Sie nicht wissen, was Sie tun.

so der Code funktioniert wie unten

extern (Windows) export uint D_mathPower(uint p) 
{  
    return p * p; 
} 

erwartet es von C# mit der folgenden Signatur Aufruf:

[DllImport(@"pathTo...\DynamicLib1.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity] 
    public static extern uint D_mathPower(uint p); 

ich einfach es verwenden könnte wie folgt:

uint powD = D_mathPower(5); 

meine Frage ist

Wie gebe ich ein Array von Strukturen zurück (vorzugsweise die kostengünstigste Methode)?

struct dpack{ char* Name; uint Id; } 

i verwendet haben versucht, beide char[] und char* aber ohne Erfolg.

ist dieser Code meine bisher

extern (Windows) export 
dpack[] D_getPacks(uint size) 
{ 
    dpack[] rtDpArr = new dpack[size]; 
    char[] str = "someText".dup; 

    for(uint i=0; i<size; i++) 
    { 

     str[$ - 1] = cast(char)('0' + i % (126 - '0')); 
     rtDpArr[i].Id = i; 
     rtDpArr[i].Name= str.dup; 
    } 
    return rtDpArr; 
} 


void getPacksPtr(uint size, dpack** DpArr) 
{ 
// this is the signature i have successfully implemented via c++ 
} 
+0

D-Arrays in eine andere Sprache zurückkehren kann funktionieren, aber in der Regel nicht der Fall ist, weil die ABI Details nicht unbedingt übereinstimmen. Versuchen Sie, Ihren eigenen Strukturtyp mit Zeiger und Länge für das Interop zu erstellen oder machen Sie etwas wie 'getArray (size_t * lengthPtr, dpack ** ptrPtr) {* lengthPtr = array.length; * ptrPtr = array.ptr; } ' –

+0

Sie sollten üben, eine C-DLL zu erstellen und in C# zu verwenden, bevor Sie es mit einer D-DLL versuchen. Finden Sie heraus, wie C-Funktionen verwendet werden, die "Arrays" aus C# zurückgeben, und verwenden Sie dieselbe Technik in D. C# hat keine Kenntnis davon, wie D Slices speichert, so dass Sie sie nicht so verwenden können, wie sie sind. –

Antwort

1

Da ein D-Array ein spezielles Layout hat, sollte man lieber einen Zeiger auf das erste Element zurück. Dann in C# können Sie jedes Element aus dem Basiszeiger werfen durch das Lese 8 Byte pro 8 Byte (dies entspricht dpack.sizeof), da Sie bereits die Zählung wissen:

struct dpack{ immutable(char)* Name; uint Id; } 

extern (Windows) export 
void* D_getPacks(uint count) 
{ 
    dpack[] rtDpArr = new dpack[count]; 
    char[] str = "someText".dup; 

    import std.string; 
    for(uint i=0; i<count; i++) 
    { 
     rtDpArr[i].Id = i; 
     // add a trailing '\0' 
     rtDpArr[i].Name = toStringz(str); 
    } 
    // pointer to the first item 
    return rtDpArr.ptr; 
} 

Auch das .Name Mitglied werfen es notwendig ist, ein hinzufügen Terminator, sonst kann man die Länge der Zeichenfolge nicht kennen.Dies geschieht durch std.string.toStringz, die ein Nullzeichen am Ende der Zeichenfolge hinzufügen wird. Das Element char* Name kann dann wie gewöhnlich Zeichenfolgen umgewandelt werden, die von einer Funktion in einer DLL mit einer C-Schnittstelle bereitgestellt werden.

+0

hey danke @Nested type..für den Code habe ich so viele Varianten getestet, aber keine 'std.string' enthalten Ich habe deinen Code ausprobiert, nachdem ich bereits eine Antwort gefunden habe und nach dem Benchmarking gegen' C++ 'implementiert habe, habe ich dann getestet 'std.string' und die Leistung wurde im Vergleich zum' char * '- Feld auf 0,75% gesenkt. und was den schnellsten Code in D angeht (was ich bisher gepostet habe). es ist immer noch langsamer als der schnellste aproach in C++ ist auch 0.75% des 'C++' codes also C++ war 45 ms, 'D (char *) 'war 57 ms, und' D (std.string) 'war 79 ms. –

+0

was ist seltsam ist, dass jedes Mal, wenn ich die Funktion aufrufen der Inhalt ist anders der Schwanz bei Element [0] könnte einmal "G" dann Ausführen es wieder ist es ';' dann ist es wieder nicht stabil G G ', hat es irgendetwas zu tun mit "malloc" ohne "frei" oder was könnte es sein? –

0

Dies ist der effizienteste Weg, den ich implementieren könnte.

extern (Windows) export 
void D_getPacksPtr(uint size, dpack** DpArr) 
{ 
    *DpArr = cast(dpack*) malloc(size * dpack.sizeof); 
    dpack* curP = *DpArr; 
    char[] str = "abcdefghij".dup; 
    uint i=0; 
    while(i!=size){ 
     str[$ - 1] = cast(char)('0' + i % (126 - '0')); 
     curP.Name = cast(char*)str.dup; curP.Id = i; 
     ++i;++curP; 
    } 
} 

    [DllImport(@"PathTo...\DynamicLib1.dll", CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurity] 
    public static extern void D_getPacksPtr(uint size, dpack** DPArr); 

mit es:

dpack* outDpack; 
    D_getPacksPtr(500000, &outDpack); 
Verwandte Themen