0

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.

Lennart
  • 9,657
  • 16
  • 68
  • 84
  • You were on the right track. You cannot use `explorer.Handle` because it gives you a process handle, not a window handle. `explorer.MainWindowHandle` works when you try it with calc.exe or notepad.exe. But explorer is somewhat special, I'm afraid you'll have to resort to [enumerating all windows](http://stackoverflow.com/a/79205/1029287). – void Jun 12 '14 at 13:16
  • Possibly irrelevant, but when I run the code, the process handle for Explorer seen in Task Manager doesn't match the process handle I get when I run `GetProcessId` on Process.Handle. Sometimes the handle is 32, and a pid 32 named "COM Surrogate" shows up in Task Manager. Sometimes the handle is close to, but slightly different from, what is seen in Task Manager. Within about a second of `explorer.Start`, `explorer.HasExited` returns true even though the Explorer window is still open. Could explorer be spawning a temporary, intermediate process to launch the actual Explorer process? – pmcoltrane Jun 12 '14 at 13:19
  • @pmcoltrane Indeed so. One of the options in explorer is to run all explorer windows out of the same process. – David Heffernan Jun 12 '14 at 16:53

1 Answers1

2

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490