问题定位窗口使用SetParent()时

我想通过PInvoke使用SetParent API将childForm设置为主Excel窗口的子项:

 Form childForm = new MyForm(); IntPtr excelHandle = (IntPtr) excelApplication.Hwnd; SetParent(childForm.Handle, excelHandle); childForm.StartPosition = FormStartPosition.Manual; childForm.Left = 0; childForm.Top = 0; 

正如你上面所看到的,我的意图也是把孩子放在Excel窗口的左上angular。 但是,由于某种原因, childForm总是会在某个奇怪的位置结束。

我做错了什么?

虽然这里的所有答案都提出了完全合乎逻辑的方法,但是没有一个对我有效 然后我尝试MoveWindow。 出于某种原因,我不明白,它做了这个工作。

代码如下:

 [DllImport("user32.dll", SetLastError = true)] internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); ... Form childForm = new MyForm(); IntPtr excelHandle = (IntPtr) excelApplication.Hwnd; SetParent(childForm.Handle, excelHandle); MoveWindow(childForm.Handle, 0, 0, childForm.Width, childForm.Height, true); 

在当前桌面的子窗体上使用SetParent时(换句话说,在没有父窗体的窗体上),必须设置WS_CHILD样式并删除WS_POPUP样式。 (请参阅MSDN条目的“备注”部分。)Windows要求所有拥有的窗口都设置了WS_CHILD样式。 这也可能导致左侧属性和顶部属性报告/设置错误的值,因为表单不知道谁是爸爸。 你可以通过在SetParent之后调用SetWindowLong来解决这个问题,但在尝试设置位置之前:

 //Remove WS_POPUP style and add WS_CHILD style const UInt32 WS_POPUP = 0x80000000; const UInt32 WS_CHILD = 0x40000000; int style = GetWindowLong(this.Handle, GWL_STYLE); style = (style & ~(WS_POPUP)) | WS_CHILD; SetWindowLong(this.Handle, GWL_STYLE, style); 

这取决于你的ShowDialog电话我相信。 如果您没有父paremeter调用ShowDialog,父级被重置。

您可以创build一个实现IWin32Window的包装类,并将HWND返回给excel。 然后,您可以将其传递给childForm的ShowDialog调用。

您还可以使用GetWindowPos查询Excel应用程序的位置,然后相应地设置childForm。

尝试几件事来诊断问题:

  • 设置Left和Top之后放置一个断点,执行Left和Top读取零点?
  • 最后调用SetParent。
  • 做一个方法,再次设置Left和Top,然后BeginInvoke方法。
  • 确保你的孩子窗口真的是孩子。 要做到这一点,调用ShowDialog,并尝试点击父窗口。 确保窗口防止焦点到父窗口。

假设你知道如何获得你想要设置z顺序的窗口的大小,你可以使用这个pInvoke:

  public stati class WindowsApi { [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); } public class WindowZOrderPositioner { public void SetZOrder(IntPtr targetHwnd, IntPtr insertAfter) { IntPtr nextHwnd = IntPtr.Zero; WindowsAPI.SetWindowPos(targetHwnd, insertAfter, 0, 0, 0, 0, SetWindowPosFlags.NoMove | SetWindowPosFlags.NoSize | SetWindowPosFlags.NoActivate); }