Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Moving Aplications to a new screen in C# 1

Status
Not open for further replies.
Jul 13, 2004
427
0
0
US
Hey all,

I am trying to write an application that will list all graphical applications and move them to a different monitor on a timed interval. I have no issues getting the list of processes that i need or the timing piece, but i'm having problem figuring out how to capture which screen an application is currently running on and how to move it to a new screen.

The reason for this for those that are curious is for a multi-plasma display that shows our network status. We want to avoid burn-in and i don't want to have people have to walk up and manually move the apps around on the screens. Anyhow, any help would be appreciated, and please bear in mind that i'm not an expert programmer!

Thanks in advance!!!

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
You are going to need to grab the handle of the window you want to move and use the move window unmanaged code of the user32 api.

Here is the move window code import from the user32 api
Code:
[DllImport("user32.dll")]
		public extern static bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

Here is the find window code import, use Spy++ to find out the classname and windowname of the window you want to grab
Code:
[DllImport("user32.dll")]
		public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

I'm not sure, but you may be able to grab the handle right from the process information. I was grabbing a window that was generated from java, so I had to grab the handle by the window name.
 
I forgot to say that the move window will move it the top right to the pixel location you pass in for x and y (x,y). You just need to tell it a pixel coordinate on the second screen
 
ok, bearing in mind once again that i don't code for a living, can you help me w/ the missing piece here? I have the following code to move all application to screen 1, but i would like this to use your FindWindow to get the current screen and increment that. here's what i have (minus the DllImports)

Process[] pros = Process.GetProcesses(".");
foreach (Process p in pros)
{
if (p.MainWindowTitle != "")
{
listBoxProcesses.Items.Add("title: " + p.MainWindowTitle);
listBoxProcesses.Items.Add("process: " + p.Id);
count++;
labelCount.Text = "Total Windows: " + count;
int i = 0;
while (i == 0)
{
System.Threading.Thread.Sleep(100);
p.Refresh();
i = p.MainWindowHandle.ToInt32();
}
IntPtr h1 = p.MainWindowHandle;
Point screenlocation = Screen.AllScreens[1].Bounds.Location;
SetWindowPos(h1, -1, screenlocation.X, screenlocation.Y, Screen.AllScreens[1].Bounds.Width, Screen.AllScreens[1].Bounds.Height, SWP_NOZORDER | SWP_SHOWWINDOW);
int lNewLong = GetWindowLong(h1, GWL_STYLE);
SetWindowLong(h1, GWL_STYLE, lNewLong & ~WS_THICKFRAME);
}

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
FindWindow just get the handle of the window, not the location. You would have to use GetWindowInfo to get the position. After you get the position, you can use the coordinates to figure out which screen the window is on and move it to the other.

Code:
		[DllImport("user32.dll")]
		public static extern bool GetWindowInfo(IntPtr hwnd, ref WINDOWINFO pwi);

//you also need to define this struct
public struct WINDOWINFO
		{
			public uint cbSize;
			public RECT rcWindow; //holds the coords of the window
			public RECT rcClient;
			public uint dwStyle;
			public uint dwExStyle;
			public uint dwWindowStatus;
			public uint cxWindowBorders;
			public uint cyWindowBorders;
			public ushort atomWindowType;
			public ushort wCreatorVersion;
		}
//this holds the coordinates
public struct RECT 
		{
			public int Left;	// Specifies the x-coordinate of the upper-left corner of the rectangle. 
			public int Top;		// Specifies the y-coordinate of the upper-left corner of the rectangle. 
			public int Right;	// Specifies the x-coordinate of the lower-right corner of the rectangle.
			public int Bottom;	// Specifies the y-coordinate of the lower-right corner of the rectangle. 

		}
GetWindowInfo(): WINDOWINFO structure:
RECT:

I haven't had to do something that extensive (switch monitors) I had to move a window and simulate a mouse click at one time, but the information is all here
 
I'll try this out and see what i can do. Thanks for all the help thus far!

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
I can move windows around within a display that i specify, but i'm not quite understanding how to pull the value of the current display.

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
Whats your resolution of a single display? I assume the width of the whole display (side by side) would be the single display with times 2 (ie: 2 1280 X 1024 side by side would equal a single 1280 X 2048). So when you get the position of the window, if the X-coor is less than 1024, it would be on your left screen, if its greater than 1024, it would be on your right screen, assuming as the 2 displays work the way i assume. IF they work that way, to switch the apps position, you would have a function that changes the x coor like this
Code:
if (x < 1024)
    x += 1024
else
    x -= 1024

Again, im not sure how the dual monitor config works with pixel locations, so this may bea all for nothing...:p
 
Yeah, this is turning out to be way more complex than i anticipated :)

