hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

F# / Excel

Last post 07-24-2006, 1:46 by govert. 1 replies.
Sort Posts: Previous Next
  •  07-22-2006, 7:39 435

    F# / Excel

    This is an example of using F# functions from within Excel through automation add-ins.

    It is a slightly modified F# version of the C# code available from : http://blogs.msdn.com/eric_carter/archive/2004/12/01/273127.aspx

    You need to reference Microsoft.Office.Interop.Excel.dll, through the compiler with, in my case, -r "C:\Program Files\Microsoft Office\Office12\Microsoft.Office.Interop.Excel.dll" or through the code using #r "path\to\my.dll" in the project.

    And you need to register for COM Interop. For C# projects, you can check the checkbox in the Properties. There is (apparently) no such option for F#Projects however. But it can be done by calling :
    C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm "complete_path_to\my.dll"
    (see http://msdn2.microsoft.com/en-us/library/shyb58c9.aspx
    )

    If this doesn't work, make a second call (note the use of /codebase after RegAsm and before the dll) afterwards. It worked for me... : C:\...\RegAsm /codebase "complete_path_to\my.dll"

    Next go to Excel > Add-ins > Automation, and add AutomationAddins.MyFunctions add-in. As in the C# version, I got a dialog about mscoree.dll, but everything nevertheless worked in Excel. 

    For Office 2007 Beta, you have to go through Windows Menu > Excel Options > Add-Ins. In the combobox at the bottom of the page, select Excel Add-ins and go to it.

    ==============

    (* Functions will appear in Excel as namespace.class_type

        Example :
            Namespace : AutomationAddin
            Class : MyFunctions
            Automation add-in : AutomationAddin.MyFunctions

     *)
    namespace AutomationAddin

     

    open System
    open System.Runtime.InteropServices
    open Microsoft.Win32

     

    module Excel = Microsoft.Office.Interop.Excel

     

    module Singleton =
    begin
        let i = ref 0    
        let Count () = incr i ; !i
    end

     


    [< ClassInterface(ClassInterfaceType.AutoDual) ; ComVisible(true) >]
    type MyFunctions =
    class

        new()={}
           


    (* Add-in Registration functions *)   

        static member GetSubKeyName (inType :Type ) =
            @"CLSID\{" + (inType.GUID.ToString()).ToUpper() + @"}\Programmable"

        [<ComRegisterFunctionAttribute>]
        static member RegisterFunction (inType :Type ) =
          Registry.ClassesRoot.CreateSubKey(MyFunctions.GetSubKeyName inType)
       

        [<ComUnregisterFunctionAttribute>]
        static member UnregisterFunction (inType :Type ) =
          Registry.ClassesRoot.DeleteSubKey(MyFunctions.GetSubKeyName inType, false)
       


    (* Usable functions *)   

        member this.GetStars inN =
            let mutable sb = new System.Text.StringBuilder () in
            for i = 1 to inN do
                sb <- sb.Append("*")
            done ;
            sb.ToString ()
           
        member this.ToUpperCase (inString : String) =
            inString.ToUpper()
           
        member this.NumberOfCells (inRange : obj) =
            (inRange :?> Excel.Range).Cells.Count   

        member this.SumRange  (inRange : obj) =
            if inRange <> null then
                let r = inRange :?> Excel.Range in
                let mutable outTotal = 0.0 in
                for i = 1 to r.Rows.Count do
                    for j = 1 to r.Columns.Count do
                        let c = r.Cells.Item(i, j) in
                        outTotal <- outTotal +. Convert.ToDouble ((c:?>Excel.Range).Value2)
                    done
                done ;
                outTotal
            else failwith "ooops"
               
        member this.Area (inRange : obj) =
            let r : Excel.Range = inRange :?> Excel.Range in
            Convert.ToDouble (r.Width) *. Convert.ToDouble (r.Height)
               
        member this.SingletonCounter () = Singleton.Count ()

    end

     

  •  07-24-2006, 1:46 437 in reply to 435

    Re: F# / Excel

    I have developed an alternative approach to .Net integration in Excel -- ExcelDna (http://exceldna.typepad.com) is a free open-source library to glue managed code and Excel, using the .xll inteferfaces. F# can be used to create user-defined functions and macros like any .Net language, and with a bit of effort could be set up to work in text files that are compiled on the fly to define user-defined function for Excel.

    ExcelDna ovecomes some of the problems with Automation Add-Ins, especially for creating user-defined functions. In particular, registration and deployment can be quite a problem with Automation Add-Ins, the performance isn't always great, function descriptions and categories are hard to set up, Automation Add-Ins only work with Excel XP and later. By using the .xll integration, ExcelDna has excellent performance,

    ExcelDna allows two ways of exposing user code - either in text-based scripting files using VB or C#, or in compiled .dlls. The compiled .dlls can be made with F# or any .Net language. I would also like to extend the script-based files to allow F#, but need some support for the CodeCompiler classes that wrap the command-line compilation.

    I have been using F# for another project, and would be keen to hear how people use F# and Excel together.

    Regards,

    Govert van Drimmelen (govert@icon.co.za)

     

     

View as RSS news feed in XML
Powered by Community Server, by Telligent Systems