Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Контекстное меню файлового браузера, Контекстное меню проводника Windows 
:(
    Опции темы
Keeper89
  Дата 26.2.2009, 16:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



Доброго времени суток!

Делаю файловый браузер на основе ListView и присоединяю свое pop-up меню.
Вопрос в следующем: каким образом можно добавить в свое меню часть контекстного меню проводника Windows с сохранением функциональности?
Желательно небольшой примерчик, а не просто совет "куда копать".

Заранее спасибо.


--------------------
PM MAIL WWW   Вверх
Rrader
  Дата 26.2.2009, 19:43 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Можно получать меню итема через IContextMenu, затем обрезать его, как надо. И все это делать только тогда, когда требуется, так наиболее удобно, т.е. не хранить меню smile 
Накидал пример - выбираем через OpenDialog файл, для него вызывается меню, у которого оставлены 5 последних итемов (включая separator). Исполнение кода главного потока приостанавливается до тех пор, пока чего-нибудь не нажмём.
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ShellAPI, ShlObj, ActiveX;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  Malloc: IMalloc;
  ID, ItemID: PItemIDList;
  CM: IContextMenu;
  Desktop: IShellFolder;
  Folder: IShellFolder2;
  PFileName, PPath: PWideChar;
  Menu: HMENU;
  ICI: TCMInvokeCommandInfo;
  ICmd: Integer;
  Command: BOOL;
  I: Integer;
begin
  if OpenDialog1.Execute then
  begin
    { File Name }
    PFileName := StringToOleStr(ExtractFileName(OpenDialog1.FileName));
    { Path }
    PPath := StringToOleStr(ExtractFilePath(OpenDialog1.FileName));
    { Show last 5 items for the Windows directory }
    if Succeeded(SHGetMalloc(Malloc)) then
    try
      { Get Desktop Root IShellFolder2 Interface }
      if Succeeded(SHGetDesktopFolder(Desktop)) then
      try
        { Target Folder }
        if Succeeded(Desktop.ParseDisplayName(0, nil, PPath, PULONG(nil)^,
          ID, PULONG(nil)^)) then
        try
          { Get IShellFolder2 Interface }
          if Succeeded(Desktop.BindToObject(ID, nil,
            IID_IShellFolder2, Folder)) then
          try
            { FileName }
            if Succeeded(Folder.ParseDisplayName(0, nil,
              PFileName, PULONG(nil)^, ItemID, PULONG(nil)^)) then
            try
              if Succeeded(Folder.GetUIObjectOf(0, 1, ItemID, IID_IContextMenu,
                nil, CM)) then
              try
                Menu := CreatePopupMenu;
                if Menu <> 0 then
                try
                  if Succeeded(CM.QueryContextMenu(Menu, 0, 1,
                    $7FFF, CMF_EXPLORE or CMF_CANRENAME)) then
                  begin
                    for I := 0 to GetMenuItemCount(Menu) - 6 do
                      DeleteMenu(Menu, 0, MF_BYPOSITION);
                    { Show }
                    Command := TrackPopupMenu(Menu, TPM_LEFTALIGN
                      or TPM_LEFTBUTTON or TPM_RIGHTBUTTON
                      or TPM_RETURNCMD, Mouse.CursorPos.X, Mouse.CursorPos.Y,
                      0, Handle, nil);
                    if Command then
                    begin
                      ICmd := Integer(Command) - 1;
                      FillChar(ICI, SizeOf(ICI), #0);
                      with ICI do
                      begin
                        cbSize := SizeOf(ICI);
                        hWND := 0;
                        lpVerb := MakeIntResourceA(ICmd);
                        nShow := SW_SHOWNORMAL;
                      end;
                      CM.InvokeCommand(ICI);
                    end;
                  end;
                finally
                  DestroyMenu(Menu);
                end;
              finally
                CM := nil;
              end;
            finally
              Malloc.Free(ItemID);
            end;
          finally
            Folder := nil;
          end;
        finally
          Malloc.Free(ID);
        end;
      finally
        Desktop := nil;
      end;
    finally
      Malloc := nil;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  OleInitialize(nil);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  OleUninitialize;
end;

end.


Это сообщение отредактировал(а) Rrader - 27.2.2009, 14:35


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Keeper89
Дата 26.2.2009, 22:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



Спасибо за пример!

И еще несколько вопросов: 
1) как заставить работать код для виртуальных папок (Например Рабочего Стола или Моего Компьютера)?
2) меню Отправить и  Открыть с помощью отображаются, но вместо вложенного меню оказывается та же надпись, для WinRAR же например все нормально...
3) можно ли каким то образом добавить полученное меню к своему pop-up?

