#!perl use strict; use warnings; use PeekPoke qw(peek poke); use Win32::API; use Win32::GUI qw(); use Win32::GUI::Constants qw( CW_USEDEFAULT WM_MEASUREITEM WM_DRAWITEM ODA_DRAWENTIRE SRCCOPY ); use constant { MENU_ITEMS => 6, # These are needed for creating menu icons MIIM_BITMAP => 0x00000080, MIM_STYLE => 0x00000010, MNS_CHECKORBMP => 0x04000000, MNS_NOCHECK => 0x80000000, HBMMENU_CALLBACK => 0xFFFFFFFF, HBMMENU_SYSTEM => 1, HBMMENU_MBAR_RESTORE => 2, HBMMENU_MBAR_MINIMIZE => 3, HBMMENU_MBAR_CLOSE => 5, HBMMENU_MBAR_CLOSE_D => 6, HBMMENU_MBAR_MINIMIZE_D => 7, HBMMENU_POPUP_CLOSE => 8, HBMMENU_POPUP_RESTORE => 9, HBMMENU_POPUP_MAXIMIZE => 10, HBMMENU_POPUP_MINIMIZE => 11, }; # Import the Win32 API functions we need Win32::API->Import( 'user32.dll', 'SetMenuItemInfo', 'LILP', 'L' ); Win32::API->Import( 'user32.dll', 'SetMenuInfo', 'LP', 'L' ); # Create a simple menu # We specify our own menu item id since we need to check the id of the item # that needs to be drawn in the WM_DRAWITEM hook below. my $mnuMain = Win32::GUI::Menu->new( 'Menu' => 'mnuMenu', map { ( "> Item $_" => { -name => "mnuMenuItem$_", -id => $_ } ) } 1 .. MENU_ITEMS, ); # Remove check mark space my $menuinfo = pack 'LLLILLL', 28, # Size MIM_STYLE, # Mask MNS_NOCHECK, # Style 0, # Max height of menu 0, # Background brush 0, # Context help identifier 0; # Application defined value SetMenuInfo( $mnuMain->{mnuMenu}->{-handle}, $menuinfo ); # Create some simple bitmaps my @bitmaps; foreach( 1 .. MENU_ITEMS ){ my $r = int rand 256; my $g = int rand 256; my $b = int rand 256; my $data = pack 'C*', map { $r, $g, $b, 0 } 0 .. ( ( 16 ** 2 ) - 1 ); push @bitmaps, Win32::GUI::Bitmap::Create( 16, 16, 1, 32, $data ); } # Specify that bitmap for each menu item will be owner drawn my $menuiteminfo = pack 'IIIIILLLLLIL', 48, # Size MIIM_BITMAP, # Mask 0, # Type 0, # State 0, # ID 0, # SubMenu 0, # Checked bitmap 0, # Unchecked bitmap 0, # Item Data 0, # Type Data 0, # Length of menu item text HBMMENU_CALLBACK; # Bitmap will be owner drawn SetMenuItemInfo( $mnuMain->{mnuMenu}->{-handle}, $_, 0, $menuiteminfo ) foreach 1 .. MENU_ITEMS; # Create a window my $winMain = Win32::GUI::Window->new( -name => 'winMain', -text => 'Win32::GUI Menu Icons', -pos => [ CW_USEDEFAULT, CW_USEDEFAULT ], -size => [ 320, 240 ], -menu => $mnuMain, ); # Create a hook for the WM_MEASUREITEM message that specifies the size of the icon $winMain->Hook( WM_MEASUREITEM, sub { # dump \@_; my( $self, $wParam, $lParam, $type, $msgcode ) = @_; return 1 unless $type == 0; return 1 unless $msgcode == WM_MEASUREITEM; if( $wParam == 0 ){ # Process if message was sent by a menu poke( $lParam + 12, 16 ); # 12 is the offset of the itemWidth member poke( $lParam + 16, 16 ); # 16 is the offset of the itemHeight member } return 1; }, ); # Create a hook for the WM_DRAWITEM message to draw the bitmap for each menu item $winMain->Hook( WM_DRAWITEM, sub { my( $self, $wParam, $lParam, $type, $msgcode ) = @_; if( $wParam == 0 ){ # Process if message is sent by a menu # Unpack data from the structure my %drawitem; @drawitem{qw(CtlType CtlID itemID itemAction itemState hwndItem hDC left top right bottom itemData)} = unpack 'IIIIILLllllL', unpack 'P48', pack 'L', $lParam; # Draw the bitmap if( $drawitem{'itemAction'} == ODA_DRAWENTIRE ){ my $hDC = $drawitem{'hDC'}; my $memdc = Win32::GUI::DC::CreateCompatibleDC($hDC); my $oldimage = $memdc->SelectObject( $bitmaps[ $drawitem{'itemID'} - 1 ] ); Win32::GUI::DC::BitBlt( $hDC, $drawitem{'left'}, $drawitem{'top'}, $drawitem{'right'} - $drawitem{'left'}, $drawitem{'bottom'} - $drawitem{'top'}, $memdc, 0, 0, SRCCOPY ); } return 1; } }, ); $winMain->Show(); Win32::GUI::Dialog(); __END__