2012-04-11 21 views
0

Was ist das geeignete Signatur/Marshall-Attribut, um Ausgabe-Parameter mithilfe von Zeigern params zu bekommen? Bisher habe ich versucht, dies:DllImport, wie man einzelne Werte als Referenz erhält

// Function to calculate the norm of vector. !0 on error. 
// int err_NormVec(int size, double * vector, double * norm) 
[DllImport("vectors.dll")] 
int err_NormVec(int size, double[] vector, ref double norm) 

Der bisherige Ansatz nicht den Wert Pop zurück von C auf .NET Ich habe auch versucht GCHandle, mit der IntPtr Unterschrift gepinnt zu verwenden.

[DllImport("vectors.dll")] 
int err_NormVec(int size, double[] vector, IntPtr norm) 

public void doSomething() 
{ 
    double norm = 0; 
    // ... 
    GCHandle handle = GCHandle.Alloc(norm, GCHandleType.Pinned); 
    int status = err_NormVec(vector.Lenght, vector, handle.AddrOfPinnedObject()); 
    // ... clean gchandle, check status and so on 
} 

In diesem Fall habe ich den Wert zurück bekam aber auf der GCHandle.Target, nicht auf der ursprünglichen Norm. Was nervt. Ich würde gerne in der Lage sein, die intptr der Norm selbst nicht nur eine Kopie zu setzen.

Was ist die geeignete Signatur, um einen Wert mit einem Zeiger zurückzugeben? Gibt es eine unterstützte Möglichkeit, IntPtr auf einen int-Wert zu setzen? Diese

+0

Ich habe vergessen zu erwähnen, dass ich win64 benutze. Das enthüllt einige schlechte Praktiken, die glücklicherweise auf Win32-Anwendungen arbeiten. – fprades

+0

Zeigen Sie uns die Implementierung (oder zumindest die Signatur) von 'err_NormVec'. Sie müssen kein Double festhalten, um es als Out-Parameter zu verwenden, "ref" reicht aus. –

+0

@EdS .: Sind Sie blind? – leppie

Antwort

1

funktioniert für mich (wie es sein soll):

//C++ DLL (__stdcall calling convention) 
extern "C" __declspec(dllexport) void Foo(double *result) { 
    *result = 1.2; 
} 

//C#  
class Program 
{ 
    [DllImport("Snadbox.dll", CallingConvention=CallingConvention.StdCall)] 
    static extern void Foo(ref double output); 

    static void Main(string[] args) 
    { 
     double d = 0;   
     Foo(ref d); 

     Console.WriteLine(d); // prints "1.2"   
    } 
} 

Vorbei an die double mit dem ref Schlüsselwort ausreichend ist. Ich bin also zu der Überzeugung gelangt, dass bei der Implementierung etwas falsch (oder falsch verstanden) ist. Können Sie die Implementierung für uns posten?

Vielleicht erstellen Sie auch die C++ - Version mit der Standard-Aufrufkonvention (cdecl), aber .NET verwendet StdCall. Hast du sichergestellt, dass diese Line-Ups? Sie können abstürzen, wenn sie gemischt sind, aber es gibt keine Garantie. Zum Beispiel, in meinem Beispiel, wenn ich die C++ Seite zu cdecl ändere, dann wird der out-Parameter als 0 zurückgelesen.

+0

Die Implementierung ist unbedeutend imo, das ist nur ein Beispiel, wie in Wirklichkeit ist es eine sehr komplexe Bibliothek. Wenn Sie so wollen, wird eine Implementierung sein: int err_NormVec (int size, double [] vector, double * norm) (* norm = 0; für (int i = 0; i fprades

+0

@ fprades.bbva: Nun, und ich will nicht unhöflich klingen, aber deine Meinung hat wenig Gewicht, da du nicht Ich weiß, warum das nicht funktioniert. Ich habe dir gezeigt, dass ein vereinfachtes Beispiel funktioniert, also stimmt etwas anderes nicht und du hast uns nicht genug Informationen gegeben, um zu wissen, was das ist. Außerdem ist der Ausschnitt, den Sie mir gaben, falsch, da Sie den Zeiger selbst hinzufügen, ohne ihn zu dereferenzieren. –

+0

Das würde auch funktionieren. Aber aus irgendeinem Grund nicht in x64-Laufzeit. Ungerade. Vielleicht habe ich etwas mit all dem Versuch und Irrtum verpasst. – fprades