I'm trying to port a custom form class that was
originally developed in Delphi to .NET.
The class provides support for modeless floating
forms in AutoCAD, as well as various other AutoCAD-
specific functionality that's commonly used in UI
based applications.
The problem I'm running into, is that in the Form
class, I cannot calll any Interop code because the
form must be instantiated in the IDE designer, which
means that Visual Studio will attempt to load any
referenced assemblies.
I see this as a massive impediment to component
based development of AutoCAD-based solutions,
because no AutoCAD interop code can be used in
any compoent that must be instantiated in the
Visual Studio IDE.
Here is an example of where the functionality is
needed. This is an override of Form.CreateParams
which sets the Form's owner window to the AutoCAD
MainFrame, and adds the WS_POPUP window style,
so AutoCAD fires WM_KEEPFOCUS messages at the
Window. Note that I can get around this specific
problem using P/Invoke (adsi_AcadMainWnd), but
this is only an _example_ for illustration purposes.
Because the form calls Interop code, I cannot derive
new Form classes from this form class, and use them
in the IDE designer:
namespace AcadUI
{
public class AcadModelessForm : System.Windows.Forms.Form
{
const UInt32 WS_OVERLAPPED = 0x00000000;
const UInt32 WS_POPUP = 0x80000000;
const UInt32 WS_CHILD = 0x40000000;
const Int32 WM_USER = 0x0400;
const Int32 WM_ACADKEEPFOCUS = WM_USER + 0x6D01;
// Handle of the AutoCAD MainFrame:
static IntPtr s_OwnerWnd = IntPtr.Zero;
// An event to query if we want to keep the focus
public delegate void OnQueryKeepFocusEvent(object sender, ref bool bKeepFocus );
public event OnQueryKeepFocusEvent OnQueryKeepFocus = null;
// This code makes the form's owner window the
// AutoCAD Mainframe, and adds the WS_POPUP style
// so AutoCAD sends us WM_KEEPFOCUS messages
protected override CreateParams CreateParams
{
get
{
if( DesignMode )
return base.CreateParams; // design-time behavior
/////////////////////////////////////////////////////////
// The following prevents this from from being used
// in the IDE designer (as a base for Inherited Forms):
if( s_OwnerWnd == IntPtr.Zero )
s_OwnerWnd = Autodesk.AutoCAD.ApplicationServices.Application.MainWindow.Handle;
Params.Parent = s_OwnerWnd;
/////////////////////////////////////////////////////////
this.TopLevel = false;
CreateParams Params = base.CreateParams;
unchecked
{
Params.Style |= (int) (WS_POPUP | WS_OVERLAPPED);
Params.Style &= ~ (int) WS_CHILD;
// Params.ExStyle |= (int) WS_EX_PALETTEWINDOW; // optional
}
return Params;
}
}
// Need to do this, because Control.Bounds is
// returning the bounds in owner/parent window
// client coordinates. Once I get rid of the WS_CHILD
// window style for the parking window this may no
// longer be necessary
public new Rectangle Bounds
{
get
{
return base.Bounds;
// TODO: Translate bounds rectangle to screen coords
}
}
protected virtual bool OnKeepFocus()
{
bool bKeepFocus = true;
if( this.OnQueryKeepFocus != null )
this.OnQueryKeepFocus(this, ref bKeepFocus);
else
{
// TODO: Implement default behavior (keep focus
// only if the mouse is in our window bounds)
}
return bKeepFocus;
}
protected override void WndProc( ref Message m )
{
if( ! this.DesignMode && m.Msg == WM_ACADKEEPFOCUS )
m.Result = (IntPtr) (OnKeepFocus() ? 1 : 0);
else
base.WndProc( ref m );
}
// A modeless Form is automatically disposed of when closed.
// We want to stop this from happening, so instead we hide
// the form which allows it to be redisplayed by calling Show(),
// or by setting the Visible property to true;
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing( e );
if( ! DesignMode )
{
e.Cancel = true;
this.Hide();
}
}
}
}
--
http://www.caddzone.com
AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com