I am making an add on for a game, but I want it to reside as an overlay to the game's client area of the window.
Basically when I start the add on, i want it to show on top of the game. The catch is if you minimize or move the window, I want the the form to stick with it.
Anyone know of anything that can do the trick without having to hook directdraw?
Thanks.
Here is a simple way to do this. First, you'll need this line in your form's using statements:
using System.Runtime.InteropServices;
Next, add these declarations to your form:
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int X;
public int Y;
public int Width;
public int Height;
}
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
Next, set your form's TopMost property to True. Finally, add a Timer control to your form, set its Interval property to 250 and its Enabled property to True, and put this code in its Tick event:
IntPtr hWnd = FindWindow(null, "Whatever is in the game's title bar");
RECT rect;
GetWindowRect(hWnd, out rect);
if (rect.X == -32000)
{
// the game is minimized
this.WindowState = FormWindowState.Minimized;
}
else
{
this.WindowState = FormWindowState.Normal;
this.Location = new Point(rect.X + 10, rect.Y + 10);
}
This code will keep your form positioned over the game's form if the game is not minimized, or it will minimize your form also if the game is minimized. To change the relative position of your application, just change the "+ 10" values in the last line.
The more complicated method would involve hooking windows messages to determine when the game form minimizes or moves or changes size, but this polling method will accomplish almost the same thing much more simply.
One last bit: FindWindow will return 0 if it finds no window with that title, so you could use this to close your own application when the game is closed.
Related
I have developed an application in C# and I want to show it in full screen mode. It should also cover up the taskbar. To accomplish this I have used the Windows API. You can find the class below:
public sealed class WinAPI
{
[DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
public static extern int GetSystemMetrics(int which);
[DllImport("user32.dll")]
public static extern void
SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter,
int X, int Y, int width, int height, uint flags);
private const int SM_CXSCREEN = 0;
private const int SM_CYSCREEN = 1;
private static IntPtr HWND_TOP = IntPtr.Zero;
private const int SWP_SHOWWINDOW = 64; // 0×0040
public static int ScreenX
{
get { return GetSystemMetrics(SM_CXSCREEN); }
}
public static int ScreenY
{
get { return GetSystemMetrics(SM_CYSCREEN); }
}
public static void SetWinFullScreen(IntPtr hwnd)
{
SetWindowPos(hwnd, HWND_TOP, 0, 0, ScreenX, ScreenY, SWP_SHOWWINDOW);
}
}
I am using this class in conjunction with the following form settings to go in full screen mode:
private void terminalModeToolStripMenuItem_Click(object sender, EventArgs e)
{
// Remove the border.
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
this.Bounds = Screen.PrimaryScreen.Bounds;
// Full screen windows API hack.
WinAPI.SetWinFullScreen(this.Handle);
}
Now comes the funny part. If I click a button in my menu bar it will show up with a gap between the button and the menu as you can see in the image below:
Does anyone knows how to fix this issue? I would like it to show up like this:
And why does this happen anyway?
As Muraad pointed you to in his comment, try moving the following block of code into your Form load event:
// Remove the border.
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
this.Bounds = Screen.PrimaryScreen.Bounds;
And see if the issue still persists.
This problem is caused by having the task bar set to the top of the screen.
It can be resolved by either moving the task bar to the bottom of the screen, or by enabling the Auto-hide task bar check box in the Properties window of the task bar.
EDIT: As stated by #slashp 's comments. The root cause of this issue comes from some inner mechanics in drawing the menu. The menu has a safety to be always drawn within the working area. Which seems to be your screen - task bar. Because the application is placed over the task bar, the calculation is placing the menu below the task bar. (you can't see it, but it's still there)
I am working on a C# WPF application that uses two screens. In the application the user is able to clone or extend the screen depending on what the user want to do. This is done in windows 7 and is using the following code:
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
private static extern long SetDisplayConfig(uint numPathArrayElements, IntPtr pathArray, uint numModeArrayElements, IntPtr modeArray, uint flags);
UInt32 SDC_TOPOLOGY_INTERNAL = 0x00000001;
UInt32 SDC_TOPOLOGY_CLONE = 0x00000002;
UInt32 SDC_TOPOLOGY_EXTEND = 0x00000004;
UInt32 SDC_TOPOLOGY_EXTERNAL = 0x00000008;
UInt32 SDC_APPLY = 0x00000080;
public void CloneDisplays()
{
SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, (SDC_APPLY | SDC_TOPOLOGY_CLONE));
}
public void ExtendDisplays()
{
SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, (SDC_APPLY | SDC_TOPOLOGY_EXTEND));
}
Now to my problem. When using the above code I manage to clone/extend the screen. However, after this is done the taskbar at the bottom of the screen is in front of the full screen application which should not be the case. How do i put the application window back at the top?
Additional information:
When I start the application it starts in fullscreen with the taskbar behind the application. This is done by setting the following:
WindowState="Maximized"
WindowStyle="None"
And this is what I want after the clone/extend has been done.
Thanks
Edit:
I have noticed that after I clone/extend the screen and sleep for say 5 seconds everything works as it should. However, as soon as the 5 seconds is over and the function exits the taskbar gets on top. Therefore it seems that I can not change something right after the clone/extend because the taskbar will always get on top in the end. So somehow I have to figure out how to stop the taskbar to behave like this, instead of changing the property of the window.
Try setting the width and height of the WPF window as follows, You could set this within window constructor.
Width = System.Windows.SystemParameters.PrimaryScreenWidth;
Height = System.Windows.SystemParameters.PrimaryScreenWidth;
To hide the taskbar try setting,
Width = System.Windows.SystemParameters.FullPrimaryScreenWidth;
Height = System.Windows.SystemParameters.FullPrimaryScreenHeight;
I'm already doing full-screen mode within my winforms applications, but i think you can do it more or less the same within WPF:
(this has to be different but similar in WPF):
form.WindowState = FormWindowState.Normal;
form.FormBorderStyle = FormBorderStyle.None;
form.Bounds = Screen.GetBounds(form);
Then the next step is to hide the task-bar if your application is on the primary screen:
if (Screen.PrimaryScreen.Equals(Screen.FromRectangle(Screen.GetBounds(form))))
{
ShowWindowsToolbar(false);
}
And the method ShowWindowsToolbar() is implemented as follows:
[DllImport("user32.dll")]
private static extern int FindWindow(string lpszClassName, string lpszWindowName);
[DllImport("user32.dll")]
private static extern int ShowWindow(int hWnd, int nCmdShow);
private const int SW_HIDE = 0;
private const int SW_SHOW = 1;
public void WindowsToolbar(bool visible)
{
int hWnd = FindWindow("Shell_TrayWnd", "");
ShowWindow(hWnd, visible ? SW_SHOW : SW_HIDE);
}
That's the way, how most of the tools out there support this kind of stuff. Also note, that this mode can mostly entered/leaved by pressing F11. So it would be good, if you also support this keystroke.
Turns out all I have to do is update the dispatcher queue and force it to do the update right after the clone/extend has been done. Then I can update the window properties.
public void ExtendDisplays()
{
SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, (SDC_APPLY | SDC_TOPOLOGY_EXTEND));
this.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { })); //Force update
current_window.hide();
current_window.show();
}
I am try to get form2 positioned relative to form1. I've tried many things an nothing seems to work right. I wanted to try:
http://www.pinvoke.net/default.aspx/user32/MoveWindow.html
As a newbie to windows programming especially C# I'm looking at the syntax/example and I find it difficult to know what to put in for the parameters. I did get a different simpler p/invoke to work:
using System.Runtime.InteropServices;
...
public partial class Form1 : Form
{
public Form1()
{ InitializeComponent(); }
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateDirectory(string lpPathName,
IntPtr lpSecurityAttributes);
private void Form1_Load(object sender, EventArgs e) { }
private void button1_Click(object sender, EventArgs e)
{ CreateDirectory(#"c:\test4", IntPtr.Zero); }
}
...
I'm taking a guess IntPtr is "saying" I'm pointing at the first node - but only a guess...
The C# signature for MoveWindow:
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
there's comments on this as well on the site. "IntPtr hWnd" - I need to get that associated with Form2 (?) , do I repaint? I'm trying to show I've looked at it and tried to figure it out - I know we are getting it from the system's dll's...the x-y I got but getting it "with" Form2 I'm lost. Help appreciated.
In general you wouldn't need PInvoke for something as simple as this.
As long as you have a reference to form2 from form1 then you can easily do this by listening to the LocationChanged event of form1. When form1 moves then you can move form2 by doing the following:
var location = this.Location;
location.Offset(xoffset, yoffset);
form2.Location = location;
That would normally be enough to make sure form2 is placed somewhere relatively to form1 and that its position is updated when form1 is moved. You may have to set an initial position of form2 if the LocationChanged event is not called when the form is first created.
Something like this should work. Tested too. You can alter this to fit exactly what you wanted to do, which shouldn't be an issue at all.
// Win32 RECT
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
// GetWindowRect gets the win32 RECT by a window handle.
[DllImport("user32.dll", SetLastError=true)]
static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
// MoveWindow moves a window or changes its size based on a window handle.
[DllImport("user32.dll", SetLastError = true)]
static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
// MoveForms moves one form to another using the win api.
void MoveForms(Form fromForm, Form toForm)
{
IntPtr hWnd_from = fromForm.Handle; // fromForm window handle
IntPtr hWnd_to = toForm.Handle; // toForm window handle
RECT rect_from, rect_to; // RECT holders for fromForm and toForm
if (GetWindowRect(hWnd_from, out rect_from) &&
GetWindowRect(hWnd_to, out rect_to)) // if it gets the win32 RECT for both the fromForm and toForm do the following ...
{
int x_to = rect_to.Left; // toForm's X position
int y_to = rect_to.Top; // toForm's Y position
int width_from = rect_from.Right - rect_from.Left; // fromForm's width
int height_from = rect_from.Bottom - rect_from.Top; // fromForm's height
// Moves fromForm to toForm using the x_to, y_to for X/Y and width_from, height_from for W/H.
MoveWindow(hWnd_from, x_to, y_to, width_from, height_from, true);
}
}
I am trying to create a program which gets the handle of the window under your cursor, show's some data about it and draws a filled rectangle (with very low alpha) on top of the whole window. I am using C# and winforms.
I have succeeded in doing so, but the problem is my draw method is in a BackgroundWorker's loop and it keeps making more and more rectangles (-> rectangle with higher alpha) on the window or when moving mouse to another window the old one still exists.
I haven't managed to find a method to clear the drawn rectangle as it just "is" on the screen and isn't bound to the graphics object or anything.
I have tried using certain native methods such as
[DllImport("User32.dll")]
public static extern Int64 SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);
[DllImport("user32.dll")]
public static extern bool UpdateWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, RedrawWindowFlags flags);
but none of the above has worked correctly. Some of them do work but as the messages get in the queue the redrawing doesn't occur immediately or is very slow and glitched (flickering etc).
So, the question is, how would I "remove" the rectangle I have drawn using Graphics.FromHwnd(handleOfWindowUnderCursor)? I actually think it doesn't matter that it is drawn on other window as I have had the very same problem earlier when trying to get rid of the drawings on my own form too (never got that fixed either!).
Alternatively, any suggestions on how I could accomplish drawing and removing the rectangle on the window under cursor without using the methods I am now?
I noticed that drawing using
Graphics g = Graphics.FromHwnd(form.Handle);
draws on the form background, under its controls. Is it whatyou want to acomplish?
// draw the rectangle
Brush b = new SolidBrush(Color.FromArgb(20, 0, 0, 255));
g.FillRectangle(b, new Rectangle(5, 5, 200, 200));
// clear the rectangle
g.Clear(this.BackColor);
If I draw on the screen directly, with this:
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
the rectangle disapears immediately after Windows refreshes the screen.
There is a third option, which is not realy strightforward.
Instead of drawing a rectangle, create a form with lowered opacity, TopMost property set to true and without borders. Then make it transparent to events:
protected override void WndProc(ref Message m)
{
const int WM_NCHITTEST = 0x0084;
const int HTTRANSPARENT = (-1);
if (m.Msg == WM_NCHITTEST)
{
m.Result = (IntPtr)HTTRANSPARENT;
}
else
{
base.WndProc(ref m);
}
}
The only things you have to take care after that is this form's Visible, Location and Size properties.
bool change = false;
private void timer1_Tick(object sender, EventArgs e)
{
try
{
if (change)
{
InvalidateRect(IntPtr.Zero, IntPtr.Zero, true);
change = false;
}
else
{
PaintRectangleToScreen();
change = true;
}
}
catch (System.Exception caught)
{
MessageBox.Show(caught.Message);
}
}
I have datagridviews on windows form, i am adding records to datagridview using small add dialogs, i want them to animate in, when the user presses the button on which they are loaded. I am using
[DllImport("user32")]
static extern bool AnimateWindow(IntPtr hwnd, int time, int flags);
Source: http://www.c-sharpcorner.com/UploadFile/kirtan007/761/
The Dialogs are animating in but at the top left of the screen. I am using belowcode on the Load event of the add dialog:
//Set the Location negative values are being returned when my dialog appears
this.Location = new Point(LocationMainX + WidthOfMain, locationMainy + 10);
//Animate form
AnimateWindow(this.Handle, 750, AW_SLIDE | AW_HOR_POSITIVE);
In the Parent form i am passing its location to child add form
AddForm form = new AddForm (this.DesktopLocation)
form.ShowDialog(); //I have also noticed doing form.Show(); messes with the position of dialog
My Main Form loads within another form so I am guessing it is returning relative location. But i tried:
AddForm form = new AddForm (this.Parent.DesktopLocation)
form.ShowDialog();
this doesnt return negative values but returns (0,24) which is also incorrect. as dialog is animating about 150 pixels above parent form.
when i set the form relative too this.Parent.Parent.Location then it appears right, so i guess is there any formal way of accessing the root parent of an application rather than doing this.parent.parent.....
Per your edit, you can just use this.ParentForm instead of this.Parent. Check for null, just in case, etc.
Update:
Not really sure where you want this form to show up. Maybe just use some pinvoke:
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
And then to show the form:
RECT fromRECT;
GetWindowRect(new HandleRef(this, button1.Handle), out fromRECT);
form.Location = new Point(fromRECT.Left + (fromRECT.Right - fromRECT.Left), fromRECT.Top);
form.Show();
The form will show up to the right of the button.