Frage

** MAJOR UPDATE ** Ich habe einen kleinen Fehler, aber ich bin immer noch neugierig, was genau passiert ist.

Die Funktion Ich bin Aufruf ist eigentlich „fooV“, eine Funktion mit dieser Signatur:

foo(const char *, const char *, EnumType, va_list)

Dies löscht die AccessViolationExceptions bis ich war immer, aber nicht erklären, warum params Parameter für jeden anderen .NET-Typen arbeiten mit Ausnahme von Strings, den Multibyte-ANSI-Zeichen umgewandelt werden müssen. Ich werde an den Entwickler der DLL bekommen, um die Version zu machen, die tatsächlich verwendet ... in der Parameterliste, keine Hinweise für PInvoking wenn va_list die Parameter?

** alte Post **

Dies bezieht sich auf, aber unterscheidet sich von einem letzten Frage ich fragte .

Ich habe PInvoke verwenden, um eine C-Library-Funktion aufrufen, die die folgende Signatur hat:

foo(const char *, const char *, EnumType, ...)

Die Funktion konfiguriert eine Ressource in einer Art und Weise, die von StructType variiert; der Fall ich interessiert konfiguriert etwas, das die varargs erwartet ein einzelner ANSI Multibyte-String zu sein. Ich habe diese PInvoke Signatur, um die Funktion aufzurufen:

    [DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo")]
    public static extern int Foo(string s1, string s2, EnumType st1, params string[] s3);

Die params string[] schien mir seltsam, aber vorherigen Signaturen, die diese Funktion genannt wurden sie für andere Arten wie bool mit so ich das Muster gefolgt.

Ich wickle diese mit einer freundlicheren .NET-Methode:

public void Foo(string s1, string s2, string s3)
{
    int error = Dll.Foo(s1, s2, EnumType.Foo, s3);
    // handle errors
}

Vor kurzem änderte ich die Unterschrift „BestFitMapping = false, ThrowOnUnmappableChar = true“ in dem DLLImport enthalten Attribut mit FxCop Vorschlägen nachzukommen. Dies ist eine falsche Fährte, wie ich später beschreiben wird.

Was ich erwarte, dass sich diese Änderung zu machen ist eine begrenzte Unterstützung für Unicode. Zum Beispiel auf einer Maschine mit einem englischen Codepage wird eine Ausnahme ausgelöst, wenn Sie eine Zeichenfolge übergeben, die ein japanisches Zeichen enthält. Auf einer japanische Maschine würde ich erwarten, dass eine japanische Zeichenfolge an die Funktion nutzen können passieren. Der englische Test funktionierte wie erwartet, aber der japanische Test wirft einen System.Runtime.InteropServices.COMException mit HRESULT 0x8007007a. Dies geschieht auch ohne die BestFitMapping und ThrowOnUnmappableChar Einstellungen.

Ich habe ein wenig getan, sah sich um und einige Seiten gesehen, die Sie vorgeschlagen konnte PInvoke varargs durch ganz normale Argumente spezifiziert, so habe ich versucht, diese Signatur:

[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo")]
public static extern int Foo(string s1, string s2, EnumType st1, string s3);

Dies wirft einen Access, wenn ich es verwenden, entweder auf Englisch oder Japanisch Maschine.

Ich kann nicht UTF-8 oder eine andere Unicode-Codierung verwenden, da diese C-Bibliothek erwartet und behandelt nur multibyte ANSI. Ich habe das funktioniert für diese Funktion vornehmen CharSet.Unicode gefunden, aber ich mache mir Sorgen, es ist nur durch Zufall und nicht etwas, auf die ich mich verlassen sollte. Ich habe darüber nachgedacht, um die Zeichenfolge zu einem byte [] Umwandlung der System-Codepage verwendet, kann aber nicht herausfinden, wie ich angeben mag, dass ein Byte-Array an dem varargs Parameter zu übergeben.

Was ist los? Auf der englischen Maschine arbeiten englische Zeichen fein und japanisches charactes ein Argument werfen, wie erwartet. Auf der japanischen Maschine arbeiten englische Zeichen fein und japanische Schriftzeichen werfen die COMException. Gibt es etwas falsch mit meiner PInvoke Signatur? Ich habe versucht, das MarshalAs Attribut auf eine Art LPArray und Subtyp von LPSTR angeben, aber dies nicht in gleicher Weise. UnmanagedType.LPStr gibt es einen Single-Byte-ANSI-String ist; ist es eine Möglichkeit, einen Multibyte ANSI-String?

angeben

** UPDATE ** Hier ist ein Zusatz von Sachen aktuelle Kommentare zu berücksichtigen.

Wenn ich eine Aufrufkonvention von CDecl angeben und normalen Parameter wie folgt erfolgen:

[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo", CallingConvention = CallingConvention.Cdecl)]
public static extern int Foo(string s1, string s2, EnumType e1, string s3) 

Wenn ich diese Spezifikation verwenden, erhalte ich eine Access. Also habe ich versucht diese:

[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo", CallingConvention = CallingConvention.CDecl)]
public static extern int Foo(string s1, string s2, EnumType e1, string s3) 

Dies funktioniert für Englisch und führt die COMException wenn ich japanische Zeichen verwendet werden.

Das einzige, was ich gefunden habe, dass works konsequent ist diese:

[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo", BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int Foo(string s1, string s2, EnumType e1, params IntPtr[] s3)

Um diese Arbeit zu machen, verwende ich Marshal.StringToHGlobalAnsi () und den Zeiger übergeben. Dies funktioniert für Englisch und Japanisch. Ich bin nicht zufrieden mit nicht zu verstehen, warum dies die Lösung, aber es funktioniert.

War es hilfreich?

Lösung

Sie wahrscheinlich auch CallingConvention=CallingConvention.Cdecl angeben müssen, da eine varargs Funktion eine _cdecl Aufrufkonvention verwenden (die Standardeinstellung ist Winapi, die wiederum standardmäßig StdCall).

Sie können etwas anderes brauchen, aber ich bin mir ziemlich sicher, dass Sie zumindest, dass benötigen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top