Jump to content


This is a ready-only archive of the InstallSite Forum. You cannot post any new content here. / Dies ist ein Archiv des InstallSite Forums. Hier können keine neuen Beiträge veröffentlicht werden.
Photo

Aufruf einer Funktion aus einer Standard DLL


18 replies to this topic

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 06 April 2011 - 14:46

Hallo Leute,


ich habe folgendes Problem:

Während der Installation(egal ob neu oder Update) werden Konfigurationsdateien kopiert. Diese heißen dann auch "[Konfigurationsdateien]_NEU" (also mit dem anhängsel "_NEU") bei einem Update gibt es also schon ein altes Konfigurationsverzeichnis mit Inhalt und benutzerspezifischen Dateien.

So gibt es nun zum Beispiel zwei Verzeichnisse bei einem Update:
1) C:\Programme\[ProductName]\Konfigurationsdateien
2) C:\Programme\[ProductName]\Konfigurationsdateien_NEU

Verzeichnis 1) soll mit den ganzen Benutzerspezifischen Änderungen also nach 2) migriert werden wo sich auch die aktuellen Dateien befinden.

Diese Migration wird in einer Funktion getätigt die in einer DLL steht.
Daher habe ich nun folgende Schritte gewählt um den Funktionsaufruf aus der DLL heraus zu tun:

=> Custom Actions:
-> New Standard DLL (Installed with Prodct)
-> Funktionsname, Parameter, Argumente hinzugefügt
-> Die "Source"-Quelle ausgewählt (also die Entsprechende DLL, die auch als Schlüsseldatei markiert wurde)
-> Return Processing ist: Synchronus (Check exit code)
-> In-Script Execution ist: Deferred Execution
-> Install Execute Sequence ist: After InstallFiles
(Diese Stelle habe ich gewählt, da hier nun die Dateien physisch auf dem System vorhanden sein müssen. Oder Irre ich mich nun?)


=> Zur Standard "DLL" selber:
-> Es handelt sich hier um eine Funktion die schon sehr lange im Einsatz ist. Bisher eben nur mit einem internen Installations-Werkzeug.


=> Ergebnis der Installation:
-> Beim Migrieren der Dateien erhalte ich folgendne Fehler:
"InstallShield DLL Custom Action Dailog:
File 'C:\Programme\[ProductName]\[ProgDir]\MEINEdll.DLL' can not be found
Make sure the file is on target System or installed already"
-> Die DLL für den Funktionsaufruf ist vorhanden auf dem System
-> Die Konfigurationsverzeichnisse sind auf dem System vorhanden.


=> Hier der Auschnitt aus dem LogFile beim Call der Funktion aus der DLL:
MSI (s) (3C:D4) [15:53:43:764]: Doing action: MEINEFUNKTION
Action 15:53:43: MEINEFUNKTION. Migriere Dateien
Action start 15:53:43: MEINEFUNKTION.
UebernehmeScriptZuordnung: File: Migriere Dateien, Directory: , Size:
Action ended 15:53:43: MEINEFUNKTION. Return value 1.




Vielen Vielen Dank schon einmal im Voraus für die Hilfe!

Mit freundlichen Grüßen,
Eugen

Edited by Eugen.Koch, 04 December 2012 - 17:24.


Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 07 April 2011 - 07:43

Ist irgendetwas unklar? Oder kann ich für klarheit sorgen?

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 08 April 2011 - 18:01

Also, auf den ersten Blick sieht fast alles richtig aus. Ich weiß auch nicht, warum er meint die Datei sei nicht vorhanden. Hier kann evtl. der ProcessExplorer von SysInternals helfen die Ursache zu finden.

Bei den Einstellungen der Custom Action solltest du "deferred in system context" nehmen denn sonst läuft die Aktion (insbesondere unter Vista und Windows 7) mit eingeschränkten Benutzerrechten, kann also nicht im Programme-Verzeichnis schreiben.

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 14 April 2011 - 11:30

Leider Funktioniert der aufruf der eigentlichen DLL-Funktionen immernoch nicht.
Die Fehlermeldung dass die benötigte DLL immernoch nicht vorhanden wäre erscheint immernoch. Dabei ist sie wie gesagt in dem benötigten Zielverzeichnis.

