Показать сообщение отдельно
  #8  
Старый 20.03.2008, 17:36
Rosenkrantz Rosenkrantz вне форума
Активный
 
Регистрация: 04.12.2007
Адрес: Москва
Сообщения: 234
Версия Delphi: Delphi 7
Репутация: 40
По умолчанию

Вот код, который добавляет пункты в меню всех открытых при старте программы окон, и удаляет эти пункты при выходе из нее.
Код:
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 - второй параметр это команда, которая связана с пунктом меню. В моем примере используется удаление по позиции.
Ответить с цитированием