Disabling the Find/Find Next options in a FindReplace dialog - winapi

When using the ::ReplaceText() Win32 api function, is it possible to disable or hide the find/find next buttons, leaving only the Replace?
If not I will need to roll my own dialog.

The ReplaceText() dialog allows you to hide the direction, Match case, and Match Whole Word boxes using the various FR_HIDE... flags, but it does not have any flags for hiding the Find Next and Replace buttons. So you will have to do it manually.
There are two ways to do this:
You can create a custom dialog resource that contains just the UI fields you want to display, and then you can enable the FR_ENABLETEMPLATE or FR_ENABLETEMPLATEHANDLE flag and provide the dialog as a template in the lpTemplateName or hInstance field, respectively.
You can enable the FR_ENABLEHOOK flag and provide a lpfnHook callback that disables/hides the existing buttons in the default dialog when processing the WM_INITDIALOG message.
These techniques are described in the MSDN documentation:
Customizing the Find or Replace Dialog Box
I would opt for #2, as it is easy to implement in code, eg:
UINT_PTR CALLBACK FRHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
if (uiMsg == WM_INITDIALOG)
{
HWND hBtn = GetDlgItem(hdlg, 1); // The "Find Next" button is ID 1
if (hBtn)
ShowWindow(hBtn, SW_HIDE);
}
return 0;
}
FINDREPLACE fr = {sizeof(fr), 0};
...
fr.Flags = FR_ENABLEHOOK;
fr.lpfnHook = &FRHookProc;
...
HWND hDlg = ReplaceText(&fr);

Related

Expanding a button width on click

I'm using checkbox buttons and I want to make the button expand in width when I click it using LBUTTONDOWN
Would this involve using something like AppendMenu()? If so, how would I do it?
This is what I have so far for my button proc:
LRESULT CALLBACK ButtonWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
static int x,y,btnwidth, btnheight;
switch (message){
case WM_USER:
btnwidth=wParam;
btnheight=lParam;
return 0;
case WM_LBUTTONDOWN:
btnwidth *= 2;
break;
}
You can expand the button by calling MoveWindow. You probably will want to first call GetWindowRect to get the current size and position, and then ScreenToClient to convert the rect to client coordinates. Then you can adjust the client coordinates as you wish and pass them to MoveWindow.

How to redirect mouse wheel message to other windows?