In der "CustomAction"-Table habe ich gesehen dass meine "Action" die Source "DLLWRAP.DLL" aufrufen möchte.
Diese verweist (in der "Binary"-Table) auf <ISProductFolder>\redist\language independent\i386\dllwrap.dll

Dabei wähle ich bei der Erstellung meiner "CustomAction" eine Standard-DLL aus, die mit der Installation kopiert wird und anschließend ausgeführt werden soll.

Übersehe ich gerade etwas oder ist es in Ordnung dass die DLL als "Source"-File angegeben ist. An der Stelle der "DLLWRAP.DLL" müsste doch <MEINDLL.dll> stehen?!



Viele Grüße!

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 18 April 2011 - 19:40

Das ist so in Ordnung. Windows Installer kann von Haus aus nur DLL-Funktionen aufrufen, die genau einen Parameter übernehmen, nämlich das MSI-Handle. Solche DLL-Funktionen nennt InstallShield "MSI DLL". Eventuelle Paraneter müssen dann als Proeprties übergeben werden.

Wenn deine DLL-Funktion nicht nach diesem Schema aufgebaut ist, sondern eine "normale" (Standard) DLL ist, dann legt InstallShield eine Wrapper-Schicht dazwischen, die das Umpacken der Parameter übernimmt.

Um dem Problem auf die SPur zu kommen, versuche doch mal den Process Monitor von SysInternals.

Oder - falls möglich - ändere deine DLL auf MSI-DLL.

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 26 April 2011 - 15:35

Anscheinend hängt an der DLL in der die Funktion aus aufgerufen wird sehr viel mit dran.

Wie muss denn ein header in einer Standard DLL für die MSI Aufrufe aussehen?

Ich würde gerne noch versuchen die Funktion aus der DLL heraus als allerletzte "Aktion" aufrufen zu lassen, sodass alle Kopiervorgänge, Zugriffe darauf etc. fertig wären zum Zeitpunkt des Zugriffes auf die DLL -> Funktion.

Wie könnte ich das ganze denn am geschicktesten verproben/umsetzen?

Vielen Dank schon einmal vorab!

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 27 April 2011 - 13:52

QUOTE
Wie muss denn ein header in einer Standard DLL für die MSI Aufrufe aussehen?
Das ist hier dokumentiert: http://msdn.microsof...8(v=VS.85).aspx

QUOTE
als allerletzte "Aktion" aufrufen zu lassen, sodass alle Kopiervorgänge, Zugriffe darauf etc. fertig wären zum Zeitpunkt des Zugriffes auf die DLL
Dazu die Custom Action in der InstallExecute Sequenz aufrufen, kruz vor InstallFinalize, oder zumindest nach InstallFiles etc.
Die Custom Action muss dazu als "Deferred in system context" konfiguriert sein.

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 28 April 2011 - 08:23

Hallo Stefan,

vielen Dank erst einmal für deine Mühe.
Aber gibt es vorgaben dafür wie der header einer Funktion in einer Standard DLL aussehen muss damit das MSIHANDLE im Wrapper vom InstallShield ordentlich übernommen wird? Ich möchte einen String übergeben.

Viele Grüße!

Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 05 May 2011 - 09:59

Ups, sorry, die Doku war für "MSI DLL". Ich verstehe aber deine Frage nicht ganz. Ein String ist doch letztlich ein Pointer auf einen Buffer, richtig?

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 04 December 2012 - 17:16

Hallo Stefan,

ich greife das Thema mal wieder auf. Der Sachverhalt und das Probelm ist immernoch derselbe (Die Funktion in der Standard DLL kann ich nicht aufrufen huh.gif ).

Zu der Standard-DLL in der ich die FunktionX aufrufen möchte.
Der Funktionskopf sieht wie folgt aus:
extern "C" BOOL __stdcall FunktionX(LPCTSTR MeineVariable)
{
}

Evtl. sollte ich erwähnen dass c++ TestFunktionen in einer eigenen DLL die extra geschrieben wurden um das Problem einzugrenzen ohne Probleme funktionieren...


Meine Frage hierzu: Gibt es Probleme mit extern "C" deklarationen? oder dem LPCTSTR als Parameter der übergeben wird an die Funktion?

Meine bisherigen Lösungsansätze wie folgt:


