Aller au contenu

Liaison LISP/.NET


GEGEMATIC

Messages recommandés

Bonjour,

Gile avait déjà expliqué pas mal de choses dans un sujet vieux de 2 ans, mais on ne trouve rien de bien en forme sur le Web

 

Pour faire une petite synthèse, en VB (nul n'est parfait)

Voici ce que j'ai mis dans le fichier AcadExtensions.vb

Il y a des auteurs crédités, mais je ne sais pas vraiment si ils sont les seuls à avoir participé:

'Classe pour évaluation lisp dans .net
'ajoutée le 20/09/2012
'http://www.theswamp.org/index.php?topic=35714.0

'LispDataType
'None           5000
'Double         5001
'Point2d        5002
'Int16          5003
'Angle          5004
'Text           5005
'ObjectId       5006
'SelectionSet   5007
'Orientation    5008
'Point3d        5009
'Int32          5010
'Void           5014
'ListBegin      5016
'ListEnd        5017
'DottedPair     5018
'Nil            5019
'T_atom (T)     5021

'PromptStatus
'None           5000
'Modeless       5027
'Other          5028
'OK             5100
'Keyword        -5005
'Cancel         -5002
'Error          -5001

Imports System.Runtime.InteropServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput

Namespace AcadExtensions
   ' Credits to Tony Tanzillo, Alexander Rivilis, Kerry Brown...

   ''' <summary>
   ''' Provides methods to comunicate with AutoLISP.
   ''' </summary>
   Public Class LispExtensions
       <System.Security.SuppressUnmanagedCodeSecurity()> _
       <DllImport("acad.exe", EntryPoint:="acedInvoke", _
       CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Cdecl)> _
       Private Shared Function acedInvoke(ByVal args As IntPtr, ByRef result As IntPtr) As Integer
       End Function

       ''' <summary>
       ''' Invoke a LISP function.
       ''' The LISP function must be defined as an external subroutine using the c: prefix or invoking vl-acad-defun.
       ''' This is no more mandatory since A2011 as the managed Application.Invoke() method wraps acedInvoke.
       ''' </summary>
       ''' <param name="args">The function name (string) following by the function arguments.</param>
       ''' <returns>The LISP function return value or null if failed.</returns>
       Public Shared Function InvokeLisp(ByVal args As ResultBuffer) As ResultBuffer
           Dim ip As IntPtr = IntPtr.Zero
           Dim status As Integer = acedInvoke(args.UnmanagedObject, ip)
           If status = CInt(PromptStatus.OK) AndAlso ip <> IntPtr.Zero Then
               Return ResultBuffer.Create(ip, True)
           End If
           Return Nothing
       End Function

       <System.Security.SuppressUnmanagedCodeSecurity()> _
       <DllImport("acad.exe", EntryPoint:="acedPutSym", _
       CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Cdecl)> _
       Private Shared Function acedPutSym(ByVal args As String, ByVal result As IntPtr) As Integer
       End Function

       ''' <summary>
       ''' Set a LISP variable value.
       ''' </summary>
       ''' <param name="name">The variable name.</param>
       ''' <param name="rb">The variable value</param>
       Public Shared Sub SetLispSym(ByVal name As String, ByVal rb As ResultBuffer)
           acedPutSym(name, rb.UnmanagedObject)
       End Sub

       <System.Security.SuppressUnmanagedCodeSecurity()> _
       <DllImport("acad.exe", EntryPoint:="acedGetSym", _
       CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.Cdecl)> _
       Private Shared Function acedGetSym(ByVal args As String, ByRef result As IntPtr) As Integer
       End Function

       ''' <summary>
       ''' Get a LISP variable value.
       ''' </summary>
       ''' <param name="name">The variable name.</param>
       ''' <returns>The variable value or null if failed.</returns>
       Public Shared Function GetLispSym(ByVal name As String) As ResultBuffer
           Dim ip As IntPtr = IntPtr.Zero
           Dim status As Integer = acedGetSym(name, ip)
           If status = CInt(PromptStatus.OK) AndAlso ip <> IntPtr.Zero Then
               Return ResultBuffer.Create(ip, True)
           End If
           Return Nothing
       End Function
   End Class
End Namespace

 

Puis voici ce que j'ai mis dans une classe de commande autocad :

Vous pourrez donc tester quelques exemples réalisés à partir des exemples de Gile.

 

(ne vous étonnez pas des commentaires naifs de mon cru que l'on trouve dans le code: Je note bêtement tout ce que je remarque et que je ne comprends pas ...)

 

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
'necessaire quand est dans un autre module :
'Imports AcadExtensions

'lorsque qu'une autre classe de commands est présente dans  le projet, il faut désactiver sa compilation pour que les 
'CommandMethod fonctionnent



Namespace LispVbsample

   Public Class Commands

       <CommandMethod("EvalCustomLisp")> _
       Public Sub EvalCustomLisp()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor

           ' create a result buffer containing a LISP list
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.ListBegin)),
               New TypedValue(CInt(LispDataType.Int16), 12),
               New TypedValue(CInt(LispDataType.Text), "toto"),
               New TypedValue(CInt(LispDataType.T_atom)),
               New TypedValue(CInt(LispDataType.ListEnd)))

           ' bind the list to a 'lst1' LISP variable
           AcadExtensions.LispExtensions.SetLispSym("lst1", input)

           ' call the 'foo' Lisp function which binds the reversed list to 'lst2'
           ' (defun foo () (setq lst2 (reverse lst1))) (vl-acad-defun 'foo)
           AcadExtensions.LispExtensions.InvokeLisp(New ResultBuffer(New TypedValue(CInt(LispDataType.Text), "foo")))

           ' get the 'lst2' variable value
           Dim output As ResultBuffer = AcadExtensions.LispExtensions.GetLispSym("lst2")

           ' print the value to the commande line
           For Each tv As TypedValue In output
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
       End Sub

       <CommandMethod("EvalCustomLispWithArg")> _
       Public Sub EvalCustomLispWithArg()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor

           ' create a result buffer containing a LISP expression containing a function call, with a single list argument  
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "fooArg"),
               New TypedValue(CInt(LispDataType.ListBegin)),
               New TypedValue(CInt(LispDataType.Int16), 12),
               New TypedValue(CInt(LispDataType.Text), "toto"),
               New TypedValue(CInt(LispDataType.T_atom)),
               New TypedValue(CInt(LispDataType.ListEnd)))

           'à ce stade, input ressemble à ça: 
           ' "fooArg" '( 12 "toto" 'T)
           'On note que les parenthèses de l'évaluation de la fonction ne sont pas nécessaires, mais celles de la liste d'arguments le sont
           'si la fonction accepte plusieurs arguments, pas de parenthèses !
          

           'copier coller suivant dans fenetre texte autocad pour définition fooarg :
           ' (defun fooArg ( lst1 ) (setq lst2 (reverse lst1))) (vl-acad-defun 'fooArg)

           ' call the 'fooArg' Lisp function which binds the reversed list to 'lst2'
           AcadExtensions.LispExtensions.InvokeLisp(input)

           ' get the 'lst2' variable value
           Dim output As ResultBuffer = AcadExtensions.LispExtensions.GetLispSym("lst2")

           ' print the value to the commande line
           For Each tv As TypedValue In output
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
       End Sub

       <CommandMethod("EvalAutoLispWithArg")> _
       Public Sub EvalAutoLispWithArg()

           
           ' create a result buffer containing a LISP list
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "Alert"),
               New TypedValue(CInt(LispDataType.Text), "toto a zéro"))

           'copier coller suivant dans fenetre texte autocad pour définition commande autolisp "alert"
           '(vl-acad-defun 'alert)

           ' call the 'fooArg' Lisp function which binds the reversed list to 'lst2'
           AcadExtensions.LispExtensions.InvokeLisp(input)

       End Sub
       'conclusion: on peut tout faire avec le lisp
       'contrainte : définir chaque commande lisp appelée par .Net avec un vl-acad-defun (pas besoin de c:)
       'même les commandes autolisp natives ont besoin de ce vl-acad-defun !
       'donc il vaut mieux bien organiser son code lisp pour grouper les intéractions avec .net


   End Class
