![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как добавить подменю в системное контекстное меню [D7, WinXP]
Lucky13 © (2007-02-08 13:40:00)Добавил пункт в системное контекстное меню. Теперь нужно, чтобы у него было подменю. Добавить подменю не проблема, вопрос как узнать что пользователь выбрал некоторый пункт подменю, ведь InvokeCommand для подменю не вызывается?
Lucky13 (2007-02-09 12:11:00) [1]Про offset я не забыл. Вся проблема была в том, что я не указал:
if (LoWord(lpici.lpVerb) > 2) then
begin
Result := E_INVALIDARG;
Exit;
end;
Спасибо DiamondShark за ответы
DiamondShark (2007-02-09 11:57:00) [2]
> Т.е. LOWORD(lpVerb) содержит идентификатор выбранного пункта
> меню
А слово offset только для красоты написано?
Если в QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT) создаются пункты с uIDNewItem равными idCmdFirst, idCmdFirst+1,..,idCmdFirst+n, то в InvokeCommand LOWORD(lpVerb) будет равно 0, 1,...,n.
> Как по вашему должен выглядить метод InvokeCommand для меню,
> приведенного выше?
В примере, который я приводил (в подменю только один пункт, тот, что раньше был самостоятельным), код InvokeCommand абсолютно без изменений.
Вот изменённый код того же демо-проекта для нескольких пунктов меню:
function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,
idCmdLast, uFlags: UINT): HResult;
// added by DiamondShark
var
SubMenu: HMENU;
// added by DiamondShark \\
begin
Result := 0; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 0);
if ((uFlags and $0000000F) = CMF_NORMAL) or
((uFlags and CMF_EXPLORE) <> 0) then begin
// added by DiamondShark
SubMenu := CreatePopupMenu;
InsertMenu(Menu, indexMenu, MF_STRING or MF_POPUP or MF_BYPOSITION, SubMenu, 'Qwuqweqwo');
// added by DiamondShark \\
// Add one menu item to context menu
// commented out by DiamondShark
//InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst,
// 'Compile...');
// commented out by DiamondShark \\
// added by DiamondShark
InsertMenu(SubMenu, 0, MF_STRING or MF_BYPOSITION, idCmdFirst,
'Compile...');
InsertMenu(SubMenu, 1, MF_STRING or MF_BYPOSITION, idCmdFirst+1,
'zzz 1');
InsertMenu(SubMenu, 2, MF_STRING or MF_BYPOSITION, idCmdFirst+2,
'zzz 2');
// added by DiamondShark \\
// Return number of menu items added
//Result := 1; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 1)
Result := 3; // by DiamondShark
end;
end;
function TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
resourcestring
sPathError = 'Error setting current directory';
var
H: THandle;
PrevDir: string;
begin
Result := E_FAIL;
// Make sure we are not being called by an application
if (HiWord(Integer(lpici.lpVerb)) <> 0) then
begin
Exit;
end;
// Make sure we aren't being passed an invalid argument number
// commented out by DiamondShark
//if (LoWord(lpici.lpVerb) <> 0) then begin
// Result := E_INVALIDARG;
// Exit;
//end;
if (LoWord(lpici.lpVerb) > 2) then begin
Result := E_INVALIDARG;
Exit;
end;
// added by DiamondShark
case LoWord(lpici.lpVerb) of
0: begin
// added by DiamondShark \\
// Execute the command specified by lpici.lpVerb
// by invoking the Delphi command line compiler.
PrevDir := GetCurrentDir;
try
if not SetCurrentDir(ExtractFilePath(FFileName)) then
raise Exception.CreateRes(@sPathError);
H := WinExec(PChar(Format(GetCompilerPath, [FFileName])), lpici.nShow);
if (H < 32) then
MessageBox(lpici.hWnd, 'Error executing Delphi compiler.', 'Error',
MB_ICONERROR or MB_OK);
Result := NOERROR;
finally
SetCurrentDir(PrevDir);
end;
// added by DiamondShark
end;
1: ShowMessage('zzz 1');
2: ShowMessage('zzz 2');
end; {case}
// added by DiamondShark \\
end;
Lucky13 (2007-02-09 09:14:00) [3]
> Очень даже прекрасно всё вызывается.А вы, видимо, что-то
> где-то не туда добавляете.
Да, Вы правы, вчера покопал, действительно вызывается, но только как-то не так как хотелось бы. Я неправильно создавал меню.
MSDN:
32-bit value that contains zero in the high-order word and a menu-identifier offset of the command to carry out in the low-order word. The shell specifies this value (using the MAKEINTRESOURCE macro) when the user chooses a menu command.
Т.е. LOWORD(lpVerb) содержит идентификатор выбранного пункта меню, а HIWORD(lpVerb) должно быть = 0. Но как выяснилось этого мало, при таких условиях команда выполняется, когда пункт меню еще даже не успел появиться. Видимо нужно проверять что-то еще.
Как по вашему должен выглядить метод InvokeCommand для меню, приведенного выше?
DiamondShark (2007-02-08 19:18:00) [4]
> ведь InvokeCommand для подменю не вызывается
Ложь. Вызывается.
Вот модифицированный фрагмент демонстационного проекта
\Demos\Activex\Shellext\contmenu
function TContextMenu.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult;
// added by DiamondShark
var
SubMenu: HMENU;
// added by DiamondShark \\
begin
Result := 0; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 0);
if ((uFlags and $0000000F) = CMF_NORMAL) or
((uFlags and CMF_EXPLORE) <> 0) then begin
// added by DiamondShark
SubMenu := CreatePopupMenu;
InsertMenu(Menu, indexMenu, MF_STRING or MF_POPUP or MF_BYPOSITION, SubMenu, 'Qwuqweqwo');
// added by DiamondShark \\
// Add one menu item to context menu
// commented out by DiamondShark
//InsertMenu(Menu, indexMenu, MF_STRING or MF_BYPOSITION, idCmdFirst,
// 'Compile...');
// commented out by DiamondShark \\
// added by DiamondShark
InsertMenu(SubMenu, 0, MF_STRING or MF_BYPOSITION, idCmdFirst,
'Compile...');
// added by DiamondShark \\
// Return number of menu items added
Result := 1; // or use MakeResult(SEVERITY_SUCCESS, FACILITY_NULL, 1)
end;
end;
Очень даже прекрасно всё вызывается.
А вы, видимо, что-то где-то не туда добавляете.
Lucky13 (2007-02-08 17:36:00) [5]Я пробовал перекрывать IContextMenu3 -> HandleMenuMsg2(), но это ничего не дало (у меня WinXP). Можете привести пример использования этой функции.
Rouse_ (2007-02-08 15:58:00) [6]IContextMenu3 -> HandleMenuMsg2()
Lucky13 (2007-02-08 15:53:00) [7]Добавил пункт в системное контекстное меню. Теперь нужно, чтобы у него было подменю. Добавить подменю не проблема, вопрос как узнать что пользователь выбрал некоторый пункт подменю, ведь InvokeCommand для подменю не вызывается?