Вот код, который добавляет пункты в меню всех открытых при старте программы окон, и удаляет эти пункты при выходе из нее.
Код:
unit asmMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
const
SNewMenuItemCaption = 'About';
var
CM_about: Cardinal;
function MenuAlreadyProcessed(Menu: HMENU): Boolean;
// Проверяет, возможно меню уже было обработано
var
i, Count : Integer;
Data : TMenuItemInfo;
begin
Result := False;
Count := GetMenuItemCount(Menu);
for i := 0 to Count - 1 do begin
FillChar(Data, SizeOf(Data), 0);
Data.cbSize := SizeOf(Data);
Data.fMask := MIIM_DATA + MIIM_ID;
if GetMenuItemInfo(Menu, i, True, Data) then
// Проверяем, если "наш" пункт меню уже присутствует, значит
// повторная обработка меню не требуется
if (Data.wID = CM_ABOUT) and (Data.dwItemData = Application.Handle) then begin
Result := True;
Exit;
end;
end;
end;
procedure DeleteItem(Menu: HMENU);
// Удалить добавленные пункты из меню
var
i, Count : Integer;
Data : TMenuItemInfo;
S : String;
begin
Count := GetMenuItemCount(Menu);
for i := Count - 1 downto 0 do begin
FillChar(Data, SizeOf(Data), 0);
Data.cbSize := SizeOf(Data);
Data.fMask := MIIM_TYPE + MIIM_DATA + MIIM_ID;
// Опознаем "свой" пункт меню по дескриптору приложения в dwItemData
if GetMenuItemInfo(Menu, i, True, Data) and (Data.dwItemData = Application.Handle) then
DeleteMenu(Menu, i, MF_BYPOSITION);
end;
end;
procedure AddItem(Menu: HMENU);
// Добавить пунк в меню
var
MenuItemInfo: TMenuItemInfo;
CaptStr: PChar;
begin
// При добавлении своих пунктов меню в dwItemData прописываем дескриптор
// приложения. При завершении приложения нам нужно
// будет удалить эти пункты меню; мы будем опознавать их по этому признаку.
// Добавляем пункт "About"
GetMem(CaptStr, Length(SNewMenuItemCaption) + 1);
StrPCopy(CaptStr, SNewMenuItemCaption);
FillChar(MenuItemInfo, SizeOf(MenuItemInfo), 0);
with MenuItemInfo do begin
cbSize := SizeOf(MenuItemInfo);
fMask := MIIM_TYPE + MIIM_DATA + MIIM_ID;
fType := MFT_STRING;
wID := CM_ABOUT;
dwItemData := Application.Handle; // Признак для опознания "своих" пунктов меню
dwTypeData := CaptStr;
cch := Length(SNewMenuItemCaption);
end;
InsertMenuItem(Menu, 0, True, MenuItemInfo);
FreeMem(CaptStr);
// Добавляем разделитель после нашего пункта
FillChar(MenuItemInfo, SizeOf(MenuItemInfo), 0);
with MenuItemInfo do begin
cbSize := SizeOf(MenuItemInfo);
fMask := MIIM_TYPE + MIIM_DATA;
fType := MFT_SEPARATOR;
dwItemData := Application.Handle;
end;
InsertMenuItem(Menu, 1, True, MenuItemInfo);
end;
function EnumWinToAddItem(hWindow: HWND): BOOL; stdcall;
// Функция добавляет пункт меню
// Вызывается из EnumWindows
var
Menu: HMENU;
WCaption: Array [0..255] Of Char;
begin
Menu := GetSystemMenu(hWindow, False);
if (Menu <> 0) and (not MenuAlreadyProcessed(Menu)) then
AddItem(Menu);
Result := True;
end;
function EnumWinToDelItem(hWindow: HWND): BOOL; stdcall;
// Функция удаляет пункт меню
// Вызывается из EnumWindows
var
Menu: HMENU;
begin
// Получаем системное меню окна
Menu := GetSystemMenu(hWindow, False);
// Меню есть не у всех окон, поэтому нужна проверка на 0
if (Menu <> 0) then
DeleteItem(Menu);
// Если вернуть False, EnumWindows закончит работу
Result := True;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
// Удаляем наши пункты меню из всех окон
EnumWindows(@EnumWinToDelItem, LongInt(Self));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Регистрируем уникальное системное сообщение
CM_ABOUT := RegisterWindowMessage('CM_ABOUT');
// Добавляем пункт меню во все окна
EnumWindows(@EnumWinToAddItem, LongInt(Self));
end;
procedure TForm1.WMSysCommand(var Msg: TWMSysCommand);
begin
// Обрабатываем команду нашего пункта меню
if Msg.CmdType = CM_ABOUT then
ShowMessage('Insert item to system menu demo.');
inherited;
end;
end.
Про создание меню я же написал - CreateMenu. А добавлять в него пункты абсолютно точно так же, как в процедуре AddItem в моем примере. Ну, если уж совсем никак - отпишитесь, я напишу демонстрационный пример. Сегодня уже лениво
Параметры DeleteMenu:
1 - Меню
2 - Смысл его зависит от третьего параметра
3 - MF_BYPOSITION или MF_BYCOMMAND. Если MF_BYPOSITION, то второй параметр означает позицию пункта, который мы удаляем в меню (начиная с нуля). Если MF_BYCOMMAND - второй параметр это команда, которая связана с пунктом меню. В моем примере используется удаление по позиции.
|