pinvokestackimbalance - wie kann ich das beheben oder ausschalten?

75

Ich habe gerade von vs2008 zu vs2010 gewechselt. Genau dieselbe Lösung, außer dass jetzt jeder einzelne Aufruf einer C ++ - DLL eine Ausnahme für "pinvokestackimbalance" ergibt.

Diese Ausnahme wird 2008 nicht ausgelöst. Ich habe vollständigen Zugriff auf die C ++ - DLL und die aufrufende Anwendung. Es scheint kein Problem mit dem Pinvoke zu geben, aber dieses Problem macht das Debuggen anderer Probleme unmöglich. Die IDE hält ständig an, um mir von diesen Dingen zu erzählen.

Hier ist zum Beispiel die C # -Signatur:

    [DllImport("ImageOperations.dll")]
    static extern void FasterFunction(
        [MarshalAs(UnmanagedType.LPArray)]ushort[] inImage, //IntPtr inImage, 
        [MarshalAs(UnmanagedType.LPArray)]byte[] outImage, //IntPtr outImage, 
        int inTotalSize, int inWindow, int inLevel);

So sieht es auf der C ++ - Seite aus:

#ifdef OPERATIONS_EXPORTS
#define OPERATIONS_API __declspec(dllexport)
#else
#define OPERATIONS_API __declspec(dllimport)
#endif
extern "C" {


OPERATIONS_API void __cdecl FasterFunction(unsigned short* inArray, 
                                       unsigned char* outRemappedImage,
                                       int inTotalSize, 
                                       int inWindow, int inLevel);

}

Was ist anders zwischen vs2010 und vs2008, was dazu führen würde, dass diese Ausnahmen ausgelöst werden? Sollte ich der DllImport-Direktive einen anderen Parametersatz hinzufügen?

mmr
quelle

Antworten:

145

Verstehen Sie zunächst, dass der Code falsch ist (und immer war). Das "pInvokeStackImbalance" ist an sich keine Ausnahme, sondern ein verwalteter Debugging-Assistent. In VS2008 war es standardmäßig deaktiviert, aber viele Leute haben es nicht aktiviert, daher ist es in VS2010 standardmäßig aktiviert. Der MDA wird nicht im Release-Modus ausgeführt und wird daher nicht ausgelöst, wenn Sie ihn für den Release erstellen.

In Ihrem Fall ist die Aufrufkonvention falsch. DllImportDer Standardwert CallingConvention.WinApiist identisch mit CallingConvention.StdCallx86-Desktopcode. Es sollte sein CallingConvention.Cdecl.

Dies kann durch Bearbeiten der folgenden Zeile [DllImport("ImageOperations.dll")]erfolgen:

[DllImport("ImageOperations.dll", CallingConvention = CallingConvention.Cdecl)]

Weitere Informationen finden Sie in dieser MSDN-Referenz

Stephen Cleary
quelle
Vielen Dank! Die Ausnahmen haben definitiv aufgehört zu schießen. Vielleicht löst dies auch einige der langfristigen Stabilitätsprobleme, die wir hatten.
mmr
4
Gut möglich. Diese besondere Art von Stapelungleichgewicht ist tatsächlich etwas häufig; Es verursacht nicht sofort Fehler, sondern verbraucht langsam den Stapel des Threads. Schließlich werden "schlechte Dinge" passieren. Die CLR ist normalerweise in der Lage, ein StackOverflowException, aber using, zu erhöhen catch, und finallyBlöcke erschweren die Sache wirklich, wenn der Stapel voll ist. Aus diesem Grund wird ab .NET 2.0 StackOverflowExceptionder Prozess nur beendet.
Stephen Cleary
Weitere Informationen zu Interop-Anrufkonventionen finden Sie hier .
Drew Noakes
Hervorragend, dies hat mich in die richtige Richtung gelenkt, nachdem ich versucht hatte, einige Projekte auf .Net 4.0 zu aktualisieren. Nachdem Cdeclich die Aufrufkonvention in der C # -Quelle in geändert hatte, musste ich eine Änderung an unseren * .h- und * .c-Dateien vornehmen, um '__cdecl` zu verwenden.
IAbstract
Vielen Dank! Diese Antwort hat den Tag gerettet. In meinem Fall trat das Problem durch Verweisen auf eine Visual C ++ 8.0-DLL (Visual Studio 2008) in einem Visual Studio 2010-Projekt auf.
Schrockwell
42

So schalten Sie es aus:

  1. STRG + ALT + E.
  2. Deaktivieren Sie unter "Managed Debugging Assistants" das Kontrollkästchen PInvokeStackImbalance.
JGogel
quelle
3
Niemals, niemals , niemals den Boten erschießen. Ein Stapelungleichgewicht frisst früher oder später Ihre Leber mit Fava-Bohnen.
Hans Passant
8

Besser, um dieses Problem zu lösen, es ist hier nicht sehr schwierig. Ich erwähne einige der Methoden, es kann dasselbe sein wie einige meiner oben erwähnten Freunde. Ich arbeite mit PCSC, einer Smartcard-Anwendung, die ich ungefähr eine Woche lang verbringe. Ich bin sauer, habe viele Änderungen vorgenommen und endlich die Lösungen gefunden.

