- Сообщения
- 5,379
- Репутация
- 2,724
В Windows Vista появилась возможность добавлять в меню битмапы содержащие прозрачность. При этом при наведении курсора на такой пункт меню, иконка не инверсируется как в Windows XP, а остается "красивой". И все это достигается стандартными API функциями без всяких танцев с бубном. Здесь я написал функцию _Create32BitHBITMAP() для конвертирования иконки (HICON) в 32-битный битмап (HBITMAP) для последующей вставки его в меню. В принципе, это немного измененный пример из MSDN, но вся загвоздка заключалась в том, что иконки не обязательно должны быть 32-битные (RGB+Alpha). Вообщем, вот, что у меня получилось. Для запуска этого примера вам понадобится WinAPIEx UDF.
Код:
#NoTrayIcon
#Include <Constants.au3>
#Include <GDIPlus.au3>
#Include <GUIMenu.au3>
#Include <WinAPIEx.au3>
#Include <WindowsConstants.au3>
If _WinAPI_GetVersion() < '6.0' Then
MsgBox(16, '', 'Require Windows Vista or later.')
Exit
EndIf
_GDIPlus_Startup()
#cs
$hForm = GUICreate('MyGUI', 400, 400)
$hFile = _GUICtrlMenu_CreateMenu()
_GUICtrlMenu_InsertMenuItem($hFile, 0, 'Options')
_GUICtrlMenu_SetItemBmp($hFile, 0, _Create32BitHBITMAP(_WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 130, 16, 16), 1))
_GUICtrlMenu_InsertMenuItem($hFile, 1, '')
_GUICtrlMenu_InsertMenuItem($hFile, 2, 'Exit')
_GUICtrlMenu_SetItemBmp($hFile, 2, _Create32BitHBITMAP(_WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 131, 16, 16), 1))
$hMenu = _GUICtrlMenu_CreateMenu()
_GUICtrlMenu_InsertMenuItem($hMenu, 0, 'File', 0, $hFile)
_GUICtrlMenu_SetMenu($hForm, $hMenu)
GUISetState()
Do
Until GUIGetMsg() = -3
#ce
Opt('TrayMenuMode', 3)
$hMenu = TrayItemGetHandle(0)
$Options = TrayCreateItem('Options')
TrayCreateItem('')
$Exit = TrayCreateItem('Exit')
_GUICtrlMenu_SetItemBmp($hMenu, 0, _Create32BitHBITMAP(_WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 130, 16, 16), 1))
_GUICtrlMenu_SetItemBmp($hMenu, 2, _Create32BitHBITMAP(_WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 131, 16, 16), 1))
TraySetState()
Do
Until TrayGetMsg() = $Exit
Func _Create32BitHBITMAP($hIcon, $fDelete = 0)
Local $tBI, $tBIHDR, $hDC, $hDstDC, $hDstSv, $hSrcDC, $hSrcSv, $hBitmap, $hImage, $hObj, $tBits, $pBits, $aIcon, $Width, $Height, $Alpha = True, $Error = False
$aIcon = _WinAPI_GetIconInfo($hIcon)
If Not IsArray($aIcon) Then
Return 0
EndIf
$tBI = DllStructCreate($tagBITMAP)
If _WinAPI_GetObject($aIcon[5], DllStructGetSize($tBI), DllStructGetPtr($tBI)) Then
$Width = DllStructGetData($tBI, 'bmWidth')
$Height = DllStructGetData($tBI, 'bmHeight')
$tBits = DllStructCreate('byte[' & (4 * $Width * $Height) & ']')
If _WinAPI_GetBitmapBits($aIcon[5], DllStructGetSize($tBits), DllStructGetPtr($tBits)) Then
If StringRegExp(DllStructGetData($tBits, 1), '^(0x)?(.{6}(00))+\Z') Then
$Alpha = 0
EndIf
Else
$Error = 1
EndIf
Else
$Error = 1
EndIf
For $i = 4 To 5
_WinAPI_DeleteObject($aIcon[$i])
Next
If $Error Then
Return 0
EndIf
$tBIHDR = DllStructCreate($tagBITMAPINFOHEADER)
DllStructSetData($tBIHDR, 'biSize', DllStructGetSize($tBIHDR))
DllStructSetData($tBIHDR, 'biWidth', $Width)
DllStructSetData($tBIHDR, 'biHeight', $Height)
DllStructSetData($tBIHDR, 'biPlanes', 1)
DllStructSetData($tBIHDR, 'biBitCount', 32)
DllStructSetData($tBIHDR, 'biCompression', $BI_RGB)
$hDC = _WinAPI_GetDC(0)
$hDstDC = _WinAPI_CreateCompatibleDC($hDC)
$hBitmap = _WinAPI_CreateDIBSection($hDC, $tBIHDR, $DIB_RGB_COLORS, $pBits)
$hDstSv = _WinAPI_SelectObject($hDstDC, $hBitmap)
If $Alpha Then
_WinAPI_DrawIconEx($hDstDC, 0, 0, $hIcon, 0, 0, 0, 0, $DI_NORMAL)
Else
_GDIPlus_Startup()
$hImage = DllCall($ghGDIPDll, 'uint', 'GdipCreateBitmapFromHICON', 'ptr', $hIcon, 'ptr*', 0)
If (Not @error) And (Not $hImage[0]) Then
$hObj = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage[2])
_GDIPlus_ImageDispose($hImage[2])
Else
$hObj = 0
EndIf
_GDIPlus_Shutdown()
If $hObj Then
$hSrcDC = _WinAPI_CreateCompatibleDC($hDC)
$hSrcSv = _WinAPI_SelectObject($hSrcDC, $hObj)
_WinAPI_BitBlt($hDstDC, 0, 0, $Width, $Height, $hSrcDC, 0, 0, $SRCCOPY)
_WinAPI_SelectObject($hSrcDC, $hSrcSv)
_WinAPI_DeleteObject($hObj)
_WinAPI_DeleteDC($hSrcDC)
Else
$Error = 1
EndIf
EndIf
_WinAPI_ReleaseDC(0, $hDC)
_WinAPI_SelectObject($hDstDC, $hDstSv)
_WinAPI_DeleteDC($hDstDC)
If $fDelete Then
_WinAPI_DestroyIcon($hIcon)
EndIf
If $Error Then
_WinAPI_DeleteObject($hBitmap)
Return 0
EndIf
Return $hBitmap
EndFunc ;==>_Create32BitHBITMAP
