none
Probleme mit übergeben von Parametern an Visual C++ dll RRS feed

  • Frage

  • Hi, ich habe eine Frage, ich habe eine in Visual Studio 2010 erstellte C++ dll, ich exportiere die Funktionen folgendermaßen:

    #define DLL  extern "C" __declspec(dllexport)
    
    DLL int returnInt15(){
    	//just a test
    	return 15;
    }
    DLL int returnInt(int zahl){
    	//just a test
    	return zahl;
    }
    

    In meinem C# Programm wollte ich nun testweise die 2 Funktionen probieren, mit folgendem Code:

    [DllImport("HeatingDll.dll")]
    public static extern int returnInt15();
    
    [DllImport("HeatingDll.dll")]
    public static extern int returnInt(int zahl);
    

    Die erste Funktion funktioniert so wie sie soll, dh. wenn ich returnInt15() aufrufe, dann erhalte ich als Rückgabewert auch die gewünschten 15 :)

    Wenn ich aber die zweite Funktion aufrufe, dann erhalte ich folgende Fehlermeldung:

    PInvokeStackImbalance wurde erkannt.
    Message: Ein Aufruf an die PInvoke-Funktion "TESTHeatDLL!TESTHeatDLL.frmMain::returnInt" hat das Gleichgewicht des Stapels gestört. Wahrscheinlich stimmt die verwaltete PInvoke-Signatur nicht mit der nicht verwalteten Zielsignatur überein. Überprüfen Sie, ob die Aufrufkonvention und die Parameter der PInvoke-Signatur mit der nicht verwalteten Zielsignatur übereinstimmen.

    Kann mir da bitte wer weiterhelfen?

    Noch ein paar Informationen zu meinem C# Projekt: Die dll wollte ich eigentlich als Referenz zu meinem C# Projekt hinzufügen, da hat es mir aber gesagt, dass es sich nicht um eine gültige Assembly oder COM-Komponente handelt, deswegen habe ich die dll einfach zum Projekt "als vorhandenes Element" hinzugeügt, und eingestellt, dass er die dll immer ins Ausgangsverzeichnis kopieren soll.

    Und noch zu C++ dll: Erstellt als win32 DLL, gemeinsam genutzt, mit /MD switch, da ich sonst fehlermeldungen beim kompilieren erhalten habe (genauen Grund kenn ich nicht, möglicherweise sogar ein MS-Bug(Feature)??)

     

    danke und schönen Tag noch, mfg chief

    Freitag, 13. August 2010 07:07