There are a total of 4 52" plasma displays attached to this computer - i'll have to check the resolution, but i'm not holding my breath on that as they plan on adding more. I'd hate to hard-code this in and have to change it later.

Anyhow, i have this partially working with the following, but it is not consistent:

private void btnGetProcesses_Click(object sender, EventArgs e)
{
listBoxProcesses.Items.Clear();
Process[] pros = Process.GetProcesses(".");

foreach (Process p in pros)
{
if (p.MainWindowTitle != "")
{
if (p.MainWindowTitle != "Move Your Apps")
{
listBoxProcesses.Items.Add("title: " + p.MainWindowTitle);
listBoxProcesses.Items.Add("process: " + p.Id);
count++;
labelCount.Text = "Total Windows: " + count;
int i = 0;
while (i == 0)
{
System.Threading.Thread.Sleep(100);
p.Refresh();
i = p.MainWindowHandle.ToInt32();
}
//This section will move all applications to screen 1.

IntPtr h1 = p.MainWindowHandle;
Point screenlocation = Screen.AllScreens[mon].Bounds.Location;
SetWindowPos(h1, -1, screenlocation.X, screenlocation.Y, Screen.AllScreens[mon].Bounds.Width, Screen.AllScreens[mon].Bounds.Height, SWP_NOZORDER | SWP_SHOWWINDOW);
int lNewLong = GetWindowLong(h1, GWL_STYLE);
SetWindowLong(h1, GWL_STYLE, lNewLong & ~WS_THICKFRAME);

int monTotal = Screen.AllScreens.Length;
if (mon != monTotal - 1)
{
mon++;
}
else
{
mon = 0;
}
}
}
}

Any more help would be appreciated.

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
so, to follow up... here's what i was hoping to do, but my remedial coding skills are stopping me :)

Find the current display that an application is running on and increment by one, then move it using that variable that just got incremented.

Well, it makes perfect sense in my head how it should work!

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
i have this partially working "
What is it currently doing? aka whats working and whats not?
 
Code:
SetWindowPos(h1, -1, screenlocation.X, screenlocation.Y, Screen.AllScreens[mon].Bounds.Width /* this sets the width of the program you are using*/, Screen.AllScreens[mon].Bounds.Height /* this sets the height of the program you are using*/, SWP_NOZORDER | SWP_SHOWWINDOW);


BOOL SetWindowPos(      
    HWND hWnd,
    HWND hWndInsertAfter,
    int X,
    int Y,
    int cx,
    int cy,
    UINT uFlags
);

    X
        [in] Specifies the new position of the left side of the window, in client coordinates. 
    Y
        [in] Specifies the new position of the top of the window, in client coordinates. 
    cx
        [in] Specifies the new width of the window, in pixels. 
    cy
        [in] Specifies the new height of the window, in pixels.

Is this a full Screen app on the screen its on?
 
I'm closing in on success now, though my code is getting ugly :)

It's all working fine with 3 monitors (what i have on my development machine), but when i toss it up to the 4 plasma display, it seems to skip over some of the monitors.

What i would really love to do is grab the current position of each app and move them to the next monitor placing them in the same spot that they were on... some of our monitors host 2 applications and the way i'm currently moving them maximizes the app to the display.

Here's my MoveWindow Function:

private void MoveWindow(Process p)
{
IntPtr h1 = p.MainWindowHandle;
Screen scrn = Screen.FromHandle(h1);
WINDOWINFO winfo = new WINDOWINFO();
WINDOWPLACEMENT wp = new WINDOWPLACEMENT();
GetWindowPlacement(h1, ref wp);
long lWindowStyle = GetWindowLong(h1, GWL_STYLE);

GetWindowInfo(h1, ref winfo);

if (wp.showCmd == 3)
{
ShowWindow(h1, 1);
}

int scrnX = scrn.Bounds.Location.X;
int scrnY = scrn.Bounds.Location.Y;

listBoxProcesses.Items.Add("title: " + p.MainWindowTitle);
listBoxProcesses.Items.Add("X: " + scrnX);
listBoxProcesses.Items.Add("Y: " + scrnY);
if (scrnX >= upperX)
{
scrnX = lowerX;
}
else
{
scrnX = scrnX + scrn.Bounds.Width;
}
int lNewLong = GetWindowLong(h1, GWL_STYLE);
SetWindowLong(h1, GWL_STYLE, lNewLong & ~WS_THICKFRAME);
SetWindowPos(h1, -1, scrnX, scrnY, scrn.Bounds.Width, scrn.Bounds.Height, SWP_NOZORDER | SWP_SHOWWINDOW);
}

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
You can get the dimension of the window form winfo.cxWindowsBorders for x and winfo.cyWindowsBorders

You need a function to change the X and Y of the location, i would do it like this. After you get the current location of the window in a Point and the screen the window is on have a function like the following

Code:
private int NextScreen(int curr, int max)
{
    if(curr < max)
        curr++;
    else
        curr = 0;
    return curr;
}
private Point MoveToNextScreen(Point OrigLocation, int OrigScreen, int NumOfScreens)


     OrigLocation.X -= Screen.AllScreens[OrigScreen].Bounds.Location.X;
     OrigLocation.X += Screen.AllScreens[NextScreen( OrigScreen, NumOfScreens)].Bounds.Location.X;
     OrigLocation.Y -= Screen.AllScreens[OrigScreen].Bounds.Location.Y;
     OrigLocation.Y += Screen.AllScreens[NextScreen( OrigScreen, NumOfScreens)].Bounds.Location.Y;

    return OrigLocation;
}

