NativeWindows or Win32? - winforms

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.

Related

WPF - Catel - Disable CommandManager for Window in different Thread

Because the PleaseWaitService was removed with Catel 5.0.0, I copied the sourcecode of the implementation out of version 4.5.0 in an separate lib and linked the "new" lib and used the Service like before.
But because there were some errors with the PleaseWaitService in combination with our existing codebase I rewrote and simpliefied the Service (just supporting WPF).
Now I'm showing the PleaseWaitWindow in a different Thread which works in my testproject but not in production. I'm getting an InvalidOperationException when I call window.Show() (the window was created in the same thread).
In the exception's stacktrace are some calls from the Catel CommandManager
at System.Windows.Threading.Dispatcher.VerifyAccess()
at Catel.MVVM.CommandManager.SubscribeToKeyboardEvents(FrameworkElement view) in C:\CI_WS\Ws\107901\Source\Catel\src\Catel.MVVM\Catel.MVVM.Shared\MVVM\Commands\CommandManager.wpf.cs:line 64
at Catel.MVVM.CommandManager.OnWindowLoaded(Object sender, RoutedEventArgs e) in C:\CI_WS\Ws\107901\Source\Catel\src\Catel.MVVM\Catel.MVVM.Shared\MVVM\Commands\CommandManager.wpf.cs:line 78
[...]
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
I have registered one Command in the CommandManager which won't be used in my custom PleaseWaitWindow.
So my question is: How can I disable the standard injection from the Commandmanager into the window?
Regards
The advantage of Catel is that everything is pluggable. If you want different behavior for the command manager, you can create your own version and override the things you want differently. Don't forget to register it in the ServiceLocator.

Force BuildWindowCore member of a HwndHost derived class to be called

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);
}
};

Get all opened desktop applications using WPF

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.

WPF rendering problem with HWND children in the way

I suppose it is safe to say that WPF renders its contents as a window background. There are no child windows in a traditional HWND sense. So, when one introduces something HWND based in a WPF app, like a WebBrowser, things start to go wrong way it terms of visual appearance.
Consider a Window having a Grid with two children, WebBrowser and something else, e.g. TextBox. If WebBrowser were a red circle instead, the TextBox would render on top of it. In case of WebBrowser, no TextBox is to be found anywhere. This is because TextBox is rendered as main window's background and WebBrowser is actually a HWND child of the main window obscuring the background.
So all is (not) well. How does one achieve the desired behavior? I want to have TextBox rendered on top of WebBrowser. Has anyone encountered this problem?
I am thinking along the lines of having a second transparent top-level borderless WPF window, re-parent it so that the main window owns it and do some other tricks to make it happen.
Before I dig in, I was wondering if anybody had an obvious or a simpler solution?
Update by Meleak
I'm offering this Bounty to anyone who can post an implementation of Ray Burns Answer AirRepair. I tried myself but in vain
Take a read through WPF Interoperation: "Airspace" and Window Regions Overview.
Suggested solution
I suggest a simple "AirRepair" class with this signature:
public class AirRepair : Decorator
{
public HwndHost Win32Host ... // DP bound to HwndHost
public Geometry RepairArea ... // Default is entire decorated control,
// or use OpacityMask
}
Used this way:
<Grid>
<WebBrowser x:Name="browser" ... />
<AirRepair Win32Host="{Binding ElementName=browser}"
Margin="10" HorizontalAlignment="Left" ...>
<TextBox ... />
</AirRepair>
</Grid>
AirRepair can be used with WebBrowser, WindowsFormsHost, or any other HwndHost. The area covered by the decorated control is displayed inside the Win32 content and it accepts focus and mouse events. For non-rectangular decorated controls, the area to display can be specified by the RepairArea and/or OpacityMask properties.
How it works
AirRepair solves airspace issues by:
Creating a child hWnd under the given HwndHost using HwndSource
Setting its hRgn to the appropriate area
Setting its RootVisual to a Border whose Background is a VisualBrush of the decorated control
Forwarding WM_MOUSEMOVE etc received by the child hWnd to the main WPF window
The result of this is that WPF continues to draw the content behind the Win32 content but AirRepair's child window redraws the same content in front of the Win32 content in a separate Win32 control.
Some important implementation details
Getting the parent hWnd
When Win32Host is originally set, it may or may not have a hWnd. The PropertyChangedCallback should use PresentationSource.AddSourceChangedHandler / PresentationSource.RemoveSourceChangedHandler to detect possible hWnd changes, then update its own hWnd pointer in a Dispatcher.BeginInvoke callback so the HwndHost has a chance to finish handling the SourceChanged event.
Creating the child hWnd
The child hWnd can be created, parented and hooked in managed code using the HwndSource class. Be sure to dispose it when the Win32Host's parent hWnd is no longer available.
Positioning the child hWnd
The child hWnd's window position (relative to its parent) can be computed as:
var compositionTarget = PresentationSource.FromVisual(this).CompositionTarget;
var position = compositionTarget.TransformToDevice(
this.TransformToVisual(Win32Host));
The UIELement.LayoutUpdated event should be used to keep this up to date.
Computing the hRgn and opacity
Optional: Omit if only rectangular repair areas are supported
When the RepairArea or OpacityMask is set and the child hWnd exists, use a RenderTargetBitmap to paint the RepairArea using the OpacityMask then create the hRgn from it. If RepairArea is null, use a rectangle. If OpacityMask is null, use black. The RenderTargetBitmap size is set by transforming the AirRepair decorator's coordinates to device coordinates. Note that this does not properly handle a variable OpacityMask such as an animated brush or a VisualBrush whose Visual is changing.
Drawing the content on the child hWnd
Use a VisualBrush whose Visual is the AirRepair decorator, not the decorated control. This allows the decorated control to be replaced without changing the content.
childHwndSource.RootVisual =
new Border
{
Background = new VisualBrush
{
Visual = this,
ViewBoxUnits = BrushMappingMode.Absolute,
ViewPortUnits = BrushMappingMode.Absolute,
}
};
Forwarding mouse messages
Add a hook using HwndSource.AddHook, then use Win32 PostMessage to the container:
childHwndSource.AddHook((hwnd, msg, wParam, lParam, handled) =>
{
// Check if message needs forwarding and update parameters if necessary
switch(msg)
{
default:
return; // Not recognized - do not forward
case WM_MOUSEMOVE:
...
}
var target = PresentationSource.FromVisual(this).CompositionTarget as HwndTarget;
if(target!=null)
Win32Methods.PostMessage(target.Handle, msg, wParam, lParam);
};
if you're looking for a quick and easy solution, just use the popup control, here's an example
http://karlshifflett.wordpress.com/2009/06/13/wpf-float-buttons-over-web-browser-control/
If you are specifically targeting a web browser, there have been a couple of attempts at this. Chris Cavanagh has created an excellent solution based on Chrome.

Custom properties on a win32 window

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" ) ;

Resources