End Namespace

----------------------------------------------------------------------

Site: https://www.g-eaux.fr

Blog: http://g-eaux.over-blog.com

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

Pour les version 2011 et ultérieures, il existe une méthode "gérée" (managed) qui permet d'éviter le P/Invoke de la méthode non gérée acedInvoke() : Application.Invoke() qui a pour signature :

 

C#

public static unsafe ResultBuffer Invoke(ResultBuffer args);

 

VB

Public static unsafe Function Invoke(args As ResultBuffer) As ResultBuffer

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
ADSK_Expert_Elite_Icon_S_Color_Blk_125.png

Lien vers le commentaire
Partager sur d’autres sites

Salut,

donc pour être clair, on peut remplacer InvokeLisp par

        
Public Shared Function InvokeLispManaged(ByVal args As ResultBuffer) As ResultBuffer
            Return Autodesk.AutoCAD.ApplicationServices.Application.Invoke(args)
       End Function

et pour tester :

<CommandMethod("EvalCustomLisp")> _
       Public Sub EvalCustomLisp()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor

           ' create a result buffer containing a LISP list
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.ListBegin)),
               New TypedValue(CInt(LispDataType.Int16), 12),
               New TypedValue(CInt(LispDataType.Text), "toto"),
               New TypedValue(CInt(LispDataType.T_atom)),
               New TypedValue(CInt(LispDataType.ListEnd)))

           ' bind the list to a 'lst1' LISP variable
           AcadExtensions.LispExtensions.SetLispSym("lst1", input)

           ' call the 'foo' Lisp function which binds the reversed list to 'lst2'
           ' (defun foo () (setq lst2 (reverse lst1))) (vl-acad-defun 'foo)
           AcadExtensions.LispExtensions.InvokeLisp(New ResultBuffer(New TypedValue(CInt(LispDataType.Text), "foo")))
           'suivant en managé:
           Dim retour As ResultBuffer
           retour = AcadExtensions.LispExtensions.InvokeLispManaged(New ResultBuffer(New TypedValue(CInt(LispDataType.Text), "foo")))
           ' print the value to the commande line
           ed.WriteMessage(vbLf & "Retour fonction:")
           For Each tv As TypedValue In retour
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
           ed.WriteMessage(vbLf & "Lst2:")
           ' get the 'lst2' variable value
           Dim output As ResultBuffer = AcadExtensions.LispExtensions.GetLispSym("lst2")

           ' print the value to the commande line
           For Each tv As TypedValue In output
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
       End Sub

Par contre, dans la mesure où il n'existe pas de methode putlisp ou getlisp, je pense qu'il faudrait les implémenter à partir de Invoke(), puisqu'on peut faire un invoke de la fonction (eval (read "mysym"))

