Recording Commands
RecentCommands requires three steps to record a command, with most of the work being done inside the hooks. In the first step, the utility detects whether the user has selected a menu. In the second step, it detects whether the user has selected a menu item. In the final step, RecentCommands detects whether the user has clicked a menu command. The process begins when the WinEvent hook function MenuStartProc() is called after the user clicks on the menu bar. The sole purpose for this hook is to set the bMenuStart variable to TRUE, indicating that the user is accessing the menu. bMenuStart is a Boolean variable that's declared inside a shared data section in the DLL. Variables declared and initialized inside a shared data section are shared by all instances of the DLL, and can be used to exchange data between processes.

The next step takes place inside the WinEvent hook function ObjectFocusProc() after the user has selected a menu item. Because the hook is called every time the focus changes, the hook first checks the value of bMenuStart. If bMenuStart is FALSE, ObjectFocusProc() exits without doing any further processing. If bMenuStart is TRUE, it uses AccessibleObjectFromEvent() to retrieve the IAccessible interface of the object that triggered the event. The hook then calls the GetRole() function to retrieve the object's Role property. GetRole() is a simple function that encapsulates calling the get_accRole() method of the IAccessible interface.

If the object's Role property is ROLE_SYSTEM_MENUITEM, the hook calls the GetCommand() function. GetCommand() takes an IAccessible interface and a child ID as arguments, and returns a string that represents the menu item's object hierarchy. GetCommand() uses the get_accParent() method to navigate to the menu item's parent object. GetCommand() then calls itself recursively until the menu bar object is reached. The names of all the elements in the menu item's object hierarchy are concatenated to form the string that the function returns. For example, if the user selects the Open command in the File menu, the string returned by the GetCommand() function is File | Open. The string is then copied to the szMenuCommand variable, which is a char array declared in the shared data section.

The hook then uses the API function PostMessage() to send a WM_COMMANDFOCUS message to the RecentCommands program. WM_COMMANDFOCUS is a private message that the WinEvent hook uses to notify RecentCommands that a menu item has been selected. When RecentCommands receives the WM_COMMANDFOCUS message, it calls the DLL function ReadCommand() to record the contents of the szMenuCommand variable. All of this happens very quickly, thanks to the speed of the in-context hooks. As soon as the user selects a new menu item, RecentCommands receives a new WM_COMMANDFOCUS message.

The process is completed when RecentCommands receives a WM_COMMANDCLICK message. WM_COMMANDCLICK is a private message sent by the WH_MOUSE and WH_KEYBOARD hooks to the utility, indicating that the user has clicked a menu command. When RecentCommands receives the WM_COMMANDCLICK message, it saves the recorded command on the hard drive.