Pinvoke MoveWindow in C# - c#

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

Related

Does windows api messages still exists?

Long long time ago (in a galaxy far away), I used to program some fun tools to assist me (as having a disability) or just support my lazyness :)
Tools that do things like "wait 30 seconds and then press play on my media player" or "save a list of all song names from winamp that streaming a live m3u based radio". it was almost 20 years ago, using C# and window messages api (not wanting to relay on mouse clicks and strict window size&position). I would've found the window's handle and the "control" handle and interact with it.
The question is: Can I still do it today in the age of Windows 10?
If so, how?
I would appreciate a starting point.
Let's say I want to press play on my bs.player after x seconds, or close an error message that comes up every 10 seconds (well, its not cause' my windows is healthy ..but theoretically).
Thank you :)
Yes you can, if you talk about Windows API.
You need to declare the external WinAPI's signatures as static extern using the DllImport attribute.
For example to know if the screen saver is active or if an app runs in full screen:
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_SCREENSAVE = 0xF140;
private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
[DllImport("user32.dll", SetLastError = true)]
static extern bool SystemParametersInfo(int action, int param, ref int retval, int updini);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
static private extern bool GetWindowRect(HandleRef hWnd, [In, Out] ref RECT rect);
[DllImport("user32.dll")]
static private extern IntPtr GetForegroundWindow();
static private bool IsForegroundFullScreen()
{
return IsForegroundFullScreen(null);
}
static private bool IsForegroundFullScreen(Screen screen)
{
if ( screen == null ) screen = Screen.PrimaryScreen;
RECT rect = new RECT();
GetWindowRect(new HandleRef(null, GetForegroundWindow()), ref rect);
return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top)
.Contains(screen.Bounds);
}
private bool IsScreensaverActive()
{
int active = 1;
SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref active, 0);
return active != 0;
}
private bool IsForegroundFullScreenOrScreensaver()
{
return IsForegroundFullScreen() || IsScreensaverActive();
}
Calling Win32 DLLs in C#
c# dllimport with pointers

How to remove scroll bar from fullscreen Console in C#?