Antworten

  • Hallo

    > als Referenz zu meinem C# Projekt hinzufügen

    dies geht nur mit Assemblies (managed Code), nicht mit native (unmanaged) DLLs.

    > PInvokeStackImbalance

    dies ist typisch wg der 'Aufrufkonvention' (wie in Fehlermeldung/MSDN) beschrieben.
    Dies ist eine C++/Win32-Sache, siehe C++ Doku zu  __stdcall  und  __cdecl, also kein C# Thema für hier, sondern Grundlagen!

    Für DLLs mit Flat-API sollte meist das __stdcall verwendet werden, oft auch als 'WINAPI'  Aufrufkonvention in Windows SDK.
    Deine C Methode würde dann etwa so aussehen:
      extern "C" __declspec(dllexport) int __stdcall returnInt(int zahl)

    Alternativ (eher unüblich) könnte man in C# die Aufrufkonvention beim DllImport explizit auf Cdecl umstellen:
    http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention.aspx


    *** diverse Links zu DLL Grundlagen:

    Exportieren aus einer DLL
    http://msdn.microsoft.com/de-de/library/z4zxe9k8.aspx

    Developing DLLs
    http://msdn.microsoft.com/en-us/library/bb687850.aspx

    Calling DLL Functions from Visual Basic Applications
    http://msdn.microsoft.com/en-us/library/dt232c9t.aspx
    http://msdn.microsoft.com/en-us/library/aa235591.aspx
    http://support.microsoft.com/kb/841293

    Die __cdecl Aufrufkonvention ist zwar default beim C/C++-Compiler,
    bei DLL-Exports sollte __cdecl aber eigentlich nur für spezielle Methoden etwa mit variabler Anzahl Parameter verwendet werden.

    Freitag, 13. August 2010 07:18
  • Hallo chieffun,

    Habe folgendes gemacht und es war erfolgreich:

    1)    DLL in Visual Studio 2010 erstellt wie folgt:

     

    // TestStringPro.cpp : Defines the exported functions for the DLL application.
    //
    #include "stdafx.h"
    #define DLL extern "C" __declspec(dllexport)
    DLL int returnInt15()
    {
     return 15;
    }
    DLL int returnInt(int zahl)
    {
     return zahl;
    }
    

     

    2)    DLL in Visual Studio 2008 (C#) gerufen wie folgt:

     

    using System;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    namespace WindowsFormsApplication1
    {
      public partial class Form1 : Form
      {
    
        [DllImport("C:\\Temp\\TestStringPro.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int returnInt(int myint);
    
        [DllImport("C:\\Temp\\TestStringPro.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int returnInt15();
    
        public Form1()
        {
          InitializeComponent();
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
          textBox1.Text = returnInt(1234567890).ToString();
          textBox2.Text = returnInt15().ToString();
        }
      }
    }
    

     

    Grüße,

    Robert

     
    • Als Antwort markiert chieffun Dienstag, 17. August 2010 06:29
    Freitag, 13. August 2010 09:20
    Moderator

Alle Antworten

  • Hallo

    > als Referenz zu meinem C# Projekt hinzufügen

    dies geht nur mit Assemblies (managed Code), nicht mit native (unmanaged) DLLs.

    > PInvokeStackImbalance

    dies ist typisch wg der 'Aufrufkonvention' (wie in Fehlermeldung/MSDN) beschrieben.
    Dies ist eine C++/Win32-Sache, siehe C++ Doku zu  __stdcall  und  __cdecl, also kein C# Thema für hier, sondern Grundlagen!

    Für DLLs mit Flat-API sollte meist das __stdcall verwendet werden, oft auch als 'WINAPI'  Aufrufkonvention in Windows SDK.
    Deine C Methode würde dann etwa so aussehen:
      extern "C" __declspec(dllexport) int __stdcall returnInt(int zahl)

    Alternativ (eher unüblich) könnte man in C# die Aufrufkonvention beim DllImport explizit auf Cdecl umstellen:
    http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention.aspx


    *** diverse Links zu DLL Grundlagen:

    Exportieren aus einer DLL
    http://msdn.microsoft.com/de-de/library/z4zxe9k8.aspx

    Developing DLLs
    http://msdn.microsoft.com/en-us/library/bb687850.aspx

    Calling DLL Functions from Visual Basic Applications
    http://msdn.microsoft.com/en-us/library/dt232c9t.aspx
    http://msdn.microsoft.com/en-us/library/aa235591.aspx
    http://support.microsoft.com/kb/841293

    Die __cdecl Aufrufkonvention ist zwar default beim C/C++-Compiler,
    bei DLL-Exports sollte __cdecl aber eigentlich nur für spezielle Methoden etwa mit variabler Anzahl Parameter verwendet werden.

    Freitag, 13. August 2010 07:18
  • Und noch zu C++ dll: Erstellt als win32 DLL, gemeinsam genutzt, mit /MD switch, da ich sonst fehlermeldungen beim kompilieren erhalten habe (genauen Grund kenn ich nicht, möglicherweise sogar ein MS-Bug(Feature)??)

    definitiv ein reines Visual C++ Thema,
    http://msdn.microsoft.com/de-de/library/2kzt1wy3.aspx
    http://msdn.microsoft.com/de-de/library/abx4dbyh.aspx

    achte insbesondere auf die Abhängigkeit deiner DLL von der C-Runtime (welche ggf die VC-Redist im Setup [beim Kunden]  benötigt).

    Freitag, 13. August 2010 08:49
  • Hallo chieffun,

    Habe folgendes gemacht und es war erfolgreich:

    1)    DLL in Visual Studio 2010 erstellt wie folgt:

     

    // TestStringPro.cpp : Defines the exported functions for the DLL application.
    //
    #include "stdafx.h"
    #define DLL extern "C" __declspec(dllexport)
    DLL int returnInt15()
    {
     return 15;
    }
    DLL int returnInt(int zahl)
    {
     return zahl;
    }
    

     

    2)    DLL in Visual Studio 2008 (C#) gerufen wie folgt:

     

    using System;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
    
    namespace WindowsFormsApplication1
    {
      public partial class Form1 : Form
      {
    
        [DllImport("C:\\Temp\\TestStringPro.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int returnInt(int myint);
    
        [DllImport("C:\\Temp\\TestStringPro.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int returnInt15();
    
        public Form1()
        {
          InitializeComponent();
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
          textBox1.Text = returnInt(1234567890).ToString();
          textBox2.Text = returnInt15().ToString();
        }
      }
    }
    

     

    Grüße,

    Robert

     
    • Als Antwort markiert chieffun Dienstag, 17. August 2010 06:29
    Freitag, 13. August 2010 09:20
    Moderator
  • vielen dank :)
    Dienstag, 17. August 2010 06:29