.NET

Reply
*Dale Levesque
Message 1 of 8 (107 Views)

Calling DLL From Lisp

107 Views, 7 Replies
09-06-2005 10:29 AM
I have the following Class Library called Lab2. I compile and load it into
AutoCAD 2006 using netload. I can type the command "getDistance" and it
works properly.

If I try to call it from Lisp using the following code it crashes when the
vla-GetInterfaceObject function is called. Any suggestions?


(setq $acad (vlax-get-acad-object))
(setq vbstrcls (vla-GetInterfaceObject $acad
"Lab2.DynamicWindowsClass1"))
(setq out (vlax-invoke-method vbstrcls "getDistance"))
out
(vlax-release-object vbstrcls)
(vlax-release-object $acad)


Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Public Class DynamicWindowsClass1

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd1()

Dim prPointOptions As PromptPointOptions = New PromptPointOptions("Select a
point")

Dim prPointRes As PromptPointResult

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

prPointRes = ed.GetPoint(prPointOptions)

If prPointRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("You selected point " & prPointRes.Value.ToString())

End Function

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd2()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim prDistOptions As PromptDistanceOptions = New PromptDistanceOptions("Find
Distance, Select First Point:")

Dim prdistRes As PromptDoubleResult

prdistRes = ed.GetDistance(prDistOptions)

If prdistRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("The distance is " & prdistRes.Value.ToString())

End Function

End Class
*Bobby C. Jones
Message 2 of 8 (107 Views)

Re: Calling DLL From Lisp

09-06-2005 11:08 AM in reply to: *Dale Levesque
Dale,
You need to set up your classes for COM interop in order to call them from
LISP this way.

Here is what I do:

Create an Interface that contains all of the members that you want to expose
to a COM client. Set its Guid and ComVisible attributes
[Guid("")]
[ComVisible(true)]

Create your class and have it implement your interface. Set these
attributes on the class.
[ClassInterface(ClassInterfaceType.None)]
[Guid("")]
[ProgId("")] //"Lab2.DynamicWindowsClass1"
[ComVisible(true)]

Make sure that your class has a public constructor that accepts no
arguments. This is the constructor that will be called when the class is
instantiated by the COM client. You can overload the constructor, but you
will only be able to call constructors with arguments from .NET consumers.

On your development machine you can set VS to register your assembly for COM
at compile time. You will need to have the installer handle COM
registration on other machines, or have them self register. I haven't gone
the self registering route, but I believe that Tony Tanzillo may have posted
some code on one of the groups showing an example.
--
Bobby C. Jones
http://www.acadx.com



"Dale Levesque" wrote in message
news:4948313@discussion.autodesk.com...
I have the following Class Library called Lab2. I compile and load it into
AutoCAD 2006 using netload. I can type the command "getDistance" and it
works properly.

If I try to call it from Lisp using the following code it crashes when the
vla-GetInterfaceObject function is called. Any suggestions?


(setq $acad (vlax-get-acad-object))
(setq vbstrcls (vla-GetInterfaceObject $acad
"Lab2.DynamicWindowsClass1"))
(setq out (vlax-invoke-method vbstrcls "getDistance"))
out
(vlax-release-object vbstrcls)
(vlax-release-object $acad)


Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Public Class DynamicWindowsClass1

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd1()

Dim prPointOptions As PromptPointOptions = New PromptPointOptions("Select a
point")

Dim prPointRes As PromptPointResult

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

prPointRes = ed.GetPoint(prPointOptions)

If prPointRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("You selected point " & prPointRes.Value.ToString())

End Function

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd2()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim prDistOptions As PromptDistanceOptions = New PromptDistanceOptions("Find
Distance, Select First Point:")

Dim prdistRes As PromptDoubleResult

prdistRes = ed.GetDistance(prDistOptions)

If prdistRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("The distance is " & prdistRes.Value.ToString())

End Function

End Class
*Dale Levesque
Message 3 of 8 (107 Views)

Re: Calling DLL From Lisp

09-06-2005 12:37 PM in reply to: *Dale Levesque
Thanks Bobby. I'm brand new to .Net so I'll look into these topics. Any
chance of a sample?






"Bobby C. Jones" wrote in message
news:4948377@discussion.autodesk.com...
Dale,
You need to set up your classes for COM interop in order to call them from
LISP this way.

Here is what I do:

Create an Interface that contains all of the members that you want to expose
to a COM client. Set its Guid and ComVisible attributes
[Guid("")]
[ComVisible(true)]

Create your class and have it implement your interface. Set these
attributes on the class.
[ClassInterface(ClassInterfaceType.None)]
[Guid("")]
[ProgId("")] //"Lab2.DynamicWindowsClass1"
[ComVisible(true)]

Make sure that your class has a public constructor that accepts no
arguments. This is the constructor that will be called when the class is
instantiated by the COM client. You can overload the constructor, but you
will only be able to call constructors with arguments from .NET consumers.

On your development machine you can set VS to register your assembly for COM
at compile time. You will need to have the installer handle COM
registration on other machines, or have them self register. I haven't gone
the self registering route, but I believe that Tony Tanzillo may have posted
some code on one of the groups showing an example.
--
Bobby C. Jones
http://www.acadx.com



"Dale Levesque" wrote in message
news:4948313@discussion.autodesk.com...
I have the following Class Library called Lab2. I compile and load it into
AutoCAD 2006 using netload. I can type the command "getDistance" and it
works properly.

If I try to call it from Lisp using the following code it crashes when the
vla-GetInterfaceObject function is called. Any suggestions?


(setq $acad (vlax-get-acad-object))
(setq vbstrcls (vla-GetInterfaceObject $acad
"Lab2.DynamicWindowsClass1"))
(setq out (vlax-invoke-method vbstrcls "getDistance"))
out
(vlax-release-object vbstrcls)
(vlax-release-object $acad)


Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Public Class DynamicWindowsClass1

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd1()

Dim prPointOptions As PromptPointOptions = New PromptPointOptions("Select a
point")

Dim prPointRes As PromptPointResult

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

prPointRes = ed.GetPoint(prPointOptions)

If prPointRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("You selected point " & prPointRes.Value.ToString())

End Function

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd2()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim prDistOptions As PromptDistanceOptions = New PromptDistanceOptions("Find
Distance, Select First Point:")

Dim prdistRes As PromptDoubleResult

prdistRes = ed.GetDistance(prDistOptions)

If prdistRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("The distance is " & prdistRes.Value.ToString())

End Function

End Class
*Dale Levesque
Message 4 of 8 (107 Views)

Re: Calling DLL From Lisp

09-06-2005 01:14 PM in reply to: *Dale Levesque
What type of value is used for the Guid?


"Bobby C. Jones" wrote in message
news:4948377@discussion.autodesk.com...
Dale,
You need to set up your classes for COM interop in order to call them from
LISP this way.

Here is what I do:

Create an Interface that contains all of the members that you want to expose
to a COM client. Set its Guid and ComVisible attributes
[Guid("")]
[ComVisible(true)]

Create your class and have it implement your interface. Set these
attributes on the class.
[ClassInterface(ClassInterfaceType.None)]
[Guid("")]
[ProgId("")] //"Lab2.DynamicWindowsClass1"
[ComVisible(true)]

Make sure that your class has a public constructor that accepts no
arguments. This is the constructor that will be called when the class is
instantiated by the COM client. You can overload the constructor, but you
will only be able to call constructors with arguments from .NET consumers.

On your development machine you can set VS to register your assembly for COM
at compile time. You will need to have the installer handle COM
registration on other machines, or have them self register. I haven't gone
the self registering route, but I believe that Tony Tanzillo may have posted
some code on one of the groups showing an example.
--
Bobby C. Jones
http://www.acadx.com



"Dale Levesque" wrote in message
news:4948313@discussion.autodesk.com...
I have the following Class Library called Lab2. I compile and load it into
AutoCAD 2006 using netload. I can type the command "getDistance" and it
works properly.

If I try to call it from Lisp using the following code it crashes when the
vla-GetInterfaceObject function is called. Any suggestions?


(setq $acad (vlax-get-acad-object))
(setq vbstrcls (vla-GetInterfaceObject $acad
"Lab2.DynamicWindowsClass1"))
(setq out (vlax-invoke-method vbstrcls "getDistance"))
out
(vlax-release-object vbstrcls)
(vlax-release-object $acad)


Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Public Class DynamicWindowsClass1

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd1()

Dim prPointOptions As PromptPointOptions = New PromptPointOptions("Select a
point")

Dim prPointRes As PromptPointResult

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

prPointRes = ed.GetPoint(prPointOptions)

If prPointRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("You selected point " & prPointRes.Value.ToString())

End Function

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd2()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim prDistOptions As PromptDistanceOptions = New PromptDistanceOptions("Find
Distance, Select First Point:")

Dim prdistRes As PromptDoubleResult

prdistRes = ed.GetDistance(prDistOptions)

If prdistRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("The distance is " & prdistRes.Value.ToString())

End Function

End Class
*Tony Tanzillo
Message 5 of 8 (107 Views)

Re: Calling DLL From Lisp

09-06-2005 05:02 PM in reply to: *Dale Levesque
Hi Dale - If you're following the related thread where
I posted code showing a simple COM server, there's
a few things I should point out.

The first is that it is, by design, a "bare-minimal"
implementation of COM-callable code, intended
for exposing code for _private_ consumption, from
visual lisp.

If the exposed code is 'private' (meaning it is not
intended for general consumption by any consumer,
but rather, only your own consumer), the lack of a
published interface serves a good purpose, which is
to make the COM component non-public. That's a
good thing, believe it or not.

If you are developing a COM-callable component
for public consumption by others, then as another
response mentions, you have to follow the pattern
that is gernally used to expose managed code via
COM, which involves creating and exposing a COM
interface; using ClassInterfaceType.None, to hide
base class members that are visible to COM; and
registering the library using an installer or regasm.

But, for private consumption by only your Visual
LISP code (which presumably already knows what
methods and properties your COM server exposes
and hence, does not require a published, public
interface), and to inhibit use of it by others, the
bare-minimal implementation like what I showed
will work, and will help to keep unwanted parties
from calling your code.

Another issue is that if your COM component uses
the AutoCAD interop libraries, it cannot be loaded
as a COM server into any COM client not running in
AutoCAD's process space. But, any Visual LISP app
can call it, provided they know what methods and
properties it exposes (and that's the fundamental
purpose of having a public interface).

So, the usual pattern for exposing .NET code to
COM for general or 'public' consumption does not
nessarily apply for private connectivity between
VisualLISP and managed code. In fact, it can pose
a security problem.

Now that we've got that out of the way, The one
thing I failed to touch on earlier, is registration.

Building an installer is not something that I
generally do if it is only for the purpose of
registering a COM server for private use only
by my own code. Hence, setting your project
to register your assembly for COM interop is
not terribly useful for deployment purposes,
only for the development cycle. Also, if your
assembly consumes COM components, like the
AutoCAD COM Interop, it must be signed.

So, here is a way to make a COM component that
uses the AutoCAD interop libraries self-registering
when the assembly is loaded into AutoCAD using
NETLOAD (sorry, this is C#):

// Dependencies:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;

// Helper property:
private Document ActiveDoc
{
get
{
return Autodesk.AutoCAD.ApplicationServices.
Application.DocumentManager.MdiActiveDocument;
}
}

// IExtensionApplication.Initialize() implementation:

// The code below will register the containing assembly
// for COM interop when the assembly is loaded into
// AutoCAD, via NETLOAD (note: it will do nothing when
// the containing assembly is loaded as a COM server
// by Windows):

public void Initialize()
{
// we only want to do this when the assembly is
// explicitly loaded by the user using NETLOAD:

if( ActiveDoc.CommandInProgress == "NETLOAD" )
{
new RegistrationServices().RegisterAssembly(
Assembly.GetExecutingAssembly(),
AssemblyRegistrationFlags.SetCodeBase);
}
}

Implementing IExtensionApplication on a COM class
may not be a good practice, because AutoCAD will
create and hold an instance of that class when the
assembly that contains it is loaded. Instead, create
another class that's invisible to COM, and implement
IExtensionApplication on that class.


--
http://www.caddzone.com

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

"Dale Levesque" wrote in message news:4948313@discussion.autodesk.com...
I have the following Class Library called Lab2. I compile and load it into
AutoCAD 2006 using netload. I can type the command "getDistance" and it
works properly.

If I try to call it from Lisp using the following code it crashes when the
vla-GetInterfaceObject function is called. Any suggestions?


(setq $acad (vlax-get-acad-object))
(setq vbstrcls (vla-GetInterfaceObject $acad
"Lab2.DynamicWindowsClass1"))
(setq out (vlax-invoke-method vbstrcls "getDistance"))
out
(vlax-release-object vbstrcls)
(vlax-release-object $acad)


Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Public Class DynamicWindowsClass1

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd1()

Dim prPointOptions As PromptPointOptions = New PromptPointOptions("Select a
point")

Dim prPointRes As PromptPointResult

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

prPointRes = ed.GetPoint(prPointOptions)

If prPointRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("You selected point " & prPointRes.Value.ToString())

End Function

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd2()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim prDistOptions As PromptDistanceOptions = New PromptDistanceOptions("Find
Distance, Select First Point:")

Dim prdistRes As PromptDoubleResult

prdistRes = ed.GetDistance(prDistOptions)

If prdistRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("The distance is " & prdistRes.Value.ToString())

End Function

End Class
*Dale Levesque
Message 6 of 8 (107 Views)

Re: Calling DLL From Lisp

09-07-2005 08:03 AM in reply to: *Dale Levesque
THANKS Tony. I did not realize that there was a related thread with posted
code though. I've searched through this newsgroup without any luck. All I
need is the bare bones code that will allow the lisp routine to call the
function stored in the DLL.

Dale



"Tony Tanzillo" wrote in message
news:4948672@discussion.autodesk.com...
Hi Dale - If you're following the related thread where
I posted code showing a simple COM server, there's
a few things I should point out.

The first is that it is, by design, a "bare-minimal"
implementation of COM-callable code, intended
for exposing code for _private_ consumption, from
visual lisp.

If the exposed code is 'private' (meaning it is not
intended for general consumption by any consumer,
but rather, only your own consumer), the lack of a
published interface serves a good purpose, which is
to make the COM component non-public. That's a
good thing, believe it or not.

If you are developing a COM-callable component
for public consumption by others, then as another
response mentions, you have to follow the pattern
that is gernally used to expose managed code via
COM, which involves creating and exposing a COM
interface; using ClassInterfaceType.None, to hide
base class members that are visible to COM; and
registering the library using an installer or regasm.

But, for private consumption by only your Visual
LISP code (which presumably already knows what
methods and properties your COM server exposes
and hence, does not require a published, public
interface), and to inhibit use of it by others, the
bare-minimal implementation like what I showed
will work, and will help to keep unwanted parties
from calling your code.

Another issue is that if your COM component uses
the AutoCAD interop libraries, it cannot be loaded
as a COM server into any COM client not running in
AutoCAD's process space. But, any Visual LISP app
can call it, provided they know what methods and
properties it exposes (and that's the fundamental
purpose of having a public interface).

So, the usual pattern for exposing .NET code to
COM for general or 'public' consumption does not
nessarily apply for private connectivity between
VisualLISP and managed code. In fact, it can pose
a security problem.

Now that we've got that out of the way, The one
thing I failed to touch on earlier, is registration.

Building an installer is not something that I
generally do if it is only for the purpose of
registering a COM server for private use only
by my own code. Hence, setting your project
to register your assembly for COM interop is
not terribly useful for deployment purposes,
only for the development cycle. Also, if your
assembly consumes COM components, like the
AutoCAD COM Interop, it must be signed.

So, here is a way to make a COM component that
uses the AutoCAD interop libraries self-registering
when the assembly is loaded into AutoCAD using
NETLOAD (sorry, this is C#):

// Dependencies:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;

// Helper property:
private Document ActiveDoc
{
get
{
return Autodesk.AutoCAD.ApplicationServices.
Application.DocumentManager.MdiActiveDocument;
}
}

// IExtensionApplication.Initialize() implementation:

// The code below will register the containing assembly
// for COM interop when the assembly is loaded into
// AutoCAD, via NETLOAD (note: it will do nothing when
// the containing assembly is loaded as a COM server
// by Windows):

public void Initialize()
{
// we only want to do this when the assembly is
// explicitly loaded by the user using NETLOAD:

if( ActiveDoc.CommandInProgress == "NETLOAD" )
{
new RegistrationServices().RegisterAssembly(
Assembly.GetExecutingAssembly(),
AssemblyRegistrationFlags.SetCodeBase);
}
}

Implementing IExtensionApplication on a COM class
may not be a good practice, because AutoCAD will
create and hold an instance of that class when the
assembly that contains it is loaded. Instead, create
another class that's invisible to COM, and implement
IExtensionApplication on that class.


--
http://www.caddzone.com

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

"Dale Levesque" wrote in message
news:4948313@discussion.autodesk.com...
I have the following Class Library called Lab2. I compile and load it into
AutoCAD 2006 using netload. I can type the command "getDistance" and it
works properly.

If I try to call it from Lisp using the following code it crashes when the
vla-GetInterfaceObject function is called. Any suggestions?


(setq $acad (vlax-get-acad-object))
(setq vbstrcls (vla-GetInterfaceObject $acad
"Lab2.DynamicWindowsClass1"))
(setq out (vlax-invoke-method vbstrcls "getDistance"))
out
(vlax-release-object vbstrcls)
(vlax-release-object $acad)


Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Public Class DynamicWindowsClass1

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd1()

Dim prPointOptions As PromptPointOptions = New PromptPointOptions("Select a
point")

Dim prPointRes As PromptPointResult

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

prPointRes = ed.GetPoint(prPointOptions)

If prPointRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("You selected point " & prPointRes.Value.ToString())

End Function

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd2()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim prDistOptions As PromptDistanceOptions = New PromptDistanceOptions("Find
Distance, Select First Point:")

Dim prdistRes As PromptDoubleResult

prdistRes = ed.GetDistance(prDistOptions)

If prdistRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("The distance is " & prdistRes.Value.ToString())

End Function

End Class
*Tony Tanzillo
Message 7 of 8 (107 Views)

Re: Calling DLL From Lisp

09-07-2005 09:33 AM in reply to: *Dale Levesque
Hi Dale - See the thread titled:

Passing arguments and returning values with .NET and LISP

--
http://www.caddzone.com

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

"Dale Levesque" wrote in message news:4949143@discussion.autodesk.com...
THANKS Tony. I did not realize that there was a related thread with posted
code though. I've searched through this newsgroup without any luck. All I
need is the bare bones code that will allow the lisp routine to call the
function stored in the DLL.

Dale



"Tony Tanzillo" wrote in message
news:4948672@discussion.autodesk.com...
Hi Dale - If you're following the related thread where
I posted code showing a simple COM server, there's
a few things I should point out.

The first is that it is, by design, a "bare-minimal"
implementation of COM-callable code, intended
for exposing code for _private_ consumption, from
visual lisp.

If the exposed code is 'private' (meaning it is not
intended for general consumption by any consumer,
but rather, only your own consumer), the lack of a
published interface serves a good purpose, which is
to make the COM component non-public. That's a
good thing, believe it or not.

If you are developing a COM-callable component
for public consumption by others, then as another
response mentions, you have to follow the pattern
that is gernally used to expose managed code via
COM, which involves creating and exposing a COM
interface; using ClassInterfaceType.None, to hide
base class members that are visible to COM; and
registering the library using an installer or regasm.

But, for private consumption by only your Visual
LISP code (which presumably already knows what
methods and properties your COM server exposes
and hence, does not require a published, public
interface), and to inhibit use of it by others, the
bare-minimal implementation like what I showed
will work, and will help to keep unwanted parties
from calling your code.

Another issue is that if your COM component uses
the AutoCAD interop libraries, it cannot be loaded
as a COM server into any COM client not running in
AutoCAD's process space. But, any Visual LISP app
can call it, provided they know what methods and
properties it exposes (and that's the fundamental
purpose of having a public interface).

So, the usual pattern for exposing .NET code to
COM for general or 'public' consumption does not
nessarily apply for private connectivity between
VisualLISP and managed code. In fact, it can pose
a security problem.

Now that we've got that out of the way, The one
thing I failed to touch on earlier, is registration.

Building an installer is not something that I
generally do if it is only for the purpose of
registering a COM server for private use only
by my own code. Hence, setting your project
to register your assembly for COM interop is
not terribly useful for deployment purposes,
only for the development cycle. Also, if your
assembly consumes COM components, like the
AutoCAD COM Interop, it must be signed.

So, here is a way to make a COM component that
uses the AutoCAD interop libraries self-registering
when the assembly is loaded into AutoCAD using
NETLOAD (sorry, this is C#):

// Dependencies:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;

// Helper property:
private Document ActiveDoc
{
get
{
return Autodesk.AutoCAD.ApplicationServices.
Application.DocumentManager.MdiActiveDocument;
}
}

// IExtensionApplication.Initialize() implementation:

// The code below will register the containing assembly
// for COM interop when the assembly is loaded into
// AutoCAD, via NETLOAD (note: it will do nothing when
// the containing assembly is loaded as a COM server
// by Windows):

public void Initialize()
{
// we only want to do this when the assembly is
// explicitly loaded by the user using NETLOAD:

if( ActiveDoc.CommandInProgress == "NETLOAD" )
{
new RegistrationServices().RegisterAssembly(
Assembly.GetExecutingAssembly(),
AssemblyRegistrationFlags.SetCodeBase);
}
}

Implementing IExtensionApplication on a COM class
may not be a good practice, because AutoCAD will
create and hold an instance of that class when the
assembly that contains it is loaded. Instead, create
another class that's invisible to COM, and implement
IExtensionApplication on that class.


--
http://www.caddzone.com

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

"Dale Levesque" wrote in message
news:4948313@discussion.autodesk.com...
I have the following Class Library called Lab2. I compile and load it into
AutoCAD 2006 using netload. I can type the command "getDistance" and it
works properly.

If I try to call it from Lisp using the following code it crashes when the
vla-GetInterfaceObject function is called. Any suggestions?


(setq $acad (vlax-get-acad-object))
(setq vbstrcls (vla-GetInterfaceObject $acad
"Lab2.DynamicWindowsClass1"))
(setq out (vlax-invoke-method vbstrcls "getDistance"))
out
(vlax-release-object vbstrcls)
(vlax-release-object $acad)


Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Public Class DynamicWindowsClass1

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd1()

Dim prPointOptions As PromptPointOptions = New PromptPointOptions("Select a
point")

Dim prPointRes As PromptPointResult

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

prPointRes = ed.GetPoint(prPointOptions)

If prPointRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("You selected point " & prPointRes.Value.ToString())

End Function

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd2()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim prDistOptions As PromptDistanceOptions = New PromptDistanceOptions("Find
Distance, Select First Point:")

Dim prdistRes As PromptDoubleResult

prdistRes = ed.GetDistance(prDistOptions)

If prdistRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("The distance is " & prdistRes.Value.ToString())

End Function

End Class
*Dale Levesque
Message 8 of 8 (107 Views)

Re: Calling DLL From Lisp

09-07-2005 09:53 AM in reply to: *Dale Levesque
Terrific, thanks again Tony.

"Tony Tanzillo" wrote in message
news:4949276@discussion.autodesk.com...
Hi Dale - See the thread titled:

Passing arguments and returning values with .NET and LISP

--
http://www.caddzone.com

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

"Dale Levesque" wrote in message
news:4949143@discussion.autodesk.com...
THANKS Tony. I did not realize that there was a related thread with posted
code though. I've searched through this newsgroup without any luck. All I
need is the bare bones code that will allow the lisp routine to call the
function stored in the DLL.

Dale



"Tony Tanzillo" wrote in message
news:4948672@discussion.autodesk.com...
Hi Dale - If you're following the related thread where
I posted code showing a simple COM server, there's
a few things I should point out.

The first is that it is, by design, a "bare-minimal"
implementation of COM-callable code, intended
for exposing code for _private_ consumption, from
visual lisp.

If the exposed code is 'private' (meaning it is not
intended for general consumption by any consumer,
but rather, only your own consumer), the lack of a
published interface serves a good purpose, which is
to make the COM component non-public. That's a
good thing, believe it or not.

If you are developing a COM-callable component
for public consumption by others, then as another
response mentions, you have to follow the pattern
that is gernally used to expose managed code via
COM, which involves creating and exposing a COM
interface; using ClassInterfaceType.None, to hide
base class members that are visible to COM; and
registering the library using an installer or regasm.

But, for private consumption by only your Visual
LISP code (which presumably already knows what
methods and properties your COM server exposes
and hence, does not require a published, public
interface), and to inhibit use of it by others, the
bare-minimal implementation like what I showed
will work, and will help to keep unwanted parties
from calling your code.

Another issue is that if your COM component uses
the AutoCAD interop libraries, it cannot be loaded
as a COM server into any COM client not running in
AutoCAD's process space. But, any Visual LISP app
can call it, provided they know what methods and
properties it exposes (and that's the fundamental
purpose of having a public interface).

So, the usual pattern for exposing .NET code to
COM for general or 'public' consumption does not
nessarily apply for private connectivity between
VisualLISP and managed code. In fact, it can pose
a security problem.

Now that we've got that out of the way, The one
thing I failed to touch on earlier, is registration.

Building an installer is not something that I
generally do if it is only for the purpose of
registering a COM server for private use only
by my own code. Hence, setting your project
to register your assembly for COM interop is
not terribly useful for deployment purposes,
only for the development cycle. Also, if your
assembly consumes COM components, like the
AutoCAD COM Interop, it must be signed.

So, here is a way to make a COM component that
uses the AutoCAD interop libraries self-registering
when the assembly is loaded into AutoCAD using
NETLOAD (sorry, this is C#):

// Dependencies:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;

// Helper property:
private Document ActiveDoc
{
get
{
return Autodesk.AutoCAD.ApplicationServices.
Application.DocumentManager.MdiActiveDocument;
}
}

// IExtensionApplication.Initialize() implementation:

// The code below will register the containing assembly
// for COM interop when the assembly is loaded into
// AutoCAD, via NETLOAD (note: it will do nothing when
// the containing assembly is loaded as a COM server
// by Windows):

public void Initialize()
{
// we only want to do this when the assembly is
// explicitly loaded by the user using NETLOAD:

if( ActiveDoc.CommandInProgress == "NETLOAD" )
{
new RegistrationServices().RegisterAssembly(
Assembly.GetExecutingAssembly(),
AssemblyRegistrationFlags.SetCodeBase);
}
}

Implementing IExtensionApplication on a COM class
may not be a good practice, because AutoCAD will
create and hold an instance of that class when the
assembly that contains it is loaded. Instead, create
another class that's invisible to COM, and implement
IExtensionApplication on that class.


--
http://www.caddzone.com

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

"Dale Levesque" wrote in message
news:4948313@discussion.autodesk.com...
I have the following Class Library called Lab2. I compile and load it into
AutoCAD 2006 using netload. I can type the command "getDistance" and it
works properly.

If I try to call it from Lisp using the following code it crashes when the
vla-GetInterfaceObject function is called. Any suggestions?


(setq $acad (vlax-get-acad-object))
(setq vbstrcls (vla-GetInterfaceObject $acad
"Lab2.DynamicWindowsClass1"))
(setq out (vlax-invoke-method vbstrcls "getDistance"))
out
(vlax-release-object vbstrcls)
(vlax-release-object $acad)


Imports Autodesk.AutoCAD.Runtime

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Public Class DynamicWindowsClass1

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd1()

Dim prPointOptions As PromptPointOptions = New PromptPointOptions("Select a
point")

Dim prPointRes As PromptPointResult

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

prPointRes = ed.GetPoint(prPointOptions)

If prPointRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("You selected point " & prPointRes.Value.ToString())

End Function

' Define command 'Asdkcmd1'

_

Public Function Asdkcmd2()

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor

Dim prDistOptions As PromptDistanceOptions = New PromptDistanceOptions("Find
Distance, Select First Point:")

Dim prdistRes As PromptDoubleResult

prdistRes = ed.GetDistance(prDistOptions)

If prdistRes.Status <> PromptStatus.OK Then

Return Nothing

End If

ed.WriteMessage("The distance is " & prdistRes.Value.ToString())

End Function

End Class

You are not logged in.

Log into access your profile, ask and answer questions, share ideas and more. Haven't signed up yet? Register

Announcements
Welcome to the new Autodesk Community!
If this is your first visit, click here to get started and make the most of the Community. Let us know what you think of the new experience in the Community Feedback Forum.

Need installation help?

Start with some of our most frequented solutions to get help installing your software.

Ask the Community