Controlling window position with the win32 API
We've been doing a bit of work around controlling the state of the windows of applications launched programmatically.
The problem we were trying to solve is to launch an arbitrary application, move it around the screen and then save its window position on the screen so that next time it's launched it loads in the same position.
There are some win32 APIs designed to do just this, although it took a fair bit of searching and trial and error to work out exactly how to use them.
Since the application we wrote to do this is in C# it was fairly easy to import the win32 APIs, the main method call being GetWindowInfo, which is imported like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
[DllImport("user32.dll")] private static extern bool GetWindowInfo(IntPtr hwnd, ref tagWINDOWINFO pwi); [StructLayout(LayoutKind.Sequential)] public struct tagRECT { /// LONG->int public int left; /// LONG->int public int top; /// LONG->int public int right; /// LONG->int public int bottom; } [StructLayout(LayoutKind.Sequential)] public struct tagWINDOWINFO { /// DWORD->unsigned int public uint cbSize; /// RECT->tagRECT public tagRECT rcWindow; /// RECT->tagRECT public tagRECT rcClient; /// DWORD->unsigned int public uint dwStyle; /// DWORD->unsigned int public uint dwExStyle; /// DWORD->unsigned int public uint dwWindowStatus; /// UINT->unsigned int public uint cxWindowBorders; /// UINT->unsigned int public uint cyWindowBorders; /// ATOM->WORD->unsigned short public ushort atomWindowType; /// WORD->unsigned short public ushort wCreatorVersion; } |
We found out how to do this from here, but for the sake of explaining how it works I'll keep it here too.
The GetWindowInfo's first argument is a window handler. We launched our application using the .NET Process class so we can access this using the MainWindowHandle property. Don't use WindowHandle as this doesn't get the handle to the window itself – I think it gets the handle to the process which launched the window which is not what we want.
Therefore, to get the position of the window on the screen we can use the following code:
1 2 3 |
tagWINDOWINFO info = new tagWINDOWINFO(); info.cbSize = (uint)Marshal.SizeOf(info); GetWindowInfo(process.MainWindowHandle, ref info); |
To put the window back in this position we first need to include the following API calls:
1 2 3 4 5 |
[DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); [DllImport("user32.dll")] private static extern bool UpdateWindow(IntPtr hWnd); |
Then call both of these methods like so:
1 2 3 4 5 |
process.Start();
process.ForceWaitForInputIdle();
MoveWindow(process.MainWindowHandle, left, top, width, height, true);
UpdateWindow(process.MainWindowHandle);
|
UpdateWindow needs to be called otherwise the window will remain in its previous position.
Good one of using Win32API is C#. I have been doing this for sometime. But I normally use AutoIT to abstract my self from the underlying C data structures and the Win32API internals…
Sai
12 Aug 08 at 5:28 am