3

我正在尝试childForm通过 PInvoke 使用 SetParent API 设置为主 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总是在某个奇怪的位置结束。

我做错了什么?

4

5 回答 5

8

虽然这里的所有答案都暗示了完全合乎逻辑的方法,但它们都不适合我。然后我尝试了 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);
于 2010-11-10T00:04:16.013 回答
6

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

//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);
于 2010-11-08T14:29:33.053 回答
1

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

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

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

于 2010-11-08T13:54:37.433 回答
0

假设您知道如何获取要设置 z 顺序的窗口的 hwnd,您可以使用此 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);
     }
于 2010-11-08T16:21:12.077 回答
0

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

  • 设置 Left 和 Top 后下断点,Left 和 Top 读为零吗?
  • 最后调用 SetParent。
  • 创建一个再次设置 Left 和 Top 的方法,然后 BeginInvoke 该方法。
  • 确保您的子窗口确实是孩子。为此,请调用 ShowDialog,并尝试单击父窗口。确保窗口阻止焦点到父窗口。
于 2010-11-08T13:35:01.187 回答