При разработке приложений, которые затем будут использоваться на большом числе различных ПК очень полезно иметь возможность не только получения информации о текущем видеорежиме, но и возможность получить все доступные видеорежимы для данного ПК. Еще одна область, где используется переключение видеорежимов при написании игр без использования DirectX.
Получить видеорежимы можно серией вызовов EnumDisplaySettings. Функция EnumDisplaySettings возвращает информацию о видеорежиме, указанном в параметре IModeNode. Функции необходимо передать структуру типа TDevMode, в которую будет записана информация о видеорежиме. Данная структура имеет поля, характеризующие видеорежим: разрешение (dmPelsWidth, dmPelsHeight), количество битов цветности (dmBitsPerPel), частота обновления экрана (dmDisplayFrequency) и др.
function EnumDisplaySettings( lpszDeviceName: PWideChar; iModeNum: DWORD; var lpDevMode: TdeviceMode ): BOOL; stdcall;Параметры
| Поле | Описание |
| DmBitsPerPel | Количество бит на пиксел |
| DmPelsWidth | Ширина в пикселях |
| DmPelsHeight | Высота в пикселях |
| DmDisplayFlags | DM_GRAYSCALE - Черно-белое устройствоDM_INTERLACED - Черезстрочная развертка. Если флаг не установлен, подразумевается построчная развертка |
| dmDisplayFrequency | Частота обновления экрана |
| DmPosition | Windows 98, Windows 2000: Номер монитора для конфигураций с несколькими мониторами |
| DmFields | Описание ниже |
Поле dmFields используется
при смене видеорежима для указания, какие именно из параметров устройства мы хотим
изменить. Каждый бит поля определяет необходимость смены одного из параметров.
Ниже приведены возможные значения и их описания.
| Флаг | Описание |
| DM_BITSPERPEL | Изменить количество бит на пиксель на значение указанное в поле dmBitsPerPel. |
| DM_PELSWIDTH | Изменить ширинку экрана на значение указанное в поле dmPelsWidth. |
| DM_PELSHEIGHT | Изменить выстоу экрана на значение указанное в поле dmPelsHeight |
| DM_DISPLAYFLAGS | Изменить флаги. |
| DM_DISPLAYFREQUENCY | Изменить частоту обновления dmDisplayFrequency. |
| DM_POSITION | Windows 98, Windows 2000: изменить номер монитора. |
Если lpDevMode равно nil, из реестра берется информация о видеорежиме установленном по умолчанию. Передавая в lpDevMode nil и в dwFlags 0 можно получить настройки текущего видеорежима.
Ниже приведена процедура, получающая и отображающая в ListBox все возможные видеорежимы.
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
DevMode : TDeviceMode;
begin
i:=0;
while EnumDisplaySettings(nil,i,DevMode) do begin
with Devmode do
ListBox1.Items.Add
(Format('%dx%d %d Colors',
[dmPelsWidth,dmPelsHeight,Int64(1) shl dmBitsperPel]));
Inc(i);
end;
end;
Помимо вызова EnumDisplaySettings инфомацию о текущем видеорежиме можно получать и другими способами.Получить количество битов цвета текущего видеорежима можно и другим способом:
GetDeviceCaps(Form1.Canvas.Handle, BITSPIXEL) * GetDeviceCaps(Form1.Canvas.Handle, PLANES)Получаемые значения при этом:
NumberOfColors := (1 shl
(GetDeviceCaps(Form1.Canvas.Handle, BITSPIXEL) *
GetDeviceCaps(Form1.Canvas.Handle, PLANES));
Текущее разрешение экрана можно узнать с помощью вызова GetSystemMetrics()
в качестве параметров передается:
Var
x, y : Integer;
Mode:String;
begin
x:=GetSystemMetrics(Sm_Cxscreen);
y:=GetSystemMetrics(Sm_CYscreen);
Mode:=Format('%d x %d',[x,y]);
If y=480 Then
Mode:=Mode+('Standard VGA')
Else
Mode:=Mode+('Super VGA');
StaticText1.Caption:=Mode;
end;
Как мы убедились получения списка и параметров видеорежимов не проблема. Теперь разберемся с программной сменой видеорежимов. Функция ChangeDisplaySettings предназначена для изменения текущего видеорежима экрана и при необходимости обновления этой информации в реестре Windows.
function ChangeDisplaySettings( var lpDevMode: TDeviceMode; dwFlags: DWORD ): Longint; stdcall;Параметры
| Value | Meaning |
| DISP_CHANGE_SUCCESSFUL | Изменения прошли успешно. |
| DISP_CHANGE_RESTART | Необходима перезагрузка для вступления изменений в силу |
| DISP_CHANGE_BADFLAGS | Передан неверный набор флагов |
| DISP_CHANGE_BADPARAM | Неверные параметры. |
| DISP_CHANGE_FAILED | Драйвер видеоустройства не смог установить режим |
| DISP_CHANGE_BADMODE | Видеорежим не поддерживается |
| DISP_CHANGE_NOTUPDATED | Windows NT/2000: Ошибка записи в реестр |
{...}
type
TForm1 = class(TForm)
Button1: TButton;
ListView1: TListView;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ListView1DblClick(Sender: TObject);
private
{ Private declarations }
{Массив для хранения информации о видеорежимах}
DevMode : array[0..20] of TDeviceMode;
public
{ Public declarations }
end;
{...}
procedure TForm1.FormCreate(Sender: TObject);
begin
{Настройка ListView}
ListView1.ViewStyle := vsReport;
ListView1.RowSelect := TRUE;
ListView1.Columns.Add;
ListView1.Columns.Add;
ListView1.Columns[0].Caption := 'Width x Height';
ListView1.Columns[0].Width := 100;
ListView1.Columns[1].Caption := 'Colors';
ListView1.Columns[1].Width := 100;
end;
{Процедура получения списка режимов}
procedure TForm1.Button1Click(Sender: TObject);
var
tmpStr1,
tmpStr2 : String;
tmpDC : HDC;
x,
Selection,
cxScreen,
cyScreen,
Resolution : Integer;
begin
{ Запоминаем текущие настройки}
tmpDC := getDC(Handle);
try
cxScreen := GetSystemMetrics(SM_CXSCREEN);
cyScreen := GetSystemMetrics(SM_CYSCREEN);
Resolution := GetDeviceCaps(tmpDC, BITSPIXEL);
finally
ReleaseDC(Handle, tmpDC);
end;
ListView1.Items.Clear;
x := 0;
{ Получаем список видеорежимов}
while EnumDisplaySettings(nil,x,DevMode[x]) do
begin
{ Разрешение экрана }
tmpStr1 := IntToStr(DevMode[x].dmPelsWidth)+
'x'+
IntToStr(DevMode[x].dmPelsHeight);
{ Цвета }
case DevMode[x].dmBitsPerPel of
4 : tmpStr2 := '16 Colors';
8 : tmpStr2 := '256 Colors';
16 : tmpStr2 := 'High Color (16 Bit)';
32 : tmpStr2 := 'True Color (32 Bit)';
end;
{ А теперь полученную информацию надо отобразить }
with ListView1.Items.Add do
begin
Caption := tmpStr1;
SubItems.Add(tmpStr2);
end;
{ В ListView надо встать не строку с описанием текущего
режима, для этого сохраним индекс элемента с описанием этого режима }
if ( cxScreen = DevMode[x].dmPelsWidth ) and
( cyScreen = DevMode[x].dmPelsHeight ) and
( Resolution = DevMode[x].dmBitsPerPel ) then
Selection := x;
inc(x);
if x = 20 then
Break;
end;
{ В ListView перемещаемся на строчку с описанием текущего режима }
ActiveControl := ListView1;
ListView1.Selected := ListView1.Items.Item[Selection];
end;
{Установка выбранного пользователем видеорежима}
procedure TForm1.ListView1DblClick(Sender: TObject);
var
tmpDevMode : TDevMode;
begin
{ Получаем сохраненную ранее информацию по выбранному режиму}
tmpDevMode := DevMode[ListView1.Items.IndexOf(ListView1.Selected)];
{ Скажем Windows, какие параметры надо сменить }
tmpDevMode.dmFields := DM_BITSPERPEL or
DM_PELSWIDTH or
DM_PELSHEIGHT or
DM_DISPLAYFLAGS or
DM_DISPLAYFREQUENCY;
{ Очень неплохо будет протестировать видеорежим и записать изменения в реестр}
if ChangeDisplaySettings(tmpDevMode,
CDS_TEST) = DISP_CHANGE_SUCCESSFUL then
ChangeDisplaySettings(tmpDevMode,
CDS_UPDATEREGISTRY);
end;
Замечание 1: Не рекомендуется устанавливать видеорежимы, отличные от полученных
вызовами EnumDisplaySettings. Возможна ситуация, когда пользователь вместо рабочего
стола увидит лишь черный экран.
...
type
TForm1 = class(TForm)
ListBox1: TListBox;
...
private
procedure WMDisplayChange(var Message:TMessage);
message WM_DISPLAYCHANGE;
...
procedure
TForm1.WMDisplayChange(var Message: TMessage);
begin
ShowMessage('Changes in display detected!');
inherited;
end;