In most applications, when you click some MenuItem, a WindowsMessage is sent (usually WM_COMMAND), with a wParam representing the ID of the chosen MenuItem.
There is a certain program that has a Window Menu (the menu accessible via clicking the program's icon on the title-bar),
and I want to find what is the WindowsMessage that is sent when I choose a specific MenuItem from that Menu.
The program is soething you all know - the Command Prompt window, in Windows XP:
(cmd.exe)
And here is the Window Menu:
I want to capture the WindowsMessage and wParam for a MenuItem there,
for example the "Paste" MenuItem.
(but not just it.. any other might be as well)
Here is what I tried:
Method 1:
The first method I always try is to use Spy++.
The problem is that when I try to Log Messages for this specific program (the DOS window), Spy++ gives me this messagebox:
For some reason Spy++ won't capture WindowsMessages for this program.
So I went on to the second method that I use..
Method 2:
Resource Hacker (ResHacker.exe) is also good for finding the WindowsMessage that is sent from clicked MenuItems, and it does it quite easily.
If you run Resource Hacker, and then Open some EXE file with it,
you usually see these trees, which one of them is called "Menu",
and it contains all the details including the wParam:
The problem is, that when I try to use Resource Hacker on cmd.exe,
I get this:
As it can be seen, no "Menu" tree there.
My question:
Are there other ways, in addition to the 2 methods that I usually use,
that can be used to find the WindowsMessage (and wParam) that is sent for the "Paste" MenuItem in the Window Menu of the DOS window?
0xfff1 is the wParam, so in C# (you didn't specify the language you were using, but it should be easy enough to translate it):
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, uint lParam);
public const int WM_KEYDOWN = 0x01000;
void PasteInCommandPrompt(IntPtr hWnd)
{
SendMessage(handle, WM_COMMAND, 0xfff1, 0);
}
http://blogs.msdn.com/b/bill/archive/2012/06/09/programmatically-paste-clipboard-text-to-a-cmd-window-c-or-c.aspx
Edit: 22 September 2019
In the comments of Console window - programmatic command code (wParam of WM_COMMAND) (a question where a user was using the above link to Bill Lin's blog, but having trouble getting it working), #eryksun gave me the idea of looking for a ConvhostV2.dll.mui to find the all available menu commands. I couldn't find ConvhostV2.dll.mui...
But on my system I found C:\Windows\System32\en-US\ConhostV1.dll.mui, which when viewed with Resource Hacker (as #spaceman tried with cmd.exe), contains all the menu items available for cmd.exe.
The complete list of commands cmd.exe has are:
0xfff0: Copy
0xfff1: Paste
0xfff2: Mark
0xfff3: Scroll
0xfff4: Find
0xfff5: Select all
Besides paste (which allows you to execute arbitrary commands), select all and copy are very useful, as they let you get console output (albeit, stripping all virtual terminal sequences, the characters that specify text color).
If you are going deep into the route of manipulating command windows you may also be interested in the new "Windows Pseudo Console", which can let you have full control over cmd.exe, or any command line based application. See https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/ .
Related
I have a Win32 application that determines whether there are any visible, non-iconic, minimizable windows being shown. To the best of my knowledge it's worked fine for Win9x through to Win8.1, but under Windows 10 it often finds several windows that aren't actually visible on the screen.
To try to identify what's going on I've written a simple test application that enumerates and records all such windows. Here's the essence of the EnumWindows callback code:
BOOL CALLBACK EnumFunc( HWND hWnd, LPARAM lParam )
{
if ( IsWindowVisible( hWnd ) )
{
if ( !IsIconic( hWnd ) )
{
const LONG style = GetWindowLong( hWnd, GWL_STYLE );
if ( WS_MINIMIZEBOX & style )
{
// record window info
}
}
}
return TRUE;
}
Most of the phantom windows under Windows 10 belong to background store app processes such as Mail, Calculator, and Photos. These are listed under the Background processes section of Task Manager, and if I use Task Manager to end those background tasks, their phantom window is no longer found by my test application.
In the above screen shot from my test application you can see that all but 1 of the offending windows belong to threads of the same process id 7768, which is ApplicationFrameHost.exe. The final window with process id 11808 is explorer.exe.
I've looked at the phantom windows with Spy++ and can't see any particular style combination that would help in uniquely identifying them.
I've had a suggestion that the undocumented Windows "bands" may be involved, but I've tried using the (undocumented, so this may be wrong) API:
BOOL WINAPI GetWindowBand (HWND hWnd, PDWORD pdwBand);
but it returns a band of 1 for any window, so doesn't differentiate these phantoms.
How to reliably identify these phantom windows?
The approved way of detecting these phantom windows is to use DwmGetWindowAttribute and DWMWA_CLOAKED.
Here's the code I've used:
static bool IsInvisibleWin10BackgroundAppWindow( HWND hWnd )
{
int CloakedVal;
HRESULT hRes = DwmGetWindowAttribute( hWnd, DWMWA_CLOAKED, &CloakedVal, sizeof( CloakedVal ) );
if ( hRes != S_OK )
{
CloakedVal = 0;
}
return CloakedVal ? true : false;
}
Thanks to Scot Br from MS for posting the answer here
Top-level windows of class ApplicationFrameWindow are containers for Windows Store apps. First, here is the window of Mail shown in Spy:
This is truly visible (not phantom). You can tell that it is because the first child is a window of class Windows.UI.Core.CoreWindow. Interestingly, the owner process of the ApplicationFrameWindow is APPLICATIONFRAMEHOST, but the owner process of the Windows.UI.Core.CoreWindow is a different one: HXMAIL. (I've not seen a child window owned by a different process than the parent one before!)
Compare that with a phantom window (as identified in your RWTool):
It is missing the child of class Windows.UI.Core.CoreWindow.
This suggests an answer to your question: If a top-level window is of class ApplicationFrameWindow, iterate it's children. If the first child has class Windows.UI.Core.CoreWindow, the window is visible, otherwise it is not (i.e. it is phantom).
But what if an old-fashioned, non-store app happened to have a top-level window of class ApplicationFrameWindow? It would not have a child of Windows.UI.Core.CoreWindow. Yet it is visible. How to tell this is an ordinary app and not a Windows Store app? I don't have a foolproof way. You could also check for the existence of the other child windows of a Store app: ApplicationFrameTitleBarWindow and ApplicationFrameInputSinkWindow. The chances of a non-Store app having this exact Windows hierarchy is vanishingly small.
EDIT
The ApplicationFrameWindow's (and also Windows.UI.Core.CoreWindow) have the WS_EX_NOREDIRECTIONBITMAP style set:
The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
At minimum, you could check for this style instead of special casing ApplicationFrameWindow. Though to see if any content was truly visible, you'd still need to make that depend on whether it has a child of Windows.UI.Core.CoreWindow.
I am working on Windows GUI Application.There are 20 Push Buttons on my Window. Against each button click, I want to open up a new window for displaying some information. It can be anything which can display some information but since I am new to all this and I didn’t want to try anything complicated, I decided to go with the idea of creating a pop up window against each button click.
Now the problem that I am facing is that since there are 20 different windows, do I need to create 20 different window callback functions? Though there is only one control in the pop up window i.e. a Close sign, but even for that I need to have a CALLBACK function.
I had been trying with this but now this idea looks senseless. Is there any other option in which I can achieve the desired functionality?
Waiting for help.
If all of the windows should behave the same way, then you can create a single window procedure (what you're calling the CALLBACK function) that is shared by all of the pop-up windows.
Window procedures do not have to be unique to individual windows, but if multiple windows share the same window procedure, they will react identically to all messages that they receive.
For example:
// Message procedure for all pop-up windows.
LRESULT CALLBACK MyPopupWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// handle any messages you want here in order to
// customize the behavior of your pop-up window
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
You specify a pointer to the MyPopupWndProc function when you register the window class for your pop-up windows (using the RegisterClassEx function), and then you pass the name of the registered window class when you call CreateWindowEx to create/display a pop-up window whenever one of the buttons on your main window is clicked.
Of course, if you're just wanting something simple for testing purposes, remember that you can always call the MessageBox function! No window procedures or class registration required.
Im trying to scroll other program (PowerPoint 2013) by sending WM_HSCROLL,
and it will work only if I offer the correct LPARAM (not NULL) to SendMessage.
The value of LPARAM is dynamic, it will change if you close and open a new program.
Now I can only get its value by hooking WM_HSCROLL and clicking scroll bar manually.
// This is my code:
LPARAM lParam = 0x0a616c38; // Found by hooking WM_HSCROLL
SendMessage(hTarget, WM_HSCROLL, SB_LINERIGHT, lParam);
So is it possible to get the correct LPARAM programatically?
Many thanks!
p.s. The scroll bar is not a real window in PowerPoint 2013.
p.s. It returns 1 if I use GetScrollInfo(hTarget, SB_CTL, &scrollinfo), but all values inside scrollinfo are zero.
p.s. Office Home and Student 2013 Official Site
Did you try to call GetLastError?
GetScrollInfo will probably not work across process boundaries, so I would say that's why you're not getting valid values back.
The lParam value of a WM_HSCROLL message is either NULL for the standard window scroll bar, or the handle of the scroll control. The handle of the scroll control will obviously change every time the program is run, so you need to find that out yourself before you can reliably simulate scroll input.
To do this, you can use the FindWindowEx function to search the parent window (hTarget in your example) for child windows of class "SCROLLBAR". As you will probably find more than one scrollbar child window you'll need some way to tell them apart - most probably, via the window's GWL_ID value as this will probably not change from run to run.
I have an MFC application using MDI, something similar to the MFC Scribble example/tutorial. When the child window is maximized, the caption/title of the main frame window is automatically adjusted so that the title of the child window is appended, like "Scribble - [Scribb1]". When the title of the child window is very long, it is truncated. The length of whole caption seems to be limited to about 160 characters. Is there a way to increase this limit and show more characters? I guess overriding WM_NCPAINT to redraw the caption is one way, but prefer other simple solution if there is one. I've tried overriding OnUpdateFrameTitle() and it doesn't seem to work for the whole combined caption.
Overriding OnUpdateFrameTitle and calling own implementation of the UpdateFrameTitleForDocument won’t work. Amit already tried your solution before even posting.
This is not even implemented by MFC. MDI window is not introduced by MFC. MDI frame window existed since I remember as part of the Windows OS.
Default MFC implementation down in the bowels of the MFC calls special MDI window procedure defined as DefFrameProc, as required.
Windows implementation for some mysterious reason truncate window text (displayed on the title bar of the MDI frame) to 160 characters, including terminating 0 when processing WM_SETTEXT message. This is probably the remnant of the old computers that did not have much memory to waste and all buffers sizes were kept to a minimum.
This is probably the remnant of the old computers that did not have much memory to waste and all buffers sizes were kept to a minimum and file names were 8.3 total 12 characters.
To fulfill your requirements and display full text you would have to make some changes.
Fortunately, I found really easy way of changing this behavior, in agreement with my MEMC requirement.
In your main frame class override DefWindowProcand change the code as follows:
LRESULT CMainFrame::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(WM_SETTEXT == message)
{
// if set text (called from UpdateFrameTitleForDocument)
// do not call DefWindowProc
return CWnd::DefWindowProc(message, wParam, lParam);
}
// otherwise call DefWindowProc that in turn calls DefFrameProc
return CMDIFrameWndEx::DefWindowProc(message, wParam, lParam);
}
Now build and run.
This works for classinc and Visual studio styles of the MFC app.
Have a look at CFrameWnd::OnUpdateFrameTitle which internally is calling CFrameWnd::UpdateFrameTitleForDocument() method. It does the magic. It is a virtual method. You can override OnUpdateFrameTitle in your CMainFrm class and set the window title as desired.
If you did not know, MFC library is provided totally with the source. The CFrameWnd source is in winfrm.cpp (search for this file, and you will learn where the source for MFC on your PC)
What Windows API function can I use to get text within a dialog? For example, if I had the handle of an error message dialog, how could I get the displayed error message?
If I correctly understand your question, your problem is very easy. Open Spy++ from the Visual Studio Tools menu. Then press Ctrl + F to receive a dialog for finding windows. Drag & drop the "Finder tool" on the control inside the dialog box from which you want to read the text; look at properties of the window, the field "Control ID" is what you need.
If you have a handle of the Dialog Window (HWND hDlg) you should use the GetDlgItemText function (see http://msdn.microsoft.com/en-us/library/ms645489(VS.85).aspx)
UINT GetDlgItemText(HWND hDlg,
int nIDDlgItem,
LPTSTR lpString,
int nMaxCount
);
to read the text. As a nIDDlgItem parameter you should place the identifier of the control. It is the value which you have found using Spy++.
Dialog boxes don't actually contain text - they contain other controls which contain the text. You must enumerate or otherwise find the appropriate child window of the dialog box, and get its text with GetWindowText.