----------------------------------------------------------------------

Site: https://www.g-eaux.fr

Blog: http://g-eaux.over-blog.com

Lien vers le commentaire
Partager sur d’autres sites

Donc voila la même chose en utilisant invoke()

J'ai ajouté une astuce pour s'affranchir du vl-acad-defun de tout ce que l'on va évaluer par .Net, le recours à eval

Donc dans mon AcadExtension.vb

 

'Classe pour évaluation lisp dans .net
'ajoutée le 20/09/2012
'http://www.theswamp.org/index.php?topic=35714.0

'LispDataType
'None           5000
'Double         5001
'Point2d        5002
'Int16          5003
'Angle          5004
'Text           5005
'ObjectId       5006
'SelectionSet   5007
'Orientation    5008
'Point3d        5009
'Int32          5010
'Void           5014
'ListBegin      5016
'ListEnd        5017
'DottedPair     5018
'Nil            5019
'T_atom (T)     5021

'PromptStatus
'None           5000
'Modeless       5027
'Other          5028
'OK             5100
'Keyword        -5005
'Cancel         -5002
'Error          -5001

Imports System.Runtime.InteropServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime

Namespace AcadExtensions


   ' Credits to Tony Tanzillo, Alexander Rivilis, Kerry Brown...

   ''' <summary>
   ''' Provides methods to comunicate with AutoLISP.
   ''' </summary>
   Public Class LispExtensions



       

       ''' <summary>
       ''' Invoke a LISP function using managed invoke() method.
       ''' The LISP function must be defined as an external subroutine using the c: prefix or invoking vl-acad-defun.
       ''' This is no more mandatory since A2011 as the managed Application.Invoke() method wraps acedInvoke.
       ''' </summary>
       ''' <param name="args">The function name (string) following by the function arguments.</param>
       ''' <returns>The LISP function return value or null if failed.</returns>
       Public Shared Function InvokeLispManaged(ByVal args As ResultBuffer) As ResultBuffer
           Return Autodesk.AutoCAD.ApplicationServices.Application.Invoke(args)
       End Function



       'accompagner cette commande la commande lisp suivante:
       '(defun ManagedGetLispSym ( strSym ) (eval (read strSym)))(vl-acad-defun 'ManagedGetLispSym)
       'par commodité, on peut la créer automatiquement au chargement
       Public Shared Function ManagedGetLispSym(ByVal name As String) As ResultBuffer
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "ManagedGetLispSym"),
               New TypedValue(CInt(LispDataType.Text), name))

           'à ce stade, input ressemble à ça: 
           ' "ManagedGetLispSym" "name"

           Return AcadExtensions.LispExtensions.InvokeLispManaged(input)

       End Function

       'accompagner cette commande la commande lisp suivante:
       '(defun ManagedPutLispSym ( strSym RsbValue) (set (read strSym) RsbValue))(vl-acad-defun 'ManagedPutLispSym)
       ''' <summary>
       ''' Set a LISP variable value using managed invoke().
       ''' </summary>
       ''' <param name="name">The variable name.</param>
       ''' <param name="rb">The variable value</param>
       Public Shared Function ManagedPutLispSym(ByVal name As String, ByVal rb As ResultBuffer)
           GetEditor.WriteMessage(vbLf & "Entrée ManagedPutLispSym:")
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "ManagedPutLispSym"),
               New TypedValue(CInt(LispDataType.Text), name)
              )
           'GetEditor.WriteMessage(vbLf & "Input")
           'For Each tv As TypedValue In input
           'GetEditor.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           'Next
           'GetEditor.WriteMessage(vbLf & "Input + rb")
           'rb.UnmanagedObject
           For Each val As TypedValue In rb
               input.Add(val)
           Next

           'à ce stade, input ressemble à ça: 
           ' "ManagedPutLispSym" "name" rbvalue
           'For Each tv As TypedValue In input
           'GetEditor.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           'Next
           Return AcadExtensions.LispExtensions.InvokeLispManaged(input)
           ' print the value to the commande line


       End Function

       'Ajoute les parenthèses à un resultBuffer représentant une liste
       'utile  si on veut réutiliser un retour de fonction lisp comme arguments d'une autre fonction lisp
       Public Shared Function AddParenthesisToresultBuffer(ByVal rb As ResultBuffer) As ResultBuffer
           Dim tv() As TypedValue = rb.AsArray
           If (1 < UBound(tv, 1)) Then
               If Not (tv(0).TypeCode = 5016) Then

                   GetEditor.WriteMessage(vbLf & "Liste sans parenthèses")
                   Dim input As New ResultBuffer(
                       New TypedValue(CInt(LispDataType.ListBegin))
                      )

                   'Ajoute les valeurs
                   For Each val As TypedValue In rb
                       input.Add(val)
                   Next
                   input.Add(New TypedValue(CInt(LispDataType.ListEnd)))
                   Return input

               Else
                   Return rb
               End If
           Else
               Return rb
           End If

       End Function

   End Class
End Namespace

Et dans mon LispSample.vb :

 

Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
'necessaire quand est dans un autre module :
'Imports AcadExtensions

'lorsque qu'une autre classe de commands est présente dans  le projet, il faut désactiver sa compilation pour que les 
'CommandMethod fonctionnent



Namespace LispVbsample

   Public Class Commands

       Implements IExtensionApplication



       Private ObjectData As System.Data.DataTable

       Public Sub AddDocColEventCreated()
           AddHandler Application.DocumentManager.DocumentCreated, _
           AddressOf InitialiseLispExtension
           GetEditor().WriteMessage(vbNewLine & "Initialisation des exemples lisp par evenement")
       End Sub
       Private Sub InitialiseLispExtension()
           GetEditor().WriteMessage(vbNewLine & "Création des routines lisp utiles à AcadExtension par evenement sur la création de document ")
           Dim doc As Autodesk.AutoCAD.ApplicationServices.Document
           doc = Application.DocumentManager.MdiActiveDocument
           doc.SendStringToExecute("(defun ManagedGetLispSym ( strSym ) (eval (read strSym)))(vl-acad-defun 'ManagedGetLispSym) ", False, False, False)
           doc.SendStringToExecute("(defun ManagedPutLispSym ( strSym RsbValue) (set (read strSym) RsbValue))(vl-acad-defun 'ManagedPutLispSym) ", False, False, False)
           GetEditor().WriteMessage(vbNewLine & "Routines lisp ManagedGetLispSym ManagedPutLispSym créées ")
       End Sub

       Private Sub Initialize() Implements IExtensionApplication.Initialize
           ' Initialize your plug-in application here
           'ajout de l'evenement pour les prochanis docs
           AddDocColEventCreated()
           InitialiseLispExtension()
          
       End Sub

       Private Sub Terminate() Implements IExtensionApplication.Terminate
           ' Do plug-in application clean up here
       End Sub

       'la seule fonction exemple qui utilise invoke() 
       <CommandMethod("ManagedEvalCustomLisp")> _
       Public Sub ManagedEvalCustomLisp()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor
           Dim retour As ResultBuffer

           ' create a result buffer containing a LISP list
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.ListBegin)),
               New TypedValue(CInt(LispDataType.Int16), 12),
               New TypedValue(CInt(LispDataType.Text), "toto"),
               New TypedValue(CInt(LispDataType.T_atom)),
               New TypedValue(CInt(LispDataType.ListEnd)))

           ' bind the list to a 'lst1' LISP variable
           AcadExtensions.LispExtensions.ManagedPutLispSym("lst1", input)


           ' call the 'foo' Lisp function which binds the reversed list to 'lst2'
           ' (defun foo () (setq lst2 (reverse lst1))) (vl-acad-defun 'foo)

           'Appel lisp en managé:
           retour = AcadExtensions.LispExtensions.InvokeLispManaged(New ResultBuffer(New TypedValue(CInt(LispDataType.Text), "foo")))
           ' print the value to the commande line
           ed.WriteMessage(vbLf & "Retour fonction:")
           For Each tv As TypedValue In retour
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
           ed.WriteMessage(vbLf & "Lst2:")
           ' get the 'lst2' variable value
           Dim output As ResultBuffer = AcadExtensions.LispExtensions.ManagedGetLispSym("lst2")
           ' print the value to the commande line
           For Each tv As TypedValue In output
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
           ed.WriteMessage(vbLf & "Put lisp managé, création de la liste lst4 avec le retour de fonction, !lst4 pour vérification:")
           'ajoute des parenthèses à retour
           retour = AcadExtensions.LispExtensions.AddParenthesisToresultBuffer(retour)
           'version managée putLisp
           AcadExtensions.LispExtensions.ManagedPutLispSym("lst4", retour)
       End Sub

       
       


   End Class
End Namespace

 

A noter la création directe des deux routines lisp ManagedGetLispSym et ManagedPutLispSym, ce qui est bien pratique.

Mais pour tester ManagedEvalCustomLisp, il ne faut pas oublier de définir

(defun foo () (setq lst2 (reverse lst1))) (vl-acad-defun 'foo)

à la ligne de commande.

----------------------------------------------------------------------

Site: https://www.g-eaux.fr

Blog: http://g-eaux.over-blog.com

Lien vers le commentaire
Partager sur d’autres sites

  • 2 mois après...

Salut à tous, et surtout à Krunch, car je m'aperçois que je n'avais jamais posté la version définitive :

A la fin, j'ai mis des fonctions exemples qui te montrent comment évaluer directement une fonction lisp avec des arguments :

EvalCustomLispWithArg

 

elle permet d'évaluer des trucs du genre : (macommandelisp '(avec une liste) "etunechaine")

 

exemple d'utilisation directement à la ligne de commande :

Commande: EVALLISPEXPRESSION

Expression lisp à évaluer (avec les parenthèses) ?: (alert "coucou")

nil

 

Retour expression évaluée :

Type: 5019 Value:

 

 

Le code :

dans LispToNetExtension.vb

'Classe pour évaluation lisp dans .net
'ajoutée le 20/09/2012
'http://www.theswamp.org/index.php?topic=35714.0

'LispDataType
'None           5000
'Double         5001
'Point2d        5002
'Int16          5003
'Angle          5004
'Text           5005
'ObjectId       5006
'SelectionSet   5007
'Orientation    5008
'Point3d        5009
'Int32          5010
'Void           5014
'ListBegin      5016
'ListEnd        5017
'DottedPair     5018
'Nil            5019
'T_atom (T)     5021

'PromptStatus
'None           5000
'Modeless       5027
'Other          5028
'OK             5100
'Keyword        -5005
'Cancel         -5002
'Error          -5001



Imports System.Runtime.InteropServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices

Namespace AcadExtensions


   ' Credits to Gile chanteau, Tony Tanzillo, Alexander Rivilis, Kerry Brown...

   ''' <summary>
   ''' Provides methods to comunicate with AutoLISP.
   ''' </summary>
   Public Class LispExtensions

       Dim ed


       ''' <summary>
       ''' Invoke a LISP function using managed invoke() method.
       ''' The LISP function must be defined as an external subroutine using the c: prefix or invoking vl-acad-defun.
       ''' Obsolète :
       ''' Lui préférer ManagedEvalStrLispExpression, qui est plus commed, car elle permet d'évaluer des fonctions qui
       ''' ne sont pas vl-acad-defun ou c:
       ''' </summary>
       ''' <param name="args">The function name (string) following by the function arguments.</param>
       ''' <returns>The LISP function return value or null if failed.</returns>
       Public Shared Function InvokeLispManaged(ByVal args As ResultBuffer) As ResultBuffer
           Return Autodesk.AutoCAD.ApplicationServices.Application.Invoke(args)
       End Function

       'accompagner cette commande la commande lisp suivante:
       '(defun ManagedEvalStrLispExpression ( strLspExp ) (eval (read strLspExp)))(vl-acad-defun 'ManagedEvalStrLispExpression)
       'par commodité, on peut la créer automatiquemen au chargement
       Public Shared Function ManagedEvalStrLispExpression(ByVal exp As String) As ResultBuffer
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "ManagedEvalStrLispExpression"),
               New TypedValue(CInt(LispDataType.Text), exp))

           'à ce stade, input ressemble à ça: 
           ' "ManagedEvalStrLispExpression" "(myLispExpression arg1 arg2 ... argn)"

           Return AcadExtensions.LispExtensions.InvokeLispManaged(input)

       End Function


       'read a lisp symbol
       'accompagner cette commande la commande lisp suivante:
       '(defun ManagedGetLispSym ( strSym ) (eval (read strSym)))(vl-acad-defun 'ManagedGetLispSym)
       'par commodité, on peut la créer automatiquemen au chargement
       Public Shared Function ManagedGetLispSym(ByVal name As String) As ResultBuffer
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "ManagedGetLispSym"),
               New TypedValue(CInt(LispDataType.Text), name))

           'à ce stade, input ressemble à ça: 
           ' "ManagedGetLispSym" "name"

           Return AcadExtensions.LispExtensions.InvokeLispManaged(input)

       End Function

       'put value to a lisp symbol
       'accompagner cette commande la commande lisp suivante:
       '(defun ManagedPutLispSym ( strSym RsbValue) (set (read strSym) RsbValue))(vl-acad-defun 'ManagedPutLispSym)
       ''' <summary>
       ''' Set a LISP variable value using managed invoke().
       ''' </summary>
       ''' <param name="name">The variable name.</param>
       ''' <param name="rb">The variable value</param>
       Public Shared Function ManagedPutLispSym(ByVal name As String, ByVal rb As ResultBuffer)
           GetEditor.WriteMessage(vbLf & "Entrée ManagedPutLispSym:")
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "ManagedPutLispSym"),
               New TypedValue(CInt(LispDataType.Text), name)
              )
           'GetEditor.WriteMessage(vbLf & "Input")
           'For Each tv As TypedValue In input
           'GetEditor.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           'Next
           'GetEditor.WriteMessage(vbLf & "Input + rb")
           'rb.UnmanagedObject
           For Each val As TypedValue In rb
               input.Add(val)
           Next

           'à ce stade, input ressemble à ça: 
           ' "ManagedPutLispSym" "name" rbvalue
           'For Each tv As TypedValue In input
           'GetEditor.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           'Next
           Return AcadExtensions.LispExtensions.InvokeLispManaged(input)
           ' print the value to the commande line


       End Function

       'Ajoute les parenthèses à un resultBuffer représentant une liste
       'utile  si on veut réutiliser un retour de fonction lisp comme arguments d'une autre fonction lisp
       Public Shared Function AddParenthesisToresultBuffer(ByVal rb As ResultBuffer) As ResultBuffer
           Dim tv() As TypedValue = rb.AsArray
           If (1 < UBound(tv, 1)) Then
               If Not (tv(0).TypeCode = 5016) Then

                   GetEditor.WriteMessage(vbLf & "Liste sans parenthèses")
                   Dim input As New ResultBuffer(
                       New TypedValue(CInt(LispDataType.ListBegin))
                      )

                   'Ajoute les valeurs
                   For Each val As TypedValue In rb
                       input.Add(val)
                   Next
                   input.Add(New TypedValue(CInt(LispDataType.ListEnd)))
                   Return input

               Else
                   Return rb
               End If
           Else
               Return rb
           End If

       End Function

   End Class
