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



## CopWorker (2. Februar 2021)

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.




Ist die Dll nicht richtig erstellt worden? 



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

Irgendwas an den Projekteinstellungen vielleicht?

Vielen Dank 
Grüße von CopWorker


----------



## CopWorker (2. Februar 2021)

Hallo, 

das ganze bin ich jetzt anders angegangen.

1. Die Dll in den Projektordner kopiert, parallel zur Projektdatei.
2. Dll ("OdbcCPCC.dll") Importierung vorgenommen:

```
[DllImport("OdbcCPCC.dll", CharSet = CharSet.Unicode)]
protected static extern int GetActVersionODBCCPCC(string strVersion);
```

3. Methode zu Aufruf der Funktion gebildet.

```
// 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.

```
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:

```
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 (3. Februar 2021)

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


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

protected static extern int GetActVersionODBCCPCC(StringBuilder strVersion);
```


----------



## Spyke (3. Februar 2021)

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


```
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


----------



## CopWorker (3. Februar 2021)

Hallo Spyke, 

mit dem StringBuilder und Marshall geht es prima. 

```
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:

```
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


----------



## Spyke (4. Februar 2021)

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 (9. Februar 2021)

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


----------

