Bildschirmeinstellungen ermitteln und ändern
Veröffentlicht: 12. Nov 2001 | Aktualisiert: 13. Jun 2004
Von Mathias Schiffer
Aktuelle Bildschirmeinstellungen ermitteln
Die Ermittlung der aktuellen Bildschirmauflösung ermöglicht die API-Funktion GetDeviceCaps in Verbindung mit den Konstanten HORZRES und VERTRES. Sie verlangt weiterhin ein Handle auf einen "Device Context" (DC) für den Bildschirm, den die Funktion GetDC unter Übergabe des Parameters 0 ermittelt:
Private Const HORZRES As Long = 8& Private Const VERTRES As Long = 10& Private Declare Function GetDC _ Lib "user32" ( _ ByVal hWnd As Long _ ) As Long Private Declare Function GetDeviceCaps _ Lib "gdi32" ( _ ByVal hdc As Long, _ ByVal nIndex As Long _ ) As Long ' --- Anwendung Dim hDCScreen As Long Dim lScreenWidth As Long Dim lScreenHeight As Long hDCScreen = GetDC(0&) lScreenWidth = GetDeviceCaps(hDCScreen, HORZRES) lScreenHeight = GetDeviceCaps(hDCScreen, VERTRES) MsgBox "Bildschirmauflösung: " & _ CStr(lScreenWidth) & " x " & _ CStr(lScreenHeight) & " Pixel.", _ vbInformation
Tipp: Oft sieht man den Ansatz, die Bildschirmauflösung in Pixelskala noch einfacher mithilfe des Screen-Objekts und dessen Eigenschaften Width, Height, TwipsPerPixelX und TwipsPerPixelY zu ermitteln. Berichten vereinzelter Entwickler zufolge werden jedoch die Eigenschaften des Screen-Objekts nach einer Änderung der Bildschirmauflösung durch den Anwender nicht in jedem Fall korrekt aktualisiert (offenbar in Abhängigkeit der eingesetzten Hardware und der Gerätetreiber dafür). Angesichts der fehlenden Möglichkeit einer Einflussnahme auf diese Faktoren rate ich von diesem Vorgehen ab. Die Möglichkeit, diese Daten mithilfe von GetDeviceCaps zu ermitteln, ist ein nur minimal größerer Aufwand.
Möchten Sie die aktuelle eingestellte Farbtiefe ermitteln, können Sie ebenfalls GetDeviceCaps verwenden. In Kombination mit der Konstanten BITSPIXEL liefert die Funktion die Anzahl der Bits zurück, die für das Speichern der Farbinformationen für ein einzelnes Pixel verwendet werden. Die Anzahl dadurch darstellbarer Farben errechnet sich aus der Farbtiefe durch einfaches Potenzieren:
Private Const BITSPIXEL As Long = 12& ' --- Anwendung Dim hDCScreen As Long Dim lScreenColDepth As Long hDCScreen = GetDC(0&) lScreenColDepth = GetDeviceCaps(hDCScreen, BITSPIXEL) MsgBox "Farbtiefe: " & _ CStr(lScreenColDepth) & " Bits pro Pixel = " & _ CStr(2 ^ lScreenColDepth) & " Farben.", _ vbInformation
Eine zentrale Information über die Bildschirmeinstellung ist die Bildwiederholfrequenz in Hertz. Ein Blick in die Dokumentation zu GetDeviceCaps legt die Verwendung der Konstanten VREFRESH nahe - verrät aber auch, dass die Verwendung dieser Konstanten nur unter Windows NT, 2000 und XP funktioniert. Unter Windows 9x/Me liefert der Aufruf konsequent den Wert 0 zurück:
Private Const VREFRESH As Long = 116& ' --- Anwendung Dim hDCScreen As Long Dim lScreenRefresh As Long hDCScreen = GetDC(0&) lScreenRefresh = GetDeviceCaps(hDCScreen, VREFRESH) MsgBox "Bildwiederholfrequenz: " & _ CStr(lScreenRefresh) & " Hz." & vbNewLine & _ "<STRONG>Hinweis:</STRONG> Funktioniert nicht unter Win9xMe!", _ vbInformation
Mit einer Ausnahme haben wir damit dank GetDeviceCaps alle interessanten Informationen über die aktuellen Bildschirmeinstellungen auf einfache Weise ermittelt. Doch auch die Ermittlung der Bildwiederholfrequenz unter Win9x/Me ist nicht etwa Hexenwerk in der Registry. Später in diesem Artikel wird gezeigt, wie diese Information mithilfe der Funktion EnumDisplayettings mit nur wenig Mehraufwand zu ermitteln ist.
Bildschirmeinstellungen ändern
Was aber, wenn wir die Bildschirmeinstellungen verändern möchten? Die Suche nach einem GetDeviceCaps-Äquivalent "SetDeviceCaps" bleibt erfolglos, einen direkten Rückwärtsgang zum obigen Vorgehen gibt es also nicht. Zuständig ist für unser Ansinnen die API-Funktion ChangeDisplaySettings, die zusätzlich die Verwendung der umfangreichen Struktur DEVMODE (für "Device Mode") erforderlich macht:
Private Const CCHDEVICENAME As Long = 32& Private Const CCHFORMNAME As Long = 32& Private Type DEVMODE dmDeviceName As String * CCHDEVICENAME dmSpecVersion As Integer dmDriverVersion As Integer dmSize As Integer dmDriverExtra As Integer dmFields As Long dmOrientation As Integer dmPaperSize As Integer dmPaperLength As Integer dmPaperWidth As Integer dmScale As Integer dmCopies As Integer dmDefaultSource As Integer dmPrintQuality As Integer dmColor As Integer dmDuplex As Integer dmYResolution As Integer dmTTOption As Integer dmCollate As Integer dmFormName As String * CCHFORMNAME dmUnusedPadding As Integer dmBitsPerPel As Long dmPelsWidth As Long dmPelsHeight As Long dmDisplayFlags As Long dmDisplayFrequency As Long End Type Private Declare Function ChangeDisplaySettings _ Lib "user32" Alias "ChangeDisplaySettingsA" ( _ ByRef lpDEVMODE As DEVMODE, _ ByVal Flags As Long _ ) As Long
Die für unseren Zweck besonders interessanten Elemente der DEVMODE-Struktur sind dmPelsWidth (Breite der Anzeige in Pixelskala), dmPelsHeight (Höhe der Anzeige in Pixelskala), dmBitsPerPel (Farbtiefe in Bits pro Pixel) und dmDisplayFrequency (Bildwiederholfrequenz). Zusätzliche Aufmerksamkeit verlangt das Element dmSize, dem vor Verwendung der DEVMODE-Struktur mittels Len-Funktion die Größe der Struktur mitgeteilt werden muss. Weiterhin interessiert uns das Element dmFields, in dem durch Or-Verknüpfung der folgenden Konstanten angegeben wird, welche DEVMODE-Informationen ein Funktionsaufruf berücksichtigen soll:
Private Const DM_BITSPERPEL As Long = &H40000 Private Const DM_PELSWIDTH As Long = &H80000 Private Const DM_PELSHEIGHT As Long = &H100000 Private Const DM_DISPLAYFREQUENCY As Long = &H400000
DM_PELSWIDTH |
Das Element dmPelsWidth der DEVMODE-Struktur soll berücksichtigt werden. |
DM_PELSHEIGHT |
Das Element dmPelsHeight der DEVMODE-Struktur soll berücksichtigt werden. |
DM_BITSPERPEL |
Das Element dmBitsPerPel der DEVMODE-Struktur soll berücksichtigt werden. |
DM_DISPLAYFREQUENCY |
Das Element dmDisplayFrequency der DEVMODE-Struktur soll berücksichtigt werden. |
Der zweite Parameter der Funktion ChangeDisplaySettings gibt an, auf welche Weise die Bildschirmeinstellungen geändert werden sollen. Für diesen Parameter sind die folgenden Konstanten vorgesehen:
Private Const CDS_UPDATEREGISTRY As Long = &H1& Private Const CDS_TEST As Long = &H2&
CDS_TEST - Es soll geprüft werden, ob die Grafikkarte die angefragten Bildschirmeinstellungen unterstützt. Die Bildschirmeinstellungen werden nicht geändert.
0 - Die Bildschirmeinstellungen sollen vorübergehend geändert werden. Nach einem Neustart werden die ursprünglichen Bildschirmeinstellungen wiederhergestellt.
CDS_UPDATEREGISTRY - Die Bildschirmeinstellungen sollen dauerhaft geändert werden. Die entsprechenden Angaben in der Registry werden aktualisiert, so dass die neuen Bildschirmeinstellungen auch nach einem Neustart des Systems aktuell bleiben.
Der Rückgabewert der Funktion gibt nicht nur Aufschluss über den Erfolg des Aufrufs, sondern liefert auch zusätzliche Informationen:
Private Const DISP_CHANGE_SUCCESSFUL As Long = 0& Private Const DISP_CHANGE_RESTART As Long = 1& Private Const DISP_CHANGE_FAILED As Long = -1& Private Const DISP_CHANGE_BADMODE As Long = -2& Private Const DISP_CHANGE_NOTUPDATED As Long = -3& Private Const DISP_CHANGE_BADFLAGS As Long = -4& Private Const DISP_CHANGE_BADPARAM As Long = -5&
DISP_CHANGE_SUCCESSFUL |
Die Bildschirmeinstellungen wurden geändert. |
DISP_CHANGE_RESTART |
Der Aufruf war erfolgreich, aber das System muss neu gestartet werden, damit die neuen Bildschirmeinstellungen verwendet werden (wie Sie Windows von Ihrem Sourcecode aus neu starten können, erfahren Sie im MSDN Quickie "Windows 95, 98 und NT herunterfahren"). |
DISP_CHANGE_FAILED |
Die Grafikarte konnte die Bildschirmeinstellungen nicht ändern. |
DISP_CHANGE_BADMODE |
Der Grafikmodus wird nicht unterstützt. |
DISP_CHANGE_BADFLAGS |
Der Aufruf schlug wegen ungültiger Flags fehl. |
DISP_CHANGE_BADPARAM |
Es wurde ein ungültiger Parameter übergeben. |
DISP_CHANGE_NOTUPDATED |
(Nur Windows NT/2000/XP) Die neuen Bildschirmeinstellungen konnten nicht in der Registry gespeichert werden. |
Um zu überprüfen, ob die Grafikkarte einen gewünschten Modus unterstützt, können wir also so vorgehen:
Dim DM As DEVMODE Dim lResult As Long ' DEVMODE-Struktur vorbereiten: With DM .dmSize = Len(DM) .dmFields = DM_PELSWIDTH _ Or DM_PELSHEIGHT _ Or DM_BITSPERPEL .dmPelsWidth = 1024 ' Breite .dmPelsHeight = 768 ' Höhe .dmBitsPerPel = 24 ' 2^24 = 16777216 Farben End With ' Testen, ob die Einstellung 1024x768 Pixel mit 16 Mio Farben unterstützt wird: lResult = ChangeDisplaySettings(DM, CDS_TEST) ' Ausgabe des Ergebnisses: Select Case lResult Case DISP_CHANGE_SUCCESSFUL MsgBox "Bildschirmmodus kann sofort gesetzt werden.", vbInformation Case DISP_CHANGE_RESTART MsgBox "Bildschirmmodus kann nach Neustart gesetzt werden.", vbInformation Case Else MsgBox "Bildschirmmodus kann nicht gesetzt werden.", vbCritical End Select
Um von der Grafikkarte unterstützte Bildschirmeinstellungen nach erfolgreichem Test zu setzen, wird die Konstante CDS_TEST für eine Änderung bis zum Neustart des Systems durch 0 ersetzt. Für eine dauerhafte Änderung verwenden Sie an dieser Stelle die Konstante CDS_UPDATEREGISTRY.
Tipp: Es empfiehlt sich, nach Windows-Art vor der endgültigen Änderung von Bildschirmeinstellungen den Anwender beurteilen zu lassen, ob ein vorgesehener Anzeigemodus für ihn brauchbar ist. Dafür schalten Sie zunächst für nur wenige Sekunden auf den neuen Modus um. Danach sollte wieder auf den vorherigen Bildschirmmodus gewechselt werden, um den Anwender zu fragen, ob der zeitweise gesetzte Bildschirmmodus für ihn stabil sichtbar war. Es ist nämlich durchaus nicht ungewöhnlich, dass eine Grafikkarte zwar problemlos mit einem Bildschirmmodus zurecht kommt, der Monitor des Anwenders aber mit der Darstellung eines solchen Modus überlastet ist. Dies kann dazu führen, dass der Anwender die Kontrolle über seinen Rechner verliert, weil er kein stabiles Bild mehr sehen kann. Erst nach Bestätigung durch den Anwender sollten Sie dann die vorgesehenen Bildschirmeinstellungen tatsächlich aktivieren.
Womit wir bei der Frage angekommen wären: Woher erfahren wir eigentlich, welche Kombinationen an Bildeinstellungen eine Grafikkarte unterstützt?
Unterstützte Bildschirmeinstellungen ermitteln
Die Grafikmodi, die von einem Grafikkarten-Treiber unterstützt werden, werden mithilfe der API-Funktion EnumDisplaySettings ermittelt:
Private Const ENUM_CURRENT_SETTINGS As Long = &HFFFFFFFE Private Const ENUM_REGISTRY_SETTINGS As Long = &HFFFFFFFD Private Declare Function EnumDisplaySettings _ Lib "user32" Alias "EnumDisplaySettingsA" ( _ ByVal lpszDeviceName As String, _ ByVal lModeNumber As Long, _ ByRef lpDEVMODE As DEVMODE _ ) As Long
Im ersten Parameter von EnumDisplaySettings - lpszDeviceName - wird der Name eines Anzeigegeräts übergeben (z.B. "\\.\DISPLAY1"). Für das aktuelle Anzeigegerät vereinfacht sich dieser Parameter durch Übergabe von vbNullString.
Im dritten Parameter findet sich die bekannte DEVMODE-Struktur, in der Windows Informationen über die jeweiligen Bildschirmeinstellungen zurück liefert.
Der für die Bedienung interessanteste Parameter ist lModeNumber: Wird er beim Aufruf von EnumDisplaySettings zu 0 gesetzt, ermittelt Windows den ersten verfügbaren Bildschirmmodus. Den zweiten verfügbaren Modus ermittelt die Funktion bei Übergabe von 1, usw., bis durch den Funktionsrückgabewert 0 signalisiert wird, dass keine weiteren Bildschirmmodi zur Verfügung stehen.
Spezielle Bedeutung kommt den oben bereits definierten Konstanten ENUM_CURRENT_SETTINGS und ENUM_REGISTRY_SETTINGS zu:
Setzen Sie für lpModeNumber die Konstante ENUM_CURRENT_SETTINGS ein, wird die Funktion EnumDisplaySettings angewiesen, in lpDEVMODE die aktuellen Bildschirmeinstellungen zurück zu liefern. Hier wird die Bildwiederholfrequenz auch unter Windows 9x/Me korrekt übergeben - unser eingangs erwähntes Problem bei der Verwendung von VREFRESH mit GetDeviceCaps unter Windows 9x/Me ist damit gelöst:
' Ermittlung der Bildwiederholfrequenz (auch unter Windows 9x/Me): Dim DM As DEVMODE Dim lResult As Long ' DEVMODE-Struktur vorbereiten: With DM .dmSize = Len(DM) .dmFields = DM_DISPLAYFREQUENCY End With ' Abrufen der aktuellen Auflösung: EnumDisplaySettings vbNullString, ENUM_CURRENT_SETTINGS, DM MsgBox "Aktuelle Bildwiederholfrequenz: " _ & CStr(DM.dmDisplayFrequency) _ & " Hertz", vbInformation
Der Konstanten ENUM_CURRENT_SETTINGS kommt analog die Bedeutung zu, die derzeit in der Registry eingetragenen Daten über den Bildschirmmodus nach einem Neustart zu ermitteln.
Tipp: Wenn Sie die Bildwiederholfrequenzen aller verfügbaren Bildschirmeinstellungen auflisten, wird Ihnen je nach eingesetzter Hardware auffallen, dass einige Einstellungen eine Bildwiederholfrequenz von 0 bzw. 1 aufweisen. Natürlich handelt es sich dabei nicht Angaben in Hertz, sondern um unbekannte Standardwerte, die anhand von Jumper-Steckern auf der Grafikkarte oder über andere Hilfsprogramme konfiguriert werden. Windows hat über die Hertz-Werte, die sich hinter diesen Einstellungen verbergen, keine Informationen und kann sie daher auch nicht zurück liefern. Im Windows-eigenen Dialog für Bildschirmeinstellungen werden Sie diese Bildschirmmodi daher auch nicht auffinden - sie werden dort der Einfachheit halber nicht aufgeführt. Wenn Sie in Ihren Anwendungen von EnumDisplaySettings angegebene Bildschirmmodi mit diesen "Bildwiederholfrequenzen" ignorieren, handeln Sie also Windows-konform.
Weitere Informationen zu den eingesetzten API-Funktionen und ihrer Bedienung finden Sie in Ihrer MSDN Library oder im MSDN Online.