Then you have a function like this to do the actual movement
Code:
private void MoveWindow(Process p)
        {
            Point WindowSize = new Point();
            Point WindowLocation = new Point();
            int max = 4;
            int scrnNum;
            IntPtr h1 = p.MainWindowHandle;
            Screen scrn = Screen.FromHandle(h1);
            WINDOWINFO winfo = new WINDOWINFO();

GetWindowInfo(h1, ref winfo);
WindowSize.X = winfo.cxWindowsBorders;
WindowSize.Y = winfo.cyWindowsBorders;
WindowLocation.X = winfo.rcWindow.Left;
WindowLocation.Y = winfo.rcWindow.Right;
scrnNum = WindowLocation.X % scrn.Bounds.Width;

WindowLocation = MoveToNextScreen(WindowLocation, scrnNum, max);


 SetWindowPos(h1, -1, WindowLocation.X , WindowLocation.Y, WindowSize.X, WindowSize.Y, SWP_NOZORDER | SWP_SHOWWINDOW);
Warning: Typed not test. Theory is there, syntax may no
 
actually, i have to take a closer look here. All works well!... with main processes. The problem i'm having is multiple apps running off the same PID. I guess i'll need to enumerate through the child processes, MDI windows, etc.

I'll keep you posted.

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
The functions I wrote up should keep the size and location of the window intact, just move it from display to display
 
I'll give it a try. BTW, i found code to fix my othe problem - i'll post it all after i test this out w/ your code.

I can't thank you enough for all your help! I wish i could give you more stars :)

~Intruder~
CEH, CISSP, MCSA/MCSE 2000/2003

 
If you have problems with apps under the same pid, the FindWindow function will allow you to get the handle from the name of the Window itself. You can find the information to pass into FindWindow by using Spy++.

For example, say I had 5 FireFox windows under the same pid (may not be the case, but theortically for this examlple)
Each FireFow window is at a different website, for the window at this thread I would use
Code:
 FindWindow("MozillaUIWindowClass", "C# (C sharp): Microsoft - Moving Aplications to a new screen in C# - Mozilla Firefox");
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top