WPF - remove system menu icon from modal window, b

2019-07-13 15:17发布

问题:

I'm trying to do (in WPF):

  1. Have an .exe file that displays the system menu icon (the icon in the upper left of the window) like normal
  2. Not have this icon show up in modal windows called by this app

I tried the solution here: Removing Icon from a WPF window

And this worked. There's a downloadable sample of the same thing at: http://blogs.msdn.com/b/wpfsdk/archive/2007/08/02/a-wpf-window-without-an-window-icon-the-thing-you-click-to-get-the-system-menu.aspx

However, it stops working if I add an .ico file to the .exe's project properties (Properties -> Application -> Icon and Manifest). You can try this with the downloadable sample.

It seems that the icon from the .exe is used in the modal windows too (which we have in .dll files) even if the properties of that .dll says "default icon". It must get passed down from the .exe. So, is there a way to show the icon on the main window, but not on a child window?

Possibly, an easier way of asking this is: Is it possible to remove the icon even though there's an .ico file specifies in the project's properties?

The only thing I've found to work is to set the WindowStye of the modal window to "ToolWindow". This gives me almost what I want: no icon and the "Close" button ("x" in upper right) is still there. Yet, the x is super small. Is this the best there is?

Thanks for any help.

回答1:

I had this same problem. It appears that WS_EX_DLGMODALFRAME only removes the icon when the WPF window's native Win32 window does not have an icon associated with it. WPF (conveniently) uses the application's icon as the default icon for all windows without an explicitly set icon. Normally, that doesn't cause any problems and saves us the trouble of manually setting the application's icon on each window; however, it causes a problem for us when we try to remove the icon.

Since the problem is that WPF automatically sets the window's icon for us, we can send WM_SETICON to the Win32 window to reset its icon when we are applying WS_EX_DLGMODALFRAME.

const int WM_SETICON = 0x0080;
const int ICON_SMALL = 0;
const int ICON_BIG = 1;

[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr SendMessage(
    IntPtr hWnd, 
    int msg,
    IntPtr wParam, 
    IntPtr lParam);

Code to remove the icon:

IntPtr hWnd = new WindowInteropHelper(window).Handle;
int currentStyle = NativeMethods.GetWindowLongPtr(hWnd, GWL_EXSTYLE);

SetWindowLongPtr(
    hWnd,
    GWL_EXSTYLE,
    currentStyle | WS_EX_DLGMODALFRAME);

// reset the icon, both calls important
SendMessage(hWnd, WM_SETICON, (IntPtr)ICON_SMALL, IntPtr.Zero);
SendMessage(hWnd, WM_SETICON, (IntPtr)ICON_BIG, IntPtr.Zero);

SetWindowPos(hWnd, IntPtr.Zero, 0, 0, 0, 0, 
    SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);

Edit: Oh, and it looks like this works only when the app is run outside of Visual Studio.