Dll aus einem C++ Projekt in C# Projekt einbinden

CopWorker

Erfahrenes Mitglied
Hallo zusammen,

ich versuche in meinem C# Projekt einen Verweis auf eine Dll zu erstellen.
Die Dll stammt aus einem C++ Projekt und wird auch in mehreren C++ Projekten verwendet.

Leider kommt in meine C# Projekt eine Fehlermeldung wenn ich den Verweis auf
diese Dll erstellen möchte.

1612257846251.png

Ist die Dll nicht richtig erstellt worden?

1612258035638.png
Aber beim Build im C++ Projekt sind keine Fehler aufgetreten.

Irgendwas an den Projekteinstellungen vielleicht?

Vielen Dank
Grüße von CopWorker
 

CopWorker

Erfahrenes Mitglied
Hallo,

das ganze bin ich jetzt anders angegangen.

1. Die Dll in den Projektordner kopiert, parallel zur Projektdatei.
2. Dll ("OdbcCPCC.dll") Importierung vorgenommen:
C#:
[DllImport("OdbcCPCC.dll", CharSet = CharSet.Unicode)]
protected static extern int GetActVersionODBCCPCC(string strVersion);

3. Methode zu Aufruf der Funktion gebildet.
C#:
// Methode die es ermöglicht von C# aus auf die dll zuzugreifen
public static int DllActVersion(string strVersion)
{
    return GetActVersionODBCCPCC(strVersion);
}

4. Zugriff auf die Methode eingebunden. Hier einfacherhalt halber in den
Standardkonstruktor der Klasse.
C#:
public Access()
{
    int iRet = 0;
    string strRevision = string.Empty;
    iRet = DllActVersion(strRevision);

    if (iRet.Equals(0))
        iRet = -1; //Define as breakpoint only
}

5. Die Funktion in der Dll auf die ich zugreifen möchte sieht so aus:
C++:
BOOL GetActVersionODBCCPCC(    LPTSTR lpszVersion )
{
    BOOL fRet = FALSE;

    if (!lpszVersion)
    {
        fRet = FALSE;
    }
    else
    {
        (void)lstrcpy(lpszVersion, ODBCCPCC_VERSIONSLABEL);
        fRet = TRUE;
    }

    return fRet;
}

Ergebnis:
Der Aufruf der Methode in der Dll scheint zu funktionieren.
Der Return Wert ist korrekt. Nur habe ich noch Probleme mit dem
Übergabeparameter "strVersion" in C# als "string" Variable.
In der Dll ist ein LPTSTR = wchar_t*.
Da wird auch nichts zurück geliefert. Das Programm erleidet auch keine Absturz.

Weiß jemand wie ich die Konvertierung bzw. die Deklaration des
Übergabeparameters vornehmen soll.

Vielen Dank.
Grüße von CopWorker
 

Spyke

Premium-User
Hab mal bei pinvoke geschaut wie dort mit LPTSTR umgegangen wird.
Ev. im Parameter nur Attribute
[MarshalAs(UnmanagedType.LPTStr)]
setzen

z.B. wie hier
pinvoke.net: CreateFile (kernel32)

alternativ könnte es ev. auch mit StringBuilder als Parametertyp funktionen

es gibt auch speziell noch In, Out Attribute für solche invokes ev. auch das mal probieren

C#:
protected static extern int GetActVersionODBCCPCC([MarshalAs(UnmanagedType.LPTStr)] string strVersion);

protected static extern int GetActVersionODBCCPCC(StringBuilder strVersion);
 
Zuletzt bearbeitet:

Spyke

Premium-User
nachtrag
ups jetzt seh ichs erst du willst den wert ja zurück haben, dann mit StringBuilder den StringBuilder aber mit einer entsprechenden Größe vor instanziieren.

ev. funzt es auch beim Parameter einfach ref mit ran setzen und oben das genannte Attribute verwenden

C#:
protected static extern int GetActVersionODBCCPCC([MarshalAs(UnmanagedType.LPTStr)] ref string strVersion);

string s= new string(' ', NeGrößeAngeben);
GetActVersionODBCCPCC(ref s);

-------------------

protected static extern int GetActVersionODBCCPCC(StringBuilder strVersion);

StringBuilder s = new StringBuilder(NeGrößeAngeben);
GetActVersionODBCCPCC(s);

Quellen:
P/Invoke with [Out] StringBuilder / LPTSTR and multibyte chars: Garbled text?
How to p/invoke a native dll with LPTSTR as an input parameter
 
Zuletzt bearbeitet:

CopWorker

Erfahrenes Mitglied
Hallo Spyke,

mit dem StringBuilder und Marshall geht es prima.
C#:
protected static extern int GetActVersionODBCCPCC([Out, MarshalAsAttribute(UnmanagedType.LPWStr)] StringBuilder sbVersion);

Dann kommt noch eine Hürde.

In meiner C++ Dll ist eine Klasse drin.
Diese Klasse enthält alle dringend benötigte Funktionen.
Hier ein kleiner Auszug aus der Klasse in der Dll:
C++:
class EXPORT CSqlDatabase
{
  private:
           CSqlError *    m_pCError;                                // zur Fehlerbehandlung

  protected:
 
    //HENV            m_hEnv;                                // identisch fuer alle Instanzen dieser Klasse
    static HENV            m_hEnv;                                // identisch fuer alle Instanzen dieser Klasse
    static int            m_nEnvConnections;                    // Anzahl der Verbindungen
 
    
  public:
                    CSqlDatabase();
                   ~CSqlDatabase();
           BOOL        Open( LPCTSTR lpszDatabaseName, LPTSTR lpszUserName, LPTSTR lpszPassword, BOOL fReadOnly, HWND hWnd );
           void        Close();
           HSTMT    Stmt();                                                            // statement handle
          
  protected:
           BOOL    GetParameters();                                                        // Datenbankeigenschaften
};

Da die Klasse "CSqlDatabase" als "EXPORT" deklariert ist müsste man doch an die
Klasse mit einem Pointer rankommen und über diesen Pointer die Funktionen nutzen.
Zumindest die "public" sind.

Aber wie?

Vielen Dank.
Grüße von CopWorker
 
Zuletzt bearbeitet:

Spyke

Premium-User
dafür gebts den IntPtr
IntPtr Struktur (System)
aber wie dann weiterverfahren, sry ich mein irgendwo hät ichs mal gemacht aber wüsst nciht mehr im welchem Projekt und wie.

ev. könnteste auch die Klasse auf C# Seite als Schnittstelle nachbilden und die als Rückgabewert angeben in der DLLImport Methode.

Beispiel anhand von OleCreateFromData
C++ Aufbau
OleCreateFromData function (ole2.h) - Win32 apps
C# Schnittstelle
pinvoke.net: IOleObject (Interfaces)
C# Aufruf
pinvoke.net: OleCreateFromData (ole32)

en anderes Beispiel für son Schnittstellen aufbau
pinvoke.net: IFileDialog (Interfaces)

was ich empfehlen würde schau dich bissl bei pinvoke.net um.
Da ist zwar deine Methode nicht mit bei, liefert aber viele Umsetzungsideen die man ausprobieren könnt.
 

CopWorker

Erfahrenes Mitglied
Hallo Spyke,

vielen Dank für die Links.
Das Blatt hat sich gewendet.
Mein Chef hat beschlossen, dass ich die Schnittstelle zur ODBC Datenbank
komplett in C# schreiben soll. Macht auch Sinn, denn .NET unterstützt das alles.
Ne Menge Arbeit, aber dafür bin ich die Altlasten los.

Grüße von
CopWorker