【问题标题】:MoveWindow returns "Invalid Window Handle"MoveWindow 返回“无效的窗口句柄”
【发布时间】:2014-08-02 18:19:53
【问题描述】:

我正在尝试为通过Process.Start() 启动的资源管理器窗口复制 Aero Snap 功能。我为此使用MoveWindow,当资源管理器启动时,我无法调整大小以与 any 应用程序一起使用。函数本身返回 false,Marshal.GetLastWin32Error() 返回 1400(无效窗口句柄)。

MoveWindow 声明:

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

用法:

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

我已经尝试将 x/y/width/height 参数转换为UInt32,因为我在 pinvoke.net 上看到计算值可能存在错误(就像我做的除法一样),但这也没有帮助。 explorer.Handle 似乎有效,而 explorer.MainWindowHandle 始终为 0。我的代码有什么问题吗?我也试过SetWindowPos,但也有同样的问题(无效的窗口句柄)。

我尝试的另一种方法是使用 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();
 }
}

虽然这似乎不会导致错误,但 Left/Top/Width/Height 的值只是保持旧值不变。如果相关,我使用的是 Windows 8.1 x64 和 .Net 4.0。

【问题讨论】:

  • 你走在正确的轨道上。您不能使用explorer.Handle,因为它为您提供了进程句柄,而不是窗口句柄。 explorer.MainWindowHandle 在您尝试使用 calc.exe 或 notepad.exe 时有效。不过explorer有点特殊,恐怕得求助enumerating all windows了。
  • 可能无关紧要,但是当我运行代码时,在任务管理器中看到的 Explorer 的进程句柄与我在 Process.Handle 上运行 GetProcessId 时得到的进程句柄不匹配。有时句柄是 32,任务管理器中会出现一个名为“COM Surrogate”的 pid 32。有时,句柄与任务管理器中的句柄很接近,但略有不同。在explorer.Start 的大约一秒钟内,explorer.HasExited 会返回 true,即使资源管理器窗口仍处于打开状态。 explorer 是否会产生一个临时的中间进程来启动实际的 Explorer 进程?
  • @pmcoltrane 确实如此。资源管理器中的选项之一是在同一个进程中运行所有资源管理器窗口。

标签: c# pinvoke


【解决方案1】:

首先,您将Process.Handle 视为窗口句柄。它不是。它是一个进程句柄。无论如何,我认为你不会用这种方法走得太远。无法保证您启动的进程将拥有新窗口。

我认为您需要将SetWindowsHookExWH_SHELLRegisterShellHookWindow 结合使用。这将通知您何时创建顶级 shell 窗口,以及它的句柄是什么。此时您可以移动窗口,因为您实际上有它的句柄。

顺便说一句,让我评论一下,如果文档告诉您,您应该只检查最后一个错误。而对于MoveWindow,那是MoveWindow 返回假的时候。请不要忽略 Win32 API 函数的返回值。

【讨论】:

  • Please don't ignore the return values of Win32 API functions+1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 2017-06-19
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
  • 2013-09-07
相关资源
最近更新 更多