I'm developing a Word addin for MS Word on Windows, and this addin has as 'advanced task pane' showing and docking on the left side of the Word document window (it's treeview(outline) showing a list of Word documents for fast editing multiple documents in a project).
My question is, the Word document window responds to mouse wheel message only when it's focused, but I want to be able to scroll the document with mouse wheel whenever the mouse cursor is hovering on it even the Word document window doesn't have a input focus.
Any hints in this particular case? Thank you!
Not quite sure it will work, but I'd try the following:
Implement a global low-level mouse hook using the SetWindowsHookEx function.
In the hook procedure, which should be called on mouse wheel scroll events, check if the window under mouse cursor is the Word document window. If so, set a shared flag indicating the needed scroll action.
Don't send WM_VSCROLL directly from the hook procedure! This procedure has to be really fast and simple.
Now, in your add-in's message loop check the flag and if it is set, send WM_VSCROLL to the Word document window.
Perhaps you could make use of the SetCapture(hWnd) Windows API function. This will cause all mouse events to go to your hWnd instead of whatever hWnd might normally expect to receive them. If you capture when the mouse enters the Word document window, and ReleaseCapture() when the mouse leaves or Word gains focus, it should work alright.
Disclaimer: I've used mouse capturing in C# before, but I've never done it in C++. I don't know if it behaves exactly the same way.
Try the following , this might help you.
1) Handle WM_MOUSEHOVER message.
2) In the handler , use SendMessage, with WM_VSCROLL as the message parameter .
Using Spy++ I saw that the window that gets the messages is of the class _Wwg (At least 2003 is) and it is responding to the WM_MOUSEWHEEL message. So you would send that window a WM_MOUSEWHELL message when you want it to scroll.
I've got the C++ code snipped below from a comment in https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx
And I used it (and variations on it) successfully.
The user who wrote it claims it was inspired by a ms recommendation on a Windows Vista best practices guide, to forward the mouse wheel event to whatever window is hovered by the mouse cursor. The virtue of his/her implementation is that it's completely unintrusive, you just drop it and it set the hooks, referencing your main thread. It avoids forwarding the event to windows belonging to other processes, but perhaps that could actually be a good thing.
namespace {
LRESULT CALLBACK mouseInputHook(int nCode, WPARAM wParam, LPARAM lParam) {
//"if nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function
//without further processing and should return the value returned by CallNextHookEx"
if (nCode >= 0) {
MSG& msgInfo = *reinterpret_cast<MSG*>(lParam);
if (msgInfo.message == WM_MOUSEWHEEL ||
msgInfo.message == WM_MOUSEHWHEEL) {
POINT pt = {};
pt.x = ((int)(short)LOWORD(msgInfo.lParam)); //yes, there's also msgInfo.pt, but let's not take chances
pt.y = ((int)(short)HIWORD(msgInfo.lParam)); //
//visible child window directly under cursor; attention: not necessarily from our process!
//http://blogs.msdn.com/b/oldnewthing/archive/2010/12/30/10110077.aspx
if (HWND hWin = ::WindowFromPoint(pt))
if (msgInfo.hwnd != hWin && ::GetCapture() == nullptr) {
DWORD winProcessId = 0;
::GetWindowThreadProcessId(//no-fail!
hWin, //_In_ HWND hWnd,
&winProcessId); //_Out_opt_ LPDWORD lpdwProcessId
if (winProcessId == ::GetCurrentProcessId()) //no-fail!
msgInfo.hwnd = hWin; //it would be a bug to set handle from another process here
}
}
}
return ::CallNextHookEx(nullptr, nCode, wParam, lParam);
}
struct Dummy {
Dummy() {
hHook = ::SetWindowsHookEx(WH_GETMESSAGE, //__in int idHook,
mouseInputHook, //__in HOOKPROC lpfn,
nullptr, //__in HINSTANCE hMod,
::GetCurrentThreadId()); //__in DWORD dwThreadId
assert(hHook);
}
~Dummy() {
if (hHook)
::UnhookWindowsHookEx(hHook);
}
private:
HHOOK hHook;
} dummy;
}

SendMessage WM_LBUTTONDOWN/UP works on buttons but not window

I am trying to send some simple mouse down/up messages to Windows Calculator using SendMessage. I have been able to press the buttons by sending the messages to the buttons directly. However, I have not been able to successfully send the same messages to the main calculator window handle. Given that hWnd is the window handle to calculator, this is my code.
IntPtr fiveKey = FindWindowEx(hWnd, IntPtr.Zero, "Button", "5");
int x = 5; // X coordinate of the click
int y = 5; // Y coordinate of the click
IntPtr lParam = (IntPtr)((y << 16) | x); // The coordinates
IntPtr wParam = IntPtr.Zero; // Additional parameters for the click (e.g. Ctrl)
const uint downCode = 0x201; // Left click down code
const uint upCode = 0x202; // Left click up code
SendMessage(fiveKey, downCode, wParam, lParam); // Mouse button down
SendMessage(fiveKey, upCode, wParam, lParam); // Mouse button up
Can anyone explain to me why sending the messages to hWnd instead of fiveKey with the x/y offsets changed to the position of the "5" key does not work? I would like to eventually use this code to simulate mouse clicks on a different application that doesn't have buttons like calculator.
I'm not sure I follow you. Are you trying to send WM_LBUTTONDOWN to the main window with the coordinates of where the 5 button is, with the hopes that the 5 button will get "clicked"? If so, that's just not going to work. WM_LBUTTONDOWN is only ever sent to the window under the mouse cursor. In theory the main window could handle WM_LBUTTONDOWN and see if any of its child windows are at that location, but nobody does that because that's not how WM_LBUTTONDOWN is designed to work.

Why can my property sheet, shown from a system tray icon, lock up the taskbar?

