.NET

Reply
*Tony Tanzillo
Message 1 of 7 (142 Views)

DelayLoad in .NET ?

142 Views, 6 Replies
06-14-2005 05:14 PM
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
*Albert Szilvasy
Message 2 of 7 (142 Views)

Re: DelayLoad in .NET ?

06-14-2005 06:09 PM in reply to: *Tony Tanzillo
Yes. I understand that this is a problem in general. I think you can get
around this with careful coding. The reason VS tries to resolve the
dependency because you have the dependency in a function that is called
(hence jitted) in the designer. Try refactoring the design time and runtime
behavior into 2 separate functions like I did below. This way
GetCreateParams won't be jitted in the designer and the dependency won't
have to be resolved.

Albert

protected override CreateParams CreateParams
{
get
{
if( DesignMode )
return base.CreateParams; // design-time behavior
return GetCreateParams(); //runtime behavior in separate function
so it won't be jitted in designer
}
}
private CreateParams GetCreateParams()
{
/////////////////////////////////////////////////////////
// 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;

}

"Tony Tanzillo" wrote in message
news:4874992@discussion.autodesk.com...
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
*Tony Tanzillo
Message 3 of 7 (142 Views)

Re: DelayLoad in .NET ?

06-15-2005 12:20 AM in reply to: *Tony Tanzillo
Albert - Thanks for the advice.

However, it doesn't seem to work. I tried refactoring exactly as
you show, and also tried putting the code that gets the AutoCAD
window handle into a separate class and even a separate source
file, and it still happens.

The problem is not that I can't open that form in the designer.
I can do that. What I can't do, is create a form class derived from
it via the IDE (e.g., Project->Add Inherited Form), using that
form as the base class. When I try to do that, I get the exception
as soon as the IDE tries to create the derived form class.

If anyone wants to reproduce the problem, I've attached the
.cs and .resx from (Visual Studio 2003) for the form.

Just create a new ClassLibrary; reference acmgd and acdbmgd;
and add the attached form class to the project (remove any
bland class that the IDE creates).

Then build the project. Then try to create an Inherited Form
that derives from the attached one, and you'll get the exception.


--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Albert Szilvasy" wrote in message news:4875015@discussion.autodesk.com...
Yes. I understand that this is a problem in general. I think you can get
around this with careful coding. The reason VS tries to resolve the
dependency because you have the dependency in a function that is called
(hence jitted) in the designer. Try refactoring the design time and runtime
behavior into 2 separate functions like I did below. This way
GetCreateParams won't be jitted in the designer and the dependency won't
have to be resolved.

Albert

protected override CreateParams CreateParams
{
get
{
if( DesignMode )
return base.CreateParams; // design-time behavior
return GetCreateParams(); //runtime behavior in separate function
so it won't be jitted in designer
}
}
private CreateParams GetCreateParams()
{
/////////////////////////////////////////////////////////
// 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;

}
*Tony Tanzillo
Message 4 of 7 (142 Views)

Re: DelayLoad in .NET ?

06-15-2005 03:57 AM in reply to: *Tony Tanzillo
I was puzzled enough by this problem to run Visual Studio
under Depends.exe's profiler, and it looks like the problem is
that the DesignMode property is returning false, and the code
is trying to call into the Interop to get the AutoCAD window
handle. That also explains why it doesn't fail when I create
an instance of that form class, but does when I try to derive
a new form class from it.

As it turns out, DesignMode returns true only when called from
the class that is actually instantiated in the designer, but does
not return true when called from a base class.

That is supposedly because an instance of a base class is not
what is being 'designed'.

So, I have to find another queue to see if the form is actually
running in AutoCAD or not. I can stick the call to get the Window
handle inside of a try/catch block, and deal with it that way, but
by the time the exception bubbles up, all kinds of stuff has
already happened in the IDE (e.g., the AutoCAD interop DLLs are
loaded; and AutoCAD starts doing its security thing).

Before I resort to P/Invoke, any other ideas are welcome :-)

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com
*Albert Szilvasy
Message 5 of 7 (142 Views)

Re: DelayLoad in .NET ?

06-15-2005 11:09 AM in reply to: *Tony Tanzillo
If you don't want to do P/Invoke you could check what the current process is
using the Process class.

