Discussion:
Comctl32.dll und Delphi
(zu alt für eine Antwort)
Thomas Cebulla
2007-01-15 17:48:41 UTC
Permalink
Hallo,

ich verwende Delphi2006 und versuche ein ActiveX-Control gethemed
darzustellen.
Theming funktioniert laut Themes.pas Zeile 501 erst ab ComctlVersion > 6.0.
Nun liegen auch diverse Versionen der comctl32.dll > 6.0 auf dem Rechner
z.B. in Windows/system32/dllcache.
Bei mehreren XP-Testrechnern liegt aber in windows/system32 eine dll mit
der Version 5.82.
Jetzt kann es vorkommen, dass eine Anwendung, die den IE als Host hat, auf
die dll mit der Version 5.82 zugreift.
Wenn ich jetzt einfach die alte dll durch eine mit der Version 6.0 ersetze,
sieht die Delphi2006 IDE etwas mitgenommen aus(Radiobuttons, Checkboxen,
Transparenz etc.).

Hat jemand Erfahrung mit diesem ganz besonderen dll-Konflikt? Benötigt
Delphi wirklich die Version 5.82 der comctl32.dll,
und wenn ja, muss die dann unter windows/system32 liegen?

Wer hat die comctl32.dll in der Version 5.82 mitgeschleppt(eventuell ein
älteres Delphi bei der Installation?). Seit IE6 ist die comctl.dll Version
6.0 aktuell und auf meinem neuen Rechner war nie ein anderer IE drauf.
Laut Google haben noch andere Leute mit 5.82 und Delphi2006 aber wer hat
eine Lösung?

Thomas
Thomas Cebulla
2007-01-16 07:49:24 UTC
Permalink
Hi,

selbst in einem frischen Vista ohne Delphi liegt in windows/system32 eine
comctl32.dll mit der Version 5.82.

Da kann doch folgende Funktion aus themes.pas nicht richtig sein:

constructor TThemeServices.Create;
const
ComCtlVersionIE6 = $00060000;
begin
inherited Create;
FThemesAvailable := InitThemeLibrary;
FNewComCtrls := GetFileVersion(comctl32) >= ComCtlVersionIE6;
UpdateThemes;
end;

Diese liefert trotz installiertem IE7 mit der 5.82ger dll einen Wert <
$00060000

