0

I'm working on an application that should do the following on start-up:

  1. Connect to an external application using COM (AutoCAD).
  2. Send message to the application to run some DLL code (opens a window).
  3. Hide AutoCAD's window, but keep the DLL's window visible.

I've successfully completed the first 2 steps, but the third is giving me some issues.

I do not know if it is possible to make a child window visible while it's parent is not visible. Every time that I make the child visible or make it the top most window, AutoCAD becomes visible as well.

My objective is to run my DLL code, but keep AutoCAD running in the background, completely invisible to my users. The DLL must be loaded, through AutoCAD, because it allows me to work with AutoCAD's .NET interface as opposed to COM.

In any case, I'm curious if what I'm trying to do is possible, perhaps through some Windows API calls or perhaps something in .NET.

PS: I'm unsure if this window relationship is really a parent-child one. I'm assuming it is though because my window belongs to the AutoCAD application instance due to the DLL loading.

Any help is greatly appreciated. Thanks! :)

EDIT: DLL Code to create a window.

//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();
}

Main Application Code

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()
}
4

3 回答 3

2

不管别人怎么想,你想要的都能实现。您只需要以不同的方式考虑问题。不要想着父母和孩子Window……相反,想想闪屏Window

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

要了解如何在 WPF 中执行此操作,请参阅我在如何在 WPF 中的 MainWindow 之前打开子窗口(如启动屏幕)?问题,在 Stack Overflow 上。稍微扩展一下这个答案,我应该指出你不需要使用Timer. 而不是链接页面中的代码,您可以执行以下操作:

private void OpenMainWindow()
{
    autoCadWindow.Visiblity = Visibility.Collapsed;
    MainWindow mainWindow = new MainWindow();
    mainWindow.Show();
}
于 2014-07-10T16:24:44.897 回答
2

做不到。父窗口控制子窗口的可见性。

您最好的选择是使 DLL 窗口成为顶级窗口(但归 AutoCAD 窗口所有)。

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

于 2014-07-10T16:08:29.880 回答
2

哈哈!我找到了!

因此,我最终调用了SetWindowPosWindows API 中的函数并提供了 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);
于 2014-07-10T18:33:00.560 回答