我正在尝试使用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
总是在某个奇怪的位置结束。
我做错了什么?
答案 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)
尝试一些方法来诊断问题:
答案 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);
}