Sending WM_HSCROLL to other program - winapi

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.

Related

Child windows does not receive WM_DESTROY?

I packaged the winapi CreateWindowEx into a simple class. Since every window sharing a same wndProc(hwnd,msg,wparam,lparam), I put every window created by CreateWindowEx into a map to distribute msg, like this:
wndProc(hwnd, msg, wparam, lparam){
if(map[hwnd]!=nil){
switch(msg){
map[hwnd].wndProc(...)
}
}
}
And each time a window or its parent window being destroyed, remove it from the map:
case WM_DESTROY: delete(map, hwnd)
But things like buttons do not receive WM_DESTROY. I printed all msg in WM_NOTIFY and WM_COMMAND but i got noting.
So how can I remove those child windows form the map at the right time? Or a way distribute the msg without creating a hwnd map?
They certainly do get that message. But their window procedure is inside Windows, not inside your program. So you never see it. Something you can read in the MSDN documentation, note how WM_DESTROY doesn't get any special treatment. Nor generate a notification that your parent window can see.
Short from automatically removing all the child windows when you see the parent window destroyed, subclassing controls is a pretty standard requirement for C++ class library wrappers. Best to not invent your own btw, this has been done many times already.
So how can I remove those child windows form the map at the right time?
You have to subclass every window you create, either with SetWindowLongPtr(GWL_WNDPROC) or SetWindowSubClass(), then you will receive all of the WM_DESTROY messages.
Or a way distribute the msg without creating a hwnd map?
Frameworks like ATL and VCL handle that by dynamically allocating a thunk for each window and putting the object pointer right in the thunk, then use the thunk as the window procedure. That way, whenever the thunk is called, it passes the message directly to its associated object.

Creating a separate window against each click on push button

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.

MFC - MDI main frame title is truncated when maximized child window has very long title

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)

How to set text on "another" win32 application

I am using spy++ and see that the control I have has the decimal that matches the hex(after conversion of course) in spy++ and I see the parent window matches as well so I have the IntPtr for a Label and IntPtr for the form/window but my SendMessage is not working to change the text in the target application.
Another approach may be may be to do something like this post but what is the control id and how do I get that
SetText of textbox in external app. Win32 API
I assume the hWnd here needs to be the controls hWnd, correct?
SendMessageCall(hWnd, WM_SETTEXT, (IntPtr)value.Length, value);
I notice that getting the text IS WORKING
SendMessageCall(hWnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
and I notice that I get the test, see the correct value, set the text yet it doesn't change and then get the text again using SendMessage AND it is the new value but the application still shows the wrong value....hmmm, do I need to send a repaint message maybe and if so, what is the code for that?
thanks,
Dean
You don't send a window message to force repaint, instead you call InvalidateRect(hWnd, NULL, TRUE).

How can I stop window rendering and later resume?

I'd like to prevent my window from being updated until I finish receiving data from the server and render it. Can I hook on the WM_PAINT event, or better still call some Win32API method to prevent the window from being updated and unfreeze it later?
More info:
In the context of an MMC snapin written in C#, our application suffers from annoying flickering and double sorting behaviour:
We use MMC's listViews, but since we subscribe to the sort event.
MMC does it's own magic and sorts the page being displayed (and we can't override that), and when we receive a reply from our server we change the listView again.
each row change is done sequentially, there's no beginUpdate etc. (AFAIK).
Normally hooking into WM_PAINT is the way to go, but make sure you also ignore all WM_ERASEBKGND notifcations, otherwise you'll still get flicker, because Windows erases the Windows area for you. (Return non-zero to prevent Windows from doing that)
One other possibility is to use the LockWindowUpdate function, but it has some drawbacks:
Only one window can be locked
Upon unlock the whole desktop and all sub-windows (i.e. everything) is repainted, resulting in short flash of the whole desktop. (It's worse on XP than on Vista)
Some controls have BeginUpdate and EndUpdate APIs for this purpose.
If you do something (e.g. hook and ignore paint events) do disable painting, then a way to force a repaint later is to call the Invalidate method.
OK, after all searching and checking I've found that LockUpdateWindow is bad idea - see for example articles of Raimond Chen OldNewThing. But even to implement the idea of SetRedrawWindow wasn't so simple - because what I had was only received from IConsole2* pConsole->GetMainWindow() HWND handler of main window. By setting it to SetRedraw = FALSE it was disappeared in very strange manner. Though to make the procedure run only for the TreeView and not for the whole application (ours left panel) I ran
EnumChildWindows(hWnd, SetChildRedraw, FALSE); //stopping redraw
//... here you do your operations
EnumChildWindows(hWnd, SetChildRedraw, TRUE); //restarting redraw
where SetChildRedraw callback was defined in next way:
#define DECLARE_STRING(str) TCHAR str[MAX_PATH]; ZeroMemory(str, sizeof(str));
BOOL CALLBACK SetChildRedraw(HWND hwndChild, LPARAM lParam)
{
RECT rcChildRect; ZeroMemory(&rcChildRect, sizeof(rcChildRect));
DECLARE_STRING(sText)
GetClassName(hwndChild, sText, MAX_PATH);
if (wcsstr(sText, L"SysTreeView32") != NULL)
{
SetWindowRedraw(hwndChild, lParam);
if (lParam == TRUE)
{
GetWindowRect(hwndChild, &rcChildRect);
InvalidateRect(hwndChild, &rcChildRect, TRUE);
}
}
return TRUE;
}

Resources