Это сообщение отредактировал(а) Keeper89 - 26.2.2009, 22:59


--------------------
PM MAIL WWW   Вверх
Rrader
  Дата 27.2.2009, 14:57 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Цитата(Keeper89 @  27.2.2009,  04:04 Найти цитируемый пост)
1) как заставить работать код для виртуальных папок (Например Рабочего Стола или Моего Компьютера)?

Для получения ItemID виртуальных папок можно воспользоваться функцией SHGetSpecialFolderLocation

Цитата(Keeper89 @  27.2.2009,  04:04 Найти цитируемый пост)
2) меню Отправить и  Открыть с помощью отображаются, но вместо вложенного меню оказывается та же надпись, для WinRAR же например все нормально...

Этот случай требует особой обработки. Вот пример:
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ShellAPI, ShlObj, ActiveX, ComCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  protected
    procedure WndProc(var Msg: TMessage); override;  
  private
    { Private declarations }
  public
    { Public declarations }
    CM2: IContextMenu2;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  Malloc: IMalloc;
  ID, ItemID: PItemIDList;
  CM: IContextMenu;
  Desktop: IShellFolder;
  Folder: IShellFolder2;
  PFileName, PPath: PWideChar;
  Menu: HMENU;
  ICI: TCMInvokeCommandInfo;
  ICmd: Integer;
  Command: BOOL;
begin
  if OpenDialog1.Execute then
  begin
    { File Name }
    PFileName := StringToOleStr(ExtractFileName(OpenDialog1.FileName));
    { Path }
    PPath := StringToOleStr(ExtractFilePath(OpenDialog1.FileName));
    if Succeeded(SHGetMalloc(Malloc)) then
    try
      { Get Desktop Root IShellFolder2 Interface }
      if Succeeded(SHGetDesktopFolder(Desktop)) then
      try
        { Target Folder }
        if Succeeded(Desktop.ParseDisplayName(0, nil, PPath, PULONG(nil)^,
          ID, PULONG(nil)^)) then
        try
          { Get IShellFolder2 Interface }
          if Succeeded(Desktop.BindToObject(ID, nil,
            IID_IShellFolder2, Folder)) then
          try
            { FileName }
            if Succeeded(Folder.ParseDisplayName(0, nil,
              PFileName, PULONG(nil)^, ItemID, PULONG(nil)^)) then
            try
              if Succeeded(Folder.GetUIObjectOf(0, 1, ItemID, IID_IContextMenu,
                nil, CM)) then
              try
                Menu := CreatePopupMenu;
                if Menu <> 0 then
                try
                  if Succeeded(CM.QueryContextMenu(Menu, 0, 1,
                    UINT(-1), CMF_EXPLORE or CMF_CANRENAME)) then
                  begin
                    Command := False;
                    if Succeeded(CM.QueryInterface(IID_IContextMenu2, CM2)) then
                    try
                      { Show }
                      Command := TrackPopupMenu(Menu, TPM_LEFTALIGN
                        or TPM_LEFTBUTTON or TPM_RIGHTBUTTON
                        or TPM_RETURNCMD, Mouse.CursorPos.X, Mouse.CursorPos.Y,
                        0, Handle, nil);
                    finally
                      CM2 := nil;
                    end;
                    if Command then
                    begin
                      ICmd := Integer(Command) - 1;
                      FillChar(ICI, SizeOf(ICI), #0);
                      with ICI do
                      begin
                        cbSize := SizeOf(ICI);
                        hWND := Handle;
                        lpVerb := MakeIntResourceA(ICmd);
                        nShow := SW_SHOWNORMAL;
                      end;
                      CM.InvokeCommand(ICI);
                    end;
                  end;
                finally
                  DestroyMenu(Menu);
                end; 
              finally
                CM := nil;
              end;
            finally
              Malloc.Free(ItemID);
            end;
          finally
            Folder := nil;
          end;
        finally
          Malloc.Free(ID);
        end;
      finally
        Desktop := nil;
      end;
    finally
      Malloc := nil;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  OleInitialize(nil);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  OleUninitialize;
end;

procedure TForm1.WndProc(var Msg: TMessage);
begin
  { SubMenu Handling }
  with Msg do
    if ((Msg = WM_INITMENUPOPUP) or (Msg = WM_DRAWITEM) or (Msg = WM_MENUCHAR)
    or (Msg = WM_MEASUREITEM)) and Assigned(CM2) then
    begin
      CM2.HandleMenuMsg(Msg, wParam, lParam);
      Result := 0;
    end;
  inherited;
end;

end.

Цитата(Keeper89 @  27.2.2009,  04:04 Найти цитируемый пост)
3) можно ли каким то образом добавить полученное меню к своему pop-up?