Note: code samples have been simplified, but the overall structure remains intact.
I am working on a Win32 application whose main interface is a system tray icon. I create a dummy window, using HWND_MESSAGE as its parent, to receive the icon's messages:
WNDCLASSEX wndClass;
wndClass.lpfnWndProc = &iconWindowProc;
// ...
iconWindowHandle = CreateWindow(wndClass.lpszClassName, _T(""), 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, GetModuleHandle(NULL), 0);
Then the icon is created, referring to this message-only window:
NOTIFYICONDATA iconData;
iconData.hWnd = iconWindowHandle;
iconData.uCallbackMessage = TRAYICON_MESSAGE;
// ...
Shell_NotifyIcon(NIM_ADD, &iconData)
When the tray icon is double-clicked, I create and show a property sheet (from comctl32.dll):
LRESULT CALLBACK iconWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case TRAYICON_MESSAGE:
switch (lParam) { // that contains the "real" message
case WM_LBUTTONDBLCLK:
showPropertySheet();
return 0;
// ...
}
break;
// ...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
The property sheet has no parent window. The PropertySheet function is called from the window procedure of the message-only window. The PSH_MODELESS flag is not set; thus, PropertySheet only returns after the property sheet window is closed again:
void showPropertySheet() {
PROPSHEETPAGE pages[NUM_PAGES];
pages[0].pfnDlgProc = &firstPageDialogProc;
// ...
PROPSHEETHEADER header;
header.hwndParent = NULL;
header.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;
header.ppsp = pages;
// ...
PropertySheet(&header);
}
Now all this works just fine, until I set a breakpoint inside the dialog procedure of one of the property sheet's pages:
BOOL CALLBACK firstPageDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
return FALSE; // breakpoint here
}
When the program stops on the breakpoint, the entire taskbar locks up!
The call stack is quite useless; it shows that the dialog procedure is called from somewhere inside comctl32.dll, via some calls inside user32.dll. No window procedure of my own is in between.
Making the property sheet modeless doesn't seem to help. Also, I'd rather not do this because it makes the code more complex.
As long as my dialog procedure returns quickly enough, this shouldn't be a problem. But it seems so weird that a longer operation inside the dialog procedure would not only lock up the dialog itself, but the entire shell. I can imagine that the message-only window procedure has the power to cause this behaviour, since it's more closely related to the tray icon... but this function is not shown on the call stack.
Am I doing something fundamentally wrong? Can anyone shed some light on this issue?
Actually, it's rather obvious, and the confusion must have been due to a lack of coffee.
The taskbar probably uses SendMessage to send the message to my application, which causes it to block until the message is handled. SendMessageTimeout is apparently not used.
I still think it's strange that no function of my own shows up on the call stack. Surely, such a message must flow through my message loop in order to be processed? Maybe the warning that "stack frames below this line may be incomplete or missing" was actually right, then.

Suppress keystrokes to dialog

I have added a keyboard hook for a dialog that I don't control (it runs its own DialogProc Function in a library with closed source). I'm able to capture the key strokes, but the key stroke is always sent the dialog. This causes error beeps as well as some weird behavior.
Installing the hook:
hKeyHook=SetWindowsHookEx(WH_KEYBOARD, KeyHookProc, hInst, GetCurrentThreadId());
The hook function:
LRESULT CALLBACK KeyHookProc(int code, WPARAM wParam, LPARAM lParam)
{
if(!(lParam & 0x80000000))
{
if(wParam == VK_mykey)
{
// Do my stuff
return 0; // Don't continue the hook chain
}
}
// Continue with next hook
return CallNextHookEx(hKeyHook, code, wParam, lParam);
}
Releasing the hook:
UnhookWindowsHookEx(hKeyHook);
Is there a way to stop the key stroke from being sent to the control that has focus in the dialog?
You could subclass the control in question by replacing its GWLP_WNDPROC (See the remarks section of this page) value. The basic concept is that you filter out the WM_KEY* messages, then pass the rest to the original WndProc.
This
if(!(lParam & 0x80000000))
is true when the key is pressed. When it's released you do nothing.
KeyHookProc is called when the keys are held down or when they are released.
Hmm. First point are you sure that you wish to use your own process thread id here. Is the dialog definitely under your process thread?

Resources