Albert

"Tony Tanzillo" wrote in message
news:4875206@discussion.autodesk.com...
I was puzzled enough by this problem to run Visual Studio
under Depends.exe's profiler, and it looks like the problem is
that the DesignMode property is returning false, and the code
is trying to call into the Interop to get the AutoCAD window
handle. That also explains why it doesn't fail when I create
an instance of that form class, but does when I try to derive
a new form class from it.

As it turns out, DesignMode returns true only when called from
the class that is actually instantiated in the designer, but does
not return true when called from a base class.

That is supposedly because an instance of a base class is not
what is being 'designed'.

So, I have to find another queue to see if the form is actually
running in AutoCAD or not. I can stick the call to get the Window
handle inside of a try/catch block, and deal with it that way, but
by the time the exception bubbles up, all kinds of stuff has
already happened in the IDE (e.g., the AutoCAD interop DLLs are
loaded; and AutoCAD starts doing its security thing).

Before I resort to P/Invoke, any other ideas are welcome :-)

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com
*Tony Tanzillo
Message 6 of 7 (142 Views)

Re: DelayLoad in .NET ?

06-15-2005 12:44 PM in reply to: *Tony Tanzillo
Thanks. I'll have a look at that.

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Albert Szilvasy" wrote in message news:4875885@discussion.autodesk.com...
If you don't want to do P/Invoke you could check what the current process is
using the Process class.

Albert

"Tony Tanzillo" wrote in message
news:4875206@discussion.autodesk.com...
I was puzzled enough by this problem to run Visual Studio
under Depends.exe's profiler, and it looks like the problem is
that the DesignMode property is returning false, and the code
is trying to call into the Interop to get the AutoCAD window
handle. That also explains why it doesn't fail when I create
an instance of that form class, but does when I try to derive
a new form class from it.

As it turns out, DesignMode returns true only when called from
the class that is actually instantiated in the designer, but does
not return true when called from a base class.

That is supposedly because an instance of a base class is not
what is being 'designed'.

So, I have to find another queue to see if the form is actually
running in AutoCAD or not. I can stick the call to get the Window
handle inside of a try/catch block, and deal with it that way, but
by the time the exception bubbles up, all kinds of stuff has
already happened in the IDE (e.g., the AutoCAD interop DLLs are
loaded; and AutoCAD starts doing its security thing).

Before I resort to P/Invoke, any other ideas are welcome :-)

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com
*Tony Tanzillo
Message 7 of 7 (142 Views)

Re: DelayLoad in .NET ?

06-15-2005 01:31 PM in reply to: *Tony Tanzillo
Thansk again. This is all that was needed:

protected bool Designing
{
get
{
Process p = Process.GetCurrentProcess();
return String.Compare(p.ProcessName, "devenv", true) == 0;
}
}

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com

"Albert Szilvasy" wrote in message news:4875885@discussion.autodesk.com...
If you don't want to do P/Invoke you could check what the current process is
using the Process class.

Albert

"Tony Tanzillo" wrote in message
news:4875206@discussion.autodesk.com...
I was puzzled enough by this problem to run Visual Studio
under Depends.exe's profiler, and it looks like the problem is
that the DesignMode property is returning false, and the code
is trying to call into the Interop to get the AutoCAD window
handle. That also explains why it doesn't fail when I create
an instance of that form class, but does when I try to derive
a new form class from it.

As it turns out, DesignMode returns true only when called from
the class that is actually instantiated in the designer, but does
not return true when called from a base class.

That is supposedly because an instance of a base class is not
what is being 'designed'.

So, I have to find another queue to see if the form is actually
running in AutoCAD or not. I can stick the call to get the Window
handle inside of a try/catch block, and deal with it that way, but
by the time the exception bubbles up, all kinds of stuff has
already happened in the IDE (e.g., the AutoCAD interop DLLs are
loaded; and AutoCAD starts doing its security thing).

Before I resort to P/Invoke, any other ideas are welcome :-)

--
http://www.caddzone.com

AcadXTabs: MDI Document Tabs for AutoCAD 2004/2005/2006
http://www.acadxtabs.com
Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.