hi, is there a send api to access a menu command in another application? For example,I am trying to access the View menu of a notepad. How am I going to do this? I already got the menu using GetSystemMenu but I can't access it. I think this has an API already but I don't know.
views:
512answers:
2The following code in Python activates the View / Status Bar menu item. You should have no trouble converting it to Delphi as it looks like pseudocode anyway. It selects the 4th menu items across ("View") and the 1st item down ("Status Bar"). If you wanted, you could change it to search for the desired item by text by walking through the items and using GetMenuString
. See the MSDN for details.
Note that it doesn't do any error checking. Note also that it expects Notepad's title to be 'Untitled - Notepad'. (You could change that to None
to search for anything; I guess that would be nil
in Delphi.)
from win32gui import *
from win32con import *
hwnd = FindWindow('Notepad', 'Untitled - Notepad') # use Winspector Spy to find window class name and title
hmenu = GetMenu(hwnd)
hviewmenu = GetSubMenu(hmenu, 3) # 3rd menu item across, starting from 0
id = GetMenuItemID(hviewmenu, 0) # 0th menu item down ("Status Bar")
PostMessage(hwnd, WM_COMMAND, id, 0)
And here some Delphi code.
Be aware that this would not work if you don't have true Menus.
From the help:
"GetMenu does not work on floating menu bars. Floating menu bars are custom controls that mimic standard menus; they are not menus. To get the handle on a floating menu bar, use the Active Accessibility APIs."
For instance, it would not work with Delphi itself...
// Grab sub menu for a Window (by handle), given by (0 based) indices in menu hierarchy
function GetASubmenu(const hW: HWND; const MenuInts: array of Integer): HMENU;
var
hSubMenu: HMENU;
I: Integer;
begin
Result := 0;
if Length(MenuInts) = 0 then
Exit;
hSubMenu := GetMenu(hW);
if not IsMenu(hSubMenu) then
Exit;
for I in MenuInts do
begin
Assert(I < GetMenuItemCount(hSubMenu), format('GetASubmenu: tried %d out of %d items',[I, GetMenuItemCount(hSubMenu)]));
hSubMenu := GetSubMenu(hSubMenu, I);
if not IsMenu(hSubMenu) then
Exit;
end;
Result := hSubMenu;
end;
// Get the caption for MenuItem ID
function GetMenuItemCaption(const hSubMenu: HMENU; const Id: Integer): string;
var
MenuItemInfo: TMenuItemInfo;
begin
MenuItemInfo.cbSize := 44; // Required for Windows 95. not sizeof(AMenuInfo)
MenuItemInfo.fMask := MIIM_STRING;
// to get the menu caption, 1023 first chars should be enough
SetLength(Result, 1023 + 1);
MenuItemInfo.dwTypeData := PChar(Result);
MenuItemInfo.cch := Length(Result)-1;
if not GetMenuItemInfo(hSubMenu, Id, False, MenuItemInfo) then
RaiseLastOSError;
// real caption's size. Should call GetMenuItemInfo again if was too short
SetLength(Result, MenuItemInfo.cch);
{$WARN SYMBOL_PLATFORM OFF}
if DebugHook > 0 then
OutputDebugString(MenuItemInfo.dwTypeData);
end;
procedure Test;
var
hwnd, hSubMenu: Cardinal;
id : Integer;
begin
// hwnd := FindWindow('Afx:00400000:8:00010013:00000000:03F61829', nil); // UltraEdit
// hSubMenu := GetASubmenu(hwnd, [5,0]);
hwnd := FindWindow('Notepad', nil); // get the 1st instance of Notepad...
hSubMenu := GetASubmenu(hwnd, [3]); // 4th submenu Menu aka &View
if hSubMenu > 0 then
begin
id := GetMenuItemID(hSubMenu, 0); // 1st Item in that sub menu (must not be a submenu itself)
if id > -1 then
begin
PostMessage(hwnd, WM_COMMAND, id, 0);
ShowMessage('Done: ' + GetMenuItemCaption(hSubMenu, id));
end
else
RaiseLastOSError;
end
else
RaiseLastOSError;
end;