2010-12-09 18 views
3

Ich werde übernächtigt versuchen herauszufinden, warum ich nicht eine externe Methode in einer alten C++ DLL aus meiner C# -Anwendung aufrufen kann.Schwierigkeit Aufruf unmanaged DLL aus C#

Hier ist der Funktionskopf:

int __export FAR PASCAL SimplePGPEncryptFile(
             HWND hWnd1, 
             LPSTR InputFileName, 
             LPSTR OutputFileName, 
             BOOL SignIt, 
             BOOL Wipe, 
             BOOL Armor, 
             BOOL TextMode, 
             BOOL IDEAOnly, 
             BOOL UseUntrustedKeys, 
             LPSTR RecipientList, 
             LPSTR SignerKeyID, 
             int SignerBufferLen, 
             LPSTR SignerPassphrase, 
             int SignerPwdBufferLen, 
             LPSTR IDEAPassphrase, 
             int IDEAPwdBufferLen, 
             LPSTR PublicKeyRingName, 
             LPSTR PrivateKeyRingName); 

meine C# Erklärung hier:

 [DllImport("smplpgp_32.dll", CallingConvention = CallingConvention.StdCall)] 
    public static extern int SimplePGPEncryptFile(
     IntPtr hWnd1, 
     [MarshalAs(UnmanagedType.LPStr)] string InputFileName, 
     [MarshalAs(UnmanagedType.LPStr)] string OutputFileName, 
     bool SignIt, 
     bool Wipe, 
     bool Armor, 
     bool TextMode, 
     bool IDEAOnly, 
     bool UseUntrustedKeys, 
     [MarshalAs(UnmanagedType.LPStr)] string RecipientList, 
     [MarshalAs(UnmanagedType.LPStr)] string SignerKeyID, 
     int SignerBufferLen, 
     [MarshalAs(UnmanagedType.LPStr)] string SignerPassphrase, 
     int SignerPwdBufferLen, 
     [MarshalAs(UnmanagedType.LPStr)] string IDEAPassphrase, 
     int IDEAPwdBufferLen, 
     [MarshalAs(UnmanagedType.LPStr)] string PublicKeyRingName, 
     [MarshalAs(UnmanagedType.LPStr)] string PrivateKeyRingName); 

Wenn ich diese Methode aufrufen, ich bin einer der beiden folgenden Fehler bekommen (im Header angegeben):

#define SIMPLEPGPENCRYPTFILE_RECIPIENTLISTDOESNOTENDWITHNEWLINE 408 
#define SIMPLEPGPENCRYPTFILE_RECIPIENTLISTDOESNOTSTARTWITHGOODCODECHAR 409 

Dies wird auch als konstante im Header definiert:

#define INCLUDE_ONLYUSERIDS 1 

Dies ist C++ Code, der diese Funktion zu arbeiten bekannt ruft:

char recipients[512]; 
recipients[0] = INCLUDE_ONLYUSERIDS; 
strcat(strcpy(&recipients[1], rID), "\n"); \\ rID is equal to "CA" 
return 0 == SimplePGPEncryptFile(INI.m_hWnd, 
    (char*)plain, (char*)cipher, 
    0, 
    0, 
    1, 
    0, 
    0, 
    1, // UseUntrustedKeys 
    recipients, 
    0, 0, 
    0, 0, 
    0, 0, 
    PGPKM.pub, 0); //PGPKM.pub is declared earlier 

diese Passing für den Parameter 'RecipientList' gibt mir die '409' Fehler:

string recipientList = "1CA\n\0"; 

Passing Dies für den 'RecipientList' Parameter gibt mir den '408' Fehler:

char[] recipients = new char[512]; 
recipients[0] = '1'; 
recipients[1] = 'C'; 
recipients[2] = 'A'; 
recipients[3] = '\n'; // also tried '\r', then '\n' 
recipients[4] = Char.MinValue; 
string paramValue = recipients.ToString(); 

Kann mir jemand ein offensichtliches Versehen vorwerfen? Ich fühle mich, als hätte ich alles, was ich brauche, um das zu lösen, aber nichts funktioniert wie erwartet.

Seitennotiz: Ich rufe erfolgreich eine andere Funktion in derselben .dll auf. Außerdem habe ich experimentiert, StringBuilder zu verwenden, um den RecipientList-Parameter zu erstellen.

