TheSwamp
Code Red => .NET => Topic started by: gswang on May 12, 2010, 08:26:17 AM
-
How to run lisp program except for SendStringToExcecute?
i know 'eval' in lisp, but in .NET which function can eval lisp expression?
-
have a look at this code
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices;
[assembly: CommandClass(typeof(ExecMethod.Commands))]
namespace ExecMethod
{
public static class Commands
{
[DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl)]
extern static int acedInvoke(IntPtr rbIn, out IntPtr rbOut);
public static ResultBuffer Invoke(ResultBuffer rbIn)
{
IntPtr pRb = IntPtr.Zero;
acedInvoke(rbIn.UnmanagedObject, out pRb);
return DisposableWrapper.Create(typeof(ResultBuffer), pRb, true) as ResultBuffer;
}
// A sample lisp that takes a list as an argument
// (defun thisisatest (a) (reverse a))
// (vl-acad-defun 'thisisatest)
[CommandMethod("doit")]
public static void MyCommand()
{
// create a list to send, the first item in the list is the lisp func
ResultBuffer rbOut = new ResultBuffer();
rbOut.Add(new TypedValue((int)LispDataType.Text, "thisisatest"));
// the argument
rbOut.Add(new TypedValue((int)LispDataType.ListBegin));
rbOut.Add(new TypedValue((int)LispDataType.Int32, 1));
rbOut.Add(new TypedValue((int)LispDataType.Int32, 2));
rbOut.Add(new TypedValue((int)LispDataType.Int32, 3));
rbOut.Add(new TypedValue((int)LispDataType.Int32, 4));
rbOut.Add(new TypedValue((int)LispDataType.ListEnd));
//rbIn is the result from the lisp func
ResultBuffer rbIn = Invoke(rbOut);
List<TypedValue> list = new List<TypedValue>(rbIn.AsArray());
list.ForEach(X =>
AcAp.Application.DocumentManager.
MdiActiveDocument.Editor.WriteMessage(X.Value.ToString()));
}
}
}
-
Thank you very much, Daniel! :-)
-
Do you think you could help me translate this code to vb.net?
I am learning .net but am not familiar enough with translation between cs and vb.
Peter
-
Hi Peter
My VB is about worthless, about all I can do is use reflector. you will need to add the LispDataTypes back in.
I hope this helps you
Public Class Commands
' Methods
<DllImport("acad.exe", CallingConvention:=CallingConvention.Cdecl)> _
Private Shared Function acedInvoke(ByVal rbIn As IntPtr, <Out> ByRef rbOut As IntPtr) As Integer
End Function
Public Shared Function Invoke(ByVal rbIn As ResultBuffer) As ResultBuffer
Dim pRb As IntPtr = IntPtr.Zero
Commands.acedInvoke(rbIn.UnmanagedObject, pRb)
Return TryCast(DisposableWrapper.Create(GetType(ResultBuffer), pRb, True),ResultBuffer)
End Function
<CommandMethod("doit")> _
Public Shared Sub MyCommand()
Dim rbOut As New ResultBuffer
rbOut.Add(New TypedValue(5005, "thisisatest"))
rbOut.Add(New TypedValue(5016))
rbOut.Add(New TypedValue(5010, 1))
rbOut.Add(New TypedValue(5010, 2))
rbOut.Add(New TypedValue(5010, 3))
rbOut.Add(New TypedValue(5010, 4))
rbOut.Add(New TypedValue(5017))
New List(Of TypedValue)(Commands.Invoke(rbOut).AsArray).ForEach(Function (ByVal X As TypedValue)
Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(X.Value.ToString)
End Function)
End Sub
End Class
-
Thanks,
I will try to get it working.
Can you tell me about this reflector?
Is ia a separate program?
Is it built in to vs?
Are you using vs or an express version.
Peter
-
It comes as a separate program or as a Visual studio add-on.. all you need is the free stand alone version. see http://www.red-gate.com/products/reflector/
-
Daniel,
I added the Autodesk.AutoCAD.Databaseservices to take care of the lisp data types but I have a problem with the nested function in the doit function.
The program has a syntax error on the New function and having trouble ith
-
Hello Peter,
could that be the difference between
new and New ??
-
No tha didn't do it.
I need to understand several parts of the code shown above.
I guess the first thing is to understand the disposable wrapper for the unmanaged code.
I hope you guys can bear with me, while I ask what seems to be stupid questions.
Also I have vs2005 but it doesn't like being on the sme machine with vb2008 so it doesn't work.
I am trying to use vb2008 to write vb.net code.
I woul like to focus on creating an interface that calls arx functions from vb.net
Hence the question above.
The first part of the cde to understand is.
Public Shared Function Invoke(ByVal rbIn As ResultBuffer) As ResultBuffer
Dim pRb As IntPtr = IntPtr.Zero
Commands.acedInvoke(rbIn.UnmanagedObject, pRb)
Return TryCast(DisposableWrapper.Create(GetType(ResultBuffer), pRb, True),ResultBuffer)
End Function
-
Well I didn't mean to post yet, but to finish the question, do any of you have a good resource that would explain the components of the code above?
Peter
-
Hi Peter,
It's really an advanced topic and there is not a lot of information out there, probably less in VB format as managed wrappers are written in C++/CLI.
A little bit about that block of code, AutoCAD's .NET API is just a wrapper around C++/ARX. Every managed class has an underlying native class I.e. Line is a wrapper around AcDbLine and ResultBuffer wraps resbuf. All the managed reference classes (Heap) derive from a single class called DisposableWrapper, its job is to handle the storage, creation and deletion of underlying native classes. the DisposableWrapper class has a property, UnmanagedObject, which exposes a pointer that you can pass to native functions. DisposableWrapper, has a create method that allows you to build a managed class from a native pointer.
-
Thanks for your help group,
I solved this puzzle yesterday and have the ability to load and run lisp routines from .NET, and not using the sendstringtoexecute or sendcommand methods.
I intend to share the material at AU, if I get my lecture approved.
If anyone is interested, I can tell you the trick.
Best Regards,
Peter
-
What's the trick?
-
Actually I found several methods.
They are acedInvokeLISP entry point, acedEvaluateLISP entry point and the VL16.tlb method
(the last of which according to TonyT has bugs when called repeatedly in a loop)
Peter
-
Yep, I went through all those, it's a transition phase that lispers go though :laugh:
-
I have several others too, and multiple variations on some of them.
I found a lot of other cool things that I am still working on.
Does .NET have a function for (vlax-product-key)?
Peter
-
Hi,
I don't know any equivalent to (vlax-product-key), but it's quite easy to build
private string GetProductKey()
{
string result = "HKEY_CURRENT_USER\\Software\\Autodesk\\AutoCAD\\";
result += (string)Registry.GetValue(result, "CurVer", "");
return result + "\\" + (string)Registry.GetValue(result, "CurVer", "");
}
-
HostApplicationServices.Current.RegistryProductRootKey
-
acedEvaluateLISP arx entry point example
Peter
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Runtime
Imports System.Runtime.InteropServices 'for DllImport()
Imports System.Security
Public Class vbvlClass
' Use P/Invoke for acedEvaluateLISP
<System.Security.SuppressUnmanagedCodeSecurity(), DllImport("acad.exe", _
CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Cdecl, EntryPoint:="?acedEvaluateLisp@@YAHPB_WAAPAUresbuf@@@Z")> _
Private Shared Function acedEvaluateLISP(ByVal strLISPExpression As String, ByRef intHandle As IntPtr) As Integer
End Function
'______________________________________________________________________________________________________________________
'
' Overload of the EvaluateLISPExpression function to accept ResultBuffer as Argument
'______________________________________________________________________________________________________________________
<LispFunction("EvaluateLisp")> _
Public Shared Function EvaluateLispExpression(ByVal rbfLISPExpression As ResultBuffer) As ResultBuffer
Dim rbfReturn As New ResultBuffer
Dim arrLispExpression As TypedValue() = rbfLISPExpression.AsArray
Return EvaluateLispExpression(arrLispExpression(0).Value.ToString)
End Function
Public Shared Function EvaluateLispExpression(ByVal strLISPExpression As String) As ResultBuffer
Dim rbfObject As IntPtr = IntPtr.Zero
Dim rbfReturn As New ResultBuffer
Try
acedEvaluateLISP(strLISPExpression, rbfObject)
If (rbfObject <> IntPtr.Zero) Then
rbfReturn = CType(DisposableWrapper.Create(GetType(ResultBuffer), rbfObject, True), ResultBuffer)
Return rbfReturn
Else
rbfReturn.Add(New TypedValue(&H138D, "Error"))
End If
Catch ex As System.Exception
rbfReturn.Add(New TypedValue(&H138D, "Catch Error"))
Return rbfReturn
End Try
Return Nothing
End Function
End Class
-
instead of returning "Catch Error" you ought to return ex.messsage
it will give the user an idea what went wrong
-
OK