Laden...

[ERLEDIGT] Unmanaged .DLL import - Deployproblem

Erstellt von Marcel-B vor 9 Jahren Letzter Beitrag vor 9 Jahren 2.536 Views
M
Marcel-B Themenstarter:in
11 Beiträge seit 2015
vor 9 Jahren
[ERLEDIGT] Unmanaged .DLL import - Deployproblem

Moin Zusammen.

Ich habe eine kleine Anwendung geschrieben welche ein paar dicke Mathematische Aufgaben zu erledigen hat. Weil der Rechenaufwand ziemlich groß ist habe ich diesen in eine unmanaged c++ dll ausgelagert. Die GUI habe ich ganz normal in C#.NET geschrieben, wo Parameter übergeben werden können, Zwischenstände angezeigt werden und das Resultat der Rechnung erscheint. Es funktioniert alles super soweit.

ABER

Es funktioniert leider nur an meinem Notebook (Visual Studio 2013 Ultimate installiert) und an meinem Desktop Arbeitsrechner (Visual Studio 2013 Professional installiert). Auf allen anderen Geräten schmiert die Anwendung ab sobald die dll aufgerufen wird.
Eine Gedanke war auch, dass der C++ Compiler von Intel u.U. nen Kopierschutz hat und deshalb die "Core.dll" nur auf den Maschinen läuft wo die Testversion installiert ist. Aber ich hab es auch mal ganz normal mit dem von Microsoft versucht, lief aber leider auch nicht.

Hier mal ein paar Codeauszüge:


        // Delegate fürs Callback
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate void tCallback(int hwnd);

        // Die Methode der dll
        [DllImport("Core.dll")]
        private static extern IntPtr Start
            (
            float alpha_start,
            float alpha_ende,
            float beta_start,
            int neuro_pro_typical,
            int n_training,
            int iteration_max,
            int nachbarStart,
            int nachbarEnde,
            float[] daten,
            int variablen,
            int datensatz,
            tCallback touch
            );