1. Ansatz)
New Standard DLL (Installed with Produkt) - Parameter wird als "STRING" in Property übergeben und liefert einen "BOOL" - Funktion ist angegeben (FunktionX).

Der Aufruf:
Immediate Execution - After InstallFinalize - Synchronous (Check Exit Code)

Ergebnis:
Fenster Poppt hoch "InstallShield DLL Custom Action" mit folgendem Inhalt:
File: 'C:\Program Files (x86)\<Firma>\<Produkt>\Programm\<MeineDLL>' can not be found. Make sure the file is on the target system or installed already.
-> Jedoch ist die Datei zum Meldungszeitpunkt genau da wo sie auch sein soll. Nämlich genau in diesem Verzeichnis... mad.gif


Im Log steht noch folgendes zur Custom Action:
MSI (s) (A0:3C) [16:59:54:169]: Doing action: Call_FunktionX
Action 16:59:54: Call_FunktionX.
Action start 16:59:54: Call_FunktionX.
MSI (s) (A0:3C) [16:59:54:169]: Creating MSIHANDLE (232) of type 790542 for thread 2620
MSI (s) (A0:24) [16:59:54:169]: Invoking remote custom action. DLL: C:\Windows\Installer\MSI8FDA.tmp, Entrypoint: DLL2
MSI (s) (A0!30) [16:59:54:200]: Creating MSIHANDLE (233) of type 790541 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Creating MSIHANDLE (234) of type 790540 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Creating MSIHANDLE (235) of type 790531 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Closing MSIHANDLE (235) of type 790531 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Closing MSIHANDLE (234) of type 790540 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Creating MSIHANDLE (236) of type 790540 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Creating MSIHANDLE (237) of type 790531 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Closing MSIHANDLE (237) of type 790531 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Closing MSIHANDLE (236) of type 790540 for thread 3120
MSI (s) (A0!30) [16:59:54:200]: Closing MSIHANDLE (233) of type 790541 for thread 3120
CustomAction Call_FunktionX returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
MSI (s) (A0:24) [16:59:56:993]: Closing MSIHANDLE (232) of type 790542 for thread 2620
Action ended 16:59:56: Call_FunktionX. Return value 3.



2. Ansatz)
New Standard DLL (Installed with Produkt) - Parameter wird als "STRING" in Property übergeben und liefert einen "BOOL" - Funktion ist angegeben (FunktionX).

Der Aufruf:
Deferred Execution in System Context - After PublishComponents - Synchronous (Check Exit Code)

Ergebnis:
Exakt das selbe Fenster wie in 1) poppt hoch mit der selben meldung etc. Die Datei ist jedoch wieder da wo sie gesucht wird.

Im Log steht noch folgendes zur Custom Action:
MSI (s) (B0:30) [17:08:11:952]: Doing action: Call_FunktionX
Action 17:08:11: Call_FunktionX.
Action start 17:08:11: Call_FunktionX.
Call_FunktionX:
Action ended 17:08:11: Call_FunktionX. Return value 1.


-> Nun habe ich in Erinnerung, dass der Rückgabewert 1 für Custom Actions = OK ist?! Jedoch wurde die FunktionX nicht gestartet huh.gif

Ich bin immernoch verzweifelt und hoffe damit etwas Licht ins dunkle bringen zu können... Lässt sich das aufrufen der Funktion über die MSI irg. wie anders noch "debug'n" Damit ich mal sehe wo das eigentliche Problem liegt?


Vielen Dank schon einmal vorab!!!!


Viele Grüße,
Eugen

Edited by Eugen.Koch, 04 December 2012 - 17:21.


Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 04 December 2012 - 20:12

Hast du meinen Vorschlag mit dem Process Explorer ausprobiert? Außerdem würde ich die DLL mal (in dem Moment wo die Fehlermeldung kommt) mit dem Dependency Walker öffnen. Das könnte verschiedene mögliche Fehlerursachen aufdecken:

1. Die DLL ist von einer anderen Datei abhängig, die zu diesem Zeitpunkt
a) nicht vorhanden ist
b) nicht registriert ist
c) nicht im erwarteten Pfad liegt (z.B. wenn sie einfach aus dem aktuellen Arbeitsverzeichnis geladen werden soll, welches aber während der Installation nicht das INSTALLDIR ist sondern der Sytem32 Ordner)