End Namespace

 

dans myPlugin.vb

 

Imports System
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput

' This line is not mandatory, but improves loading performances
<Assembly: ExtensionApplication(GetType(AutoCAD_VB_plug_in___lisp1.MyPlugin))> 

Namespace AutoCAD_VB_plug_in___lisp1

   ' This class is instantiated by AutoCAD once and kept alive for the 
   ' duration of the session. If you don't do any one time initialization 
   ' then you should remove this class.
   Public Class MyPlugin
       Implements IExtensionApplication


       Public Sub AddDocColEventCreated()
           AddHandler Application.DocumentManager.DocumentCreated, _
           AddressOf InitialiseLispExtension
           GetEditor().WriteMessage(vbNewLine & "Initialisation des exemples lisp par evenement")
       End Sub

       Private Sub InitialiseLispExtension()
           'Si plusieurs dll  chargées contiennent la classe AcadExtension, chacune recréera ces fonctions lisp:
           'Car pour l'instant, il n'est pas possible de tester l'existance de ces commandes tant qu'elles n'existent pas !
           'sauf en utilisant la comamnde non managée GetLispSym, mais ce n'est pas le but.
           GetEditor().WriteMessage(vbNewLine & "Création des routines lisp utiles à AcadExtension par evenement sur la création de document ")
           Dim doc As Autodesk.AutoCAD.ApplicationServices.Document
           doc = Application.DocumentManager.MdiActiveDocument
           'fonction lisp pour évaluer un symbole lisp, passé sous forme de chaine de carractère, ex : "myvar"
           'est utilisée par la Shared Function ManagedGetLispSym
           doc.SendStringToExecute("(defun ManagedGetLispSym ( strSym ) (eval (read strSym)))(vl-acad-defun 'ManagedGetLispSym) ", False, False, False)
           'fonction lisp pour évaluer une expression lisp, passé sous forme de chaine de carractère,avec les parenthèses ex : "(ManagedGetLispSym \"myvar\")"
           'en réalité, est complètement identique à ManagedGetLispSym, mais permet d'éviter la confusion entre l'évalusatio nd'un symbole et d'une expression
           'est utilisée par la Shared Function ManagedEvalStrLispExpression
           doc.SendStringToExecute("(defun ManagedEvalStrLispExpression ( strLspExp ) (eval (read strLspExp)))(vl-acad-defun 'ManagedEvalStrLispExpression) ", False, False, False)
           'fonction lisp pour affecter une valeur à un symbole lisp passé sous forme de chaine de carractère et d'un resultbuffer, ex : ManagedPutLispSym "myvar" MyRsbvalue
           'est utilisée par la Shared Function ManagedPutLispSym
           doc.SendStringToExecute("(defun ManagedPutLispSym ( strSym RsbValue) (set (read strSym) RsbValue))(vl-acad-defun 'ManagedPutLispSym) ", False, False, False)
           GetEditor().WriteMessage(vbNewLine & "Routines lisp ManagedEvalStrLispExpression, ManagedGetLispSym, ManagedPutLispSym créées ")
       End Sub

       Public Sub Initialize() Implements IExtensionApplication.Initialize
           ' Add one time initialization here
           ' One common scenario is to setup a callback function here that 
           ' unmanaged code can call. 
           ' To do this:
           ' 1. Export a function from unmanaged code that takes a function
           '    pointer and stores the passed in value in a global variable.
           ' 2. Call this exported function in this function passing delegate.
           ' 3. When unmanaged code needs the services of this managed module
           '    you simply call acrxLoadApp() and by the time acrxLoadApp 
           '    returns  global function pointer is initialized to point to
           '    the C# delegate.
           ' For more info see: 
           ' http:'msdn2.microsoft.com/en-US/library/5zwkzwf4(VS.80).aspx
           ' http:'msdn2.microsoft.com/en-us/library/44ey4b32(VS.80).aspx
           ' http:'msdn2.microsoft.com/en-US/library/7esfatk4.aspx
           ' as well as some of the existing AutoCAD managed apps.

           ' Initialize your plug-in application here
           'ajout de l'evenement pour les prochains docs
           AddDocColEventCreated()
           InitialiseLispExtension()

       End Sub

       Public Sub Terminate() Implements IExtensionApplication.Terminate
           ' Do plug-in application clean up here
       End Sub

       'GetEditor est utile pour afficher des messages
       Public Shared Function GetEditor() As Autodesk.AutoCAD.EditorInput.Editor
           GetEditor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor
       End Function

     'fonction exemple qui utilise invoke() 
       <CommandMethod("ManagedEvalCustomLisp")> _
       Public Sub ManagedEvalCustomLisp()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor
           Dim retour As ResultBuffer

           ' create a result buffer containing a LISP list
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.ListBegin)),
               New TypedValue(CInt(LispDataType.Int16), 12),
               New TypedValue(CInt(LispDataType.Text), "toto"),
               New TypedValue(CInt(LispDataType.T_atom)),
               New TypedValue(CInt(LispDataType.ListEnd)))

           ' bind the list to a 'lst1' LISP variable
           AcadExtensions.LispExtensions.ManagedPutLispSym("lst1", input)


           ' call the 'foo' Lisp function which binds the reversed list to 'lst2'
           ' (defun foo () (setq lst2 (reverse lst1))) (vl-acad-defun 'foo)

           'Appel lisp en managé:
           retour = AcadExtensions.LispExtensions.InvokeLispManaged(New ResultBuffer(New TypedValue(CInt(LispDataType.Text), "foo")))
           ' print the value to the commande line
           ed.WriteMessage(vbLf & "Retour fonction:")
           For Each tv As TypedValue In retour
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
           ed.WriteMessage(vbLf & "Lst2:")
           ' get the 'lst2' variable value
           Dim output As ResultBuffer = AcadExtensions.LispExtensions.ManagedGetLispSym("lst2")
           ' print the value to the commande line
           For Each tv As TypedValue In output
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
           ed.WriteMessage(vbLf & "Put lisp managé, création de la liste lst4 avec le retour de fonction, !lst4 pour vérification:")
           'ajoute des parenthèses à retour
           retour = AcadExtensions.LispExtensions.AddParenthesisToresultBuffer(retour)
           'version managée putLisp
           AcadExtensions.LispExtensions.ManagedPutLispSym("lst4", retour)
       End Sub

   

       'fonction exemple qui utilise invoke(), l'expression lisp est directement entrée à la ligne de commande Autocad
       'exemple : evaluer "(Prompt \"\nCoucou\")"
       <CommandMethod("EvalLispExpression")> _
       Public Sub EvalLispExpression()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor
           Dim retour As ResultBuffer
           Dim strEval As String = ed.GetString("Expression lisp à évaluer (avec les parenthèses) ?").StringResult

           'Appel lisp en managé:
           retour = AcadExtensions.LispExtensions.ManagedEvalStrLispExpression(strEval)
           ' print the value to the commande line
           ed.WriteMessage(vbLf & "Retour expression évaluée :")
           For Each tv As TypedValue In retour
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
           
       End Sub

       'fonction exemple qui utilise invoke(), le nom de la variable lisp est directement entrée à la ligne de commande Autocad
       'exemple : evaluer "myVar"
       <CommandMethod("EvalLispSymbole")> _
       Public Sub EvalLispSymbole()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor
           Dim strEval As String = ed.GetString("Nom de la variable lisp à évaluer ?").StringResult

           
           ed.WriteMessage(vbLf & "ManagedGetLispSym " & strEval & " :")
           ' get the 'lst2' variable value
           Dim output As ResultBuffer = AcadExtensions.LispExtensions.ManagedGetLispSym(strEval)
           ' print the value to the commande line
           ed.WriteMessage(vbLf & "Value of  the lisp symbol '" & strEval & " as resultBuffer :")
           For Each tv As TypedValue In output
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
           ed.WriteMessage(vbLf & "Put lisp managé, création de la liste lst avec le retour d'évaluation , !lst pour vérification que lst = " & strEval & " :")
           'ajoute des parenthèses à retour
           output = AcadExtensions.LispExtensions.AddParenthesisToresultBuffer(output)
           'version managée putLisp
           AcadExtensions.LispExtensions.ManagedPutLispSym("lst", output)
       End Sub


       'Exemples suivants, évaluation  lisp en code non managé aced (obsolete)
       <CommandMethod("EvalCustomLisp")> _
       Public Sub EvalCustomLisp()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor

           ' create a result buffer containing a LISP list
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.ListBegin)),
               New TypedValue(CInt(LispDataType.Int16), 12),
               New TypedValue(CInt(LispDataType.Text), "toto"),
               New TypedValue(CInt(LispDataType.T_atom)),
               New TypedValue(CInt(LispDataType.ListEnd)))

           ' bind the list to a 'lst1' LISP variable
           AcadExtensions.LispExtensions.SetLispSym("lst1", input)


           ' call the 'foo' Lisp function which binds the reversed list to 'lst2'
           ' (defun foo () (setq lst2 (reverse lst1))) (vl-acad-defun 'foo)
           AcadExtensions.LispExtensions.InvokeLisp(New ResultBuffer(New TypedValue(CInt(LispDataType.Text), "foo")))

           ed.WriteMessage(vbLf & "Lst2:")
           ' get the 'lst2' variable value
           Dim output As ResultBuffer = AcadExtensions.LispExtensions.GetLispSym("lst2")

           ' print the value to the commande line
           For Each tv As TypedValue In output
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next

       End Sub

       <CommandMethod("EvalCustomLispWithArg")> _
       Public Sub EvalCustomLispWithArg()
           Dim doc As Document = Application.DocumentManager.MdiActiveDocument
           Dim ed As Editor = doc.Editor

           ' create a result buffer containing a LISP expression containing a function call, with a single list argument  
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "fooArg"),
               New TypedValue(CInt(LispDataType.ListBegin)),
               New TypedValue(CInt(LispDataType.Int16), 12),
               New TypedValue(CInt(LispDataType.Text), "toto"),
               New TypedValue(CInt(LispDataType.T_atom)),
               New TypedValue(CInt(LispDataType.ListEnd)))

           'à ce stade, input ressemble à ça: 
           ' "fooArg" '( 12 "toto" 'T)
           'On note que les parenthèses de l'évaluation de la fonction ne sont pas nécessaires, mais celles de la liste d'arguments le sont
           'si la fonction accepte plusieurs arguments, pas de parenthèses !


           'copier coller suivant dans fenetre texte autocad pour définition fooarg :
           ' (defun fooArg ( lst1 ) (setq lst2 (reverse lst1))) (vl-acad-defun 'fooArg)

           ' call the 'fooArg' Lisp function which binds the reversed list to 'lst2'
           AcadExtensions.LispExtensions.InvokeLisp(input)

           ' get the 'lst2' variable value
           Dim output As ResultBuffer = AcadExtensions.LispExtensions.GetLispSym("lst2")

           ' print the value to the commande line
           For Each tv As TypedValue In output
               ed.WriteMessage(vbLf & "Type: {0}" & vbTab & "Value: {1}", tv.TypeCode, tv.Value)
           Next
       End Sub

       <CommandMethod("EvalAutoLispWithArg")> _
       Public Sub EvalAutoLispWithArg()


           ' create a result buffer containing a LISP list
           Dim input As New ResultBuffer(
               New TypedValue(CInt(LispDataType.Text), "Alert"),
               New TypedValue(CInt(LispDataType.Text), "toto a zéro"))

           'copier coller suivant dans fenetre texte autocad pour définition commande autolisp "alert"
           '(vl-acad-defun 'alert)

           ' call the 'fooArg' Lisp function which binds the reversed list to 'lst2'
           AcadExtensions.LispExtensions.InvokeLisp(input)

       End Sub
       'conclusion: on peut tout faire avec le lisp, et on a plus besoin de 
       'définir chaque commande lisp appelée par .Net avec un vl-acad-defun ni besoin de c:


   End Class

