Lennart
Lennart

Reputation: 10333

MoveWindow returns "Invalid Window Handle"

I'm trying to replicate the Aero Snap functionality for an explorer window I'm starting via Process.Start(). I use MoveWindow for that and while the explorer starts, I'm unable to get the resizing to work with any application. The function itself returns false, and Marshal.GetLastWin32Error() returns 1400 (Invalid Window Handle).

MoveWindow declaration:

[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint);

Usage:

Process explorer = new Process
{
 StartInfo =
   {
    FileName = "explorer.exe",
    Arguments = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
    UseShellExecute = false
   }
 };

 explorer.Start();

 // returns false               
 var return = NativeDeclarations.MoveWindow(
         explorer.Handle,
         SystemParameters.WorkArea.Left.ToInt32(),
         SystemParameters.WorkArea.Top.ToInt32(),
         (SystemParameters.WorkArea.Width/2).ToInt32(),
         SystemParameters.WorkArea.Height.ToInt32(),
         true);

 // returns 1400
 var err = Marshal.GetLastWin32Error();

I already tried casting the x/y/width/height parameters to UInt32 because I read on pinvoke.net there may be errors with computed values (like the division I do), but that didn't help either. The explorer.Handle seems to be valid, while explorer.MainWindowHandle is always 0. Is there anything wrong with my code? I also tried SetWindowPos, but that has the same issue (Invalid Window handle).

Another way I tried was with SHDocVw:

string filename;
foreach (SHDocVw.InternetExplorer window in new SHDocVw.ShellWindows())
{
 filename = Path.GetFileNameWithoutExtension(window.FullName).ToLower();
 if (filename.ToLowerInvariant() == "explorer")
 {
   window.Left = SystemParameters.WorkArea.Left.ToInt32();
   window.Top = SystemParameters.WorkArea.Top.ToInt32();
   window.Width = (SystemParameters.WorkArea.Width / 2).ToInt32();
   window.Height = SystemParameters.WorkArea.Height.ToInt32();
 }
}

While this seems not to cause errors, the values for Left/Top/Width/Height simply stay on the old values. I'm on Windows 8.1 x64 and .Net 4.0 if that's relevant.

Upvotes: 0

Views: 1908

Answers (1)

David Heffernan
David Heffernan

Reputation: 612884

For a start, you are treating Process.Handle as though it were a window handle. It is not. It is a process handle. In any case, I don't think you will get very far with this approach. There's no guarantee that the process you start will own the new window.

I think you need to use SetWindowsHookEx hook with WH_SHELL or RegisterShellHookWindow. Either of these This will give you notification of when the top-level shell window is created, and what its handle is. At that point you can move the window around because you actually have its handle.

As an aside, let me comment that you should only ever check the last error if the documentation tells you to. And for MoveWindow that is when MoveWindow returns false. Please don't ignore the return values of Win32 API functions.

Upvotes: 2

Related Questions