2. Die DLL exportiert die Funktion unter anderem Namen (Name Mangling oder Schreibfehler)

3. Es gibt ein Rechteproblem

4. Die DLL wird doch nicht dort gesucht, wo sie ist, aber du übersiehst den Fehler (Betriebsblindheit, ist mir schon oft genug passiert), etwa ein Punkt zu viel, ein Leerzeichen zu viel, ...

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 05 December 2012 - 09:22

Erst einmal Dank dir Stefan für deine schnelle Antwort!

Ja ich hab mir deine Vorschläge zu Herzen genommen und den Process Explorer ausprobiert. Sehr schlau wurde ich daraus jedoch nicht dry.gif
Dieses Tool ist aber wohl meine einzigste Chance da irg. wie hineinzu "Debug'n"....
Das werde ich jetzt noch einmal versuchen und mich dann erneut melden.
Mit hoffentlich mehr resultaten

Den Dependeny Walker öffne ich immer sobald ich solche Probleme bekomme
Zu den Fehlerursachen die du vorgeschlagen hast erst einmal.
1)
a) Ja sie hat mehrer Abhängigkeiten. Diese sind jedoch alle zum Startpunkt des "Calls" auf die Funktion vorhanden.
cool.gif Registriert sind alle notwendigen DLL's, außer ich überseh gerade etwas. Ich habe nun aber zum Test die Installation laufen lassen und die DLLs erneut Händisch registriert. Anschließend eine Reperatur Installation -> Leider ohne Erfolg.
Der Dependeny Walker meldet auch keine Veränderung.
c) Bei der Installation ist es das "[INSTALLDIR]Programm" und wird während der Installation auch nicht verändert. Daher glaub ich dass es das auch nicht ist

2) Die Funktion wird ja schon bei uns eingesetzt nur in einem anderen Werkzeug wie dem MSI-Installationswerkzeug. Aber ich habe es trotzdem nachgeschaut. Es ist 1:1 dieselbe Funktion die Exportiert wird und Existiert.

3) Ich Installiere ja nach "C:\Program Files (x86)\...", könnte das so Probleme bereiten? Das Problem hätt doch schon jemand anderes haben müssen? Ich dachte, dass ich hierfür extra "Deferred Execution in System Context" ausführen sollte, damit das kein Problem sein sollte. Die Installation setzt zudem Administratorrechte voraus.

4) Ich habe die Fehlermeldung in der der Pfad geschrieben wird 1:1 in den Explorer getippt und versucht die Datei zu starten. "Leider" war dies nicht der Grund meines Fehlers....


Vielen Dank für deine Unterstützung!!!
Eugen

Edited by Eugen.Koch, 05 December 2012 - 09:23.


Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 05 December 2012 - 09:59

Bei 1 c) hast du mich glaube ich missverstanden. Es gibt ja mehrere Möglichkeiten, wie eine DLL eine andere laden kann. Z.B. kann man den vollständigen Pfad zur zweiten DLL angeben, oder z.B. nur den Dateinamen. In dem Fall wird im aktuellen Arbeitsverzeichnis (current working directory, CWD) gesucht. Das ist üblicherwewise das Verzeichnis, in dem das aufrufende Programm liegt. Wenn also die DLL im gleichen verzeichnis wie deine EXE liegt und die EXE die DLL aufruft, dann funktioniert es. Wenn aber msiexec.exe die DLL lädt, dann ist dass CWD eben nicht das Instalationsverzeichnis sondern das Verzeichnis, in dem msiexec.exe liegt, und dann schlägt das fehl.

Das sind natürlich nur so ein paar Ideen, was schief gehen könnte. Es kann auch an was ganz anderem liegen. Was mich stutzig macht ist, dass es mit einer Test-DLL funktioniert.

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 05 December 2012 - 10:57

Ok - Jetzt verstehe ich was du meinst bei 1 c).
Meine bisherige Konfiguration von meiner Custom Action ist wie folgt:

-> Type: Standard-DLL
-> Location: Installed with the product
(da wähle ich ja die dll aus. Hier habe ich immer gedacht, dass die DLL
die "Location" der Componente heranzieht? Könnte das, das Problem sein?)

