2010-12-13 3 views
4

Meine Frage ist ein wenig allgemein, also bin ich nicht für eine exakte Antwort suchen, aber möglicherweise einige Richtungen zu prüfen, dass mir helfen ...C# DllImport Probleme

An meinem Arbeitsplatz I-Programm vor allem in C#. Wir haben diese 3rd-Party-Firma, mit der wir arbeiten, die uns eine native C++ - DLL gab, die wir verwenden müssen. Da die C++ - Methode, die ich brauchte, nicht in einer Weise offengelegt wurde, die leicht aus C# referenziert werden konnte, habe ich die DLL in eine andere Native C++ - DLL geschrieben.

So jetzt habe ich 2 Native C++ dlls, eine die andere Verpackung.

Ich habe eine kleine C# -Konsolenanwendung erstellt, die die Methode aufruft, die ich in C++ erstellt habe. Meine Methode Signatur wie folgt aussieht:

[DllImport("HashMethodWrapper.dll")] 
[return: MarshalAs(UnmanagedType.LPStr)] 
private static extern string CreateHash(
      string input, 
      [MarshalAs(UnmanagedType.LPStr)]StringBuilder output); 

In meiner Konsolenanwendung, funktioniert alles in Ordnung, und ich immer die Zeichenfolge im im Ergebnis erwartet erhalten.

Aber wenn ich es zu einem Webdienst oder einer Webanwendung verschiebe, die ich erstellt habe (da dies ist, wo ich es wirklich brauche), sehe ich, dass die Zeichenfolge im Empfangen ist Müll und nicht einmal konsistent. Es scheint, als würde ich nur einen Verweis auf Speicher bekommen, der verloren ist oder so etwas, aber das ist nur eine Vermutung von mir ...

Ich weiß nicht, warum das passiert, da in meiner Konsolenanwendung alles funktioniert fein.

Hat eine Richtung jemand, der mir helfen könnte ??? ...

Vielen Dank im Voraus, gillyb

Edit: ich dachte, es könnte mit einigen nicht fixierten Objekten zu tun haben, Also habe ich versucht, die Methode in einer festen Anweisung, etwa wie folgt aufzurufen:

... aber das tat es immer noch nicht für mich. Ist das der richtige Weg, um Objekte zu fixieren?

2. Edit: Die Methodensignatur in C++ wie folgt aussieht:

extern "C" __declspec(dllexport) char *CreateRsaHash(char *inputPass, char *hashPass); 

3. Edit: ich die Signatur der Methode

extern "C" __declspec(dllexport) bool CreateRsaHash(char *inputPass, char *hashPass); 

und die geändert werden Rückgabewert, den ich suche, wird in den Parameter *hashPass gesetzt.

Jetzt habe ich eine einfache Konsolenanwendung erstellt, um es zu testen. Wenn ich den DllImport in meine Hauptklasse einfüge und direkt die Methode aufruft, funktioniert alles super, aber wenn ich den DllImport verschiebe und die Methode in eine andere Klasse bringe und diese Klasse über die 'Main'-Methode der Konsole aufruft, bekomme ich eine StackOverflow-Ausnahme!

Wer hat irgendwelche Ideen, warum das passiert?

+0

Können Sie uns zeigen, wie der Funktionsheader in C/C++ deklariert wird. Das könnte helfen :) –

+0

Töte den API-Autor, es ist ein sehr klares Speicherleck passiert ... – leppie

+0

Warum ??? Kannst du bitte erklären warum und warum ist das so klar von der Signatur? Hoffentlich können wir es noch reparieren! – gillyb

Antwort

0

Ich fand die Lösung für mein Problem, und jetzt fühle ich mich irgendwie (wenn nicht wirklich!) Dumm ...: - |

Ich verwendete die LoadLibrary() Methode in C++, um eine Methode von der anderen nativen DLL dynamisch aufzurufen. Das Problem war, dass ich der Methode keinen Pfad und nur den DLL-Dateinamen gegeben habe. In .net würde es im aktuellen Ordner gesucht haben, scheint aber im nativen Code nicht so zu funktionieren.

Das größere Problem in meinen Programmierpraktiken ist offensichtlich die Tatsache, dass ich die Fehlerbehandlung in meiner nativen C++ - DLL nicht vollständig behandelt habe! Alle

die asnwers ich auf dieser Seite erhielten, waren aber nicht umsonst ...

Nachdem ich herausgefunden habe, dass ich Problem mit dem Verzeichnispfad hatte, lief ich in verschiedene Ausnahmen zu versuchen, korrupten Speicher zuzugreifen, usw. Und dann musste ich gepinnte Objekte erstellen und eine Größe für mein StringBuilder-Objekt deklarieren.

Danke an alle für Ihre Hilfe !!

:)

+0

Schön. Gut gemacht. –

1

Es ist wirklich schwer, von den spärlichen Informationen zu wissen, aber wenn ich raten müsste, würde ich sagen, dass Sie sicherstellen müssen, dass Sie das Ausgabeobjekt festhalten.Auch würde ich wahrscheinlich den Ausgabeparameter zu einem anderen Typ ändern, es scheint ziemlich seltsam, dass StringBuilder überhaupt aufrichtig arbeitet.

Ich weiß, dass wenn Sie ein Objekt zuweisen, wird es einen Zeiger bekommen, aber das bedeutet nicht, dass es sich nicht bewegt. Wenn Sie also versuchen, einen Zeiger auf ein verwaltetes Objekt in eine nicht verwaltete Umgebung zu übergeben, müssen Sie sicherstellen, dass Sie dem GC mitteilen, dass er den Speicher "anheften" soll, damit er nicht unter Ihnen ausgefahren wird.

Hier ist eine wirklich grobe Version von dem, was ich damit meinen Pinning:

string input = "..."; 
StringBuilder output = new StringBuilder(); 
var handle = System.Runtime.InteropServices.GCHandle.Alloc(output, GCHandleType.Pinned); 
try 
{ 
    CreateHash(input, output); 
} 
finally 
{ 
    handle.Free(); 
} 
+0

Nun, über den StringBuilder, las ich irgendwo, dass ich einen Stringbuilder benötigen würde, wenn der Wert sich ändert, da 'String' unveränderlich ist und in diesem Fall den Job nicht ausführen wird. Ist das wahr ? – gillyb

+0

Und über das gepinnte Objekt dachte ich, dass das das Problem sein könnte, also versuchte ich etwas zu pinnen. Ich werde es zu meiner Frage hinzufügen, können Sie mir bitte sagen, was ist der Unterschied zwischen dem, was ich getan habe und was Sie mir mit GCHandle gezeigt haben? – gillyb

+0

Zwei Dinge: Sie haben das Zeichen * gepinnt, aber nicht den StringBuilder.Warum haben Sie auch den StringBuilder, der 'Ausgabe' und auch ein Rückgabewert genannt wird? Es sieht so aus, als ob Sie den StringBuilder vollständig ignorieren und nur den Rückgabewert zurückgeben. –

0

ich in einer C# freigegebenen Assembly/DLL anstelle einem C++ dll und dann versuchen, verziehen hielte zu Ihrer Konsole-Anwendung zu erhalten, arbeite mit der dll. Es empfiehlt sich, externe Abhängigkeiten trotzdem auf diese Weise zu umbrechen.
Sonst sind einige traditionelle Probleme 32 vs 64 Bit, der Ladepfad zu der gemeinsam genutzten Bibliothek. Ist es wirklich nur eine Zeichenfolge oder etwas komplexer?