// .........

            // In einem BackgroundWorker wird dann die Methode aufgerufen
            // MessageBox.Show("START");  Hier hab ich mal zum Debuggen ne Message Box platziert die auch noch angezeigt wird
            IntPtr back = Start
                (
                parameter.AlphaStart,
                parameter.AlphaEnd,
                1.1F,
                parameter.NeuronProTypical,
                parameter.n_training,
                parameter.iterationMax,
                parameter.nachbarStart,
                parameter.nachbarEnde,
                parameter.Werte,
                parameter.Variablen,
                parameter.Datensätze,
                callBack
                );
             // MessageBox.Show("END"); Hier gabe es auch eine, diese wurde wohl nicht mehr erreicht

            // Hier wird das Ergebnis dann verarbeitet
            unsafe
            {
                Ergebnis plom = (Ergebnis)Marshal.PtrToStructure(back, typeof(Ergebnis));
///.......


C++ Core.cpp


Ergebnis* __stdcall  Start
(
  float alpha_start,
  float alpha_ende,
  float beta_start,
  int neuro_pro_typical,
  int n_training,
  int iteration_max,
  int nachbarStart,
  int nachbarEnde,
  float *daten,
  int variablen,
  int datensatz,
  tCallback callBack
)

{
   // hier wird ne Menge gerechnet ...
  // zwischendurch wird auch das callBack aufgerufen ...
  return ergebnis....
}

C++ Core.h


extern "C"
{
   typedef void(__stdcall * tCallback)(int);

   __declspec(dllexport) Ergebnis* __stdcall  Start(
	float alpha_start,
	float alpha_ende,
	float beta_start,
	int neuro_pro_typical,
	int n_training,
	int iteration_max,
	int nachbarStart,
	int nachbarEnde,
	float* daten,
	int variablen,
	int datensatz,
	tCallback callBack
	);
}

Zum debuggen habe ich auch die komplette Berechnung (samt CallBack-Aufruf) mal rausgelassen, so das nur die Methode samt Parameter aufgerufen wird, half aber leider auch nichts.
Hab auch versucht das Programm auf verschiedene Wege zu installieren:
Einfach die Exe ausführen. Als OneClick und einmal mit Install Shield. Der Fehler war immer der Gleiche.

Hat von Euch jemand eine Idee woran es liegen könnte? Ach ja, die .DLL liegt im gleichen Verzeichnis wie die .EXE.

Grüße
Marcel Benders

Gelöschter Account
vor 9 Jahren

Paar Betriebssysteminfos (Test und Deploay) wären hilfreich, angefangen bei 32/64 Bit. Abschmieren heisst keine Exception sondern TILT ?

Und verpass deinem Struct mittels Attribute auf jeden Fall ein sequenzielles Speicherlayout.

StructLayoutAttribute

Nachtrag: Der Grund für die Verwendung von unsafe erschliesst sich hier für mich nicht und ich habe auch keine Erfahrung damit aber PtrToStructure führt gewöhnlicher Weise auch bei fehlerhafter Verwendung nicht zum Totalabsturz, zumindest im safe mode.

Hat es vielleicht nicht so sehr was mit Test/Deploy System zu tun sondern eher mit Debug/Release?

M
Marcel-B Themenstarter:in
11 Beiträge seit 2015
vor 9 Jahren

Danke für die schnelle Antwort.

Am Notebook läuft Windows 8.1 Prof., am Desktop Win 7 Ultimate, das sind quasi die beiden Rechner wo es ohne Probleme läuft (die Exe-Datei im Release Ordner läuft, und wenn ich es als OneClick installiere geht es auch).

Hab es jetzt zu Hause noch mal am PC versucht (Windows 8.1 Prof., auch Visual Studio installiert) und da geht es nicht.

Die komplette Anwendung ist in 32Bit geschrieben, also beide Teile.

Unsafe:
Die Stuktur in der DLL ist ein float* und zwei Integer die die Dimensionsgröße speichern (eigentlich müsste ich ein dreidimensionales Array zurrückgeben, was aber scheinbar nicht geht). Auf C#-Seite wird das float* dann verarbeitet , float[] ging leider nicht weil ein float* verlangt wird. Um das float* dann mit Hilfe der Integerwerte zu entpacken brauche ich den unsafe-Teil.


// Das Ergibnis wird als String gespeichert und später Angezeigt
unsafe
{
    Ergebnis resultStruct = (Ergebnis)Marshal.PtrToStructure(back, typeof(Ergebnis));
    ergebnis += resultStruct.numDataSet.ToString() + Environment.NewLine;
    ergebnis += resultStruct.variablen.ToString() + Environment.NewLine;
    int counter = 0;
    for (int i = 0; i < resultStruct.numDataSet; i++)
    {
         ergebnis += i + 1 + ". ";
         for (int j = 0; j < resultStruct.variablen; j++)
         {
              if (j < resultStruct.variablen - 1)
                  ergebnis += resultStruct.floatArray[counter].ToString() + " -- ";
              else
                  ergebnis += resultStruct.floatArray[counter].ToString();
               counter++;
          }
          ergebnis += Environment.NewLine;
     }
}

Struct:


public struct Ergebnis
{
    public int variablen;
    public int numDataSet;
    unsafe public float* floatArray;
}

Der Absturtz passiert unmittelbar beim Zugriff auf die dll. Die Berechnung dauert ca. 25 Sekunden. Drücke ich auf den Start-Button schmiert es sofort ab.
Ich werde als nächstes das CallBack - Delegate raus nehmen, mal sehen ob das Ärger macht und das StructLayoutAttribute werde ich mir mal anschauen.

Edit:
Den Teil mit der Struct habe ich mal komplett rausgenommen. Methoden überall auf void gesetzt, daran kann es leider nicht gelegen haben.

Gelöschter Account
vor 9 Jahren

Aus Interesse habe ich nochmal geschaut:

Marshaling Simple Types

Für unmanaged float ist der korrespondierende CLR type System.Double. (float ist ja ein typedef für System.Single) Wie schon erwähnt könnte es am Debugger liegen das es bei dir funktioniert bzw. ich kenne auch den Fall wo es dann mal funktioniert und dann wieder nicht. (EDIT: Hat sich durch deine Antwort das es im Release auf deinem Rechner auch geht erledigt)

Nochmal bezüglich des "Abschmierens" was als Fehlerbeschreibung nicht wirklich optimal ist: Ich kann nicht sagen ob das unsafe anders läuft aber aber wenn im umanaged Bereich von PtrToStructure ein Fehler auftritt passiert das vereinfacht gesagt nicht im aufrufenden Thread was den obligatorischen try/catch Block um deinen Aufruf aushebelt. Ich weiss nicht welche Art von Lösung du hast aber in einer WindowsForms Anwendung würde die Exception in der Program.cs bei Application.Run(...) landen.

(Noch ein Edit: Arrays kann man "marscheln", ist aber nicht in 2 Aufrufen erledigt. Microsoft bietet einige vordefinierte Custom Marshaler für Arrays in einem extra Assembly an aber die sind zum weglaufen langsam. Wenns anders geht, sollte man es auch anders machen)

M
Marcel-B Themenstarter:in
11 Beiträge seit 2015
vor 9 Jahren

Ah Danke, sehr gut. Das mit dem Float und Double ist mir jetzt auch neu. Ich bin gerade auch wieder ein Stück weiter gekommen. Die Rückgabe hatte ich ja raus genommen und das Callback-Delegate auch. Der gleiche Fehler war noch immer da.

Ich hab jetzt alles noch mal gelöscht (dll, release-ordner usw) und alles noch mal neu durchkompiliert (diesmal mit dem microsoft c++ compiler). Im Moment läuf es, warum es Heute mittag nicht mit dem ms-compiler lief ist mir jetzt wohl ein Rätsel (vielleicht hat das "aufräumen" was gebracht). Na dann werde noch mal bei Intel nachhaken, ob es an der Schüler- bzw. Trialversion liegen kann.

Fehlerbehandlung habe ich im Moment noch nicht implementiert, deshalb schmeißt mich das Programm ganz raus.

Gelöschter Account
vor 9 Jahren

Hmm, du willst den Pointer auf das float Array kopieren. Auf die Idee bin ich noch nie gekommen. (Dir ist schon klar das der unmanaged Zeiger auf das float Array aber kein float ist sondern sizeof(byte) oder? Weisst du das CLR float* und float* kompatibel sind?)

In dem Fall würde ich doch auf den Custom Marshaler setzen, dann bleibst du sogar safe 😃

M
Marcel-B Themenstarter:in
11 Beiträge seit 2015
vor 9 Jahren

Hab es jetzt von C++ so übernommen (das Ergebnis sah eigentlich immer stimmg aus), werde das aber mit dem Custom Marshaler mal in Angriff nehmen.

Hab jetzt das Projekt auf dem PC geöffnet wo Visual Studio installiert ist, wo es aber nicht lief und dort mal ausgeführt. Da kam folgende Meldung (wenn es mit Intel Compiliert ist, was auf dem PC nicht installiert ist):

Zusätzliche Informationen: Die DLL "Core.dll": Das angegebene Modul wurde nicht gefunden. (Ausnahme von HRESULT: 0x8007007E) kann nicht geladen werden.

Also entweder Compilereinstellung oder es ist wirklich eine Art Kopierschutz, dass es zum Testen nur dort läuft wo auch die Intel-Software istalliert ist....

Gelöschter Account
vor 9 Jahren

Zwischenfrage: Hat dein CLR struct inzwischen ein sequenzielles Speicherlayout sowie es unmanaged der Fall ist? (Die Frage nach dem Bit Matching also ob Test und Deploy System jeweils beide 32/64 Bit sind oder sich unterscheiden hast du übrigens unterschlagen)

Das mit der Fehlerbehandlung auf irgendwie später zu verschieben war aus meiner Sicht nicht die beste Idee. Bevor wir hier zusammen weiter rumrätseln wäre es schon hilfreich zu wissen ob sich um einen Security Fehler handelt, Access Violation oder BadImageFormat(möglicherweise durch die Intel Compilierung, muss ja nen Grund haben das er diese Abhängigkeit bereits in in Visual Studio moniert) Funktionieren denn andere Aufrufe a la Hello World() auf dem Issue System problemlos?

Kümmer dich um die Fehlerbehandlung, um rauszukriegen woran es wirklich hängt. Wenn dir der Fehler selbst nix sagt ist das kein Beinbruch, dafür hats ja ne C# Community. Du ersparst dir selbst unter Umständen viel Zeit bevor du in die falsche Richtung rennst.

W
872 Beiträge seit 2005
vor 9 Jahren

Bei Microsoft musst Du das 32 /64 bit SDK installieren, falls Du die STL benutzt. VS installiert das SDK automatisch mit.
Mit dem Intel Compiler ist es wahrscheinlich ähnlich - ich habe aber mit dem noch nicht gearbeitet.
Falls Du nicht die STL benutzt, würde ich mal prüfen, ob es überflüssige include Anweisungen gibt und die rausnehmen.

M
Marcel-B Themenstarter:in
11 Beiträge seit 2015
vor 9 Jahren

Nope, hat die Struct noch nicht, macht allerdings auch kein Problem. Unten auf dem Foto ist zu sehen, dass die Werte korrekt übertragen werden. Hab sie aber auch ganz auskommentiert um es ohne Rückgabe zu versuchen, leider fehlgeschlagen.

Alle Systeme haben 64bit, die Anwendung selber ist in 32bit geschrieben (beim Kunden sind leider noch 32bit Systeme im Umlauf). Die Fehlermeldung ist eine DllNotFoundException, also die Dll wird erste gar nicht gefunden. Ich nehme an dass es was mit der Compilereinstellung zu tun hat.

Das mit dem SDK ist eine gute Idee, werde da mal nachschauen.

W
872 Beiträge seit 2005
vor 9 Jahren

Ich würde es sonst mit dem Dependency Walker versuchen. Das ist an sich das beste Vorgehen, um zu sehen, welche Dlls wirklich referenziert werden.

M
Marcel-B Themenstarter:in
11 Beiträge seit 2015
vor 9 Jahren

Der Dependency Walker war ein echt guter Tipp. Vielen Dank dafür!

EDIT:
Aber hab gerade mal genauer nachgeschaut. Dort wo das Programm ohne Probleme läuft fehlen die gleichen DLLs. Bei der Core.dll wird aber eine LIBIOMP5MD.DLL als fehlend angezeigt. Auf dem System wo es läuft gibt es diese dll jedoch mit Warnung. Bei der Spalte CPU wird ein rotes x64 angezeigt was jetzt eingiges erklärt.

M
Marcel-B Themenstarter:in
11 Beiträge seit 2015
vor 9 Jahren
[erledigt] Unmanaged .DLL import - Deployproblem

So, Thema erledigt. Durch die fehlende dll habe ich die passenden Quellen mit Antworten im Netz finden können. Auf dem Zielsystem fehlten die "Redistributable Libraries" von Intel.

Ein großes DANKE an Euch für die Mithilfe und einen schönen Tag noch!