Für mich ist die Arbeit mit PInvoke Extension, die ich für VS2010 installiert habe, hier erhältlich. Http://www.red-gate.com/products/dotnet-development/pinvoke/

Laden Sie es herunter und installieren Sie es. Schließen Sie Visual Studio und öffnen Sie es erneut. Die Erweiterung finden Sie in der Menüleiste. Geben Sie hier die Bildbeschreibung ein

Wenn der Fehler auf eine nicht übereinstimmende Signatur zurückzuführen ist, klicken Sie einfach auf PInvoke.net> PInvoke-Signaturen einfügen

Das neue Fenster wird wie folgt angezeigt Geben Sie hier die Bildbeschreibung ein

Geben Sie den Namen der DLL ein und klicken Sie auf Suchen. Sie können alle Funktionen dieser DLL im Suchergebnisfenster sehen. Klicken Sie auf die Funktion, für die Sie eine Signatur für diese bestimmte Funktion erhalten.

Verwenden Sie diese Signatur, und Sie müssen Ihre Programme entsprechend dieser Signatur, hauptsächlich dem Datentyp, ändern.

Dies löst mein Problem. Möglicherweise haben Sie ein anderes Problem wie das Aufrufen von Convention oder zusätzliche Attribute, die beim Importieren der DLL angegeben werden müssen.

Happy Coding Sei gesund!

AirCodeOne
quelle
Die meisten DLLs können nicht im Suchfenster gefunden werden. Leider sieht es ziemlich ordentlich aus.
rollt
3

Ich habe dieses Problem auch bei der Verwendung von VS2010. Was es ist: Visual Studio verwendet standardmäßig 64-Bit-Code für 'jede CPU'. Die Zeiger auf Variablen (z. B. Zeichenfolgen) werden jetzt 64-Bit, wenn Sie Ihre externen DLLs aufrufen, wobei alle Ihre zuverlässigen und vertrauenswürdigen DLLs 32-Bit-Zeiger verwenden.

Gehen Sie nicht davon aus, dass mit Ihren DLLs etwas nicht stimmt.

Ändern Sie Ihre VS-Einstellungen, um X86-Code wie folgt zu generieren (Express-Versionen von C #).

  1. Gehen Sie zu Extras -> Optionen.
  2. Aktivieren Sie in der unteren linken Ecke des Dialogfelds "Optionen" das Kontrollkästchen "Alle Einstellungen anzeigen".
  3. Wählen Sie in der Baumansicht auf der linken Seite "Projekte und Lösungen".
  4. Aktivieren Sie in den Optionen auf der rechten Seite das Kontrollkästchen "Erweiterte Build-Konfigurationen anzeigen".
  5. OK klicken.
  6. Gehen Sie zu Build -> Configuration Manager ...
  7. Klicken Sie in der Spalte Plattform neben Ihrem Projekt auf das Kombinationsfeld und wählen Sie "".
  8. Wählen Sie in der Einstellung "Neue Plattform" "x86".
  9. OK klicken.
  10. Klicken Sie auf Schließen.

Ich stelle auch fest, dass mein aktueller Computer mit 1 GB RAM nicht schneller zu sein scheint als mein erster 486 mit 4 Meg., Obwohl sich die Leistung der Computer alle 12 Monate verdoppelt hat. Machen Sie sich keine Sorgen um die Verwendung von 64-Bit-Code, er wird nicht schneller oder besser sein, da er auf einem riesigen, schwerfälligen, objektorientierten Turm aus Bloat aufgebaut ist.

Pinguinmann
quelle
1
Danke für die Tipps, ich werde sie überprüfen. Wenn Sie jedoch ein Windows 64-Bit-Betriebssystem mit nur 1 GB RAM ausführen, treten Geschwindigkeitsprobleme auf. Sie sollten ein Upgrade auf mindestens 4 GB durchführen, da sonst Probleme beim Austauschen auftreten. 64-Bit-Betriebssysteme bieten mehr Informationen im Speicher als auf der Festplatte, und diese Änderung kann je nach Vorgang zu erheblichen Geschwindigkeitssteigerungen führen. Wenn Ihr Computer nicht schneller als ein 486 ist, ist es möglicherweise an der Zeit, Viren zu überprüfen :)
mmr
Das hat funktioniert, vielen Dank! hat mir Stunden gespart, wenn nicht Tage!
Alex Z
0

Ich habe versucht, DLL mit dem CallingConventionis aufzurufen ThisCallund es hat bei mir funktioniert. Hier ist mein Code, der mit BLOB MS SQL Server arbeitet.

[DllImport("sqlncli11.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.ThisCall)]
            private static extern SafeFileHandle OpenSqlFilestream(
                        string FilestreamPath,
                        UInt32 DesiredAccess,
                        UInt32 OpenOptions,
                        byte[] FilestreamTransactionContext,
                        UInt32 FilestreamTransactionContextLength,
                        Int64 AllocationSize);

Weitere Informationen finden Sie unter : https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention(v=vs.110).aspx

Hao
quelle