MFC-hosted WPF usercontrol how to close parent window on button press - c#

I'm trying to get a legacy MFC application and a new WPF usercontrol to shut down a dialog window based on a button press in the WPF usercontrol. In essence, I would like some tips on how I can get the DoModal() function of MFC return.
For various reasons the dialog is a MFC CDialog started via DoModal, which hosts a single WPF component and nothing else. This component then has a button which will need to close the CDialog after doing some various tasks. This application is an.. exiting.. case of legacy and it's really hard to track control flow and where the actual message pumps driving this thing resides. It's also full of #defines that makes everything twice as difficult as it should be. I think I have identified the message pump, so I think I can insert something into that to make it close - if I can get to that from the WPF control.
I do not know how to send a windows message out from the usercontrol to the host, or how to get the HWND of the host from the usercontrol. I'm sure there is a way to get that, or another better way of communicating?
Is the correct approach to send a WM_CLOSE message to the parent HWND? Or perhaps I can send a WM_USER to the dialog pump and handle the actual closing there?

Try this. It should work for any WPF element (if it's a Visual), by finding it's containing HWND, tracing up the HWND tree until it finds the root parent, then sending that a WM_CLOSE message.
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern IntPtr GetParent(IntPtr hWnd);
//I'd double check this constant, just in case
static uint WM_CLOSE = 0x10;
private void CloseContainingWindow(Visual visual)
{
// Find the containing HWND for the Visual in question
HwndSource wpfHandle = PresentationSource.FromVisual(this) as HwndSource;
if (wpfHandle == null)
{
throw new Exception("Could not find Window handle");
}
// Trace up the window chain, to find the ultimate parent
IntPtr hWindow = wpfHandle.Handle;
while (true)
{
IntPtr parentHWindow = GetParent(hWindow);
if (parentHWindow == (IntPtr)0) break;
hWindow = parentHWindow;
}
// Now send the containing window a close message
SendMessage(hWindow, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
}

Declare a close event in the control. Raise the event when the close button is closed.
In your CDialog-derived class, subscribe to the event, then call EngDialog in the event handler.

WM_CLOSE should work, but you have to try it.
Another approach is to post a WM_COMMAND message to the parent dialog.
Sending a WM_USER looks too complicated.

Related

Maximize WPF application from the taskbar using another application instance and Caliburn.Micro

I'm writing a WPF application in Caliburn.Micro that needs to minimize to the Taskbar when closed. That part is easy using Hardcodet TaskbarIcon control. This app should also be a single instance application which I'm using a global mutex for.
The problem I'm running into is: I want to maximize the current instance from the taskbar if another instance of the application is trying to start. So check the mutex, if it cant get a lock, find the other instance and maximize it from the taskbar and shut itself down. I can't do a user32.dll ShowWindow because there is no window handle to grab when its in the taskbar.
I ideally want to do a SendMessage from the opening instance to the existing instance and tell it to maximize itself, but I cant figure out how to handle a SendMessage event using Caliburn.Micro. Unfortunately, this is the only solution I can think of and I can't figure out how to do it.
Have a look at PostMessage
Here is a great example of someone using PostMessage to do exactly what you're talking about.
Basically, you use PostMessage to broadcast a custom message:
NativeMethods.PostMessage(
(IntPtr)NativeMethods.HWND_BROADCAST,
NativeMethods.WM_SHOWME,
IntPtr.Zero,
IntPtr.Zero);
Then you override WndProc to receive the message:
protected override void WndProc(ref Message m)
{
if(m.Msg == NativeMethods.WM_SHOWME)
{
// code here to maximize
}
base.WndProc(ref m);
}
Note that you need to register your custom message and extern in the needed win32 stuff:
internal class NativeMethods
{
public const int HWND_BROADCAST = 0xffff;
public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
[DllImport("user32")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);
}

Close a dialog programmatically after running an executable

I have a .EXE that performs several calculations and was implemented by another company. I do not have access to the source code of this executable and it is out of question trying to modify its behaviour.
My problem is:
I am writing a code in c# to call this EXE and read its file output. After the EXE is done with the calculation, it opens a MessageBox -> "Calculation Done", and only after clicking in a "OK Button" the output file is written. That really sucks, since it is necessary the user manually click with the mouse to close the MessageBox. I am wondering if it is possible to close this MessageBox programmatically?
I have googled it and my guess is that is it possible using MainWindowHandle, but I am not sure. Any help?
You can call FindWindow to locate your MessageBox, and then use SendMessage to send a close message
[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd,uint Msg,int wParam,int lParam);
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lp1, string lp2);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
IntPtr window = FindWindow(null, "MessageBox Title Here");
if (window != IntPtr.Zero)
{
SendMessage(window, WM_SYSCOMMAND, SC_CLOSE, 0);
}
Read more here

SendMessage() only working when window is open, not when minimized

I've been using SendMessage to send mouse clicks to a couple of windows. One being a game(everything works perfectly), but the other window, being a 3rd party tool for the game is having trouble with SendMessage. If the window is 'not minimized' everything works fine, don't matter if window is completely covered up by another. But if that same window is minimized then nothing happens, I checked with spy++ and the messages are indeed getting received but not being processed (correct term?). I've tried to solve this last couple days, doing both searches on here and Google alike, many of topics but nothing helped?
//MyImports
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
And this is how I have it wrapped
public static void LClick(string windowclass, int x, int y)
{
IntPtr WHandle = FindWindow(windowclass, null);
SendMessage(WHandle, (int)WMessages.WM_LBUTTONDOWN, (IntPtr)1, (IntPtr)MakeLParam(x, y));
SendMessage(WHandle, (int)WMessages.WM_LBUTTONUP, (IntPtr)0, (IntPtr)MakeLParam(x, y));
}
I have tried focus, activate. One thing that might be useful info is that the third party program is being loaded as module("Qt5QWindowIcon") of the game.
I tried PostMessage as well, and it does the same thing as SendMessage() same problem when minimized.
This game does allow for macroing and unattended macroing, Hints the third part tool designed to execute the macros (published by the creators) I'm just trying to simulate a mouse click on the program to start the macro.
I would just use SendInput, but the entire purpose of my program is to run in background.
I 've faced same problem .Please change assembly name and project name (Changed name not started with name on that you are throwing/posting windows message)then rebuild it and check it. Now you will able to debug.

How to prevent a window from opening from another application?

I will prevent a window from iTunes to be opened.
I googled a lot but can't find an iTunes library that allows me to control such things, so I think I must get back to basics and close it after it opens, but how?
I think:
Tick a timer every 500 ms
Check if the window handle is opened
Close it
Is that possible?
How can I recognize a window from this application on other computers (I will give away my application)?
Language is C#.Net 2.0.
Yes it's an option to find the window and close it. However the user will still see it.
You can do the PInvoke method of FindWindow or use the C# ones (prefer those)
using System.Diagnostics;
Process[] processes = Process.GetProcessesByName("notepad");
foreach (Process p in processes)
{
p.CloseMainWindow();
}
From here
This is only for closing the top application, I dont know if you can find the subwindow with Process.
I know you can with PInvoke, see example here
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
or
[DllImport("user32.dll", EntryPoint="FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
Sure there are ways to do this, an approach I used before was based on the win32APIs, you'll want to look at the following:
FindWindow
SendMessage
In short you can use the timer, and when it fires use FindWindow (either using the window title bar, or the application "class") to get the handle, once you have that you SendMessage to the window of at least a WM_CLOSE or WM_DESTROY

SendMessage vs. WndProc

I'm trying to extend TextBox control to add watermarking functionality. The example I've found on CodeProject is using imported SendMessage function.
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, uint wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
void SetWatermark()
{
SendMessage(this.Handle, 0x1501, 0, "Sample");
}
I'm wondering why not use protected WndProc instead
void SetWatermark()
{
var m =new Message() { HWnd = this.Handle, Msg = 0x1501, WParam = (IntPtr)0, LParam = Marshal.StringToHGlobalUni("Sample") };
WndProc(ref m);
}
Both seem to work fine. Almost all examples I've seen on internet use SendMessagefunction. Why is that? Isn't WndProc function designed to replace SendMessage?
P.S. I don't know right to convert string to IntPtr and found that Marshal.StringToHGlobalUni works ok. Is it right function to do this?
WndProc does not replace SendMessage, it is the .NET equivalent of WindowProc. WndProc is called by your application's message pump (which receives messages that are sent or posted by SendMessage or PostMessage) to process them. By calling WndProc directly, you by-pass the special message handling that Windows performs, such as bundling WM_PAINT messages, and can potentially cause some nasty problems where messages appear out of the order that they're expected by windows within your application.
As stated in MSDN,
All messages are sent to the WndProc
method after getting filtered through
the PreProcessMessage method.
The WndProc method corresponds exactly
to the Windows WindowProc function.
For more information about processing
Windows messages, see the WindowProc
function documentation in the MSDN
library at
http://msdn.microsoft.com/library.
By calling it directly, you deprive the system of a chance to perform preprocessing or any other handling of that message. The .NET framework runs on top of Windows and without sending or posting the message, the underlying system cannot do anything with that message, so you lose out on anything the underlying system might do for you.

Categories