Laden...

DLL (wahrscheinlich C++ native?) durch eine C# ersetzen? Geht das?

Letzter Beitrag vor einem Jahr 28 Posts 1.177 Views
DLL (wahrscheinlich C++ native?) durch eine C# ersetzen? Geht das?

Hallo liebe Community,

nach vielen vielen Jahren stehe ich vor folgender Herausforderung:

Eine DLL in einer unserer laufenden Anwendungen soll ersetzt werden (Outlook Anbindung).

Nach meiner Analyse ist das eine C++ DLL welche Funktionen nach folgenden Schema bereitstellt:

extern "C" __declspec(naked) void OM_AddTO(){__asm push offset ACOutlook + 0x1D20 __asm ret}

Im Hauptprogramm werden diese externen Funktionen angesprochen bzw. eingebunden.

Diese DLL soll durch eine neue ersetzt werden, wobei das Hauptprogramm, welches die DLL lädt nicht "angefasst" bzw. verändert werden kann.

Da ich kaum Erfahrung mit C oder C++ habe, muss ich euch mal um Rat fragen.
Kann ich eine DLL in C# erstellen, welche die gleiche "Funktions-Signatur" bietet? 
Ist es überhaupt möglich eine andere DLL mit externen Funktionen einfach so zu ersetzen?

Vielen Dank für eure Tipps
und viele Grüße

Mario

Salut rockxk

Du könntest die Funktionalität in C# implementieren und eine Wrapper-DLL per C++/CLI bereitstellen:
https://learn.microsoft.com/de-de/cpp/dotnet/dotnet-programming-with-cpp-cli-visual-cpp?view=msvc-170

Gruss
Alf

Ok.. danke, in diese Richtung hatte ich auch schon gedacht und recherchiert. Gibt es da irgendwo ein Code-Beispiel?

Zitat von rockxk

Gibt es da irgendwo ein Code-Beispiel?

C unmanaged call .net

Ansonsten den Link angeklicken, den Du direkt - genau deswegen - unter der Antwort erhalten hast.
Die 5Min zwischen den Beiträgen zeigen, dass Du das nicht ansatzweise durchgelesen haben kannst 😉

Die 5Min zwischen den Beiträgen zeigen, dass Du das nicht ansatzweise durchgelesen haben kannst

Nun, das habe ich schon. In Abständen von mehreren Tagen und jeweils mehrere Stunden habe ich bereits dazu recherchiert.
Ich habe den Beitrag nicht "unvorbereitet" erfasst, es sollte eine Frage sein, welche mir vielleicht einen Ansatz liefert, den ich noch gar nicht in Betracht gezogen hatte.
Meine ersten Versuche in diese Richtung sind leider eher ernüchternd.

Aber vielen Dank für deine sehr schnelle Hilfe. 😉

Hallo rockxk,

gehts um .NET Framework od. um .NET (Core)?
Je nachdem gibt es verschiedene Möglichkeiten, denn bei neuen Versionen von .NET kann via NativeAOT eine DLL erstellt werden, welche ein C-ABI hat ("DllExport") und dadurch könnte neben der genannten Möglichkeit mit C++/CLI auch die DLL erstellt werden.

Beim gezeigten nativen Code wird mit Inline-Assembler direkt gearbeitet, daher bedenke dass dies mit C# / .NET nicht möglich ist. Vllt. bist du besser dran wenn diese Teile in C++ bleiben? (Kann ich natürlich so nicht für dich beantworten).

Im Hauptprogramm werden diese externen Funktionen angesprochen bzw. eingebunden.

Per [DllImport] od. durch Laden der DLL?

Diese DLL soll durch eine neue ersetzt werden, wobei das Hauptprogramm, welches die DLL lädt nicht "angefasst" bzw. verändert werden kann.

