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()
}
Nicholas Miller
  • 4,205
  • 2
  • 39
  • 62

3 Answers3

2

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.

Eric Brown
  • 13,774
  • 7
  • 30
  • 71
  • Thanks for the quick reply. Apparently my window is already top-level and not a child. According to the links here: http://forums.codeguru.com/showthread.php?491610-Windows-SDK-What-is-a-top-level-window http://forums.codeguru.com/showthread.php?491604-Windows-SDK-What-is-a-child-window Children are bound to parent's client area, but top-level windows are not. – Nicholas Miller Jul 10 '14 at 16:26
  • @Eric when you show an owned window, it's owner shoiws too. I think. – David Heffernan Jul 10 '14 at 17:46
2

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();
}
Community
  • 1
  • 1
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • The type of window I'm dealing with for AutoCAD is a `System.Windows.Forms.IWin32Window`. Do you suppose it is possible to collapse this type of window instead of a WPF window? – Nicholas Miller Jul 10 '14 at 16:35
  • Take a look at the [How to: Make a Startup Windows Form Invisible](http://msdn.microsoft.com/en-us/library/754w18dd(v=vs.110).aspx) page on MSDN. Also, how about if you just initialise the `AutoCAD Window`, but don't show it? – Sheridan Jul 10 '14 at 19:38
  • Unfortunately, I do not believe I have that kind of control when working with AutoCAD. To instantiate, I'm required to use COM interop which starts the AutoCAD application in a separate process. That means I do not have control over how the window is displayed initially. After the process is created and I establish a connection to it via obtaining a COM object (AcadApplication), then I can modify the application. `AcadApplication app = (AcadApplication)Activator.CreateInstance(Type.GetTypeFromProgID("AutoCAD.Application.18", true));` – Nicholas Miller Jul 10 '14 at 19:49
2

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: When using SetWindowPos, Windows tends to remember the values entered for the next time that application window is shown. This means that if not restored properly, then the next time the user opens AutoCAD manually, it will have the coordinates of 0,0 and the minimum width/height.

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);
Nicholas Miller
  • 4,205
  • 2
  • 39
  • 62