# chres.pl - change the resolution of the screen
#
# This script was written by Aldo Calpini (dada@perl.it) in 2001.
# It is released into the public domain. You may use it freely, however,
# if you make any modifications and redistribute, please list your name
# and describe the changes. This script is distributed without any warranty,
# express or implied.
use Win32
::API 0.20;
use Getopt
::Mixed;
my $VERSION = '0.51';
# the required APIs
my $EnumDisplaySettings = new Win32
::API(
"user32", "EnumDisplaySettings", "PNP", "N"
);
my $ChangeDisplaySettings = new Win32
::API(
"user32", "ChangeDisplaySettings", "PN", "N"
);
my $CreateDC = new Win32
::API(
"gdi32", "CreateDC", "PPPP", "N"
);
my $GetDeviceCaps = new Win32
::API(
"gdi32", "GetDeviceCaps", "NN", "N"
);
my $DeleteDC = new Win32
::API(
"gdi32", "DeleteDC", "N", "V"
);
# process command line options
Getopt
::Mixed::getOptions qw(
help h
>help
?>help
quiet q
>quiet
test t
>test
list l
>list
info i
>info
permanent p
>permanent
global g
>global
reset r
>reset
x
=i
y=i
colordepth
=s c
>colordepth
frequency
=i f
>frequency
);
# beautify list for BPPs
my %colors = (
4 => "16 Colors",
8 => "256 Colors",
16 => "High Color",
24 => "True Color",
32 => "True Color",
);
$opt_colordepth = color2bpp
($opt_colordepth) if $opt_colordepth;
# process non-options on command line
$doing = "x";
while(@ARGV) {
$argv = shift @ARGV;
if($doing eq "x") {
if($argv =~ /(\d+)x(\d+)/i) {
$opt_x = $1;
$opt_y = $2;
$doing = "colordepth";
} else {
$opt_x = $argv;
$doing = "y";
}
} elsif($doing eq "y") {
$opt_y = $argv;
$doing = "colordepth";
} elsif($doing eq "colordepth") {
$opt_colordepth = color2bpp
($argv);
$doing = "frequency";
} elsif($doing eq "frequency") {
$opt_frequency = $argv;
$doing = "skip";
}
}
if($opt_test) {
$flag = 0x02
;
} elsif($opt_permanent) {
$flag = 0x01
;
} elsif($opt_global) {
$flag = 0x08
;
} else {
$flag = 0;
}
if($opt_help) {
display_help
();
exit();
}
if($opt_reset) {
$res = $ChangeDisplaySettings->Call( 0, 0 );
print "Default mode restored.\n" unless $opt_quiet;
exit($res);
}
if($opt_info) {
($X, $Y, $BPP, $HZ) = getres
();
printf "%dx%d %s (%d Bit) %dHz\n",
$X, $Y, $colors{$BPP}, $BPP, $HZ unless $opt_quiet;
exit();
}
if($opt_list) {
exit( list_modes
($opt_x, $opt_y, $opt_colordepth, $opt_frequency) );
}
if(
not defined $opt_x
and not defined $opt_y
and not defined $opt_colordepth
and not defined $opt_frequency
) {
if(not $opt_quiet) {
print "Nothing to do.\n";
print "Type $0 --help for more information.\n";
}
exit();
}
$res = chres
($opt_x, $opt_y, $opt_colordepth, $opt_frequency, $flag);
unless( $opt_quiet ) {
if($res == 0) {
if($opt_test) { print "Test successful.\n"; }
else { print "Mode changed.\n"; }
}
if($res == 1) { print "The computer must be restarted.\n"; }
if($res == -1) {
print "The display driver failed the specified graphics mode.\n";
}
if($res == -2) { print "The graphics mode is not supported.\n"; }
if($res == -3) { print "Unable to write settings to the registry.\n"; }
if($res == -4) { print "Invalid parameters.\n"; }
if($res == -5) { print "Invalid parameters.\n"; }
}
exit($res);
sub chres
{
my($wanted_X, $wanted_Y, $wanted_BPP, $wanted_HZ, $flags) = @_;
$flags = 0 unless defined $flags;
my($actual_X, $actual_Y, $actual_BPP, $actual_HZ) = @_;
if(not defined $wanted_X
or not defined $wanted_X
or not defined $wanted_BPP
or not defined $wanted_HZ) {
($actual_X, $actual_Y, $actual_BPP, $actual_HZ) = getres
();
}
my $wanted;
$wanted = ((defined $wanted_X) ? $wanted_X : $actual_X);
$wanted .= "," . ((defined $wanted_Y) ? $wanted_Y : $actual_Y);
$wanted .= "," . ((defined $wanted_BPP) ? $wanted_BPP : $actual_BPP);
$wanted .= "," . ((defined $wanted_HZ) ? $wanted_HZ : $actual_HZ);
my $devmode = init_devmode
();
my $newmode = undef;
my $i = 0;
my $res = $EnumDisplaySettings->Call( 0, $i, $devmode );
while( $res != 0) {
($BPP, $X, $Y, undef, $HZ) = unpack("x104 LLLLL", $devmode);
$mode = "$X,$Y,$BPP,$HZ";
if($mode eq $wanted) {
$newmode = $devmode;
last;
}
$res = $EnumDisplaySettings->Call( 0, ++$i, $devmode );
}
if(defined $newmode) {
$res = $ChangeDisplaySettings->Call( $newmode, $flags );
} else {
$res = -2;
}
return $res;
}
sub getres
{
my $hdc = $CreateDC->Call("DISPLAY", 0, 0, 0);
if(!$hdc) {
return undef;
}
my $HORZRES = 8;
my $VERTRES = 10;
my $BITSPIXEL = 12;
my $VREFRESH = 116;
my $X = $GetDeviceCaps->Call($hdc, $HORZRES);
my $Y = $GetDeviceCaps->Call($hdc, $VERTRES);
my $BPP = $GetDeviceCaps->Call($hdc, $BITSPIXEL);
my $HZ = $GetDeviceCaps->Call($hdc, $VREFRESH);
$DeleteDC->Call($hdc);
return ($X, $Y, $BPP, $HZ);
}
sub list_modes
{
my($wanted_X, $wanted_Y, $wanted_BPP, $wanted_HZ) = @_;
my $modes = 0;
my $devmode = init_devmode
();
my $i = 0;
my $res = $EnumDisplaySettings->Call( 0, $i, $devmode );
while( $res != 0) {
($BPP, $X, $Y, undef, $HZ) = unpack("x104 LLLLL", $devmode);
if( (not defined $wanted_X or $wanted_X == $X)
and (not defined $wanted_Y or $wanted_Y == $Y)
and (not defined $wanted_BPP or $wanted_BPP == $BPP)
and (not defined $wanted_HZ or $wanted_HZ == $HZ)
) {
printf "%dx%d %s (%d Bit) %dHz\n",
$X, $Y, $colors{$BPP}, $BPP, $HZ unless $opt_quiet;
$modes++;
}
$res = $EnumDisplaySettings->Call( 0, ++$i, $devmode );
}
print "No matching graphics modes.\n" if not $opt_quiet and $modes == 0;
return $modes;
}
sub init_devmode
{
return pack(
"B" x
32 . "SSSSLsssssssssssss" . "B" x
32 . "SLLLLL",
(0 x
32), # dmDeviceName
0, # dmSpecVersion
0, # dmDriverVersion
124, # dmSize
0, # dmDriverExtra
0, # dmFields
0, # dmOrientation
0, # dmPaperSize
0, # dmPaperLength
0, # dmPaperWidth
0, # dmScale
0, # dmCopies
0, # dmDefaultSource
0, # dmPrintQuality
0, # dmColor
0, # dmDuplex
0, # dmYResolution
0, # dmTTOption
0, # dmCollate
(0 x
32), # dmFormName
0, # dmLogPixels
0, # dmBitsPerPel
0, # dmPelsWidth
0, # dmPelsHeight
0, # dmDisplayFlags
0, # dmDisplayFrequency
);
}
sub color2bpp
{
my($arg) = shift;
$arg = lc $arg;
my %table = (
1 => 1,
2 => 2,
16 => 4,
256 => 8,
65000 => 16,
'64k' => 16,
'65k' => 16,
high
=> 16,
'16m' => 24,
true
=> 32,
);
if($arg =~ /^(\d+)b$/) {
return $1;
} elsif(exists $table{$arg}) {
return $table{$arg};
}
}
sub display_help
{
print qq(
$0 version
$VERSION, (c
) 2001 Aldo Calpini
<dada
\@perl.it
>
usage
: $0 [OPTIONS
] [NNNxNNN
] [COLORS
] [FREQ
]
OPTIONS
:
--help shows this help
--x NNN width
, in pixels
--y NNN height
, in pixels
--colordepth COLORS color depth
(see below
)
--frequency NNN vertical refresh rate
, in Hz
(only WinNT
/2000)
--quiet does
not display information on
STDOUT
--reset reset the screen to the default mode
--info isplay the current mode
and exit
--list list the available modes
. can be combined with
--x
, --y, --colordepth
and --frequency
, for
example
: '--x 1024 --list' lists all the
modes with width of
1024 pixels
--test test the given mode without making changes
--permanent make change permanent
(for the current user
)
--global make change permanent
and global
(for all
users
) (only WinNT
/2000)
all options can be given in the short form too
(eg
. -t
for --test
,
-h
for --help
, -x
for --x
and so on
).
COLORS
:
recognized
values are
:
1, 2, 1b
> 2 colors
(1 bpp
)
16, 4b
=> 16 colors
(4 bpp
)
256, 8b
=> 256 colors
(8 bpp
)
65000, 64k
, high
, 16b
=> 65536 colors
(16 bpp
)
16m
, true
, 32b
=> 16 millions colors
(32 bpp
)
the
--x
, --y, --colordepth
and --frequency options can also be
given on command line without introduction
, but in this
case
order must be respected
. for example
, to change to a 800x600
screen resolution
:
$0 800x600
or $0 800 600
to change to 800x600
, 32bpp
, 85Hz
:
$0 800 600 32 85
);
}
=head1 NAME
chres - CHange RESolution
=head1 DESCRIPTION
Change the resolution of the screen on a Windows machine.
Launch the script with the --help option for a detailed
description of the usage.
=head1 README
Change the resolution of the screen on a Windows machine.
=head1 PREREQUISITES
This script requires C<Win32::API 0.20> and C<Getopt::Mixed>.
=pod OSNAMES
MSWin32
=pod SCRIPT CATEGORIES
Win32
Win32/Utilities
=head1 AUTHOR
Aldo Calpini (dada@perl.it).
=cut