Also wenn die DLL durch eine managed Komponente (C# DLL) ersetzt werden soll, so wäre es naheliegend auch im Hauptprogramm das direkt od. via "Assembly Load" anzusprechen, statt einen Umweg managed → native → managed zu gehen.
Wenn du diese Einschränkung also irgendwie ändern kannst...

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

Hallo gfoidl,

so wie ich das verstehe, ist das Hauptprogramm auch nativ (C bzw. C++) und bindet die DLL direkt ein (per Linker) bzw. als Plugin (dynamisch).

@rockxk, ist das richtig so?

Sind denn die meisten anderen Funktionen auch bisher mit inline-Assembler umgesetzt?

Ich bin mir auch nicht sicher, ob man einfach eine C++/CLI-Assembly in ein natives Programm einbinden kann, denn es muß ja die .NET-Runtime angesprochen werden?!

Der Beschreibung - leider hat das der Thread-Ersteller vergessen - könnte das die alte/veraltete C++ API von Outlook (2010?) sein.
Wenn es das ist, dann ist es eh eine Sackgasse, denn seit 15 Jahren sagt Microsoft: nimm die Office Addin Schnittstellen. Auch die .NET APIs sind seit >10 Jahren abgekündigt.

Könnte auch irgendeine andere hacky Outlook Automatisierung sein über OL. Oder eben ein altes Plugin, das eine andere DLL nutzt und wir sehen genau das.
Die Eingriffsmöglichkeit wäre dann aber so oder so nicht gegeben.


Zitat von gfoidl

Beim gezeigten nativen Code wird mit Inline-Assembler direkt gearbeitet, daher bedenke dass dies mit C# / .NET nicht möglich ist.

Das ist mir gar nicht aufgefallen.. 👍

Guten Morgen, vielen vielen Dank für eure Posts, Anregungen und Analysen.

Der Beschreibung - leider hat das der Thread-Ersteller vergessen - könnte das die alte/veraltete C++ API von Outlook (2010?) sein.

Ja, es ist eine DLL, welche ein "altes" Outlook bis 2013 anspricht.

Der Architektur nach zu urteilen wird die DLL dynamisch (per Linker) angesprochen. 
Allerdings bin ich mir da nicht sicher, da diese auch beim Programmstart entweder geprüft oder aufgerufen wird.

Als weiterführende Info (siehe Screenshots):
Das Hauptprogramm ist durch Scripting anpassbar (C ähnliche Sprache). Die Funktionen der "Outlook" DLL werden in den Scripts per Import angesprochen, ich nehme an, dass das zur Laufzeit per Linker dynamisch angesprochen wird?

Ich kann nicht beurteilen, ob es eine alte Microsoft Bibliothek ist, die DLL ist jedenfalls vom Softwarehersteller.

Ich suche nach einem Weg, diese Schnittstelle zu ersetzen, um eine neueres Office/Outlook damit ansprechen zu können.
Genau diese Schnittstelle ist der Grund, weshalb die ganze Firma immer noch mit Office 2010 arbeiten muss.

Ein Upgrade der Hauptsoftware ist aus Kostengründen (>100.000€) nicht möglich und nach heutigem Stand auch nicht mehr sinnvoll. 
Ein Ersatz ebenfalls nicht, da eine ganze Produktion daran hängt.

Achso, mein aktueller Stand ist:

Ich habe die DLL erfolgreich als Visual Studio Projekt per Reverse E. erstellen können.  Daher kenne ich zumindest die externen Methoden.
Dieses Projekt kann ich bereits als eigene DLL wieder kompilieren und dem Hauptprogramm "unterschieben" ohne einen Programmfehler zu verursachen.

Da ich aber kein C++ Profi bin, komme ich nicht wirklich richtig weiter.

Zitat von rockxk

Da ich aber kein C++ Profi bin, komme ich nicht wirklich richtig weiter.

Sei nicht immer so sparsam mit deinen Infos. Woran hapert es denn genau? Was hast du gemacht?

Hallo rockxk,

die DLL erfolgreich als Visual Studio Projekt per Reverse E. erstellen können

ist das lizenzrechtlich hier gestattet?

wird die DLL dynamisch (per Linker) angesprochen

Genau, daher heißt es ja "dynamic link library". Allerdings erledigt dieses dynamische Linken nicht ein Benutzerprogramm, sondern das Betriebssystem in Form der "Loader"-Komponente.

Mir ist die ganze Architektur hier noch unklar und du beantwortest leider die Fragen nicht. Ebenso ist es sehr hilfreich wenn du nicht beurteilen kannst ob X od. Y -- wie sollen hier hilfreiche Kommentare produziert werden?

  • Ist die Hauptanwendung nativ od. managed -- also C/C++ od. C#?
  • Was soll die zu ersetzende DLL genau ansprechen? Neueres Outlook...nunja das kann auch wieder Vieles sein. Falls dort wiederum Inline-Assembler nötig ist, so geht das mit C# / .NET nicht. Ist Inline-Assembler nicht nötig, so geht das womöglich (siehe Kommentare oben).

Ein Upgrade der Hauptsoftware ist aus Kostengründen (>100.000€) nicht möglich und nach heutigem Stand auch nicht mehr sinnvoll.
Ein Ersatz ebenfalls nicht, da eine ganze Produktion daran hängt.

Da habt ihr aber eine sehr weitsichtige Führungsetage. Das ist schon fast grob fahrlässig -- leider aber auch sehr oft anzutreffen.
Wir hier ernsthaft daran geglaubt, dass das System, an welchem die ganze Produktion hängt, durch Reverse Engineering, Rumbasteln an einer DLL, etc. in die Zukunft gehebelt wird?

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

Du müßtest jetzt mal dieses native DLL-Projekt zu einem C++/CLI-Projekt machen (bzw. ein neues erstellen) und dann mal testweise eine Funktion erzeugen, welche intern einen .NET-Datentyp (wie z.B. String) benutzt.

Ich nehme an, daß die Scriptsprache nur die Einbindung von nativen C-Funktionen ermöglicht (und keine C++ Klassen), so daß der Code dann z.B. so aussehen könnte:

#using <mscorlib.dll>
using namespace System;
using namespace System::Runtime::InteropServices;

#include <msclr/marshal.h>
using namespace msclr::interop;

extern "C"
{

__declspec(dllexport)
const char* MyTest(int id)
{
  String^ str = gcnew String("Test: ");
  str += id;
  marshal_context ^ context = gcnew marshal_context();
  const char* s = context->marshal_as<const char*>(str);
  // delete context; // ich bin mir nicht sicher, ob dies schon vor der Ausgabe freigegeben werden kann (daher ersteinmal auskommentiert)
  return s;
}

}

(s.a. Convert from System::String to Char in Visual C++ [bes. ganz unten "C++/CLI sample code (Visual C++ 2005 and Visual C++ 2008)"])

Und dann vom Script aus (ich nehme an, du kannst in deiner nativen Anwendung dort eigene Skripte erstellen und laufen lassen?!):

external string function MyTest(int id) "BGOutlook", "MyTest"

// Aufruf (genaue Syntax müsstest du ja kennen bzw. herausfinden können)
string test = MyTest(42)

Und hoffentlich bietet diese Skriptsprache Möglichkeiten diese Variable test irgendwie auszugeben (MessageBox, Konsole, Datei o.ä.).

Wenn das funktioniert, dann kann man über die weitere Anbindung der Outlook-API sprechen.

oh vielen Dank Th69..  das ist doch schon mal ein Ansatz.. dem werde ich nachgehen und mal testen.. 😃

@gfoidl

Da habt ihr aber eine sehr weitsichtige Führungsetage. Das ist schon fast grob fahrlässig -- leider aber auch sehr oft anzutreffen.
Wir hier ernsthaft daran geglaubt, dass das System, an welchem die ganze Produktion hängt, durch Reverse Engineering, Rumbasteln an einer DLL, etc. in die Zukunft gehebelt wird?

ja, du hast ja so recht... leider :- |  seit ich hier die letzten 2 Jahre arbeite, mache ich nur solche Dinge, um hier irgendwie Ordnung und Fortschritt zu ermöglichen. Das letzte Update dieser Software war 2013 und hat nach Aussagen der Mitarbeiter fast 1 Jahr benötigt bis alles wieder lief. Kein Wunder, durch das integrierte Scripting wurde die Sofware zu >80% customized.

Als einziger mit Entwickler Know-How versuche ich solche Dinge ohne große "Schmerzen" zu lösen. Hier gibt es eben noch etliche andere Projekte.

Mir ist die ganze Architektur hier noch unklar und du beantwortest leider die Fragen nicht.

Das habe ich schon erklärt, die Hauptanwendung unterstützt eine Scriptsprache (ähnlich C). Letztendlich ein Software-Kern, der per Scriptsprache gesteuert und weiterentwickelt werden kann. Ein Großteil der Programmlogik ist damit abgebildet. In dieser Scripts werden aber auch externe DLL (wie die Outlookanbindung) angesprochen. Siehe das Bild, was ich mit gepostet hatte.

  • Ist die Hauptanwendung nativ od. managed -- also C/C++ od. C#?

Ist keinesfalls C# , vermutlich C++. Woran könnte man das erkennen? Vom Stil her sieht der Client aus wie ein Office 2010. Die Anwendung benötigt die vcredist_x86.exe Runtime als Vorraussetzung.

Was soll die zu ersetzende DLL genau ansprechen? Neueres Outlook...

Ja, ein neues Outlook oder eine neuere API. Die Methoden sollten weitestgehend gleich bleiben, um die Anwendungslogik nicht überall anpassen zu müssen.
Die Idee war eigentlich schon, eine .NET Implementierung als Brücke zu nehmen.

Ich hoffe, dass die Infos nun etwas besser sind.. 😉

Achso als Nachtrag:

ist das lizenzrechtlich hier gestattet?

Wie haben einen "guten Draht" zum Softwarehersteller, bzw. zum Implementierer. Der Tipp kam vom Entwickler selbst, in diese Richtung zu gehen. Der Hersteller, bzw. die Ansprechpartner wissen, dass wir nie ein Update machen werden. Kaufmännisch gesehen ist es hier verbrannte Erde. Unsere GF möchte dafür keinen mehr Invest tätigen. 
Und ja, ich weiß, dass das eine schwieriges Thema ist. Aktuell habe ich das nur als Test, wenn überhaupt, wird mir das nur bei der Rekonstruktion der Methoden Signatur helfen.

Hallo rockxk,

Die Anwendung benötigt die vcredist_x86.exe Runtime als Vorraussetzung.

Dann wissen wir einmal dass es eine 32-bit native Windows Anwendung auf Basis der C++ Runtime ist.
Wenn du die C++/CLI Variante probierst, achte daher auf 32-bit Einstellung.
Ich vermute der Weg via NativeAOT wird hier hingegen nicht klappen, da der Office-Teil eher nicht dazu bereit ist. Sonfern also ein Test wie von Th69 vorgeschlagen klappt, so wäre das der mögliche Weg: C# / .NET Logik -> Kapselung per C++/CLI -> Einbindung ins Skript der Hauptanwendung.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

Ja.. das werde ich die nächsten Tage einmal testen. Ich werde berichten 😉...

Vielen Dank an euch und dass ihr euch die Zeit dafür nehmt. Das schätze ich sehr.

Viele Grüße
Mario

Zitat von rockxk

Was soll die zu ersetzende DLL genau ansprechen? Neueres Outlook...

Ja, ein neues Outlook oder eine neuere API. Die Methoden sollten weitestgehend gleich bleiben, um die Anwendungslogik nicht überall anpassen zu müssen.

Das ist eine Sackgasse. Die Office 2016 Basis ist die letzte, die überhaupt diese DLL Schnittstellen hat - und schon dort sind sie nicht mehr garantiert und könnten mit jedem Update raus fallen.
Seit Outlook 2022 ist die seit Jahren einzige unterstützte Schnittstelle Addins.

Hallo.. und Freude, Freude, Freude..

@Th69

Dein Testbeispiel hat funktioniert. Ich habe ein CLR Projekt erstellt und das Testbeispiel als .cpp Datei implementiert. Diese als DLL kompiliert und in das Verzeichnis vom Hauptprogramm kopiert.

An einer passenden Stelle in einem Script vom Hauptprogramm habe ich einen Toolbarbutton erzeugt und eine Methode ausgeführt, welche den externen Aufruf in die DLL macht. So sieht der Aufruf aus dem Script aus (genau wie bei der Outlook DLL):

external string function MyTest(long id)  "DllTest", "MyTest";
void function DllTest_ButtonClick()
{
    // use external method from DllTest.dll
    string result = MyTest(999);   
    // show result as MessageBox
    MgB(result);
}  

Und siehe da, es geht einfach. 😃

Das ist doch mal ein Ansatz.. aber noch ein Weg. 😉

Na, das freut mich auch für dich. 😉

Auf welche Outlook (bzw. Office)-Version wollt ihr denn wechseln?

Für Office 365 gibt es nun eine REST-Schnittstelle:

Darauf achten: die Office 365 REST ist bereits abgekündigt (wurde verlängert, bleibt abgekündigt, wird nicht weiter entwickelt, neue Features nicht vorhanden).
Graph API ist hier die Zukunft (das SDK ist aber leider mies).

Vielen, vielen Dank noch mal für eure Hinweise und Unterstützung.

Welche Variante es nun wird, das muss ich mir noch genau überlegen.

Den Aufwand möchte ich möglichst gering gehalten. Im Grunde ist es der erste Meilenstein die paar Outlook Methoden zu implementieren.
Das ist das einzige Hindernis bezüglich Erneuerung der Office Software Umgebung und endlich die "Entkopplung" zu der alten Produktionssoftware.

Mit O365 ist meine Firma nicht so glücklich, wegen der allgemeinen "Cloud" Abhängigkeit. Aber mal sehen, sehr wichtig war hier einen Fuss in diese Schnittstelle zu kriegen.

Also, vielen vielen Dank noch mal an alle Mitwirkenden.

Viele Grüße
Mario

Hallo, i'll be back.. mit einem kleinen Problem:

Abschliessend zu diesem Thema habe ich erfolgreich dem Hauptprogramm meine DLL's untergeschoben. Auf meinem Rechner alles wunderbar.

Bei abschliessenden Tests hänge ich jedoch bei folgendem Problem:

Auf meinem lokalen Rechner (auch Entwicklungsrechner) funktioniert das tauschen der DLL einwandfrei. Die Hauptanwendung spricht diese Problemlos an und lädt diese auch. Alles Fehlerfrei.

Auf einem anderen frisch installierten Windows 10 Rechner lädt das Hauptprogramm einfach nicht die DLL's und quittiert dies natürlich mit einer Menge Fehlermeldungen.

Nach unzähligen Prüfungen habe keine Idee mehr, bin aber schon mal dahintergekommen, dass die DLL's einfach nicht geladen werden.

Noch mal zur Erkläung vom Ablauf:
Das Hauptprogramm lädt beim Start und während der Laufzeit C-ähnliche Skriptdateien. Dieser werden erst zur Laufzeit ausgeführt. In diesen Skriptdateien sind Verweise/Aufrufe zu externen DLL's eingebunden. Dieser werden auch erst bei ansprechen einer Funktion geladen und verwendet. 
Die DLL's werden also erst sehr spät geladen und verwendet.
So ist bspw. die Schnittstelle zu Outlook und Excel implementiert.

Auf meinem "Entwicklungsrechner" funktioniert dies ohne Probleme, auf zwei anderen Rechnern nicht. 
Bereits durchgeführte Maßnahmen (aber ohne Auswirkung):

  • die DLLs sind alle mit einem CodeSigning Zertifikat Signiert
  • alle DLLs als 32bit erstellt, da die Hauptanwendung auch 32bit ist
  • Assembly Informationen hinzugefügt und vervollständigt

Hat jemand von euch da eine Idee? Habe jetzt schon ziemlich viel ausprobiert, leider schreibt die Hauptanwendung keinerlei Protokoll oder Log.

Vielen, vielen Dank
Mario

Ist denn das verwendete .NET (Framework) installiert?

Oder umgekehrt: mit einer anderen .NET-Version das C++/CLI-Projekt erstellen.

Mmhh.. eingestellt und verwendet für das C++/CLI-Projekt ist v4.8

Auf beiden System ist die gleiche Version des .NET Framework installiert (4.8.09037). (laut Registry)

Auf dem Entwicklungsrechner sind die Targeting Packs für 4.7.2 (4.7.03062) und 4.8 (4.8.03761) installiert.

Du könntest mal auf dem Rechner mit den beiden Programmen Dependency Walker (nativ) und DependencyWalker.Net deine DLL öffnen und schauen, ob dort fehlende DLLs bzw. Assemblies angezeigt werden.

@Th69 du bist Spitze. 😉

Hatte heute mal ein bisschen Zeit mich damit zu beschäftigen. Dein Tipp mit dem Tool war natürlich goldrichtig.
Die DLL's habe ich ja mit einer neueren Redist (Runtime) erstellt. Da fehlte auf dem Test System die richtige VCRUNTIME DLL.

Kurzum, die aktuelle VC Redist installiert und da ging die Suche los, denn es hatte nicht funktioniert.

Super einfacher Fehler, aber da muss man erst mal drauf kommen:
DependencyWalker zeigte, dass meine DLL's mit der "VCRUNTIME140D.DLL" verlinkt sind, 
diese sind auf meinem System lokal auch vorhanden waren, aber in der Test VM nicht.
Denn normal müsste das eigentlich die "VCRUNTIME140.DLL" sein.

Die Erklärung:
Ja klar, wenn man mit DEBUG das Projekt erstellt, wird der Output mit einer Debug Runtime verlinkt, die Visual Studio mitbringt.
Einfach als RELEASE erstellt und alles wunderbar. Damit wurden die DLL's auch korrekt mit der "VCRUNTIME140.DLL" verlinkt.

Das wusste ich nicht, da man auch bei Google über die "VCRUNTIME140D.DLL" nicht viel findet, bin nur stutzig geworden als ich irgendwo gelesen hatte, dass die "D" Variante zu Visual Studio gehört.

Ich bin jedenfalls glücklich, dass es dann doch so was banales war und jetzt alles einwandfrei funktioniert.

Vielen, vielen Dank für die Unterstützung.

Viele Grüße
Mario