September 2014

Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30        








« Metaprogramming with AutoCAD - Part 2 | Main | Leaving Las Vegas »

November 26, 2007

Metaprogramming with AutoCAD - Part 3

In parts 1 & 2 of this series we looked at metaprogramming with AutoCAD using AutoLISP and VB(A), and then using VB.NET and C#.

In this post we're going to look at what's possible from F#, through the lens of my relative inexperience with the language, of course.

The quotations mechanism in F# appears to be the way to represent, analyse and execute program structure. This article describes the concepts, although it's quite deep and doesn't address the case that's most immediately interesting to AutoCAD develeopers: the ability to evaluate and execute code represented as a string. In fact, this doesn't yet appear to be part of the F# language, according to this thread, which helped me formulate the below F# version of the code I showed in my last post.

I would like to see a Microsoft.FSharp.FSharpCodeProvider class allowing execution of F# code provided as a string. I don't know whether the plan is to provide this - or something like it - but I can certainly see it being of use.

What we can do today is execute C# and VB.NET code, just as we did in the previous post, but this time the generation language is F#. The C# and VB.NET code we create is heterogeneous from the perspective of F#, of course.

Here's the F# code:

#light


module MyNamespace.MyApplication


// Import managed assemblies


#I @"C:\Program Files\Autodesk\AutoCAD 2008"


#r "acdbmgd.dll"

#r "acmgd.dll"


open System

open System.CodeDom.Compiler

open System.Reflection;

open Microsoft.VisualBasic;

open Microsoft.CSharp;

open Autodesk.AutoCAD.Runtime

open Autodesk.AutoCAD.ApplicationServices

open Autodesk.AutoCAD.DatabaseServices


let acadFolder =

  "c:\\Program Files\\Autodesk\\AutoCAD 2008\\"


let CompileVBExpression (expression:string) =

    let source =

        "Imports System\n" ^

        "Imports Autodesk.AutoCAD.Runtime\n" ^

        "Imports Autodesk.AutoCAD.ApplicationServices\n" ^

        "Imports Autodesk.AutoCAD.DatabaseServices\n" ^

        "Imports Autodesk.AutoCAD.EditorInput\n" ^

        "Imports Autodesk.AutoCAD.Geometry\n" ^

        "Namespace VBCodeEval\n" ^

        "Public Class VBCodeEval\n" ^

        "Public Function EvalCode() As Object\n" ^

        "Return " ^ expression ^ "\n" ^

        "End Function\n" ^

        "End Class\n" ^

        "End Namespace"


    let provider = new VBCodeProvider()

    let parameters = new CompilerParameters()

    ignore

      (parameters.ReferencedAssemblies.Add

        ("system.dll"))

    ignore

      (parameters.ReferencedAssemblies.Add

        (acadFolder ^ "acdbmgd.dll"))

    ignore

      (parameters.ReferencedAssemblies.Add

        (acadFolder ^ "acmgd.dll"))

    parameters.CompilerOptions <- "/t:library"

    parameters.GenerateInMemory <- true

    provider.CompileAssemblyFromSource(parameters, [|source|])


let RunVBCode (expression:string) =

    let results = CompileVBExpression expression

    if not results.Errors.HasErrors then

        let a = results.CompiledAssembly

        let o = a.CreateInstance("VBCodeEval.VBCodeEval")

        let t = o.GetType()

        let mi = t.GetMethod("EvalCode")

        mi.Invoke(o, null)

    else

        null


let CompileCSExpression (expression:string) =

    let source =

        "using System;\n" ^

        "using Autodesk.AutoCAD.Runtime;\n" ^

        "using Autodesk.AutoCAD.ApplicationServices;\n" ^

        "using Autodesk.AutoCAD.DatabaseServices;\n" ^

        "using Autodesk.AutoCAD.EditorInput;\n" ^

        "using Autodesk.AutoCAD.Geometry;\n" ^

        "namespace CSCodeEval{\n" ^

        "public class CSCodeEval{\n" ^

        "public object EvalCode(){\n" ^

        "return " ^ expression ^ ";\n" ^

        "}\n" ^

        "}\n" ^

        "}"


    let provider = new CSharpCodeProvider();

    let parameters = new CompilerParameters();

    ignore

      (parameters.ReferencedAssemblies.Add

        ("system.dll"))

    ignore

      (parameters.ReferencedAssemblies.Add

        (acadFolder ^ "acdbmgd.dll"))

    ignore

      (parameters.ReferencedAssemblies.Add

        (acadFolder ^ "acmgd.dll"))

    parameters.CompilerOptions <- "/t:library"

    parameters.GenerateInMemory <- true

    provider.CompileAssemblyFromSource(parameters, [|source|])


let RunCSCode (expression:string) =

    let results = CompileCSExpression expression

    if not results.Errors.HasErrors then

        let a = results.CompiledAssembly

        let o = a.CreateInstance("CSCodeEval.CSCodeEval")

        let t = o.GetType()

        let mi = t.GetMethod("EvalCode")

        mi.Invoke(o, null)

    else

        null


[<CommandMethod("ev")>]

let evaluate () =


  let csCode =

    "typeof(Autodesk.AutoCAD." ^

    "ApplicationServices.Application)"


  let vbCode =

    "GetType(Autodesk.AutoCAD." ^

    "ApplicationServices.Application)"


  let ed =

    Autodesk.AutoCAD.ApplicationServices.

      Application.DocumentManager.

        MdiActiveDocument.Editor;


  ed.WriteMessage("\nEvaluating C# code:\n" ^ csCode);


  let csRes = RunCSCode csCode


  if csRes != null then

    ed.WriteMessage("\nC# code returned: " ^ csRes.ToString());


  ed.WriteMessage("\nEvaluating VB code:\n" ^ vbCode);


  let vbRes = RunVBCode vbCode


  if vbRes != null then

    ed.WriteMessage("\nVB code returned: " ^ vbRes.ToString()); 

And when we run the "ev" command, we see the same results as with the VB.NET and C# implementation in the last post:

Command: ev

Evaluating C# code:

typeof(Autodesk.AutoCAD.ApplicationServices.Application)

C# code returned: Autodesk.AutoCAD.ApplicationServices.Application

Evaluating VB code:

GetType(Autodesk.AutoCAD.ApplicationServices.Application)

VB code returned: Autodesk.AutoCAD.ApplicationServices.Application

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83452464869e200e54f8b8fa28833

Listed below are links to weblogs that reference Metaprogramming with AutoCAD - Part 3:

» Through the Interface: Metaprogramming with AutoCAD - Part 3 from CadKicks.com
You've been kicked (a good thing) - Trackback from CadKicks.com [Read More]

blog comments powered by Disqus

Feed/Share

10 Random Posts