End Namespace

----------------------------------------------------------------------

Site: https://www.g-eaux.fr

Blog: http://g-eaux.over-blog.com

Lien vers le commentaire
Partager sur d’autres sites

Ok merci bien

 

Je suis resté sur la version de gile postée ailleurs qui a l'avantage de rester en C# (pour moi c'est déjà suffisamment compliqué comme ça ..) et que je remets ci dessous.

Sur mon 2010 ça marche, à la réserve près qu'un appel de c:function provoque une erreur fatale, je dois utiliser le vl-acad-defun.

 

J'ai vu que ta méthode permets d'éviter le vl-acad-defun, mais sinon pas d'inconvénient a priori ?

 

using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

namespace InvokeLispSample
{
public class Class1
{
   	[system.Security.SuppressUnmanagedCodeSecurity]
   	[DllImport("acad.exe", EntryPoint = "acedInvoke", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
   	extern static private int acedInvoke(IntPtr args, out IntPtr result);

   	/// Invoke a LISP function.
   	/// The LISP function must be defined as an external subroutine using the c: prefix or invoking vl-acad-defun.
   	/// This is no more mandatory since A2011 as the managed Application.Invoke() method wraps acedInvoke.
   	public static ResultBuffer InvokeLisp(ResultBuffer args)
   	{
       	IntPtr ip = IntPtr.Zero;
       	int status = acedInvoke(args.UnmanagedObject, out ip);
       	if (status == (int)PromptStatus.OK && ip != IntPtr.Zero)
           	return ResultBuffer.Create(ip, true);
       	return null;
   	}


   	// Test avec :
   	// (defun foo (l) (mapcar 'strcase l))
   	// (vl-acad-defun 'foo)
   	[CommandMethod("Test")]
   	public void Test()
   	{
       	Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

       	// Argument pour InvokeLisp
       	ResultBuffer resbuf = new ResultBuffer();

       	// Nom de la fonction LISP : foo
       	resbuf.Add(new TypedValue((int)LispDataType.Text, "foo"));

       	// Argument de la fonction LISP : ("test" "invoke" "lisp")
       	resbuf.Add(new TypedValue((int)LispDataType.ListBegin));
       	resbuf.Add(new TypedValue((int)LispDataType.Text, "test"));
       	resbuf.Add(new TypedValue((int)LispDataType.Text, "invoke"));
       	resbuf.Add(new TypedValue((int)LispDataType.Text, "lisp"));
       	resbuf.Add(new TypedValue((int)LispDataType.ListEnd));

       	// Résultat de l'évaluation de (foo '("test" "invoke" "lisp"))
       	ResultBuffer result = InvokeLisp(resbuf);
       	foreach (TypedValue tv in result)
       	{
           	ed.WriteMessage(tv.Value + " ");
       	}
   	}
}
}

Lien vers le commentaire
Partager sur d’autres sites

Non non, ton truc marche je pense.

Mais à l'usage, le vl-acad-defun est très contraignant, car il t'oblige à n'utiliser que des commandes lisp sans arguments.

Ce n'est pas la majorité de mes routines.

Ce qui m'interresse dans la liaison net / lisp, c'est de pouvoir utiliser l'interface net avec des fonctions lisp.

Avec le vl-acad-defun, ce n'étais pas possible pour moi.

Bon courage,

Gégé

----------------------------------------------------------------------

Site: https://www.g-eaux.fr

Blog: http://g-eaux.over-blog.com

Lien vers le commentaire
Partager sur d’autres sites

Mais à l'usage, le vl-acad-defun est très contraignant, car il t'oblige à n'utiliser que des commandes lisp sans arguments.

 

Pas du tout, dans l'exemple donné par krunch, on appelle la fonction foo définie comme telle :

(defun foo (l) (mapcar 'strcase l))
(vl-acad-defun 'foo)

Cette fonction requiert bien un argument : une liste de chaînes, et retourne une autre liste de chaines. Elle est appelée depuis la commande .NET "Test" avec l'argument requis.

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
ADSK_Expert_Elite_Icon_S_Color_Blk_125.png

Lien vers le commentaire
Partager sur d’autres sites

salut,

Autant pour moi, ça date de septembre, je ne me rappelais plus de cette histoire de vl-acad-defun, pourtant j'avais fait des tests avec le même système ...

 

Maintenant, je pense quand même que :

retour = AcadExtensions.LispExtensions.ManagedEvalStrLispExpression("(alert "\"ça marche\")")

c'est vraiment ce qu'il y a de plus simple pour faire communiquer lisp et .net

et je n'ai pas à me soucier de faire un vl-acad-defun pour les milliers de routines dont je dispose.

 

Par contre, je n'ai à peine eu le temps de m'en servir, c'est dommage.

----------------------------------------------------------------------

Site: https://www.g-eaux.fr

Blog: http://g-eaux.over-blog.com

Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité