HwndHost doesn't display content when Desktop Composition is enabled - wpf

I'm using HwndHost to embed an external application in my WPF window. I noticed on some Windows 7 machines, if an Aero Theme is selected and Desktop Composition is enabled, the external application starts, flickers on the screen for a split second and then it disappears. If I turn off Desktop Composition or use the basic theme, the application is embedded successfully inside the WPF window.
This is the code I use in a class derived from HwndHost:
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("USER32.DLL", SetLastError = true)]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
private const int GWL_STYLE = (-16);
private const int WS_CHILD = 0x40000000;
private const int WS_EX_APPWINDOW = 0x00040000;
[DllImport("user32.dll", SetLastError = true)]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
while (Process.MainWindowHandle == IntPtr.Zero)
{
Process.Refresh();
System.Threading.Thread.Sleep(10);
}
SetLastError(0);
var ret = SetWindowLong(Process.MainWindowHandle, GWL_STYLE, WS_CHILD);
int e1 = Marshal.GetLastWin32Error();
SetParent(Process.MainWindowHandle, hwndParent.Handle);
int e2 = Marshal.GetLastWin32Error();
ShowWindow(Process.MainWindowHandle, 0);
int e3 = Marshal.GetLastWin32Error();
return new HandleRef(this, Process.MainWindowHandle);
}
I don't get any windows errors when the issue occurs. The process starts from another window which injects it to my class. I've checked with task manager and the process runs but it's not visible inside my WPF window. Any thoughts?

Look at the system addin namespace for how you can use the native HWIND_PTR as a control.
You don't need to use all of the library to do the work.
https://learn.microsoft.com/en-us/dotnet/framework/wpf/app-development/wpf-add-ins-overview

Related

Is it possible to host a QT application into a WPF application?

