隐藏父窗口,但显示子窗口

时间:2014-07-10 16:01:20

标签: c# wpf winapi dll autocad-plugin

我正在开发一个应用程序,应该在启动时执行以下操作:

  1. 使用COM(AutoCAD)连接到外部应用程序。
  2. 向应用程序发送消息以运行某些DLL代码(打开一个窗口)。
  3. 隐藏AutoCAD的窗口,但保持DLL的窗口可见。
  4. 我已成功完成前两个步骤,但第三个步骤给了我一些问题。

    我不知道是否可以在父窗口不可见的情况下使子窗口可见。每当我让孩子看到或使其成为最顶层的窗口时,AutoCAD也会变得可见。

    我的目标是运行我的DLL代码,但让AutoCAD在后台运行,对我的用户完全不可见。必须通过AutoCAD加载DLL,因为它允许我使用AutoCAD的.NET接口而不是COM。

    无论如何,我很好奇我是否有可能做的事情,可能是通过一些Windows API调用或.NET中的东西。

    PS:我不确定这种窗口关系是否真的是亲子关系。我假设它是因为我的窗口属于AutoCAD应用程序实例,因为DLL加载。

    非常感谢任何帮助。谢谢! :)

    修改 DLL Code创建一个窗口。

    //CommandMethod is an AutoCAD attribute for entering into the DLL.  This code is called
    //when the user attempts the command "AUTOCADCOMMANDNAME" or can be done by simulating
    //the command programmatically.
    [CommandMethod("AUTOCADCOMMANDNAME", CommandFlags.Session)]
    public void CommandEntry()
    {
        MainWindow mainWin = new MainWindow();
        mainWin.ShowDialog();
    }
    

    主要应用程序代码

    public static void Main()
    {   //Use a utility class to create a connection to AutoCAD via COM
        AcadApplication acadApp = ACUtil.GetAcadInstance(out createdNewInstance);
        acadApp.Visible = false;
        //Irrelevant code omitted...
        acadApp.ActiveDocument.SendCommand("AUTOCADCOMMANDNAME");
        acadApp.Quit(); //Exit AutoCAD application
        //Note: doesn't quit until mainWin closes because of ShowDialog()
    }
    

3 个答案:

答案 0 :(得分:2)

无法完成。父窗口控制子窗口可见性。

您最好的选择是将DLL窗口设置为顶级窗口(但由AutoCAD窗口拥有)。

请注意,DLL窗口仍然是AutoCAD线程的一部分。

答案 1 :(得分:2)

你想要可以实现什么,尽管别人可能会想到。您只需要以不同的方式思考问题。不要考虑父母和孩子Window ...而是考虑一下启动画面Window

通常情况下,启动屏幕会在主应用程序Window之前出现,但这会使它们成为父应用程序吗?不,它没有。通常情况下,它们会在主Window打开后关闭,但没有理由不隐藏它而不是关闭它。

要了解如何在WPF中执行此操作,请参阅How to open a child Window like a splash screen before MainWindow in WPF?问题的答案,此处为Stack Overflow。稍微扩展一下这个答案,我应该指出你不需要使用Timer。您可以执行以下操作,而不是链接页面中的代码:

private void OpenMainWindow()
{
    autoCadWindow.Visiblity = Visibility.Collapsed;
    MainWindow mainWindow = new MainWindow();
    mainWindow.Show();
}

答案 2 :(得分:1)

哈哈!我找到了它!

因此,我最终调用了Windows API中的SetWindowPos函数,并提供了AutoCAD窗口的句柄。我在我的主要应用程序中做到了这一点:

[DllImport("User32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int w, int h, uint flags);
public const int SWP_HIDEWINDOW = 0x0080;

public static void Main()
{
    //...Setup AutoCAD...

    //Change window size and hide it before calling to open mainWin inside the DLL.
    SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 0, 0, 0, 0, SWP_HIDEWINDOW);

    //Display mainWin by entering the DLL.
    acadApp.ActiveDocument.SendCommand("AUTOCADCOMMANDNAME");

    //Terminate application as before...
}

基本上我是通过直接修改HWND告诉AutoCAD窗口隐藏的。我还将尺寸设置为width=0height=0,这会导致窗口占用最小尺寸。不幸的是,窗口会闪烁一次,但就我的目的而言,这可以忽略不计。 如果有人能找到消除闪烁的方法,那就太棒了!:)

<小时/> 编辑:使用SetWindowPos时,Windows会记住下次显示应用程序窗口时输入的值。这意味着如果没有正确恢复,则下次用户手动打开AutoCAD时,其坐标为0,0,最小宽度/高度。

要更改该行为,必须获取窗口信息。对于我的程序,我使用GetWindowRect获取原始设置。在关闭我的程序之前,我使用SetWindowPos恢复了这些设置。有关详细信息,请参阅以下代码:

首先,导入必要的WINAPI函数和结构:

[DllImport("User32.dll")]
    static extern bool GetWindowRect(IntPtr hwnd, out RECT rect);

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }

在修改窗口之前获取原始设置:

RECT originalRect;
GetWindowRect(new IntPtr(acadApp.HWND), out originalRect);

修改窗口以隐藏(和调整大小):

SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 0, 0, 0, 0, SWP_HIDEWINDOW);

退出前恢复原始设置:

SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 
    originalRect.Left, 
    originalRect.Top, 
    originalRect.Right - originalRect.Left,
    originalRect.Bottom - originalRect.Top, 0);