Vielen Dank für Anregungen!

+1

Empfänger [0] = INCLUDE_ONLYUSERIDS; - Verwandelt sich das nicht in Empfänger [0] = 1; was ist anders als Empfänger [0] = '1'; - das C# -Aquivalent wäre Empfänger [0] = (char) 1; – jeffora

+0

Was ist der Zweck der Empfänger [4] = Char.MinValue ;? –

+0

Im Code, der funktioniert, die Zeile strcat (strcpy (& recipient [1], rID), "\ n"): Wie sieht die resultierende Zeichenfolge aus, d. H. Wo wurde \ n kopiert? Nach 512 Bytes? Oder ist es schlau genug, jeden Teil der Empfänger [] zu kürzen? Schon eine Weile her, seit meinen C++ Tagen, verzeih mir –

Antwort

2

TLDR:

string recipientList = (char) 1 + "CA\n\0"; 

habe einige graben basierend auf Jeffora Kommentar ... Er ist wahrscheinlich richtig, mein erster Vorschlag wahrscheinlich werden Sie nicht kaufen nichts. Ich einige Test-Code geschrieben, hier ist was ich gefunden habe:

Wenn Sie diesen Code verwenden:

string recipientList = "1CA\n\0"; 

Die Bytes, die Sie mit auf der Innenseite der Funktion am Ende nach als LPSTR Marshalling sind:

49-67-65-10-0 

Was aussieht wie du willst.

Wenn Sie diesen Code:

char[] recipients = new char[512]; 
recipients[0] = '1'; 
recipients[1] = 'C'; 
recipients[2] = 'A'; 
recipients[3] = '\n'; // also tried '\r', then '\n' 
recipients[4] = Char.MinValue; 
string paramValue = recipients.ToString(); 

Die Bytes, die Sie auf der Innenseite der Funktion erhalten, nachdem als LPSTR Marshalling sind:

83-121-115-116-101-109-46-67-104-97-114-91-93 

Welche ist ASCII für „System.Char [ ] ". Sie müssen also unbedingt einen Encoder verwenden, um das Zeichen [] in die gewünschte Zeichenfolge umzuwandeln.

Warum der erste String nicht funktioniert ... Ich vermute, dass Ihre DLL wirklich nach dem Wert '1' sucht, und nicht das ASCII-Zeichen für '1' (49). In dem Code, der funktioniert, sagen Sie:

recipients[0] = INCLUDE_ONLYUSERIDS; 

wo INCLUDE_ONLYUSERIDS = 1

Try this:

string recipientList = (char) 1 + "CA\n\0"; 


Ursprüngliche Antwort:
ich das Problem glauben, dass Char.ToString() behandelt das Zeichen als ein Unicode-Zeichen, aber Sie Marshalling als LPStr, nicht LPWStr. LPStr sucht nach einer Reihe von ANSII-Zeichen.

Um dies zu beheben, versuchen Sie es mit einem Byte-Array.

byte[] recipients= new byte[512]; 
... 
// Pass this string to SimplePGPEncryptFile 
string recipientsToPass = System.Text.ASCIIEncoding.ASCII.GetString(recipients); 

+0

Ziemlich sicher, dass der Marshaller das Marshalling von .NET-Unicode-Strings zur angeforderten ASCII-Zeichenfolge durchführt, da er über die MarshalAs-Attribute angegeben hat, dass der Stringtyp ASCII lautet: http://msdn.microsoft.com/en-us/library /system.runtime.interopservices.unmanagedtype.aspx – jeffora

+0

Hmm, ja, du hast recht, das kauft dir wahrscheinlich kein verdammtes Ding. Ich sollte aufhören zu versuchen, Fragen nach Mitternacht zu beantworten: P –

+0

Aber fügt der Marshaller auch die 0 am Ende der Zeichenfolge automatisch hinzu? Ich denke, das ist es, was er mit Empfängern versucht [4] = Char.MinValue; –

0

Haben Sie versuchen, die Aufrufkonventionen zu ändern? In C++ deklarieren Sie die Funktion mit Pascal Aufruf Konvention und in C# als Stdcall. Die Aufrufkonvention muss übereinstimmen.