Hide the icon from a WPF window - wpf

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

Related

HwndHost doesn't display content when Desktop Composition is enabled

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

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:

Is there a way of taking a screenshot of the whole screen with White?

Is there an API that would let me do it in http://teststack.github.com/White/?
I can't seem to find it.
Thanks
Pawel
I know this is a very old post. But I though can't hurt to update it. TestStack.White has these functions now:
//Takes a screenshot of the entire desktop, and saves it to disk
Desktop.TakeScreenshot("C:\\white-framework.png", System.Drawing.Imaging.ImageFormat.Png);
//Captures a screenshot of the entire desktop, and returns the bitmap
Bitmap bitmap = Desktop.CaptureScreenshot();
From looking through the code on GitHub, it doesn't appear to have an API for that (perhaps add it as a feature request?).
You can do it fairly simply yourself though using a combination of the Screen class and Graphics.CopyFromScreen. There are some examples of how to capture the screen or the active window in the answers to this question.
The White.Repository project actually records the flow of your test, with screenshots but it is not very well documented and is not released on NuGet yet (it will be soon).
Personally I use this class we have put together from a bunch of sources and forget where I got it originally. This captures modal dialogues and other things that many of the other implementations didn't capture for some reason.
/// <summary>
/// Provides functions to capture the entire screen, or a particular window, and save it to a file.
/// </summary>
public class ScreenCapture
{
[DllImport("gdi32.dll")]
static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop);
[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDc);
[DllImport("gdi32.dll")]
static extern IntPtr DeleteDC(IntPtr hDc);
[DllImport("gdi32.dll")]
static extern IntPtr DeleteObject(IntPtr hDc);
[DllImport("gdi32.dll")]
static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll")]
static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp);
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr ptr);
public Bitmap CaptureScreenShot()
{
var sz = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Size;
var hDesk = GetDesktopWindow();
var hSrce = GetWindowDC(hDesk);
var hDest = CreateCompatibleDC(hSrce);
var hBmp = CreateCompatibleBitmap(hSrce, sz.Width, sz.Height);
var hOldBmp = SelectObject(hDest, hBmp);
BitBlt(hDest, 0, 0, sz.Width, sz.Height, hSrce, 0, 0, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
var bmp = Image.FromHbitmap(hBmp);
SelectObject(hDest, hOldBmp);
DeleteObject(hBmp);
DeleteDC(hDest);
ReleaseDC(hDesk, hSrce);
return bmp;
}
}
Then to consume
var sc = new ScreenCapture();
var bitmap = sc.CaptureScreenShot();
bitmap.Save(fileName + ".png"), ImageFormat.Png);

WPF: Non focusable window

I am developing WPF Touch Screen Keyboard.
I need to know how is it possible to make main window non focusable, so other windows will be receiving the input when I click on virtual keyboard buttons.
Simple applying "Focusable="False"" to the main window and all child controls doesn't work.
I think there is a clickable attribute you can set to false which stops the form receiving click messages.
Problem was solved by using Popup instead of Window, which not grab the focus, when you click on it.
From here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/41ca3605-247c-4c5b-ac5d-74ce5abd7b92/making-a-window-invisible-to-mouse-events-ishittestvisiblefalse-not-working?forum=wpf
I've figured out how to do this. The key being the WS_EX_TRANSPARENT flag for the window's extended style.You can set the topmost property like you normally would, then this code takes care of making the window transparent to mouse clicks:
Code Snippet
public const int WS_EX_TRANSPARENT = 0x00000020;
public const int GWL_EXSTYLE = (-20);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Get this window's handle
IntPtr hwnd = new WindowInteropHelper(this).Handle;
// Change the extended window style to include WS_EX_TRANSPARENT
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
}

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