I've heard (well read, at http://www.ddj.com/windows/184416861), that it's possible to set custom properties on a Win32 window.
The trouble is, the download for the article above is on an ftp server that won't let me in.
As a bit of background info, I have a .NET app. The main window is registered to handle custom window messages. From a separate app, I need to post messages to this window. I can't find the window by caption as the caption changes. I can't find it JUST by window class, as the window class is the same for all forms in that app domain.
Ideally, I'd like to set a custom property on the Win32 window of the main form (Form1) that say, yes, this is form1. Then when I'm enumerating the windows of this app, I can tell that this is the required form by seeing if this custom property exists.
Cheers,
Steve
See here for an overview of window properties. Basically, you call the Win32 API function SetProp to set a window property and GetProp to retrieve it. There are a few more functions for enumerating properties and the like, but it sounds as if SetProp and GetProp is all you need.
As Martin says, the answer is the Win32 APIs GetProp and SetProp.
Here's what I now do when I create the main form:
[DllImport("user32.dll", SetLastError=true)]
static extern bool SetProp(IntPtr hWnd, string lpString, IntPtr hData);
SetProp( this.Handle, #"foo", new IntPtr( 1 ) ) ;
Now, I can check this property when enumerating the windows:
[DllImport("user32.dll")]
private static extern IntPtr GetProp(IntPtr hWnd, string lpString);
IntPtr result = GetProp( (IntPtr) hWnd, #"foo" ) ;
Related
I'm a bit confused about the difference between:
LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam);
and
virtual void WndProc(Message %m);
I know that the first is to get message to menage event in win32, but so "WndProc(Message %m)" is the same thing when we are programming a Windows Form project?
The last question is: When is better to use NativeWindow methods and when is better to use win32 methods to manage events?
My project is a simple window form with a panel, on the Panel I call a window where I can menage OpenGL operations.
Could someone help me?
The former is raw C-style Win32 API. The latter is a member of a .NET classes System.Windows.Forms.Control and System.Windows.Forms.NativeWindow, as expressed in C++/CLI.
I imagine that .NET runtime internally implements WndProc the Win32 callback, and arranges for it to call WndProc the class method, if you choose to override it in your class derived from Control.
I'm not sure why you need NativeWindow. If for some reason you want to handle raw window messages, then derive your class from Panel and override WndProc there; Panel derives from Control.
we have a wpf application that should be 'piloted' by a legacy win32 winform application. (We don't own the code ;) )
The legacy application should pilot our application (minimize, bring to front, shut, etc) via windowsclass name we should provide as a configuration parameter written into an ini file.
The problem is we cannot make it work with wpf since if we insert the classname Spy++ gives us, nothing happens. The point is Spi++ returns something like this
HwndWrapper[MyWpfProgram.exe;;16978ce2-3b8d-4c46-81ee-e1c6d6de4e6d]
where the guid is randomly generated at every run.
Is there any way to solve this issue?
Thank you.
There is no way to do what I asked. But we found a walkaround. "Simply" embedding the xaml windows within a windows form.
These are the steps we followed:
1 - Add a Windows Form to the project.
2 - Remove the app.xaml and make the new form the entry point of the application.
3 - Since we need the hwnd of the main.xaml we added this prop to its code behind
public IntPtr Hwnd
{
get { return new WindowInteropHelper(this).Handle; }
}
4 - then from the constructor of the form we create an instance of the wpf window class
private Main app;
public ContainerForm()
{
InitializeComponent();
app = new Main();
ElementHost.EnableModelessKeyboardInterop(app);
}
we needed
ElementHost.EnableModelessKeyboardInterop(app);
since we want all the keyboard input to pass from the the windows form to the xaml window
5 - now we want to bond the xpf window to the winform. In order to do that we need to use Windows Api and we do it at the OnShow event of the form (the reason why will be explicated later).
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetFocus(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
private static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
private const int GWL_STYLE = (-16);
private const int WS_VISIBLE = 0x10000000;
private void ContainerForm_Shown(object sender, EventArgs e)
{
app.Show();
SetParent(app.Hwnd, this.Handle);
SetWindowLong(app.Hwnd, GWL_STYLE, WS_VISIBLE);
MoveWindow(app.Hwnd, 0, 0, this.Width, this.Height, true);
SetFocus(app.Hwnd);
}
with
SetParent(app.Hwnd, this.Handle);
wo do the magic, then with
SetWindowLong(app.Hwnd, GWL_STYLE, WS_VISIBLE);
we remove al the chrome from the wpf window (there is a border even if the window is defined borderless, don't ask me why)
then we make the wpf window fill all the client area of the winform
MoveWindow(app.Hwnd, 0, 0, this.Width, this.Height, true);
and then we focus the wpf window
SetFocus(app.Hwnd);
that's the reason why we do everything in the show event. Since if we do it at form's constructor, then the wpf window will loose its focus since the in winform the main window got the focus from the operating system.
We didn't understand why we needed to add the other api calls at this point, but if we left them at constructor's the trick didn't work.
Anyway,
problem solved ;)
Use HwndSource.
You can use native Windows API calls to create a window with the expected classname, then use HwndSource to add WPF content to it:
var source = HwndSource.FromHwnd(nativeWindowHandle);
source.RootVisual = mainGrid;
If you need to use a WPF window, I think you could still solve this with a "proxy" window, but it wouldn't be pretty:
Have your WPF application spawn a native message-only window.
Use HwndSource.AddHook to handle messages like WM_CLOSE, WM_SIZE on the native window and pass them along to the "real" WPF window.
For the window handles, titles, and class names, Spy++ uses fairly simple Windows APIs.
FindWindowEx http://msdn.microsoft.com/en-us/library/windows/desktop/ms633500%28v=vs.85%29.aspx
EnumWindows http://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx
GetClassName http://msdn.microsoft.com/en-us/library/windows/desktop/ms633582%28v=vs.85%29.aspx
You can create a "loader" program that will...
Start the wpf app
Use the above APIs to get the proper class names and windows handles
Edit the legacy INI
Start the legacy app
I'm working on an XBAP app where Users primarily use the Keyboard for Navigation. When I display a MessageBox, I can hit Enter to close it but then the main application doesn't seem to regain focus. I have to manually click the mouse on the screen to put focus back on the application.
Is there a way around this?
Edit
I can verify that the app still has Logical Focus, but it just doesn't have Keyboard Focus
I found a hack that works, although I don't like it because I feel it ties my Views to my ViewModel
I'm using an IsFocused AttachedProperty to bind a control to a boolean property behind the View. The same View is also subscribing to a DisplayError event that displays a MessageBox error and reset the IsFocused property afterwards so it updates the UI. Last change made was to update my ViewModels to publish errors to the EventAggregator instead of handling themselves with a MessageBox, which is probably better anyways.
I suppose it works, even if I don't like it
Not sure if this will help your situation but in my circumstance it was ok for me to set focus back to main window, which was able to be accomplished with
App.Current.MainWindow.Focus();
Just be sure main window is properly initialized, which may not be the case if a splash screen or some login window or something initially grabbed the main window role (ie by StartupUri) and then nothing else was updated thereafter.
This worked for me since I was handling all keyboard events at the main window level to drive updates to my view model.
using System.Runtime.InteropServices;
using System.Windows.Interop;
public class Interop
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
public static IntPtr GetWindowHandle(Window window)
{
return new WindowInteropHelper(window).Handle;
}
}
// In main window, when the MessageBox is closed
IntPtr window = Interop.GetWindowHandle(this);
IntPtr focused = Interop.GetForegroundWindow();
if (window != focused)
{
Interop.SetForegroundWindow(window);
}
http://tech.avivo.si/2009/11/how-to-focus-window-in-wpf-when-it-gets-out-of-focus/
I use a class derived from HwndHost to host a Win32 window. It is in turn used within a user control. That user control doesn't get shown (Visibility) unless the internal Win32 window gets successfully created. However, the BuildWindowCore method doesn't appear to be called unless the HwndHost window is visible, so I have a chicken & egg situation.
If a HwndHost derived class is not visible, is there another way to get it's BuildWindowCore method called?
Well, a month has passed with no answers. Looks like I've stumped everyone including myself.
So, the answer as of .NET 4.0 is "No, there is no way to force BuildWindowCore to be called before the framework is ready to call it."
You can create your Win32 window yourself and just use HwndHost as a wrapper like in the example below.
ref class MyHost : HwndHost
{
private:
HWND m_hWnd;
public:
MyHost(HWND hWnd)
{
m_hWnd = hWnd;
}
protected:
virtual HandleRef BuildWindowCore(HandleRef hwndParent) override
{
// Simply re-parent the window
SetParent(m_hWnd, (HWND) hwndParent.Handle.ToPointer());
return HandleRef(this, (IntPtr) m_hWnd);
}
virtual void DestroyWindowCore(HandleRef hwnd) override
{
::DestroyWindow(m_hWnd);
}
};
I am trying to create a Visual Tree Explorer application (like Snoop, Mole) which should automatically identify all desktop applications and detect whether it is a WPF app. or not. I am tring to do this in WPF. Is there any way to get all WPF opened applications. Any special API, or native functions in system dlls, etc.
Regards,
Jawahar
I think you can iterate through the list of all processes and for those processes who have a window, check if the window class name starts with HwndWrapper (I've noticed the WPF windows have a class name like this: HwndWrapper[DefaultDomain;;2e60e21a-8752-4daf-820b-aed289668930])
The code should be something like this:
Process[] procs = Process.GetProcesses();
foreach(Process p in procs)
{
if (p.MainWindowHandle != null)
{
Console.WriteLine(p.MainWindowTitle);
StringBuilder sb = new StringBuilder(257);
RealGetWindowClass(p.MainWindowHandle, sb, 256);
Console.WriteLine(sb.ToString());
if(sb.ToString().StartsWith("HwndWrapper"))
{
Console.WriteLine("WPF window");
}
}
}
[DllImport("user32.dll")]
static extern uint RealGetWindowClass(IntPtr hwnd, [Out] StringBuilder pszType, uint cchType);
with maybe some adjustments depending on your case. When dealing with such a window, one should assume it's a WPF window not take it for a certainty, so error checking must be extensive.