Genau wie du wunder ich mich aber über das selbe... Das deutet doch ALLES darauf hin, dass etwas beim Aufruf der Funktion fehlt mad.gif
Der Dependency Walker meldet mir aber nichts Besorgniserregendes...

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 05 December 2012 - 16:51

Ich habe neue Erkentnisse, Stefan!!!
Du hattest es eigentlich schon erraten. Es liegt anscheinend wirklich an der CWD... die msiexec.exe möchte ALLE anderen abhängigen Dateien aus "C:\Windows\SysWOW64\<AndereDLLs>" anziehen... Der Process Monitor sagt mir jedenfalls an der Stelle als "Result": NAME NOT FOUND.

Wie kann ich das denn so hinbiegen, dass er die DLLs aus meinem "[INSTALLDIR]Programm" anzieht?
Bzw. Kann ich das Current Working Directory nicht selber bestimmten? Sodass ich meiner CustomAction sage, Führe in der DLL "X", die Funktion "Y" aus in dem Verzeichnis "Z"? (So jedenfalls funktioniert das auch bei unserem momentanen Installationswerkzeug)


Vielen Dank schon einmal!
Eugen

Edited by Eugen.Koch, 06 December 2012 - 11:15.


Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 06 December 2012 - 17:27

Ich glaube dafür gibt es in InstallShield keine Einstellung. Das müsstest du in deiner DLL machen.
Übrigens kann das Verhalten auch noch davon abhängen, welche Sicherheitsupdates auf dem Ziel-Windows installiert sind. Da gab es in der DLL Suchreihenfolge eine Änderung aus Sicherheitsgründen.

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 11 December 2012 - 06:55

Also das fände ich sehr schwach von Microsoft... sogar unser Installationswerkzeug besitzt einen Parameter, der sich auf den Ausführungsort bezieht...

Ich werde mal sehen ob es noch die Möglichkeit gibt, dieses "Ausführungsverzeichnis" zu konfigurieren. Weil den Code nun wg. so einer Änderung anzupassen finde ich äußerst unschön.

Hat sich das Ganze mit den neuen Sicherheitsupdates so ausgewirkt? Oder wird es erst mit den neuen/aktuellsten möglich? Weist du das evtl. genauer?

Würde das Ganze funktionieren wenn ich die DLL Funktion als InstallScript callen würde? Wäre es da möglich den Ausführungsort zu bestimmen?

Vielen Dank dir nochmal!

Grüssla,
Eugen

Edited by Eugen.Koch, 11 December 2012 - 08:51.


Stefan Krueger

Stefan Krueger

    InstallSite.org

  • Administrators
  • 13,269 posts

Posted 11 December 2012 - 15:55

Ich weiß nur, dass sich was geändert hat, weil man früher einem Programm fremde DLLs (mit gleichem Namen) unterschieben konnte, was ein Sicherheitsrisiko ist.

In InstallScript gibt es die Funktion ChangeDirectory mit der man das CWD ändern kann. Das könntest du mal versuchen.

Eugen.Koch

Eugen.Koch
  • Full Members
  • 31 posts

Posted 11 December 2012 - 18:21

Hi Stefan,

erst einmal dankeschön! Ich habe das Ganze nun aber wie folgt gelöst! Mein Problem war es ja, dass ich eine Funktion in einer Standard DLL aufrufen wollte die noch mehrere Referenzen hatte.
Ich lasse eine CustomAction(CA) vorher laufen die mir mein Current Working Directory (CWD) ändert. Gemacht habe ich das nun in VBScript. Folgendes zur CA:
- In-Script-Execution: Immediate Execution
- Install Exec Sequence: After Install Finalize (gleich danach kommt auch mein call auf meine Funktion in meiner DLL)

Nun zum Script. Das sieht folgendermaßen aus. Damit lässt sich das CWD je nach belieben anpassen falls es noch jemand anderes braucht. Sind nur ein paar zeilen:

Dim objShell
Dim sValue

sValue = Session.Property("INSTALLDIR") & "Programm"
On Error Resume Next
Set objShell = CreateObject("Wscript.Shell")
objShell.CurrentDirectory = sValue
On Error Goto 0



Sobald das Problem klar war, war es ein einfaches das richtige zu tun.
Vielen lieben Dank an dich Stefan!

Grüssla,
Eugen