Можно добавлять вручную, но придется решать несколько проблем, например, подсчет индекса выбранной команды.

Это сообщение отредактировал(а) Rrader - 28.2.2009, 12:50


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Keeper89
Дата 28.2.2009, 15:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



Цитата(Rrader @  27.2.2009,  14:57 Найти цитируемый пост)
Этот случай требует особой обработки. Вот пример:

Спасибо, работает отлично.

Цитата(Rrader @  27.2.2009,  14:57 Найти цитируемый пост)
Для получения ItemID виртуальных папок можно воспользоваться функцией SHGetSpecialFolderLocation

Пользуюсь следующей функцией для определения ItemID:
Код

function GetSpecialFolderLocation(nFolder: Integer): String;
var
  ppidl: PItemIDList;
  Malloc: IMalloc;
  szPath: array[0..MAX_PATH - 1] of Char;
begin
  SHGetSpecialFolderLocation(0, nFolder, ppidl);
  SHGetMalloc(Malloc);
  SHGetPathFromIDList(ppidl, szPath);
  Malloc.Free(ppidl);
  Malloc := nil;
  Result := String(szPath);
end;

Но при этом меню работает только для папок, к которым можно определить путь (например Рабочий стол), а Мой Компьютер и Рабочий стол как виртуальная папка не работают.

----------

+ еще вопрос: в таком компоненте как ShellListView уже реализовано меню, которое мне необходимо. Можно ли как то его "выдернуть" и добавить из него элементы в своему меню?





--------------------
PM MAIL WWW   Вверх
Rrader
  Дата 1.3.2009, 08:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Цитата(Keeper89 @  28.2.2009,  21:18 Найти цитируемый пост)
Но при этом меню работает только для папок, к которым можно определить путь (например Рабочий стол), а Мой Компьютер и Рабочий стол как виртуальная папка не работают.

Путь не нужен, нужен ItemID:
Код

SHGetSpecialFolderLocation(0, nFolder, ppidl);

И далее работать нужно с ним через GetUIObjectOf.
Цитата(Keeper89 @  28.2.2009,  21:18 Найти цитируемый пост)
еще вопрос: в таком компоненте как ShellListView уже реализовано меню, которое мне необходимо. Можно ли как то его "выдернуть" и добавить из него элементы в своему меню?

ShellListView использует примерно такой же код, какой привел я. Меню нигде не хранится и не является дельфийским TPopupMenu.

Это сообщение отредактировал(а) Rrader - 1.3.2009, 08:44


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Keeper89
Дата 1.3.2009, 17:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



Цитата(Rrader @  1.3.2009,  08:42 Найти цитируемый пост)
И далее работать нужно с ним через GetUIObjectOf.

Немного подкорректировал ваш код под себя следующим образом, где путь я передаю как параметр:
Код