I'm trying to create WPF GUI application to host an already exist QT GUI application as part of the main UI.
The QT application don't need to deal with mouse/keyboard input.
I've tried approach mentioned in this SO Post. Seems all those approach does not work for a QT application.
I don't know if it's a right thing to do, but that's what I used some times to embedd other apps (found on the internet):
public partial class MainWindow : Window
{
private Process _process;
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);
[DllImport("user32")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
private const int SWP_NOZORDER = 0x0004;
private const int SWP_NOACTIVATE = 0x0010;
private const int GWL_STYLE = -16;
private const int WS_CAPTION = 0x00C00000;
private const int WS_THICKFRAME = 0x00040000;
const string patran = "patran";
public MainWindow()
{
InitializeComponent();
Loaded += (s, e) => LaunchChildProcess();
}
private void LaunchChildProcess()
{
_process = Process.Start("/path/to/QtExecutable.exe");
_process.WaitForInputIdle();
var helper = new WindowInteropHelper(this);
SetParent(_process.MainWindowHandle, helper.Handle);
// remove control box
int style = GetWindowLong(_process.MainWindowHandle, GWL_STYLE);
style = style & ~WS_CAPTION & ~WS_THICKFRAME;
SetWindowLong(_process.MainWindowHandle, GWL_STYLE, style);
// resize embedded application & refresh
ResizeEmbeddedApp();
}
private void ResizeEmbeddedApp()
{
if (_process == null)
return;
SetWindowPos(_process.MainWindowHandle, IntPtr.Zero, 0, 0, (int)ActualWidth, (int)ActualHeight, SWP_NOZORDER | SWP_NOACTIVATE);
}
protected override Size MeasureOverride(Size availableSize)
{
Size size = base.MeasureOverride(availableSize);
ResizeEmbeddedApp();
return size;
}
Just modify this skeleton to your necessities.
Let me know if it works.
Yes. It is possible. A very simple way for your quick start without the effort of coding.
Check this link: Hosting EXE Applications in a WPF Window Application (http://www.codeproject.com/Tips/673701/Hosting-EXE-Applications-in-a-WPF-Window-Applicati). Download the project. Find "notepad.exe" in the project and replace it with the file name of your QT application. Just a remind: for the WPF exe to launch the QT application, you may need to take care of the environment variables required by QT.
What it looks like:

How can I know whether a form is showing to user?

I have a system monitor program which cost system resource heavly. I hope the program run tasks only when the form is showing to users. One way is to check whether the form is foreground window or active window.
But if the form is not activated but is showing to users (for example, you can see two windows in following picture, one of the window is not activated but showing to users), I can't handle the situation well.
window example http://www.chip.de/ii/117599040_a933fb45fe.gif
Any ideas? Thanks in advanced.
Edit:
I have found the solution according to my colleague's suggest.
Here is my solution:
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[DllImport("user32.dll", SetLastError = true)]
static extern bool IsZoomed(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
static extern bool IsWindowVisible(IntPtr hwnd);
[DllImport("user32.dll", EntryPoint = "GetWindow", SetLastError = true)]
static extern IntPtr GetNextWindow(IntPtr hWnd, uint cmd);
[DllImport("user32.dll", EntryPoint = "GetWindowText", SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetForegroundWindow")]
private static extern IntPtr GetForegroundWindow();
//I have made some simplifications. My form is maximized. If the form is not
// maximized, you should calculate the region of current form and top level form
// to check it.
private bool IsShowing()
{
if(this.Visible == false || this.WindowState = FormWindowState.Minimized)
return false;
IntPtr currentHandler = this.Handle;
if (currentHandler == GetForegroundWindow())
return true;
while (currentHandler != GetForegroundWindow())
{
IntPtr hwnd = GetNextWindow(currentHandler, (uint)GetWindow_Cmd.GW_HWNDPREV);
currentHandler = hwnd;
if (IsZoomed(currentHandler) && IsWindowVisible(currentHandler))
{
StringBuilder sb = new StringBuilder(255);
GetWindowText(currentHandler, sb, sb.Capacity + 1);
Debug.WriteLine("masked by:" + sb.ToString());
return false;
}
}
if (IsZoomed(currentHandler) && IsWindowVisible(currentHandler))
{
StringBuilder sb = new StringBuilder(255);
GetWindowText(currentHandler, sb, sb.Capacity + 1);
Debug.WriteLine("masked by:" + sb.ToString());
return false;
}
return true;
}
It is not clear when you want to run or not your tasks, but in any case, I think that the best approach is to let the system notify you when your form acvtive or visible state changes. In this case you should write the activation and deactivation tasks's code in the forms event Activated, Deactivate and/or VisibleChanged
From MSDN
Deactivate: Occurs when the form loses focus and is no longer the
active form.
Activated: Occurs when the form is activated in code or by the user.
VisibleChanged: Occurs when the Visible property value changes.
You could also find useful to refer to this article that shows the order of events in the loading and closing of a form

Hide the icon from a WPF window

I know that there are many questions about hiding or removing the icon from the upper left corner of a WPF window, the place where the system menu is. I've tried many of them but none works. Here are my requirements:
The icon disappears and does not take any empty space (i. e. no transparent icon)
The window title starts directly at the left edge of the window
The close button in the upper right corner is still there and works
Minimise/maximise buttons are still there if enabled (optional, didn't test this)
No custom-drawing of the entire window frame
Works on Windows 7 with Aero Glass enabled (Windows 8 anybody?)
Works on 32 and 64 bit Windows (x86 and x64 build)
Works with WPF .NET 4.0
Works when not in a debugger like Visual Studio (would be nice if it also works in the debugger)
Should also work on Windows XP (optional)
The available answers basically use the Windows API functions GetWindowLong, SetWindowLong and sometimes also SetWindowPos to add the extended window style WS_EX_DLGMODALFRAME and call SWP_FRAMECHANGED. Sometimes, other styles are also set or unset.
Unfortunately, none of this works at all. I can either have no icon with no close button, or both are still there. But it's also noticeable that all of that content is from 2010 or eariler. It seems it's targeted at earlier .NET or Windows versions and fails since.
I've already compared the window styles of system dialogs (from Explorer) and my WPF windows with Microsoft Spy++ (included in Visual Studio). But I can try to set all flags the same, the icon won't go away. It's like black magic that overrules every other API function or physics.
Does anybody have a solution that still works today and in the indicated environment?
If you had just put the words in your title into a search engine instead of here as I just did, then you would have found many more results than these. You can find your answer in the following:
Removing Icon from a WPF window
Is it possible to display a wpf window without an icon in the title bar?
How to remove the icon of a WPF window
How to remove Icon from window titlebar
How to hide window icon in WPF
Your last comment about this not working on large scale applications made me wonder. As such, I then added the code to a large scale application and once again it worked just fine. However, I continued to test this and you must be using a RibbonWindow in your application, because when I tested this code on a large scale application with a RibbonWindow the code did not work.
If you are using a normal Window then give this code a try (From #MichalCiechan's answer to the first linked post):
First add this class:
public static class IconHelper
{
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x,
int y, int width, int height, uint flags);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr
lParam);
const int GWL_EXSTYLE = -20;
const int WS_EX_DLGMODALFRAME = 0x0001;
const int SWP_NOSIZE = 0x0001;
const int SWP_NOMOVE = 0x0002;
const int SWP_NOZORDER = 0x0004;
const int SWP_FRAMECHANGED = 0x0020;
const uint WM_SETICON = 0x0080;
public static void RemoveIcon(Window window)
{
// Get this window's handle
IntPtr hwnd = new WindowInteropHelper(window).Handle;
// Change the extended window style to not show a window icon
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
// Update the window's non-client area to reflect the changes
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
Then add this to MainWindow.xaml.cs:
protected override void OnSourceInitialized(EventArgs e)
{
IconHelper.RemoveIcon(this);
}
Oh... and one other thing to note... it won't work if you have set the Window.Icon property, but I'm guessing that you haven't done that if you don't want an icon to appear.
The above does not work, when creating a dialog window from a WPF application having an icon.
However, when adding the following two lines, the icon correctly vanishes from the dialog window:
SendMessage(hwnd, WM_SETICON, new IntPtr(1), IntPtr.Zero);
SendMessage(hwnd, WM_SETICON, IntPtr.Zero, IntPtr.Zero);
(s.a. https://connect.microsoft.com/VisualStudio/feedback/details/745230/wpf-window-cannot-be-displayed-without-titlebar-icon)
This is what I came up with after seeing different solutions to this question:
internal const int SWP_NOSIZE = 0x0001;
internal const int SWP_NOMOVE = 0x0002;
internal const int SWP_NOZORDER = 0x0004;
internal const int SWP_FRAMECHANGED = 0x0020;
internal const int GWL_EXSTYLE = -20;
internal const int WS_EX_DLGMODALFRAME = 0x0001;
[DllImport("user32.dll", SetLastError = true)]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
internal static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
/// <summary>
/// Hides icon for window.
/// If this is called before InitializeComponent() then the icon will be completely removed from the title bar
/// If this is called after InitializeComponent() then an empty image is used but there will be empty space between window border and title
/// </summary>
/// <param name="window">Window class</param>
internal static void HideIcon(this Window window)
{
if (window.IsInitialized)
{
window.Icon = BitmapSource.Create(1, 1, 96, 96, PixelFormats.Bgra32, null, new byte[] {0, 0, 0, 0}, 4);
}
else
{
window.SourceInitialized += delegate
{
// Get this window's handle
var hwnd = new WindowInteropHelper(window).Handle;
// Change the extended window style to not show a window icon
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
// Update the window's non-client area to reflect the changes
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
};
}
}
Example:
public partial class ExampleWindow : Window
{
public ExampleWindow()
{
// Hides icon completely
this.HideIcon();
InitializeComponent();
}
}

user32.dll FindWindowEx, finding elements by classname on remote WPF window

I have a WPF application that is being started from a command-line application.
I am trying to do some simple automation (get/set text, click some buttons, etc). I cannot seem to find any of the child windows in WPF.
I have working models with WPF and UIA Framework, WinForms and WinAPI, but cannot seem to get WinAPI and WPF to play nicely.
I have used UISpy, WinSpy++, Winspector, the UIA Verify app to look at the controls, etc, but they do not seem to carry the same information for WPF as WinForms.
For example, in the WinForms app, I see a textbox with a ClassName of "WindowsForms10.EDIT.app.0.33c0d9d" when I look via the spy tools. The UIA Automation Verify app is the only one to acknowledge the element exists and reports "TextBox".
So, my question is how do I find the correct class name to pass or is there an easier route to find the child elements?
// does not work in wpf
IntPtr child = NativeMethods.FindWindowEx(parent, prevElement, "TextBox", null);
// works in winforms
IntPtr child = NativeMethods.FindWindowEx(parent, prevElement, "WindowsForms10.EDIT.app.0.33c0d9d", null);
and here is the user32.dll imports I am using:
public class NativeMethods
{
public const int WM_SETTEXT = 0x000C;
public const int WM_GETTEXT = 0x000D;
public const uint CB_SHOWDROPDOWN = 0x014F;
public const uint CB_SETCURSEL = 0x014E;
public const int BN_CLICKED = 245;
public const uint WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, string lParam);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern int SendMessage(int hWnd, int Msg, int wParam, StringBuilder lParam);
}
If you want to automate WPF, you must use the UI Automation, not the "old thing of the past" windows API :-).
There is a good introduction on UI automation here: Bugslayer: GUI Control to Major Tom
There is also an interesting open source project named "White" that leverages UI automation: White on codeplex. There are some samples in there if you want to dig in.

How do I preview a Windows Media Encoder session in WPF?

This code works in a windows forms application (it shows the preview) but not in a WPF application.
WMEncoder _encoder;
WMEncDataView _preview;
_encoder = new WMEncoder();
IWMEncSourceGroupCollection SrcGrpColl = _encoder.SourceGroupCollection;
IWMEncSourceGroup2 sourceGroup = (IWMEncSourceGroup2)SrcGrpColl.Add("SG_1");
IWMEncVideoSource2 videoDevice = (IWMEncVideoSource2)sourceGroup.AddSource(WMENC_SOURCE_TYPE.WMENC_VIDEO);
videoDevice.SetInput("Default_Video_Device", "Device", "");
IWMEncAudioSource audioDevice = (IWMEncAudioSource)sourceGroup.AddSource(WMENC_SOURCE_TYPE.WMENC_AUDIO);
audioDevice.SetInput("Default_Audio_Device", "Device", "");
IWMEncProfile2 profile = new WMEncProfile2();
profile.LoadFromFile("Recording.prx");
sourceGroup.set_Profile(profile);
_encoder.PrepareToEncode(true);
_preview = new WMEncDataView();
int lpreviewStream = videoDevice.PreviewCollection.Add(_preview);
_encoder.Start();
_preview.SetViewProperties(lpreviewStream, (int)windowsFormsHost1.Handle);
_preview.StartView(lpreviewStream);
I've tried to use the WindowsFormsHost control to get a handle to pass (as shown in the sample), but still no luck.
I've recently done something similar to integrate an existing DirectShow video component with a new WPF UI. There are a variety of ways to do it, but probably the easiest is to derive a new class from HwndHost. You then simply override a couple of methods, give the window handle to your preview stream and it should all just work. depending on your requirements you may need to handle a couple of Windows messages in your WndProc to handle display changes and redrawing when the video's not playing.
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace SOQuestion
{
public class VideoHost : HwndHost
{
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
IntPtr hwndHost = IntPtr.Zero;
int hostHeight = (int) this.ActualHeight;
int hostWidth = (int) this.ActualWidth;
hwndHost = CreateWindowEx(0, "static", "",
WS_CHILD | WS_VISIBLE,
0, 0,
hostHeight, hostWidth,
hwndParent.Handle,
(IntPtr)HOST_ID,
IntPtr.Zero,
0);
return new HandleRef(this, hwndHost);
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(hwnd.Handle);
}
protected override void OnWindowPositionChanged(Rect rcBoundingBox)
{
base.OnWindowPositionChanged(rcBoundingBox);
_preview.SetViewProperties(lpreviewStream, (int)this.Handle);
}
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle a couple of windows messages if required - see MSDN for details
return base.WndProc(hwnd, msg, wParam, lParam, ref handled);
}
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Auto)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x, int y,
int width, int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,
[MarshalAs(UnmanagedType.AsAny)] object pvParam);
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Auto)]
internal static extern bool DestroyWindow(IntPtr hwnd);
internal const int WS_CHILD = 0x40000000;
internal const int WS_VISIBLE = 0x10000000;
internal const int HOST_ID = 0x00000002;
}
}

Resources