0
votes

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()
}
3
You need to show the code that creates the window in the DLL. - Eric Brown
Done, although the window isn't initialized in any fancy way :P - Nicholas Miller

3 Answers

2
votes

Can't be done. Parent windows control child window visibility.

Your best alternative is to make the DLL window a top-level window (but owned by the AutoCAD window).

Note that the DLL window will still be part of the AutoCAD thread.

2
votes

What you want can be achieved, despite what others may think. You just need to think about the problem in a different way. Don't think about parent and child Windows... instead, think about a splash screen Window.

Typically, splash screens appear before the main application Window, but does that make them the parent? No, it doesn't. Normally, they'd be closed after the main Window has opened, but there is no reason why you couldn't hide it instead of closing it.

To find out how to do this in WPF, please refer to my answer from the How to open a child Window like a splash screen before MainWindow in WPF? question, here on Stack Overflow. Extending that answer a little bit, I should point out that you won't need to use a Timer. Instead of the code from the linked page, you could do something like this:

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

Haha! I found it!

So, I ended up calling the SetWindowPos function in the Windows API and supplied the handle for AutoCAD window. I did this inside my main application:

[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...
}

Basically I'm telling the AutoCAD window to hide by modifying the HWND directly. I also set the dimensions to width=0 and height=0 which causes the window to take up the minimum size possible. Unfortunately, the window will flicker once, but for my purposes, that is negligible. If anyone can find a way to remove the flicker, that would be great! :)


EDIT:SetWindowPos

To change that behavior, it is necessary to obtain the window information. For my program, I used GetWindowRect obtain the original settings. Before closing my program, I restored those settings using SetWindowPos. See the code below for details:

First, import necessary WINAPI functions and structs:

[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;
    }

Obtain original settings before modifying window:

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

Modify the window to hide (and resize):

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

Restore original settings before quitting:

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