Long story short: I just picked up C# about a week ago. Most of my programming knowledge comes from Java. I want to try my hand at making a text adventure game (yes I know I can used Unity, but I want to make it from scratch) and part of the setup is getting a full screen Console window with no distractions.
I've scavenged about on StackOverflow and so far I've put this together:
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int handle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleDisplayMode(IntPtr ConsoleOutput, uint Flags, out COORD NewScreenBufferDimensions);
[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
public short X;
public short Y;
public COORD(short X, short Y)
{
this.X = X;
this.Y = Y;
}
}
Alongside this bit in the Main method:
IntPtr hConsole = GetStdHandle(-11);
SetConsoleDisplayMode(hConsole, 1, out COORD b1);
Console.ReadLine();
So I've managed to get in full screen successfully, but problem is a scroll bar is still there.
I've done my best to understand exactly how this works and how the scroll bar would be removed. My current understanding is that the Console's screen buffer needs to be changed to match the size of the screen so that the scroll bar can disappear.
From the code I managed to put together, it seems that the buffer is already being played with in order to go full screen. Looks like the 'SetConsoleDisplayMode' method does that.
So my question is, how do I add in the removal of the scroll bar to this code? My mind is saying it has something to do with the 'COORD' struct but honestly I'm totally out of my element here with a new language and new concepts (like structs), any help would be appreciated!
this class is defineatly work for you it full screen automatically the console and remove the scroll bars the clear and black console screen is appers only and you do what ever you want
##
public class SetLayout
{
// Control the console whole setting
public void Set()
{
Console.SetBufferSize(Console.LargestWindowWidth, Console.LargestWindowHeight); // Remove the console both scroll bars
IntPtr hConsole = FullScreen.GetStdHandle(-11); // Get console handle
FullScreen.COORD xy = new FullScreen.COORD(100, 100);
FullScreen.SetConsoleDisplayMode(hConsole, 1, out xy); // Set the console to fullscreen
AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); // Set to not show the "Press any key to continue"
Console.CursorVisible = false; // Remove the cursor from the console
}
// Handler Method to remove the "Press any key to continue........."
void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
FullScreen.ShowWindow(FullScreen.ThisConsole,0);
}
}
// Class is setting the console window full screen
internal static class FullScreen
{
[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
public short X;
public short Y;
public COORD(short x, short y)
{
this.X = x;
this.Y = y;
}
}
[DllImport("kernel32.dll")]
public static extern IntPtr GetStdHandle(int handle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetConsoleDisplayMode(IntPtr ConsoleOutput, uint Flags, out COORD NewScreenBufferDimensions);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GetConsoleWindow();
public static IntPtr ThisConsole = GetConsoleWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
you just have to write in the main method :
SetLayout s = new SetLayout();
s.Set();
The scrollbar will disapear when your buffer height is equal to your screen height (in Lines). You can test that with a noraml cmd.exe window.
When you make your console fullscreen, Windows will make your Buffer bigger if it was too small and return the new size in the last argument of
SetConsoleDisplayMode. You probably need that size as you progress with your project. So if you make the buffer really small Windows fill "fix" it for you.
In order to change your buffer size you will need to call SetConsoleScreenBufferSize:
BOOL WINAPI SetConsoleScreenBufferSize(
_In_ HANDLE hConsoleOutput,
_In_ COORD dwSize
);
That will look like this (untested):
[DllImport("kernel32.dll")]
private static extern bool SetConsoleScreenBufferSize(int handle, COORD newSize);

Moving window with SetWindowPos

I'm trying to move the window of the program I am building inside of unity. I'm getting it's handle via interating through all processes in Process.GetProcesses(). Then, I'm calling SetWindowPos, but nothing happens. Here's my code.
internal static void CheckHandle()
{
Process[] ps = Process.GetProcesses();
foreach (Process p in ps)
{
try
{
if (string.Equals(p.ProcessName, "TestBuild0001"))
{
_correctHandle = true;
_handle = p.Handle;
}
}
catch
{
//no catch, simply exited process
}
}
}
internal static void SetPosition()
{
if (!_correctHandle)
CheckHandle();
if (_correctHandle)
{
NewGUI.SetWarning("Window set!",5,50,900,300,50);
SetWindowPos(_handle, 0, 0, 0, 0, 0, 0x0001);
}
}
NewGUI.SetWarning just displays a label and shows up properly. _correctHandle is a simple bool and SetWindowPos is put in as
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern bool SetWindowPos(IntPtr hwnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
I've tried moving quite a few things to get it to work but am out of ideas. Trying to get foregroundwindow brings back a entirely incorrect handle, findwindow for name brings back 0, and quite a few other things don't seem to work. Anyone know what my error could be/
p.Handle is the process' handle, not the window handle. You want p.MainWindowHandle.
It's also possible that the process you're trying to attach to has a hidden message-only main window. To figure that out, you'd need to use a tool like Spy++ to look at the structure of the windows.
If all else fails Spy++ will also give you a window class, which you can use with FindWindowEx to locate the window. (I do the same trick with Sticky Notes windows in this answer)
The GetActiveWindow idea from this thread : Any way to bring Unity3d to the foreground? got me the right window ID, but changing resolutions still caused me issues since unity was setting the window location to halfway between both monitors after my SetWindowPos is called. Here's my solution for other people needing something like this.
void FixedUpdate()
{
if (Handle == IntPtr.Zero)
{
Handle = GetActiveWindow();
uint uP;
GetWindowThreadProcessId(Handle, out uP);
System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById((int)uP);
if (string.Equals(p.ProcessName, "Unity"))
AllowReset = false;
else if (string.Equals(p.ProcessName, "TestBuild00001"))
AllowReset = true;
else
Handle = IntPtr.Zero;
}
}
void Update()
{
if (ScreenSet && AllowReset && GuiValidReset)
{
GuiValidReset = false;
ScreenSet = false;
SetPosition();
}
}
void OnGUI()
{
if (ScreenSet && AllowReset && !GuiValidReset)
GuiValidReset = true;
}
internal static void SetPosition()
{
SetWindowPos(Handle, 0, 0, 0, 0, 0, 0x0001);
}
Dll imports of
[DllImport("User32.dll")]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
internal static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetWindowPos(IntPtr hwnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
Did update and ongui check to assure that a full redraw of unity would happen before positioning the window, since calling it at the same time a resolution change caused the window to reset to midscreen. ScreenSet is set to true right after my resolution is set.

Setting position of a Console Window opened in a WinForms App

I found some source code in this thread posted by Rex Logan here on SO :
link text
... there's also some very interesting code posted in this same thread by Foredecker, but it is incomplete and complex : I'm not up enough on the 'Trace facility to know how to fully implement it ...
I am able to use this Console code Rex (kindly) posted successfully in a WinForms application to log various events, and to push messages onto which are useful in debugging; I can clear it from the application code, also.
What I can't seem to do is to reliably set the screen position of the Console Window when I open the Console Window (in the Main Form load event). I get compile blocking System.ArgumentOutOfRangeException errors if I try to set WindowLeft or WindowTop properties like this :
The window position must be set such
that the current window size fits
within the console's buffer, and the
numbers must not be negative.
Parameter name: left Actual value was
#
I am able, however, to set WindowWidth and WindowHeight properties.
I have tried moving the code that activates the Console various locations including :
in the Program.cs file before the MainForm is 'run
before and after the call to 'InitializeComponent() in the MainForm ctor
in the Form Load event
in the Form Shown event
The Console was activated okay in all these places in the code, but with no change in the seemingly random switching around of where in the upper-left quadrant of the screen it appeared.
Where the Console window opens seems to vary at random (the Main Form is always initialized in the same place on the screen).
you can try something like this.
This code set the position of the Console Window in a Console Application.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication10
{
class Program
{
const int SWP_NOSIZE = 0x0001;
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GetConsoleWindow();
private static IntPtr MyConsole = GetConsoleWindow();
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int wFlags);
static void Main(string[] args)
{
int xpos = 300;
int ypos = 300;
SetWindowPos(MyConsole, 0, xpos, ypos, 0, 0, SWP_NOSIZE);
Console.WriteLine("any text");
Console.Read();
}
}
}
This code set the position of the Console Window in a WinForm Application.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication10
{
static class Program
{
const int SWP_NOSIZE = 0x0001;
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AllocConsole();
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int wFlags);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetConsoleWindow();
[STAThread]
static void Main()
{
AllocConsole();
IntPtr MyConsole = GetConsoleWindow();
int xpos = 1024;
int ypos = 0;
SetWindowPos(MyConsole, 0, xpos, ypos, 0, 0, SWP_NOSIZE);
Console.WindowLeft=0;
Console.WriteLine("text in my console");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

find window Height & Width

how to find focused window Height & Width ..
it might be any windows window like notepad,mspaint etc...
i can get the focused window by help of this code
[DllImport("user32")]
public static extern IntPtr GetForegroundWindow();
hi f3lix it's working but it's return the value depends on the location only.. if i change the location it's return some other values
Kunal it's return error msg....like object refrence not set
I think you have to use user32.dll functions via PInvoke. I'm not sure, but I would do it somewhat like this:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out Rectangle lpRect);
Rectangle rect = new Rectangle();
GetWindowRect(GetForegroundWindow(), out rect);
Note: I did not try this code, because I am currently not working on Windows...
EDIT:
Rory pointed out to me (see comments) that we can't use the standard Rectangle here and we need to define our own RECT.
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Don't forget to replace Rectangle with RECT in the first piece of code.
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
public static Size GetControlSize(IntPtr hWnd)
{
RECT pRect;
Size cSize = new Size();
// get coordinates relative to window
GetWindowRect(hWnd, out pRect);
cSize.Width = pRect.Right - pRect.Left;
cSize.Height = pRect.Bottom - pRect.Top;
return cSize;
}
What exactly is your question?
How to get the focused window?
How to get the width and height of a Window?
If question 2, use Window.ActualWidth and Window.ActualHeight
If your window is inside your aplication, having an MDI app, you might use this,
having
public static extern IntPtr GetForegroundWindow();
with you, try this
int wHeight = Control.FromHandle(GetForegroundWindow()).Height;
int wWidth = Control.FromHandle(GetForegroundWindow()).Width;
If you're building an MDI app, you could use:
parentForm.ActiveMDIChild.Size

Categories

Resources