Kann ich mein *.ocx/*.dll zwingen mit einer anderen comctl32.dll zu
arbeiten, als mit der im windowssystem-Verzeichnis?

Thomas
Soeren Muehlbauer
2007-01-16 09:39:24 UTC
Permalink
Hallo Masine,
Post by Thomas Cebulla
ich verwende Delphi2006 und versuche ein ActiveX-Control gethemed
darzustellen.
Theming funktioniert laut Themes.pas Zeile 501 erst ab ComctlVersion > 6.0.
Nun liegen auch diverse Versionen der comctl32.dll > 6.0 auf dem Rechner
z.B. in Windows/system32/dllcache.
Bei mehreren XP-Testrechnern liegt aber in windows/system32 eine dll mit
der Version 5.82.
Jetzt kann es vorkommen, dass eine Anwendung, die den IE als Host hat, auf
die dll mit der Version 5.82 zugreift.
Wenn ich jetzt einfach die alte dll durch eine mit der Version 6.0 ersetze,
sieht die Delphi2006 IDE etwas mitgenommen aus(Radiobuttons, Checkboxen,
Transparenz etc.).
Hat jemand Erfahrung mit diesem ganz besonderen dll-Konflikt? Benötigt
Delphi wirklich die Version 5.82 der comctl32.dll,
und wenn ja, muss die dann unter windows/system32 liegen?
Wer hat die comctl32.dll in der Version 5.82 mitgeschleppt(eventuell ein
älteres Delphi bei der Installation?). Seit IE6 ist die comctl.dll Version
6.0 aktuell und auf meinem neuen Rechner war nie ein anderer IE drauf.
Laut Google haben noch andere Leute mit 5.82 und Delphi2006 aber wer hat
eine Lösung?
IIRC, ist ab Windows XP ein sogenanntes Side-By-Side Verfahren für diese und andere Dlls eingeführt worden. Durch Einbinden eines Manifestes in eine Anwendung kann man Windows mitteilen, welche Version man wünscht. Der
Code in Themes.pas ist durchaus korrekt. Er ruft GetFileVersion aus der SysUtils, welche wiederum die API Funktion GetFileVersionInfoSize aufruft. Diese versucht per LoadLibrary dann das Modul zu laden. Windows erkennt
den Wunsch nach der ComCtl.dll und lädt sie aus dem Ast \Windows\WinSxS\x86_Microsoft.Windows.Common-Controls... . Dein Problem dürfte sein, daß der Explorer bzw. die Hostanwendung schon eine Version der ComCtl geladen
hat. Prüfe das doch mal indem Du einen Haltepunkt vor dem GetFileVersion in der Themes.pas setzt.

Wie Du das Problem lösen kannst weiß ich so aus dem Hut auch nicht.

HTH, Sören
Soeren Muehlbauer
2007-01-16 09:47:52 UTC
Permalink
Hi,
Post by Soeren Muehlbauer
Wie Du das Problem lösen kannst weiß ich so aus dem Hut auch nicht.
Du könntest von www.mustangpeak.net die EasyNSE Bibliothek nehmen. Dort gibt es eine Unit EasyActivationContext.pas. Das Objekt dadrin sieht vielversprechend aus.

Probiers mal.

Bye, Sören
Thomas Cebulla
2007-01-16 12:52:47 UTC
Permalink
Post by Soeren Muehlbauer
Hi,
Post by Soeren Muehlbauer
Wie Du das Problem lösen kannst weiß ich so aus dem Hut auch nicht.
Du könntest von www.mustangpeak.net die EasyNSE Bibliothek nehmen.
Dort gibt es eine Unit EasyActivationContext.pas. Das Objekt dadrin
sieht vielversprechend aus.
Probiers mal.
Bye, Sören
OK, ich habe mir nun in initialization eine TEasyContextActivation -
Instanz erzeugt. Die erkennt im create auch, das mei *.ocx etwas will.
Die Funktion CreateActCtxA innerhalb des create liefert aber leider ein
INVALID_HANDLE_VALUE zurück.

???
Thomas
Soeren Muehlbauer
2007-01-16 12:58:32 UTC
Permalink
Hi,
Post by Thomas Cebulla
OK, ich habe mir nun in initialization eine TEasyContextActivation -
Instanz erzeugt. Die erkennt im create auch, das mei *.ocx etwas will.
Die Funktion CreateActCtxA innerhalb des create liefert aber leider ein
INVALID_HANDLE_VALUE zurück.
Siehe auch PM. Scheinbar darf man das im Initialisierungsteil noch nicht. Mach das bevor Du das Formular erzeugst.

HTH, Sören
Thomas Cebulla
2007-01-16 09:56:28 UTC
Permalink
Hi Sören (GL) M.
Post by Soeren Muehlbauer
IIRC, ist ab Windows XP ein sogenanntes Side-By-Side Verfahren für
diese und andere Dlls eingeführt worden. Durch Einbinden eines
Manifestes in eine Anwendung kann man Windows mitteilen, welche
Version man wünscht. Der Code in Themes.pas ist durchaus korrekt. Er
ruft GetFileVersion aus der SysUtils, welche wiederum die API Funktion
GetFileVersionInfoSize aufruft. Diese versucht per LoadLibrary dann
das Modul zu laden. Windows erkennt den Wunsch nach der ComCtl.dll und
lädt sie aus dem Ast
\Windows\WinSxS\x86_Microsoft.Windows.Common-Controls... . Dein
Problem dürfte sein, daß der Explorer bzw. die Hostanwendung schon
eine Version der ComCtl geladen hat. Prüfe das doch mal indem Du einen
Haltepunkt vor dem GetFileVersion in der Themes.pas setzt.
Wie Du das Problem lösen kannst weiß ich so aus dem Hut auch nicht.
In der themes.pas heist die zu ladende dll schlicht 'comctl32.dll' ohne
Pfad und alles.
Per Filemon kann man sehen, dass der IE6 (und das ist in diesem Fall mein
Host) die 'alte' dll aus windows/system32 läd.
Firefox läd übrigens eine 'gute' dll aus dem von dir genannten \Windows
\WinSxS\x86_Microsoft.Windows.Common-Controls - Verzeichnis.

Ich kann jetzt schlecht anweisen(per Manifest oder was auch immer), welche
dll der IE zu nehmen hat.
Bleibt die Möglichkeit, einfach alle 'alten' dlls in Windows durch neue
auszutauschen. Dann bleibt das Problem, dass Delphi2006 komisch aussieht
und, was noch viel schlimmer ist, ich kann nicht einfach bei der
Installation der Software allen Nutzen die neue comdll32.dll ins Windows-
Systemverzeichnis schreiben, oder kann ich?

Thomas
Soeren Muehlbauer
2007-01-16 10:11:53 UTC
Permalink
Hi,
Post by Thomas Cebulla
Ich kann jetzt schlecht anweisen(per Manifest oder was auch immer), welche
dll der IE zu nehmen hat.
Siehe meine andere Antwort.
Post by Thomas Cebulla
Bleibt die Möglichkeit, einfach alle 'alten' dlls in Windows durch neue
auszutauschen. Dann bleibt das Problem, dass Delphi2006 komisch aussieht
und, was noch viel schlimmer ist, ich kann nicht einfach bei der
Installation der Software allen Nutzen die neue comdll32.dll ins Windows-
Systemverzeichnis schreiben, oder kann ich?
Nein. Du willst doch nicht das System aushebeln. Das ist die schlechteste Möglichkeit. Versuch lieber die andere.

HTH, Sören
Soeren Muehlbauer
2007-01-16 10:28:27 UTC
Permalink
Hi Masine,
Post by Thomas Cebulla
In der themes.pas heist die zu ladende dll schlicht 'comctl32.dll' ohne
Pfad und alles.
Per Filemon kann man sehen, dass der IE6 (und das ist in diesem Fall mein
Host) die 'alte' dll aus windows/system32 läd.
Firefox läd übrigens eine 'gute' dll aus dem von dir genannten \Windows
\WinSxS\x86_Microsoft.Windows.Common-Controls - Verzeichnis.
In Themes.pas werden ja nur API-Funktionen aufgerufen. Der Windows-Loader sorgt für die Zuordnung. Wenn ich bei meinem XP den Process-Explorer bemühe siehe ich 2 geladene ComCtl.dll. Eine aus Windows\System32 und eine
aus Windows\WinSxS.....

HTH, Sören
NineBerry Schwarz
2007-01-16 12:44:44 UTC
Permalink
Hallo
Post by Thomas Cebulla
ich verwende Delphi2006 und versuche ein ActiveX-Control gethemed
darzustellen.
Das ActiveX-Control ist eine DLL, richtig?

In XP und höher gibt es einen Mechanismus namens Side-by-Side-Sharing.
Das bedeutet u.a., dass eine System-Bibliothek in verschiedenen
Versionen auf dem System installiert sein kann. Die Anwendung sagt dem
System über ein Manifest, welche Version sie verwenden will.

Das soll "DLL-Hell" in Zukunft vermeiden.

Bei normalen Exe-Dateien ist das Einbinden von Manifesten recht einfach
(Passende "xxx.exe.manifest" als Datei neben die "xxx.exe" kopieren
oder das Manifest als Ressource in die Anwendung einbetten), bei DLLs
gibt es aber keinen einfachen Mechanismus. Dort muss man API-Funktionen
verwenden. Details dazu in
<news:<***@TK2MSFTNGP10.phx.gbl>>

Neun
Thomas Cebulla
2007-01-16 13:00:28 UTC
Permalink
Post by NineBerry Schwarz
Hallo
Post by Thomas Cebulla
ich verwende Delphi2006 und versuche ein ActiveX-Control gethemed
darzustellen.
Das ActiveX-Control ist eine DLL, richtig?
In XP und höher gibt es einen Mechanismus namens Side-by-Side-Sharing.
Das bedeutet u.a., dass eine System-Bibliothek in verschiedenen
Versionen auf dem System installiert sein kann. Die Anwendung sagt dem
System über ein Manifest, welche Version sie verwenden will.
Das soll "DLL-Hell" in Zukunft vermeiden.
Bei normalen Exe-Dateien ist das Einbinden von Manifesten recht einfach
(Passende "xxx.exe.manifest" als Datei neben die "xxx.exe" kopieren
oder das Manifest als Ressource in die Anwendung einbetten), bei DLLs
gibt es aber keinen einfachen Mechanismus. Dort muss man API-Funktionen
verwenden. Details dazu in
Neun
Aber woher weiß ich denn, wo auf dem Zielsystem eine neue 6.0-dll liegt?
Bei XP kann es das windows/system32/dllcache-Verzeichnis sein, und bei
Vista?
Die dll ist not redistributable. Oder soll ich per Manifest gezielt eine
6.0-Version der comctl32.dll anfordern?
Kann man mit Delphi2006 eine passende Manifest-Datei erzeugen?

Thomas
Soeren Muehlbauer
2007-01-16 13:08:04 UTC
Permalink
Hi,
Post by Thomas Cebulla
Aber woher weiß ich denn, wo auf dem Zielsystem eine neue 6.0-dll liegt?
Bei XP kann es das windows/system32/dllcache-Verzeichnis sein, und bei
Vista?
Die dll ist not redistributable. Oder soll ich per Manifest gezielt eine
6.0-Version der comctl32.dll anfordern?
Kann man mit Delphi2006 eine passende Manifest-Datei erzeugen?
Das steht doch im Manifest. Wenn ich das Verfahren richtig verstehe, ist es so, daß Windows einen "Stack" vorhält. Bindest Du in Deine Exe ein Manifest ein wird die Version auf ebendiesen gelegt. Benutzt Du das Objekt
wird das Manifest aus der Dll auf den Kontext gepackt. Alles stark vereinfacht ausgedrückt. Windows sorgt dafür, daß die richtige comctl geladen wird.

HTH, Sören
Thomas Cebulla
2007-01-16 13:17:40 UTC
Permalink
Post by Soeren Muehlbauer
Hi,
Post by Thomas Cebulla
Aber woher weiß ich denn, wo auf dem Zielsystem eine neue 6.0-dll
liegt? Bei XP kann es das windows/system32/dllcache-Verzeichnis sein,
und bei Vista?
Die dll ist not redistributable. Oder soll ich per Manifest gezielt
eine 6.0-Version der comctl32.dll anfordern?
Kann man mit Delphi2006 eine passende Manifest-Datei erzeugen?
Das steht doch im Manifest. Wenn ich das Verfahren richtig verstehe,
ist es so, daß Windows einen "Stack" vorhält. Bindest Du in Deine Exe
ein Manifest ein wird die Version auf ebendiesen gelegt. Benutzt Du
das Objekt wird das Manifest aus der Dll auf den Kontext gepackt.
Alles stark vereinfacht ausgedrückt. Windows sorgt dafür, daß die
richtige comctl geladen wird.
HTH, Sören
Hi,
ich habe ja schon Mike Lischkes winXP.res Manifest in das OCX eingebunden
(ID 1 und 123)
Da steht unter anderem drin:
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls"
version="6.0.0.0" processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df" language="*" />

Es wird also offensichtlich die Version 6 der dll angefordert. Trotzdem
holt sich das Programm bei der Programmausführung die dll mit der Version
5.82?

Thomas
NineBerry Schwarz
2007-01-16 13:24:44 UTC
Permalink
Hallo
Post by Thomas Cebulla
Post by Thomas Cebulla
Aber woher weiß ich denn, wo auf dem Zielsystem eine neue
6.0-dll liegt?
Musst du nicht wissen. Du musst nur dem System sagen, welche Version du
willst. Das System besorgt die dann für dich.
Post by Thomas Cebulla
ich habe ja schon Mike Lischkes winXP.res Manifest in das OCX
eingebunden (ID 1 und 123)
Das ist ja eben der Unterschied zwischen EXE und DLL. Bei einer Exe
wird das Manifest automatisch geladen. Bei einer DLL muss das Manifest
über ActivateCtxA exlizit zugewiesen werden.

Neun
Soeren Muehlbauer
2007-01-16 13:29:13 UTC
Permalink
Hi,
Post by Thomas Cebulla
Hi,
ich habe ja schon Mike Lischkes winXP.res Manifest in das OCX eingebunden
(ID 1 und 123)
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls"
version="6.0.0.0" processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df" language="*" />
Es wird also offensichtlich die Version 6 der dll angefordert. Trotzdem
holt sich das Programm bei der Programmausführung die dll mit der Version
5.82?
Das bestimmende ist der Prozess. Wird dieser geladen (in deinem Fall also der InternetExplorer) ordnet Windows diesem einen Kontext zu. Dazu wird nach der Resource geschaut. Ist diese nicht drin bekommt der Prozess die
alte comctl32.dll. Dein OCX ist eigentlich eine DLL. Diese DLL wird innerhalb des Prozesses ausgeführt. Deine DLL hast da leider gar nichts mehr zu vermelden. Sie kann nur einen neuen Kontext anfordern. Und genau das tut
die Komponente.

Bye, Sören
NineBerry Schwarz
2007-01-16 13:44:44 UTC
Permalink
Hallo
Post by Soeren Muehlbauer
Das bestimmende ist der Prozess. Wird dieser geladen (in deinem
Fall also der InternetExplorer) ordnet Windows diesem einen
Kontext zu. Dazu wird nach der Resource geschaut. Ist diese nicht
drin bekommt der Prozess die alte comctl32.dll. Dein OCX ist
eigentlich eine DLL. Diese DLL wird innerhalb des Prozesses
ausgeführt. Deine DLL hast da leider gar nichts mehr zu vermelden.
Die DLL übernimmt aber nicht den Kontext des Prozesses, in den sie
geladen wird. Jede DLL bekommt immer erst mal die alte ComCtl32. Sie
muss einen anderen Kontext explizit setzen.

Neun
Soeren Muehlbauer
2007-01-16 13:54:50 UTC
Permalink
Hi,
Post by NineBerry Schwarz
Die DLL übernimmt aber nicht den Kontext des Prozesses, in den sie
geladen wird. Jede DLL bekommt immer erst mal die alte ComCtl32. Sie
muss einen anderen Kontext explizit setzen.
In der Hilfe zu ActiveActCtx steht:

[..]
The top item of an activation context stack is the active, default-activation context of the current process. If a null activation context handle is pushed onto the stack, thereby activating it, the default settings in
the original manifest override all activation contexts that are lower on the stack.
[..]

Wie passt das zusammen? Wie ich das verstehe ordne ich mit der Funktion einem Thread einen Kontext zu. Wie kann der Thread bei Dll Aufruf seinen Kontext ändern? Wird bei einem LoadLibrary der Kontext verändert?

Bye, Sören
NineBerry Schwarz
2007-01-16 17:19:44 UTC
Permalink
Hallo
Post by Soeren Muehlbauer
Wie passt das zusammen? Wie ich das verstehe ordne ich mit der
Funktion einem Thread einen Kontext zu. Wie kann der Thread bei
Dll Aufruf seinen Kontext ändern? Wird bei einem LoadLibrary der
Kontext verändert?
Ein Experiment zeigt, dass normale DLLs tatsächlich den Kontext des
zugehörigen Prozesses übernehmen. Für COM-DLLs scheint das aber nicht
zu gelten...

Neun
Thomas Cebulla
2007-01-17 06:44:38 UTC
Permalink
Post by NineBerry Schwarz
Hallo
Ein Experiment zeigt, dass normale DLLs tatsächlich den Kontext des
zugehörigen Prozesses übernehmen. Für COM-DLLs scheint das aber nicht
zu gelten...
Neun
Hallo

ja mit normalen dlls funktioniert die Erzeugung eines Kontextes mittels
TEasyContextActivation, bei meiner Com-ActiveX-dll gibts die Fehlermeldung
INVALID_HANDLE_VALUE.
Muss ich evtl. innerhalb der COM-dll das application handle auf irgendwas
vernünftiges setzen, IE ider so? Das sehe ich zur Zeit als einzige
Möglichkeit noch irgendwas zu verändern.

Thomas
Thomas Cebulla
2007-01-17 07:51:28 UTC
Permalink
Also,

wenn man auch noch die winxp_dll.res von EasyNSE einbindet, kann man sich
mit der EasyActivationContext - Komponente tatsächlich auch innerhalb einer
Com-dll einen Kontext erzeugen.
Jetzt wird auch alles das gethemed, was von Windows gezeichnet wird
Buttons, Toolbars).
Nicht gethemed wird das dargestellt, was in irgendwelchen Paint-Methoden
von Delphi gezeichnet wird(z.B. TGroupbox).
Das liegt daran, dass die Themeservices-Klasse aus der Unit themes schon
erzeugt wurde, bevor ich meinen Kontext erzeugen konnte. An der dortigen
InternalServices-Variable steht, dass zum Zeitpunkt der Erzeugung die alte
Comctl32-dll geladen war.

Aber das ist ja schon einmal ein Teilerfolg, den Rest bekomme ich
vielleicht auch noch hin.

Danke an Sören und Neun für die Hilfe.

Thomas
Soeren Muehlbauer
2007-01-17 08:18:25 UTC
Permalink
Hi,
Post by Thomas Cebulla
Nicht gethemed wird das dargestellt, was in irgendwelchen Paint-Methoden
von Delphi gezeichnet wird(z.B. TGroupbox).
Das liegt daran, dass die Themeservices-Klasse aus der Unit themes schon
erzeugt wurde, bevor ich meinen Kontext erzeugen konnte. An der dortigen
InternalServices-Variable steht, dass zum Zeitpunkt der Erzeugung die alte
Comctl32-dll geladen war.
Setz doch mal einen Haltepunkt in Themes.pas: function ThemeServices: TThemeServices;.
Dann weißt Du, wer das Ding haben will. Vielleicht kannst Du noch davor den Kontext initialisieren.
Post by Thomas Cebulla
Danke an Sören und Neun für die Hilfe.
Gerne. Bye, Sören
Thomas Cebulla
2007-01-17 08:57:55 UTC
Permalink
Soeren Muehlbauer <***@gmx.de> wrote in news:***@mid.individual.net:

Hi,

Habe den Konstruktor des Hauptformulars überschrieben, den
Easyactivationkontext dort erzeugt und die Anwendung tut mir endlich den
Gefallen und sieht gethemed aus.

Thomas (, jetzt sehr glücklich!)

Lesen Sie weiter auf narkive:
Loading...