I have created a custom window in WPF using the Microsoft.Windows.Shell DLL and .NET 4.0.
The problem is that if the taskbar is set to autohide and the window is maximized, the window completely covers the taskbar. I have tried several different solutions (the first few Google results) but none actually work.
The method the MahApps.Metro package uses will set the window 1px off of the bottom of the screen if the taskbar is not autohidden.
I need a solution that
Works in .NET 4.0
Works no matter which side the taskbar is docked to
Works when the taskbar is set to both always show and autohide.
A customized WPF window does not respect the area occupied by the task bar. In order to do this, you need support from the Win32 API.
The first method you will need is...
[DllImport("user32.dll")]
public static extern IntPtr MonitorFromWindow(IntPtr hwnd, int dwFlags);
The MonitorFromWindow function retrieves a handle to the display monitor that has the largest area of intersection with the bounding rectangle of a specified window. http://msdn.microsoft.com/en-us/library/windows/desktop/dd145064(v=vs.85).aspx
Set dwFlags = 2
The next one is...
[DllImport("user32.dll")]
public static extern bool GetMonitorInfo(HandleRef hmonitor,
[In, Out] MonitorInfoEx monitorInfo);
The GetMonitorInfo function retrieves information about a display monitor. http://msdn.microsoft.com/en-us/library/windows/desktop/dd144901(v=vs.85).aspx
The MonitorInfoEx struct looks like...
[StructLayout(LayoutKind.Sequential)]
public class MonitorInfoEx
{
public int cbSize;
public Rect rcMonitor;
public Rect rcWork;
public int dwFlags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
public char[] szDevice;
}
The MONITORINFOEX structure contains information about a display monitor. http://msdn.microsoft.com/en-us/library/windows/desktop/dd145066(v=vs.85).aspx
The Rect being passed is...
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Of particular interest here is that you are getting the working area in DPI at its current resolution.
Finally, you'll need the HwndSource.FromHwnd method from the Interop namespace of the PresentationCore (WPF)
Once you have all the info together, you can use CompositionTarget.TransformFromDevice to... Gets a matrix that can be used to transform coordinates from the rendering destination device to this target. http://msdn.microsoft.com/en-us/library/system.windows.media.compositiontarget.transformfromdevice.aspx
... and that will give you the dimensions you need to position your customized window such that it respects the status bar.
Related
How can I change another program's -- let's say Skype's -- window's size, from my C# program?
You can use MoveWindow (Where hWnd is the window you want to move):
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
MoveWindow(ApplicationHandle, 600, 600, 600, 600, true);
If you don't know the window pointer, you can use the FindWindow functionality.
Also worth a read is MSDN SetWindowPos (Very similar to MoveWindow).
You need to get the window handle of the other program, use Process.MainWindowHandle or FindWindow.
Having this, you can PInvoke SetWindowPos() to move, resize, change the Z-order or the min/max/restore state of the window.
I would use the Windows Api SetWindowPos
check this one out: Using SetWindowPos in C# to move windows around
of course first you should know the handle of the window you want to resize, this can be done in many ways like getting the process by name then the MainWindow of that process or with EnumWindow or FindWindow APIs
I have a screen capturing utility on which I can rubber band an area on the desktop. I've done this is a fairly easy manner, I have a form which is the same size as the screen on which I draw a screenshot of the desktop transformed into grayscale. When the user holds down the left mouse button he/she can select an area on the form. The rectangle which the user draws is filled with TransparentColor. Once the users lifts up his/her mouse the transparent rectangle is left in place and the actual desktop is visible. Here comes my problem:
On my dev PC I can actually click through this transparent rectangle and navigate around etc. while on my other PC the form responds on mouse clicks on the actual transparent rectangle.
I'm using .NET 4.0 in C#, any ideas on how I can make it actually click through to the desktop on all cases??
Thank you and much appreciated :)
I managed to find a proper solution for this problem after looking very deeply into this. It turns out with the proper Win32 API calls it is possible to set a form "Invisible" to mouse clicks. This can be achieved by:
public const int GWL_EXSTYLE = -20;
public const uint WS_EX_LAYERED = 0x00080000;
public const uint WS_EX_TRANSPARENT = 0x00000020;
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
public void SetFormTransparent(IntPtr Handle) {
oldWindowLong = GetWindowLong(Handle, GWL_EXSTYLE);
SetWindowLong(Handle, GWL_EXSTYLE, Convert.ToInt32(oldWindowLong | WS_EX_LAYERED | WS_EX_TRANSPARENT));
}
public void SetFormNormal(IntPtr Handle) {
SetWindowLong(Handle, GWL_EXSTYLE, Convert.ToInt32(oldWindowLong | WS_EX_LAYERED));
}
But there is a trick to everything. You need to be careful that all clicks made on the forum will fall through the form and be sent to anything below the form. To ensure that if I click on my form e.g. on a button and I want the button clicked I did a simple trick. I have a timer in the background running every N milliseconds and analyzing the position of the Cursor. If it's above the area I want it to be, it'll set the Form to Normal via SetFormNormal() otherwise it'll be transparent.
Hope this code bit helps and people will use it.
I have both dark and light versions of my application icon; the dark version works best on gray surfaces such as Windows XP taskbar, where the light version works best as an icon in the titlebar.
Is there a way I can set the icon in the taskbar to a different icon than the one used in my form in C# (P/Invoke is fine)?
Send the WM_SETICON message to your form with different icon handles for the ICON_SMALL and the ICON_BIG parameter:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);
private const uint WM_SETICON = 0x80u;
private const int ICON_SMALL = 0;
private const int ICON_BIG = 1;
public MyForm()
{
InitializeComponent();
SendMessage(this.Handle, WM_SETICON, ICON_SMALL, Properties.Resources.IconSmall.Handle);
SendMessage(this.Handle, WM_SETICON, ICON_BIG, Properties.Resources.IconBig.Handle);
}
I know this is an old question but I came across it when trying to achieve the same thing, and well yes you can do this, on Windows 7/8 at least.
It turns out an ICO file doesn't just contain one image, it contains 9 different images at 9 different resolutions:
16x16
24x24
32x32
48x48
64x64
72x72
80x80
96x96
128x128
On Windows 7 and 8, the 64x64 image is used on the taskbar, and the 16x16 image is used on the icon which is placed on the top left hand corner of your form.
You can use a tool like Greenfish Icon Editor Pro (I don't work for them or anything, this isn't a plug!) to have these as two seperate images, and then add this *.ico file as normal to your Windows Form/WPF form in Visual Studio.
The end result is shown below:
As you can see my WPF application has two seperate icons, one in the taskbar and another on the form.
i need to implement a cursor with some very specific features:
it has to be animated
because after n seconds it automatically clicks - so the animation is feedback for the user when the click will happen
it has to snap to some of our controls
it has to work outside of our application
the approaches so far:
render my WPF-control into a bitmap, make a cursor-struct out of it and use user32.dll/SetSystemCursor to set it
PRO
the cursor has no delay after the mouse since it's a real cursor
CON
snapping is quite hard, especially since we have absolute and relative inputdevices and i would have to reset the mouseposition all the time or use user32.dll/ClipCursor (System.Windows.Forms.Cursor.Clip does the same) but the snapped cursor is always shaking around the snapped position (tries to escape, get's reset again....)
the code i use throws strange exceptions after some random time - so my current code seems quite unstable
render my own cursor into a maximized, topmost, allowtransparent, windowstyle=none, invisible window and manually move the cursor after the mouse (like Canvas.SetLeft(cursor, MousePosition.X))
PRO
snapping can be (easily) done
CON
when the mouse clicks and hit's the cursor the cursor get's clicked and not the window beyond
polling the mouseposition in a dispatcher-background-loop all the time doesn't seem very beautiful to me
to solve the second approach my cursor would have to have at least one transparent pixel
in the hotspot, so that the mouse can click through... that doesn't seem like a real solution to me...
any idea's anyone?
EDIT:
some example-source to show the problems...:
example app & source to show the problem with snapping the mouse to a fixed position: ClipIt.rar
example app & source that fails after random time - setting a self-drawn cursor: TryOwnCur.rar
can be found under: http://sourcemonk.com/Cursor
thanks to http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a3cb7db6-5014-430f-a5c2-c9746b077d4f
i can click through my self-drawn cursor which follows the mouse-position by
setting the window style:none, and allowtransparent as i already did and
then
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);
public static void makeTransparent(IntPtr hwnd) {
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
}
and call makeTransparent from OnSourceInitialized...
I am interested in writing an application that overlays a small heads up display (HUD) over another application, in VB.NET. What is an example of this?
I will need to enumerate all open windows to find the window that I want, and then overlay some text in a specific position on the window. If the user moves that window, my text will need to follow. (I will probably be painting the text in a loop over and over).
Edit: nobody answered my original query - I added C# to the keywords to see if any of gurus in that language might have an answer.
You can use WinApi to enumerate windows.
You can start googling with
[DllImport("user32.dll")]
public static extern int EnumWindows(EnumWindowsProc ewp, int lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, ref WapiRect lpRect);
When you have found your window and has its handle, there is no problem to plot on it with something like
Graphics g = Graphics.FromHwnd(win.Handle);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, 1000, 1000);
But to overlay... One possible solution is to create own border less form(it can be made even transparent) and place your text on it. Then just place this special form on top of another application.