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

时间:2010-11-08 12:58:14

标签: c# winforms excel office-automation setparent

我正在尝试使用SetParent API通过PInvoke将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窗口的左上角。但是,出于某种原因,childForm总是在某个奇怪的位置结束。

我做错了什么?

5 个答案:

答案 0 :(得分:7)

虽然这里的所有答案都提出了完美的逻辑方法,但它们都不适用于我。然后我尝试了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);

答案 1 :(得分:5)

在当前桌面的子窗体上使用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);

答案 2 :(得分:1)

这取决于我相信你的ShowDialog电话。如果在没有父级参数的情况下调用ShowDialog,则会重置父级。

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

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

答案 3 :(得分:0)

尝试一些方法来诊断问题:

  • 设置Left后设置断点 和Top,do Left和Top读零?
  • 最后调用SetParent。
  • 创建一个设置Left和Top的方法 再次,并且BeginInvoke方法。
  • 确保您的孩子窗口真的如此 孩子要做这个电话 ShowDialog,并尝试单击 父窗口。确保窗户 防止焦点到父窗口。

答案 4 :(得分:0)

假设您知道如何获取要设置z顺序的窗口的hwnds,可以使用此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);
     }