Einsatz einer Manifest-Datei
Bedeutung
Vereinfacht gesprochen ist eine Manifest-Datei eine Brücke zwischen einem Xbase++-Programm sowie verschiedenen Funktionalitäten des Betriebssystems, die anders nur sehr schwer abgreifbar sind.
Das volle Programm, das über die Einbindung einer Manifest-Datei genutzt werden kann, ist nicht unbedingt im ganzen Umfang über Xbase++ nutzbar, aber es gibt viele Aspekte, die im heutigen Umfeld beim Programmeinsatz zwingend nötig sind, um den erwarteten Komfort zu gewährleisten, den die Anwender vom Betriebssystem oder anderen Anwendungen kennen.
Alaska Software liefert zwei Beispiele für das Einbinden von Manifest-Dateien mit, diese Beispiele sind unter ..\source\samples\basic\manifest zu finden. Beide Beispiele sind ein guter Startpunkt, um sich an das Thema anzunähern.
Um mehr über die technischen Hintergründe zu erfahren, gibt es entsprechende Dokumentation von Microsoft, allerdings nur auf Englisch: Manifest Files Reference.
Beispiel einer Manifest-Datei
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="YourCompanyName.YourDivision.YourApp" type="win32" /> <description>Your app description here</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly>
Diese Manifest-Datei ist aus dem oben genannten Beispiel von Alaska Software entnommen.
Einbinden von ActiveX-Controls
ActiveX-Controls müssen eigentlich auf dem entsprechenden PC, auf dem sie genutzt werden sollen, installiert sein.
Es gibt jedoch die Möglichkeit, sie über eine Manifest-Datei einzubinden, ohne dass eine zusätzliche Installation erforderlich ist.
<file name="ctTray.ocx"> <comClass description="ctTray ActiveX Control 4.0" clsid="{F64C15F5-713B-4A9F-AB48-04B10ABC1483}" progid="ctTRAY.ctTrayCtrl.4" threadingModel="apartment" /> </file>
Verbindung zwischen einer Manifest-Datei und dem Programm
als externe Datei
Wird eine externe Manifest-Datei verwendet, muss sie einer bestimmten Namenskonvention folgen. Sie muss den gleichen Namen wie das zugeordnete Programm haben, mit der zweiten Namenserweiterung .manifest. Heisst das Programm also krautsalat.exe, so muss die Manifest-Datei krautsalat.exe.manifest heissen, andernfalls wird sie ignoriert.
als Bestandteil der .exe-Datei
In diesem Fall muss die Manifest-Datei über eine .arc-Datei eingebunden werden.
In der .arc-Datei muss der Eintrag dann z.B. so aussehen:
#define MANIFEST_RESID 1 #define MANIFEST 24 USERDEF MANIFEST MANIFEST_RESID = FILE "extfile.exe.manifest"
Die .arc-Datei ist dann - wie üblich - für den Linker mit einzubinden.
In diesem Fall unterliegt übrigens der Namen der Manifest-Datei keinen Beschränkungen, da der Linker den Inhalt aus der .res-Datei übernimmt und die Namensübereinstimmung nicht für das Laden beim Programmbeginn erforderlich ist.
Beispiele für den Einsatz einer Manifest-Datei
Ermitteln der Skalierung des Monitors
Windows erlaubt es, abweichend von der "normalen" Skalierung von 100 % auch grössere Skalierungen einzustellen. Unter Windows 10 ist dies je Bildschirm möglich, d.h. man kann den einen Bildschirm mit 100 % und den zweiten mit 150 % Skalierung nutzen.
Wird eine höhere Skalierung verwendet, sollte ein Programm dies auch erkennen und seine Dialog-Elemente entsprechend anpassen können.
Um die Skalierung des Monitors ermitteln zu können, muss man unter Xbase++ mit einer Manifest-Datei arbeiten, die das Programm als "dpiAware" ausweist.
Hier zuerst ein Beispiel für eine solche Manifest-Datei:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="demoprogramm" type="win32" /> <description>Demo Programm</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" > <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> <dpiAware>true</dpiAware> </asmv3:windowsSettings> </asmv3:application> </assembly>
Entscheidend für unser Beispiel ist der Eintrag <dpiAware>true</dpiAware>. Er besagt, dass die Anwendung unterschiedlich DPI-Werte erkennen soll.
Der Xbase++-Code für eine Erkennung der Skalierung sieht so aus:
#INCLUDE "Gra.ch" ... FUNCTION GetTextDPI() LOCAL aTmp Local nRelation LOCAL oPS oPS := XbpPresSpace():New():Create( AppDesktop():WinDevice(), {100,100}, GRA_PU_LOENGLISH) aTmp:= oPS:SetViewport() oPS:Destroy() nRelation := aTmp[3]-aTmp[1] RETURN (nRelation)
Es wird ein XbpPresSpace()-Objekt erzeugt, das die Ausgabeeinheit des Desktops verwendet. Der Bereich ist 100 * 100 Einheiten gross. Die Einheiten werden durch den Parameter GRA_PU_LOENGLISH definiert. In diesem Fall ist eine Einheit 0,01 Inch, entsprechend ist die Fläche des XbpPresSpace()-Objektes 1 Inch zum Quadrat. Die Methode :setViewPort() ruft die Koordinaten des XbpPresSpace()-Objektes ab. Die Differenz zwischen den entsprechenden Koordinaten-Paaren ergibt den DPI-Wert, wobei 96 der Standard-Wert für eine Skalierung von 100 % ist.