...
procedure TfrmMain.DoContextMenu(const curPath: String);
var
  Malloc: IMalloc;
  ID, ItemID: PItemIDList;
  CM: IContextMenu;
  Desktop: IShellFolder;
  Folder: IShellFolder2;
  PFileName, PPath: PWideChar;
  Menu: HMENU;
  ICI: TCMInvokeCommandInfo;
  ICmd: Integer;
  Command: BOOL;
begin

  { File Name }
    PFileName := StringToOleStr(ExtractFileName(curPath));
    { Path }
    PPath := StringToOleStr(ExtractFilePath(curPath));
    if Succeeded(SHGetMalloc(Malloc)) then
    try
      { Get Desktop Root IShellFolder2 Interface }
      if Succeeded(SHGetDesktopFolder(Desktop)) then
      try
        { Target Folder }
        if Succeeded(Desktop.ParseDisplayName(0, nil, PPath, PULONG(nil)^,
          ID, PULONG(nil)^)) then
        try
          { Get IShellFolder2 Interface }
          if Succeeded(Desktop.BindToObject(ID, nil,
            IID_IShellFolder2, Folder)) then
          try
            { FileName }
            if Succeeded(Folder.ParseDisplayName(0, nil,
              PFileName, PULONG(nil)^, ItemID, PULONG(nil)^)) then
            try
              if Succeeded(Folder.GetUIObjectOf(0, 1, ItemID, IID_IContextMenu,
                nil, CM)) then
              try
                Menu := CreatePopupMenu;
                if Menu <> 0 then
                try
                  if Succeeded(CM.QueryContextMenu(Menu, 0, 1,
                    UINT(-1), CMF_EXPLORE or CMF_CANRENAME)) then
                  begin
                    Command := False;
                    if Succeeded(CM.QueryInterface(IID_IContextMenu2, CM2)) then
                    try
                      { Show }
                      Command := TrackPopupMenu(Menu, TPM_LEFTALIGN
                        or TPM_LEFTBUTTON or TPM_RIGHTBUTTON
                        or TPM_RETURNCMD, Mouse.CursorPos.X, Mouse.CursorPos.Y,
                        0, Handle, nil);
                    finally
                      CM2 := nil;
                    end;
                    if Command then
                    begin
                      ICmd := Integer(Command) - 1;
                      FillChar(ICI, SizeOf(ICI), #0);
                      with ICI do
                      begin
                        cbSize := SizeOf(ICI);
                        hWND := Handle;
                        lpVerb := MakeIntResourceA(ICmd);
                        nShow := SW_SHOWNORMAL;
                      end;
                      CM.InvokeCommand(ICI);
                    end;
                  end;
                finally
                  DestroyMenu(Menu);
                end; 
              finally
                CM := nil;
              end;
            finally
              Malloc.Free(ItemID);
            end;
          finally
            Folder := nil;
          end;
        finally
          Malloc.Free(ID);
        end;
      finally
        Desktop := nil;
      end;
    finally
      Malloc := nil;
    end;
end;
...

Никак не могу разобраться, где здесь можно использовать GetUIObjectOf и передавать ItemID?

---

Как можно однозначно идентифицировать виртуальную папку для раскрытия меню? Например, если определять через путь, то Мои Документы будут иметь путь, а Мой Компьютер нет. По названию непонятно, ведь обычная папка тоже может называться Рабочий Стол и т.д....



Это сообщение отредактировал(а) Keeper89 - 1.3.2009, 17:33


--------------------
PM MAIL WWW   Вверх
Rrader
  Дата 2.3.2009, 06:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Keeper89, давайте обговорим несколько вещей...

Цитата(Keeper89 @  1.3.2009,  23:32 Найти цитируемый пост)
 где путь я передаю как параметр:

Shell для работы с файловой системой и объектами использует свой особый подход. В них вместо файловых путей используются ItemIDs. Подробности здесь
Еще прочитайте это
Затем откройте файл ShellCtrls.pas и посмотрите, как там все реализовано (файл лежит в папке Demos\...\ShellCtrls\ )

Цитата(Keeper89 @  1.3.2009,  23:32 Найти цитируемый пост)
Никак не могу разобраться, где здесь можно использовать GetUIObjectOf и передавать ItemID?

Позле ознакомления с предыдущим материалом таких вопросов уже не должно возникнуть.


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Keeper89
Дата 2.3.2009, 15:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



Цитата(Rrader @  2.3.2009,  06:33 Найти цитируемый пост)
Shell для работы с файловой системой и объектами использует свой особый подход. В них вместо файловых путей используются ItemIDs. Подробности здесь
Еще прочитайте это
Затем откройте файл ShellCtrls.pas и посмотрите, как там все реализовано (файл лежит в папке Demos\...\ShellCtrls\ )

Спасибо, разобрался.

Как можно еще сделать 2 вещи:
  • искать элементы в полученном меню по надписи на нем (для дальнейшего удаления по найденному индексу)?
  • добавить элементы к своему TPopupMenu?




--------------------
PM MAIL WWW   Вверх
Rrader
  Дата 4.3.2009, 15:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Цитата(Keeper89 @  2.3.2009,  21:26 Найти цитируемый пост)
искать элементы в полученном меню по надписи на нем (для дальнейшего удаления по найденному индексу)?

Можно использовать Menu API. Но учтите, чтобы это работало при разных локализациях, т.е. используйте метод на свой страх и риск. smile Если итемы имеют канонические имена, то лучше использовать их.
Код

procedure ShowMenuStrings(Menu: HMENU);

  { Universal routine }
  procedure ShowItemText(AMenu: HMENU; AIndex: Integer);
  var
    Info: TMenuItemInfoW;
    Txt: WideString;
  begin
    FillChar(Info, SizeOf(TMenuItemInfoW), 0);
    with Info do
    begin
      fMask := MIIM_FTYPE or MIIM_STRING;
      fType := MFT_STRING;
      cbSize := SizeOf(TMenuItemInfoW);
    end;
    if GetMenuItemInfoW(AMenu, AIndex, True, Info) then
      if Info.fType = MFT_SEPARATOR then
        ShowMessage('-')
      else
      begin
        SetLength(Txt, Info.cch);
        Info.dwTypeData := @Txt[1];
        Inc(Info.cch);
        if GetMenuItemInfoW(AMenu, AIndex, True, Info) then
          ShowMessage(Txt);
      end;
  end;

var
  I: Integer;
begin
  if Menu <> 0 then
    for I := 0 to GetMenuItemCount(Menu) - 1 do
      ShowItemText(Menu, I);
end;

Использование:
Код

...

if Succeeded(CM.QueryContextMenu(Menu, 0, 1,
  UINT(-1), CMF_EXPLORE or CMF_CANRENAME)) then
begin
  { На данном этапе SubMenu еще не созданы }
  ShowMenuStrings(Menu);
  Command := False;

...

Цитата(Keeper89 @  2.3.2009,  21:26 Найти цитируемый пост)
добавить элементы к своему TPopupMenu?

Ну если это настолько необходимо, то вручную, через Menu API. Но я бы делал наоборот - вносил все изменения только в оригинал (Menu в примере). Это сильно упрощает хэндлинг, как выше уже говорил.

Это сообщение отредактировал(а) Rrader - 11.3.2009, 17:12


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Keeper89
Дата 4.3.2009, 21:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



Цитата(Rrader @  4.3.2009,  15:50 Найти цитируемый пост)
Можно использовать Menu API. Но учтите, чтобы это работало при разных локализациях, т.е. используйте метод на свой страх и риск. smile Если итемы имеют канонические имена, то лучше использовать их.

А как можно удалить элемент (с подменю если оно есть)?
Возможно стоит воспользоваться функцией
Код

function AppendMenu(hMenu: HMENU; uFlags, uIDNewItem: UINT; lpNewItem: PChar): BOOL; 

с параметром MF_DELETE = $200, определив заранее вашим способом нужный индекс элемента?


Цитата(Rrader @  4.3.2009,  15:50 Найти цитируемый пост)
Ну если это настолько необходимо, то вручную, через Menu API. Но я бы делал наоборот - вносил все изменения только в оригинал (Menu в примере). Это сильно упрощает хэндлинг, как выше уже говорил.

Как можно реализовать то что вы советуете, если у меня имеются:
  • названия пунктов меню - String;
  •  стандартные процедуры по их обработке (на OnClick).




--------------------
PM MAIL WWW   Вверх
Rrader
  Дата 5.3.2009, 08:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Цитата(Keeper89 @  5.3.2009,  03:46 Найти цитируемый пост)
А как можно удалить элемент (с подменю если оно есть)?

Для простоты используйте DeleteMenu:
Код

DeleteMenu(Menu, <Index>, MF_BYPOSITION);

Цитата

If the menu item opens a menu or submenu, this function destroys the handle to the menu or submenu and frees the memory used by the menu or submenu. 

Цитата(Keeper89 @  5.3.2009,  03:46 Найти цитируемый пост)
Как можно реализовать то что вы советуете, если у меня имеются:

Для этого есть AppendMenu, InsertMenuItem. При щелчке на итеме главному окну-владельцу посылается сообщение WM_COMMAND.


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Keeper89
Дата 5.3.2009, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



Цитата(Rrader @  5.3.2009,  08:10 Найти цитируемый пост)
Для этого есть AppendMenu, InsertMenuItem. При щелчке на итеме главному окну-владельцу посылается сообщение WM_COMMAND. 

Прощу прощения. все-таки необходимо вставлять HMENU в свое меню. Дело в том, я использую специальный компонент ToolBar2000, где всплывающее меню имеет дополнительные характеристики по сравнению с дельфийским TPopupMenu.
Как постараться реализовать это?

Это сообщение отредактировал(а) Keeper89 - 5.3.2009, 12:51


--------------------
PM MAIL WWW   Вверх
Keeper89
Дата 11.3.2009, 15:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2580
Регистрация: 26.2.2009

Репутация: 14
Всего: 58



Так все-таки как постараться это сделать?


--------------------
PM MAIL WWW   Вверх
Rrader
  Дата 11.3.2009, 16:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 29
Всего: 191



Сорри, забыл про темку smile  С ToolBar2000 знаком...

Что делать - нужно создать процедуру конвертации меню через API, создавать ImageList для меню TB2000, в него динамически добавлять Bitmap'ы из меню Menu (через TBitmap). Меню на основе TB2000 проще создавать и удалять вместе с Menu из примера. Подменю - тут посложнее, так как пока показано основное меню, HandleMenuMsg может вызываться многократно (каждый раз при открытии), что затрудняет преобразование.

Попробуйте написать функцию, а там дальше, если что неясно станет, помогу smile 

Пример простейшей конвертации
Код

procedure TForm1.Button1Click(Sender: TObject);

  function GetItemText(AMenu: HMENU; Item: Integer): String;
  var
    Info: TMenuItemInfoW;
  begin
    FillChar(Info, SizeOf(TMenuItemInfoW), 0);
    with Info do
    begin
      fMask := MIIM_FTYPE or MIIM_STRING;
      fType := MFT_STRING;
      cbSize := SizeOf(TMenuItemInfoW);
    end;
    if GetMenuItemInfoW(AMenu, Item, True, Info) then
      if Info.fType = MFT_SEPARATOR then
        Result := '-'
      else
      begin
        SetLength(Result, Info.cch);
        Info.dwTypeData := @Result[1];
        Inc(Info.cch);
        GetMenuItemInfoW(AMenu, Item, True, Info);        
      end;
  end;

var
  TBMenu: TTBPopupMenu;
  NewItem: TTBItem;
  Menu: HMENU;
begin
  Menu := CreateMenu;
  AppendMenuW(Menu, MF_STRING, 0, 'Item1');
  if Menu <> 0 then
  try
    TBMenu := TTBPopupMenu.Create(Self);
    with TBMenu do
    try
      NewItem := TTBItem.Create(TBMenu);
      NewItem.Caption := GetItemText(Menu, 0);
      Items.Add(NewItem);
      Popup(0, 0);
    finally
      Free;
    end;
  finally
    DestroyMenu(Menu);
  end;
end;


Это сообщение отредактировал(а) Rrader - 11.3.2009, 17:09


--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.1176 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.