Quantcast
Channel: exceldna Wiki & Documentation Rss Feed
Viewing all 143 articles
Browse latest View live

Updated Wiki: Home

$
0
0

Introduction

Excel-DNA is an independent project to integrate .NET into Excel. I hope it will be useful to Excel users who currently write VBA code for functions and macros, and would like to start using .NET. Also interested would be C/C++ based .xll add-in developers who want to use the .NET framework to develop their add-ins.

The Excel-DNA Runtime is free for all use, and distributed under a permissive open-source license that also allows commercial use.

Excel-DNA is developed using .NET, and users have to install the freely available .NET Framework runtime. The integration is by an Excel Add-In (.xll) that exposes .NET code to Excel. The user code can be in text-based (.dna) script files (C#, Visual Basic or F#), or compiled .NET libraries (.dll). Excel-DNA supports both the .NET runtime version 2.0 (which is used by .NET versions 2.0, 3.0 and 3.5) and version 4. Add-ins can target either version of the runtime, and concurrent loading of both runtime versions into an Excel instance is supported.

Excel versions '97 through 2010 can be targeted with a single add-in. Advanced Excel features are supported, including multi-threaded recalculation (Excel 2007 and later), registration-free RTD servers (Excel 2002 and later) and customized Ribbon interfaces (Excel 2007 and 2010). Most managed UDF assemblies developed for Excel Services can be exposed to the Excel client with no modification.

There is newly introduced support for integrated Custom Task Panes (Excel 2007 and later), offloading UDF computations to a Windows HPC cluster from Excel 2010, and for the 64-bit version of Excel 2010 in the latest release - Excel-DNA version 0.29.

Important Links

The new home for Excel-DNA is at http://www.excel-dna.net.

The documentation is still sparse, but if you need any help, try the main Excel-DNA support forum on Google Groups, http://groups.google.com/group/exceldna, where an extensive history of discussions can found and searched through.

You are also welcome to contact me (Govert) directly at govert@icon.co.za with questions, comments or suggestions.

Getting Started

Download the latest release, and work through the Getting Started page.

And view some additional pointers, including a step-by-step guide to making your first C# add-in, on the work-in-progress Documentation page.

External Links

If you are a VBA developer interesting in moving to .NET, you should start with Patrick O'Beirne's detailed VBA to Excel-DNA migration guide.

Next, check out the brilliant step-by-step tutorial series by Ross McLean:
As a comprehensive example using many of the Excel-DNA features, be inspired by the Financial Analytics Suite (FinAnSu), an open-source C# add-in built by Bryan McKelvey.

Or browse through the variety of samples and tutorials elsewhere:
Projects using Excel-DNA
And if you get stuck or have any questions, don't hesitate to ask on http://groups.google.com/group/exceldna.

Related Projects

  • NetOffice is a set of version-independent assemblies to allow Office integration through the COM automation interface. The NetOffice libraries can be used from an Excel-DNA add-in to ease version-independent Excel add-in development, and ease compatibility with VBA.
  • Visual Studio Tools for Office (VSTO) is Microsoft's preferred plan for integrating .NET with Office. It is mainly aimed at making it easy for Visual Studio developers to create solutions integrated with the Office applications. In contrast, Excel-DNA is (eventually) aimed at Excel end-users, as a compelling replacement for VBA, completely independent of Visual Studio.
  • Add-in Express is a commercial alternative to VSTO for users with Visual Studio. It support making add-ins for the various Office products, not just Excel, and has helpful wizards and graphics designers.
  • Jens Thiel's ManagedXll is an established, commercial product to easily create .xll libraries in .NET. If ManagedXll were free, Excel-DNA would not exist.
  • For making Excel Add-Ins in Python, have a look at PyXLL.
  • There are a number of C/C++ libraries and tools that make creating .xlls easier than using the Excel SDK directly:
    • I initially used the XLW open-source library.
    • The XLL+ toolkit is a highly regarded commercial option.
    • Keith Lewis has some modern C++ libraries for making .xlls, available on CodePlex at http://xll.codeplex.com/.

Performance

Information about the performance of Excel-DNA user-defined functions can be found on the ExcelDna Performance page.

Formal Support Agreements

Corporate users of Excel-DNA, using the library as part of their mission critical infrastructure, may be interested in a more formal support arrangement. I offer an annual subscription-based technical support agreement to such companies. For more details, please contact me by email at govert@icon.co.za.

Donations

Financial support for the Excel-DNA project encourages future development and is greatly appreciated. Transactions are processed by PayPal.
Donate via PayPal

Updated Wiki: Getting Started

$
0
0

Getting Started with ExcelDna

Do this first:

  • The .NET Framework 2.0 Runtime or a later version must be installed. The .NET Framework Version 2.0 Redistributable Package is available from Microsoft.
  • Get the most recent release of ExcelDna: Download Excel-DNA version 0.29, unzip in a convenient directory.
  • Macro security in Excel must not be 'Very High' or 'High' (if set to Medium -- it will prompt whether to enable each macro library). To use the .NET macros you will have to 'Enable' at the prompt.

1. Create a user-defined function in Visual Basic

  • Make a copy of ExcelDna.xll in a convenient directory, calling the copy Test1.xll.
  • Create a new text file, called Test1.dna (the same prefix as the .xll file), with contents:

<DnaLibrary><![CDATA[

        Public Module MyFunctions


            Function AddThem(x, y)
                AddThem = x + y
            End Function


        End Module
    ]]></DnaLibrary>
  • Load Test1.xll in Excel (either File->Open or Tools->Add-Ins and Browse...).
  • You should be prompted whether to Enable Macros, click Enable.
  • Enter =AddThem(4,2) into a cell - you should get 6. (Under some localized versions of Excel the parameters are separated by a ';', so you'd say =AddThem(4; 2) instead).
  • There should also be an entry for AddThem in the function wizard, under the category Test1.

Troubleshooting
  • If you are not prompted to Enable Macros and nothing else happens, your security level is probably on High. Set it to Medium.
  • If you get a message indicating the .Net 2.0 runtime could not be loaded, you might not have the .NET Framework 2.0 installed. Install it.
  • If Excel crashes with an unhandled exception, an access violation or some other horrible error, either during loading or when running the function, please let me know. This shouldn't happen, and I would like to know if it does.
  • If a window appears with the title 'ExcelDna Error Display' then there were some errors trying to compile the code in the .dna file. Check that you have put the right code into the .dna file.
  • If Excel prompts for Enabling Macros, and then the function does not work and does not appear in the function wizard, you might not have the right filename for the .dna file. The prefix should be the same as the .xll file and it should be in the same directory.
  • Excel is only able to load add-ins, including .xll add-ins, if VBA is installed. (This is under the Office Shared Tools option when installing Office.) Check that VBA is installed by pressing Alt+F11 to open the VBA editor. If it does not open, add VBA to your Office installation.
  • Otherwise, if something goes wrong, let me know, or post on the discussion list.

2. Creating a user-defined function in C#

Change the contents of Test1.dna to:

<DnaLibraryLanguage="CS"><![CDATA[

        using ExcelDna.Integration;
	
                public class MyFunctions
                {
                        [ExcelFunction(Description="Joins a string to a number", Category="My functions")]
                        public static string JoinThem(string str, double val)
                        {
                                return str + val;
                        }
                }
    ]]></DnaLibrary>
  • Reload the .xll, either from File->Open or in Tools->Add-Ins.
  • Check with the formula =JoinThem("abc", 123)
  • If the first example worked, this one should too.

3. Making the functions from a compiled library available

ExcelDna can also load any compiled .NET library. Public static functions with a compatible signature are exported to Excel.
  • Create a file called TestLib.cs containing the following code:
using ExcelDna.Integration;
			
publicclass MyFunctions
{
        [ExcelFunction(Description="Multiplies two numbers", Category="Useful functions")]
        publicstaticdouble MultiplyThem(double x, double y)
        {
                return x * y;
        }
}
  • You need to reference the ExcelDna.Integration.dll assembly (the ExcelFunction attribute is defined there). Copy the file ExcelDna.Integration.dll next to your source file, or reference it in your project. You need not redistribute this file - a copy is embedded as a resource in the redistributable .xll
  • Compile TestLib.cs to TestLib.dll: from the command-line: c:\windows\microsoft.net\framework\v2.0.50727\csc.exe /target:library /reference:ExcelDna.Integration.dll TestLib.cs
  • Modify Test1.dna to contain:
<DnaLibrary><ExternalLibraryPath="TestLib.dll"/></DnaLibrary>
  • Reload the .xll and check =MultiplyThem(2,3) (or =MultiplyThem(2; 3) on some versions).
  • If you are compiling your assembly to target .NET 4, you need to tell Excel-DNA to load the right version of the CLR:
<DnaLibraryRuntimeVersion="v4.0"><ExternalLibraryPath="TestLib.dll"/></DnaLibrary>

Updated Wiki: FSharp Type Inference

$
0
0
When creating UDFs with F#, the flexible type inference might lead to function signatures that are not supported by Excel-DNA, or lead to unexpected results.

let MakeTwo x = 2 

This doesn't work (the UDF doesn't get registered) since the inferred type is 'a -> int, so is generic over the argument. This is equivalent to the C# signature:

public int MakeTwo<T>(T input) = { return 2; }
However, the following, with explicit typing, does work:

let MakeTwo (x : float) = 2 

This would apply to any function that is generic over its input. Another example is:

let AddString x y = x.ToString() + y.ToString()

which is of the type a' -> b' -> string and doesn't get exposed as an UDF either.

Adding explicit types removes the generic parameters:

let AddString (x:obj) (y:obj) = x.ToString() + y.ToString()

Even the simple example in the distribution can be a concern:

let Add x y = x + y 
F# infers this function to be of the type int -> int -> int, and if called in Excel as =Add(2.5,3.5) then this function will return 7 not 6.

let Add (x:float) (y:float) = x + y 

Updated Wiki: Documentation

$
0
0

Getting started

Get going with some first steps by following the Getting Started page.

To make a C# add-in with Visual Studio consult the Excel-DNA - Step-by-step C# add-in.doc guide.

Otherwise, browse through the list of other resources and examples on the Home page.

Reference

Experimental Features

Helpful Snippets

Main Non-Wiki

  • In the download: Distribution\GettingStarted.txt -- step by step for simple UDF.
  • In the download: Distribution\Samples\*.dna
  • In the download: Distribution\Excel-DNA - Step-by-step C# add-in.doc (for Visual Studio).
  • http://groups.google.com/group/exceldna -- A lot of good posts here.
  • http://www.excel-dna.net New main portal page, but docs and downloads are in Codeplex.

Support

There is a searchable record of more than 3300 messages on the Google group: http://groups.google.com/group/exceldna.

Please don't hesitate to ask. If you are stuck or need some help using Excel-DNA your questions really are very welcome - whether you are just getting started, or an Excel-DNA expert.

And if you could help put together some proper documentation, please contact me. I'd be happy to add you as an editor on the CodePlex project.

-Govert

Updated Wiki: Asynchronous Functions

$
0
0

Asynchronous Functions

Note - this feature is still experimental. It is only available in the latest source code check-ins, ans the API and usage might still change.

Excel-DNA now has a core implementation to support asynchronous functions. In a future version we will improve the ease of use.

Usage

  • You have to call ExcelAsyncUtil.Initialize() in your AutoOpen:

    public class AsyncTestAddIn : IExcelAddIn
    {
        public void AutoOpen()
        {
            ExcelAsyncUtil.Initialize();
            ExcelIntegration.RegisterUnhandledExceptionHandler(
                ex => "!!! EXCEPTION: " + ex.ToString());
        }

        public void AutoClose()
        {
        }
    }

  • Your async UDF then calls AsyncUtil.Run like this:

        public static object SleepAsync(string ms)
        {
            return ExcelAsyncUtil.Run("SleepAsync", ms, delegate
            {
                Debug.Print("{1:HH:mm:ss.fff} Sleeping for {0} ms", ms, DateTime.Now);
                Thread.Sleep(int.Parse(ms));
                Debug.Print("{1:HH:mm:ss.fff} Done sleeping {0} ms", ms, DateTime.Now);
                return "Woke Up at " + DateTime.Now.ToString("1:HH:mm:ss.fff");
            });
        }



The parameters to ExcelAsyncUtil.Run are:
  • string functionName - identifies this async function.
  • object parameters - identifies the set of parameters the function is being called with. Can be a single object (e.g. a string) or an object[] array of parameters.
  • ExcelFunc function - a delegate that will be evaluated asynchronously.

More Samples

Note: This code does not scale very well, since the web calls block a treadpool thread. Using .NET 4 Tasks or .NET 4.5 async support could lead to a much better implementation.

        public static object DownloadAsync(string url)
        {
            // Don't do anything else here - might run at unexpected times...
            return ExcelAsyncUtil.Run("DownloadAsync", url,
                delegate { return Download(url); });
        }

        public static object WebSnippetAsync(string url, string regex)
        {
            // Don't do anything else here - might run at unexpected times...
            return ExcelAsyncUtil.Run("WebSnippetAsync", new object[] {url, regex},
                delegate
                {
                    string result = Download(url);
                    string match = Regex.Match((result as string), regex,          
                        RegexOptions.Singleline).Groups[1].Value;

                    match = Regex.Replace(match, "\r", " ");
                    match = Regex.Replace(match, "\n", " ");
                    match = Regex.Replace(match, "\t", " ");
                    return match;
                });
        }

        static string Download(string url)
        {
            return new WebClient().DownloadString(url);
        }

Updated Wiki: Reactive Extensions for Excel - VB.NET

$
0
0
Imports System.Runtime.CompilerServices
Imports ExcelDna.Integration

Public Module RxExcel

    <Extension()>
    Public Function ToExcelObservable(Of T)(observable As IObservable(Of T)) As IExcelObservable
        Return New ExcelObservable(Of T)(observable)
    End Function

    Public Function Observe(Of T)(functionName As String, parameters As Object, observableSource As Func(Of IObservable(Of T))) As Object
        Return ExcelAsyncUtil.Observe(functionName, parameters, Function() observableSource().ToExcelObservable())
    End Function
End Module

Public Class ExcelObservable(Of T)
    Implements IExcelObservable

    ReadOnly _observable As IObservable(Of T)

    Public Sub New(observable As IObservable(Of T))
        _observable = observable
    End Sub

    Public Function Subscribe(observer As IExcelObserver) As IDisposable _
        Implements IExcelObservable.Subscribe
        Return _observable.Subscribe(Sub(value) observer.OnNext(value), Sub(ex) observer.OnError(ex), Sub() observer.OnCompleted())
    End Function
End Class

Updated Wiki: Reactive Extensions for Excel

$
0
0

Reactive Extensions for Excel

Note - this feature is still experimental. It is only available in the latest source code check-ins, and the API and usage might still change.

Excel-DNA has support for integrating Rx with Excel via RTD.
  • You have to call ExcelAsyncUtil.Initialize() in your AutoOpen for any of the Rx stuff to work.

    public class AsyncTestAddIn : IExcelAddIn
    {
        public void AutoOpen()
        {
            // This call is required for the async function and Rx support.
            ExcelAsyncUtil.Initialize();

            // This is optional - allows a custom return value for Exceptions
            // By default exceptions just return #VALUE
            ExcelIntegration.RegisterUnhandledExceptionHandler(ex => "!!! EXCEPTION: " + ex.ToString());
        }

        public void AutoClose()
        {
        }
    }

  • I created an adapter class – called RxExcel but I see it is still in the RxAdapter.cs file - to map the .NET 4 Rx types to the Excel-DNA fake types. The idea would be that any add-in doing Rx stuff would just include the RxExcel file.
I need this because I still want to target .NET 2.0 with Excel-DNA, so the System.IObservable is not available.

using System;

namespace ExcelDna.Integration.RxExcel
{
    public static class RxExcel
    {
        public static IExcelObservable ToExcelObservable<T>(this IObservable<T> observable)
        {
            return new ExcelObservable<T>(observable);
        }

        public static object Observe<T>(string functionName, object parameters, Func<IObservable<T>> observableSource)
        {
            return ExcelAsyncUtil.Observe(functionName, parameters, () => observableSource().ToExcelObservable());
        }
    }

    public class ExcelObservable<T> : IExcelObservable
    {
        readonly IObservable<T> _observable;

        public ExcelObservable(IObservable<T> observable)
        {
            _observable = observable;
        }

        public IDisposable Subscribe(IExcelObserver observer)
        {
            return _observable.Subscribe(value => observer.OnNext(value), observer.OnError, observer.OnCompleted);
        }
    }
}


(VB.NET version here: Reactive Extensions for Excel - VB.NET).
  • UDFs that hook up Observables then look like this:

        // Publishes a single value after the interval elapses.
        public static object rxTimerWaitInterval(int intervalSeconds)
        {
            return RxExcel.Observe("rxTimerWaitInterval", intervalSeconds,
            () => Observable.Timer(TimeSpan.FromSeconds(intervalSeconds)));
        }


The main entry point is then the RxExcel.Observe function, which takes the function name, an object or array of objects representing the ‘parameters’, and then a delegate that will return the IObservable.
The combination of function name and parameters is used to identify the topic. You could have different cells (callers) with their own Observables even though they are calling the same function with the same parameters by adding the caller - XlCall.Excel(XlCall.xlfCaller) - to the array of parameters.

Some more examples:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using ExcelDna.Integration;
using ExcelDna.Integration.RxExcel;

namespace AsyncFunctions
{
    public class RxTest
    {
        // Just returns a single value and completes the sequence.
        public static object rxReturn(object value)
        {
            return RxExcel.Observe("rxReturn", value, 
                () => Observable.Return(value));
        }

        // We don't currently distinguish between Empty and Never.
        // Empty is a sequence that immediately completes without pushing a value.
        // So we return #N/A (the pre-Value 'Not Available' return state), 
        // and then never have anything else to return when the sequence completes.
        // CONSIDER: Should we rather transition to an empty string if we comlete without seeing a value?
        public static object rxEmpty()
        {
            return RxExcel.Observe("rxEmpty", null,
                () => Observable.Empty<string>());
        }

        // Never just doesn't return anything, so our functions stays in the #N/A pre-value return state.
        // This seems fine.
        public static object rxNever()
        {
            return RxExcel.Observe("rxNever", null,
                () => Observable.Never<string>());
        }

        // By default, all exceptions are just returned as #VALUE, consistent with the rest of Excel-DNA.
        // If an UnhandledExceptionHandler is registered via Integration.RegisterUnhandledExceptionHandler, 
        // then the result of that handler will be returned by this function.
        public static object rxThrow()
        {
            return RxExcel.Observe("rxThrow", null,
                () => Observable.Throw<string>(new Exception()));
        }

        // Note that the System.Timers.Timer used here will raise it's Elapsed events from a ThreadPool thread.
        // This is fine - the RxExcel RTD server does all the cross-thread marshaling.
        public static object rxCreateTimer(int intervalSeconds)
        {
            return RxExcel.Observe("rxCreateTimer", intervalSeconds,
            () => Observable.Create<string>(
                observer =>
                {
                    var timer = new System.Timers.Timer();
                    timer.Interval = intervalSeconds * 1000;
                    timer.Elapsed += (s, e) => observer.OnNext("Tick at" + DateTime.Now.ToString("HH:mm:ss.fff"));
                    timer.Start();
                    return timer;
                }));
        }

        // Excel will not update for every value in the sequence - just as often as the ThrottleInreval allows.
        // Observable.Interval might generate many values we ignore.
        public static object rxInterval(int intervalSeconds)
        {
            return RxExcel.Observe("rxInterval", intervalSeconds,
            () => Observable.Interval(TimeSpan.FromSeconds(intervalSeconds)));
        }

        // Publishes a single value after the interval elapses.
        public static object rxTimerWaitInterval(int intervalSeconds)
        {
            return RxExcel.Observe("rxTimerWaitInterval", intervalSeconds,
            () => Observable.Timer(TimeSpan.FromSeconds(intervalSeconds)));
        }

        // Publishes a single value at the given time.
        public static object rxTimerWaitUntil(DateTime timeUntil)
        {
            return RxExcel.Observe("rxTimerWaitUntil", timeUntil,
            () => Observable.Timer(timeUntil));
        }

        // A custom sequence returning squares every 5 seconds, up to 20 * 20.
        // Not Observing 'Per Caller' ensures we share a sequnce if using the function in different cells
        public static object rxCreateValues()
        {
            return RxExcel.Observe("rxCreateValuesShared", null,
            () => Observable.Generate(
                    1,
                    i => i <= 20,
                    i => i + 1,
                    i => i * i,
                    i => TimeSpan.FromSeconds(5)));
        }

        // A custom sequence returning squares every intervalSeconds seconds, up to 10 * 10.
        // Observe 'Per Caller' by sending the caller is one of the 'parameters' into RxExcel.Observe. 
        // This ensures we get different sequences if using the function in different cells
        public static object rxCreateValuesPerCaller(int intervalSeconds)
        {
            object caller = XlCall.Excel(XlCall.xlfCaller);

            return RxExcel.Observe("rxCreateValues", new[] {intervalSeconds, caller},
            () => Observable.Generate(
                    1,
                    i => i <= 10,
                    i => i + 1,
                    i => i * i,
                    i => TimeSpan.FromSeconds(5)));
        }

        // Some experiments returning arrays ... not really useful yet.
        public static object rxCreateArrays()
        {
            return RxExcel.Observe("rxCreateArrays", null,
            () => Observable.Generate(
                    new List<object> {1,2,3},
                    lst => true,
                    lst => { lst.Add((int)lst[lst.Count-1] + 1); return lst;},
                    lst => Transpose(lst.ToArray()),
                    lst => TimeSpan.FromSeconds(2)));
        }

        static object[,] Transpose(object[] array)
        {
            object[,] result = new object[array.Length, 1];
            for (int i = 0; i < array.Length; i++)
            {
                result[i,0] = array[i];
            }
            return result;
        }
    }
}

Updated Wiki: Asynchronous Functions with Tasks

$
0
0
This example shows how to implement an asynchronous Excel function in VB.NET using the .NET 4 Task class. This has an advantage over the ExcelAsyncUtil.Run method, which just runs the code on a ThreadPool thread. If we are able to use the .NET 4 Task class, the outstanding requests will not block any threads, so should scale better. Supporting .NET 4 Tasks also allow us to use the .NET 4.5 Async/Await language extensions.

We want to make an asynchronous function to download a string from a URL. I'm using the System.Net.Http package (if you're not using .NET 4.5, add to your project by getting the Microsoft.Net.Http package from NuGet).

Our function, called webDownloadString will be implemented like this:

Imports System.Net.Http
Imports ExcelDna.Integration

PublicModule WebUdf
    ReadOnly myHttpClient AsNew HttpClient

    PublicFunction webDownloadString(url AsString) AsObjectReturn ExcelAsyncUtil.Observe("webDownloadString", url, Function() myHttpClient.GetStringAsync(url).ToExcelObservable())

    EndFunctionEndModule

The implementation of the async function uses the ExcelAsyncUtil.Observe function, which takes an IExcelObservable as its last parameter. The HttpClient.GetStringAsync call returns a Task(Of String), so the missing part is the ToExcelObservable() function which converts a Task to an ExcelObservable.

ToExcelObservable is implemented like this:

Imports System.Threading.Tasks
Imports System.Runtime.CompilerServices
Imports ExcelDna.Integration

Module TaskExcelObservableExtensions

    ' Careful - this would only work as long as the task is not shared between calls, since cancellation cancels that task' Another implementation would be via Reactive Extension: Task.ToObservable() (in System.Reactive.Linq.dll) and RxExcel<Extension()>
    PublicFunction ToExcelObservable(Of TResult)(task As Task(Of TResult)) As IExcelObservable

        If task IsNothingThenThrowNew ArgumentNullException("task")
        EndIfReturnNew ExcelTaskObservable(Of TResult)(task)
    EndFunction'' Wraps a Task in an Observable - basically allowing one Subscriber.PrivateClass ExcelTaskObservable(Of TResult)
        Implements IExcelObservable

        PrivateReadOnly _task As Task(Of TResult)

        PublicSubNew(task As Task(Of TResult))
            _task = task
        EndSubPublicFunction Subscribe(observer As IExcelObserver) As IDisposable Implements IExcelObservable.Subscribe
            SelectCase _task.Status
                Case TaskStatus.RanToCompletion
                    observer.OnNext(_task.Result)
                    observer.OnCompleted()
                Case TaskStatus.Faulted
                    observer.OnError(_task.Exception.InnerException)
                Case TaskStatus.Canceled
                    observer.OnError(New TaskCanceledException(_task))
                CaseElse
                    _task.ContinueWith(
                        Sub(t)
                            SelectCase t.Status
                                Case TaskStatus.RanToCompletion
                                    observer.OnNext(t.Result)
                                    observer.OnCompleted()
                                Case TaskStatus.Faulted
                                    observer.OnError(t.Exception.InnerException)
                                Case TaskStatus.Canceled
                                    observer.OnError(New TaskCanceledException(t))
                            EndSelectEndSub)
            EndSelect' No cancellationReturn DefaultDisposable.Instance
        EndFunctionEndClassPrivateClass DefaultDisposable
        Implements IDisposable
        PublicSharedReadOnly Instance AsNew DefaultDisposable()

        PrivateSubNew()
        EndSubPublicSub Dispose() Implements IDisposable.Dispose
            ' no opEndSubEndClassEndModule

We also need to initialize the Excel-DNA async support:
Imports ExcelDna.Integration

PublicClass AddIn
    Implements IExcelAddIn

    PublicSub AutoOpen() Implements ExcelDna.Integration.IExcelAddIn.AutoOpen
        ExcelIntegration.RegisterUnhandledExceptionHandler(AddressOf HandleError)
        ExcelAsyncUtil.Initialize()
    EndSubPublicSub AutoClose() Implements ExcelDna.Integration.IExcelAddIn.AutoClose
        ExcelAsyncUtil.Uninitialize()
    EndSubPrivateSharedFunction HandleError(ex AsObject) AsObjectReturn"!!! ERROR: "& ex.ToString()
    EndFunctionEndClass

Note that the string returned would be truncated at the maximum string length for Excel - either 255 characters for Excel 2003, or 32767 characters for Excel 2007+.

The function can be called from an Excel sheet as =webDownloadString("http://www.bing.com").
A next step might be to build a function that use regular expressions to extract data from the downloaded string.

Updated Wiki: Documentation

$
0
0

Getting started

Get going with some first steps by following the Getting Started page.

To make a C# add-in with Visual Studio consult the Excel-DNA - Step-by-step C# add-in.doc guide.

Otherwise, browse through the list of other resources and examples on the Home page.

Reference

Helpful Snippets

Main Non-Wiki

  • In the download: Distribution\GettingStarted.txt -- step by step for simple UDF.
  • In the download: Distribution\Samples\*.dna
  • In the download: Distribution\Excel-DNA - Step-by-step C# add-in.doc (for Visual Studio).
  • http://groups.google.com/group/exceldna -- A lot of good posts here.
  • http://www.excel-dna.net New main portal page, but docs and downloads are in Codeplex.

Support

There is a searchable record of more than 3300 messages on the Google group: http://groups.google.com/group/exceldna.

Please don't hesitate to ask. If you are stuck or need some help using Excel-DNA your questions really are very welcome - whether you are just getting started, or an Excel-DNA expert.

And if you could help put together some proper documentation, please contact me. I'd be happy to add you as an editor on the CodePlex project.

-Govert

Updated Wiki: Reactive Extensions for Excel - VB.NET

$
0
0
Imports System.Runtime.CompilerServices
Imports ExcelDna.Integration

PublicModule RxExcel

    <Extension()>
    PublicFunction ToExcelObservable(Of T)(observable As IObservable(Of T)) As IExcelObservable
        ReturnNew ExcelObservable(Of T)(observable)
    EndFunctionPublicFunction Observe(Of T)(functionName AsString, parameters AsObject, _
                                                observableSource As Func(Of IObservable(Of T))) AsObjectReturn ExcelAsyncUtil.Observe(functionName, parameters, 
                                     Function() observableSource().ToExcelObservable())
    EndFunctionEndModulePublicClass ExcelObservable(Of T)
    Implements IExcelObservable

    ReadOnly _observable As IObservable(Of T)

    PublicSubNew(observable As IObservable(Of T))
        _observable = observable
    EndSubPublicFunction Subscribe(observer As IExcelObserver) As IDisposable _
        Implements IExcelObservable.Subscribe
        Return _observable.Subscribe(Sub(value) observer.OnNext(value), 
            Sub(ex) observer.OnError(ex), Sub() observer.OnCompleted())
    EndFunctionEndClass

Updated Wiki: Reactive Extensions for Excel - VB.NET

$
0
0
Imports System.Runtime.CompilerServices
Imports ExcelDna.Integration

PublicModule RxExcel

    <Extension()>
    PublicFunction ToExcelObservable(Of T)(observable As IObservable(Of T)) As IExcelObservable
        ReturnNew ExcelObservable(Of T)(observable)
    EndFunctionPublicFunction Observe(Of T)(functionName AsString, parameters AsObject, _
                           observableSource As Func(Of IObservable(Of T))) AsObjectReturn ExcelAsyncUtil.Observe(functionName, parameters, 
                                     Function() observableSource().ToExcelObservable())
    EndFunctionEndModulePublicClass ExcelObservable(Of T)
    Implements IExcelObservable

    ReadOnly _observable As IObservable(Of T)

    PublicSubNew(observable As IObservable(Of T))
        _observable = observable
    EndSubPublicFunction Subscribe(observer As IExcelObserver) As IDisposable _
        Implements IExcelObservable.Subscribe
        Return _observable.Subscribe(Sub(value) observer.OnNext(value), 
            Sub(ex) observer.OnError(ex), Sub() observer.OnCompleted())
    EndFunctionEndClass

Updated Wiki: Async macro example - formatting the calling cell from a UDF

$
0
0
We define a function that schedules a macro call to update the format of the calling range.

    public static DateTime asyncFormatCaller()
    {
        object caller = XlCall.Excel(XlCall.xlfCaller);
        ExcelAsyncUtil.QueueAsMacro(
            delegate
            {
                if (caller is ExcelReference)
                {
                    // Set the formatting of the function caller
                    using (new ExcelSelectionHelper((ExcelReference)caller))
                    {
                        XlCall.Excel(XlCall.xlcFormatNumber, "h:mm:ss");
                    }
                }
            });

        return DateTime.Now;
    }


We use the following helper class to keep track of the current selection in a macro, so that the selection is correctly restored after the macro has completed.
    // RIIA helper class to set and restore Excel selections
    public class ExcelSelectionHelper : XlCall, IDisposable
    {
        object oldSelectionOnActiveSheet;
        object oldActiveCell;
        object oldSelectionOnRefSheet;

        public ExcelSelectionHelper(ExcelReference refToSelect)
        {
            oldSelectionOnActiveSheet = Excel(xlfSelection);
            oldActiveCell = Excel(xlfActiveCell);

            // Remember old selection and select the first cell of the target
            string refSheet = (string)Excel(xlSheetNm, refToSelect);
            Excel(xlcWorkbookSelect, new object[] { refSheet });
            oldSelectionOnRefSheet = Excel(xlfSelection);
            Excel(xlcFormulaGoto, refToSelect);
        }

        public void Dispose()
        {
            Excel(xlcSelect, oldSelectionOnRefSheet);
            Excel(xlcFormulaGoto, oldSelectionOnActiveSheet, oldActiveCell);
        }
    }


An improved function would first check whether the format of the caller needs to be updated before scheduling the macro call.

Updated Wiki: Documentation

$
0
0

Getting started

Get going with some first steps by following the Getting Started page.

To make a C# add-in with Visual Studio consult the Excel-DNA - Step-by-step C# add-in.doc guide.

Otherwise, browse through the list of other resources and examples on the Home page.

Reference

Helpful Snippets

Main Non-Wiki

  • In the download: Distribution\GettingStarted.txt -- step by step for simple UDF.
  • In the download: Distribution\Samples\*.dna
  • In the download: Distribution\Excel-DNA - Step-by-step C# add-in.doc (for Visual Studio).
  • http://groups.google.com/group/exceldna -- A lot of good posts here.
  • http://www.excel-dna.net New main portal page, but docs and downloads are in Codeplex.

Support

There is a searchable record of more than 3300 messages on the Google group: http://groups.google.com/group/exceldna.

Please don't hesitate to ask. If you are stuck or need some help using Excel-DNA your questions really are very welcome - whether you are just getting started, or an Excel-DNA expert.

And if you could help put together some proper documentation, please contact me. I'd be happy to add you as an editor on the CodePlex project.

-Govert

Updated Wiki: Async macro example - formatting the calling cell from a UDF

$
0
0
We define a function that schedules a macro call to update the format of the calling range.

    public static DateTime asyncFormatCaller()
    {
        object caller = XlCall.Excel(XlCall.xlfCaller);
        ExcelAsyncUtil.QueueAsMacro(
            delegate
            {
                if (caller is ExcelReference)
                {
                    // Set the formatting of the function caller
                    using (new ExcelSelectionHelper((ExcelReference)caller))
                    {
                        XlCall.Excel(XlCall.xlcFormatNumber, "h:mm:ss");
                    }
                }
            });

        return DateTime.Now;
    }


We use the following helper class to keep track of the current selection in a macro, so that the selection is correctly restored after the macro has completed.
    // RIIA helper to deal with Excel selections
    public class ExcelSelectionHelper : XlCall, IDisposable
    {
        object oldScreenUpdating;
        object oldSelectionOnActiveSheet;
        object oldActiveCellOnActiveSheet;

        object oldSelectionOnRefSheet;
        object oldActiveCellOnRefSheet;

        public ExcelSelectionHelper(ExcelReference refToSelect)
        {
            oldScreenUpdating = Excel(xlfGetWorkspace, 40);
            Excel(xlcEcho, false);

            // Remember old selection state on the active sheet
            oldSelectionOnActiveSheet = Excel(xlfSelection);
            oldActiveCellOnActiveSheet = Excel(xlfActiveCell);

            // Switch to the sheet we want to select
            string refSheet = (string)Excel(xlSheetNm, refToSelect);
            Excel(xlcWorkbookSelect, new object[] { refSheet });

            // record selection and active cell on the sheet we want to select
            oldSelectionOnRefSheet = Excel(xlfSelection);
            oldActiveCellOnRefSheet = Excel(xlfActiveCell);

            // make the selection
            Excel(xlcFormulaGoto, refToSelect);
        }

        public void Dispose()
        {
            Excel(xlcSelect, oldSelectionOnRefSheet, oldActiveCellOnRefSheet);

            string oldActiveSheet = (string)Excel(xlSheetNm, oldSelectionOnActiveSheet);
            Excel(xlcWorkbookSelect, new object[] { oldActiveSheet });

            Excel(xlcSelect, oldSelectionOnActiveSheet, oldActiveCellOnActiveSheet);

            Excel(xlcEcho, oldScreenUpdating);
        }
    }


An improved function would first check whether the format of the caller needs to be updated before scheduling the macro call.

Updated Wiki: Async macro example - formatting the calling cell from a UDF

$
0
0
We define a function that schedules a macro call to update the format of the calling range.

    public static DateTime asyncFormatCaller()
    {
        object caller = XlCall.Excel(XlCall.xlfCaller);
        if (caller is ExcelReference)
        {
            ExcelAsyncUtil.QueueAsMacro(
                delegate
                {
                      // Set the desired selection, then apply formatting
                      using (new ExcelSelectionHelper((ExcelReference)caller))
                      {
                          XlCall.Excel(XlCall.xlcFormatNumber, "h:mm:ss");
                      }
                }
            });

        return DateTime.Now;
    }


We use the following helper class to keep track of the current selection in a macro, so that the selection is correctly restored after the macro has completed.
    // RIIA helper to deal with Excel selections
    public class ExcelSelectionHelper : XlCall, IDisposable
    {
        object oldScreenUpdating;
        object oldSelectionOnActiveSheet;
        object oldActiveCellOnActiveSheet;

        object oldSelectionOnRefSheet;
        object oldActiveCellOnRefSheet;

        public ExcelSelectionHelper(ExcelReference refToSelect)
        {
            oldScreenUpdating = Excel(xlfGetWorkspace, 40);
            Excel(xlcEcho, false);

            // Remember old selection state on the active sheet
            oldSelectionOnActiveSheet = Excel(xlfSelection);
            oldActiveCellOnActiveSheet = Excel(xlfActiveCell);

            // Switch to the sheet we want to select
            string refSheet = (string)Excel(xlSheetNm, refToSelect);
            Excel(xlcWorkbookSelect, new object[] { refSheet });

            // record selection and active cell on the sheet we want to select
            oldSelectionOnRefSheet = Excel(xlfSelection);
            oldActiveCellOnRefSheet = Excel(xlfActiveCell);

            // make the selection
            Excel(xlcFormulaGoto, refToSelect);
        }

        public void Dispose()
        {
            Excel(xlcSelect, oldSelectionOnRefSheet, oldActiveCellOnRefSheet);

            string oldActiveSheet = (string)Excel(xlSheetNm, oldSelectionOnActiveSheet);
            Excel(xlcWorkbookSelect, new object[] { oldActiveSheet });

            Excel(xlcSelect, oldSelectionOnActiveSheet, oldActiveCellOnActiveSheet);

            Excel(xlcEcho, oldScreenUpdating);
        }
    }


An improved function would first check whether the format of the caller needs to be updated before scheduling the macro call.

Updated Wiki: Async macro example - formatting the calling cell from a UDF

$
0
0
We define a function that schedules a macro call to update the format of the calling range.

    public static DateTime asyncFormatCaller()
    {
        object caller = XlCall.Excel(XlCall.xlfCaller);
        if (caller is ExcelReference)
        {
            ExcelAsyncUtil.QueueAsMacro(
                delegate
                {
                      // Set the desired selection, then apply formatting
                      using (new ExcelSelectionHelper((ExcelReference)caller))
                      {
                          XlCall.Excel(XlCall.xlcFormatNumber, "h:mm:ss");
                      }
                }
            });
        }
        return DateTime.Now;
    }


We use the following helper class to keep track of the current selection in a macro, so that the selection is correctly restored after the macro has completed.
    // Helper class to deal with Excel selections in 'using' style
    public class ExcelSelectionHelper : XlCall, IDisposable
    {
        object oldScreenUpdating;
        object oldSelectionOnActiveSheet;
        object oldActiveCellOnActiveSheet;

        object oldSelectionOnRefSheet;
        object oldActiveCellOnRefSheet;

        public ExcelSelectionHelper(ExcelReference refToSelect)
        {
            oldScreenUpdating = Excel(xlfGetWorkspace, 40);
            Excel(xlcEcho, false);

            // Remember old selection state on the active sheet
            oldSelectionOnActiveSheet = Excel(xlfSelection);
            oldActiveCellOnActiveSheet = Excel(xlfActiveCell);

            // Switch to the sheet we want to select
            string refSheet = (string)Excel(xlSheetNm, refToSelect);
            Excel(xlcWorkbookSelect, new object[] { refSheet });

            // record selection and active cell on the sheet we want to select
            oldSelectionOnRefSheet = Excel(xlfSelection);
            oldActiveCellOnRefSheet = Excel(xlfActiveCell);

            // make the selection
            Excel(xlcFormulaGoto, refToSelect);
        }

        public void Dispose()
        {
            Excel(xlcSelect, oldSelectionOnRefSheet, oldActiveCellOnRefSheet);

            string oldActiveSheet = (string)Excel(xlSheetNm, oldSelectionOnActiveSheet);
            Excel(xlcWorkbookSelect, new object[] { oldActiveSheet });

            Excel(xlcSelect, oldSelectionOnActiveSheet, oldActiveCellOnActiveSheet);

            Excel(xlcEcho, oldScreenUpdating);
        }
    }


An improved function would first check whether the format of the caller needs to be updated before scheduling the macro call.

Updated Wiki: Async macro example - formatting the calling cell from a UDF

$
0
0
We define a function that schedules a macro call to update the format of the calling range.
    public static DateTime asyncFormatCaller()
    {
        object caller = XlCall.Excel(XlCall.xlfCaller);
        if (caller is ExcelReference)
        {
            ExcelAsyncUtil.QueueAsMacro(
                delegate
                {
                      // Set the desired selection, then apply formatting
                      using (new ExcelSelectionHelper((ExcelReference)caller))
                      {
                          XlCall.Excel(XlCall.xlcFormatNumber, "h:mm:ss");
                      }
                }
            });
        }
        return DateTime.Now;
    }

Above we use the following helper class to keep track of the current selection in a macro, so that the selection is correctly restored after the macro has completed.
    // Helper class to deal with Excel selections in 'using' style
    public class ExcelSelectionHelper : XlCall, IDisposable
    {
        object oldScreenUpdating;
        object oldSelectionOnActiveSheet;
        object oldActiveCellOnActiveSheet;

        object oldSelectionOnRefSheet;
        object oldActiveCellOnRefSheet;

        public ExcelSelectionHelper(ExcelReference refToSelect)
        {
            oldScreenUpdating = Excel(xlfGetWorkspace, 40);
            Excel(xlcEcho, false);

            // Remember old selection state on the active sheet
            oldSelectionOnActiveSheet = Excel(xlfSelection);
            oldActiveCellOnActiveSheet = Excel(xlfActiveCell);

            // Switch to the sheet we want to select
            string refSheet = (string)Excel(xlSheetNm, refToSelect);
            Excel(xlcWorkbookSelect, new object[] { refSheet });

            // record selection and active cell on the sheet we want to select
            oldSelectionOnRefSheet = Excel(xlfSelection);
            oldActiveCellOnRefSheet = Excel(xlfActiveCell);

            // make the selection
            Excel(xlcFormulaGoto, refToSelect);
        }

        public void Dispose()
        {
            Excel(xlcSelect, oldSelectionOnRefSheet, oldActiveCellOnRefSheet);

            string oldActiveSheet = (string)Excel(xlSheetNm, oldSelectionOnActiveSheet);
            Excel(xlcWorkbookSelect, new object[] { oldActiveSheet });

            Excel(xlcSelect, oldSelectionOnActiveSheet, oldActiveCellOnActiveSheet);

            Excel(xlcEcho, oldScreenUpdating);
        }
    }

An improved function could first check whether the format of the caller needs to be updated before scheduling the macro call.

Updated Wiki: Home

$
0
0

Introduction

Excel-DNA is an independent project to integrate .NET into Excel. I hope it will be useful to Excel users who currently write VBA code for functions and macros, and would like to start using .NET. Also interested would be C/C++ based .xll add-in developers who want to use the .NET framework to develop their add-ins.

The Excel-DNA Runtime is free for all use, and distributed under a permissive open-source license that also allows commercial use.

Excel-DNA is developed using .NET, and users have to install the freely available .NET Framework runtime. The integration is by an Excel Add-In (.xll) that exposes .NET code to Excel. The user code can be in text-based (.dna) script files (C#, Visual Basic or F#), or compiled .NET libraries (.dll). Excel-DNA supports both the .NET runtime version 2.0 (which is used by .NET versions 2.0, 3.0 and 3.5) and version 4. Add-ins can target either version of the runtime, and concurrent loading of both runtime versions into an Excel instance is supported.

Excel versions '97 through 2010 can be targeted with a single add-in. Advanced Excel features are supported, including multi-threaded recalculation (Excel 2007 and later), registration-free RTD servers (Excel 2002 and later) and customized Ribbon interfaces (Excel 2007 and 2010). There is support for integrated Custom Task Panes (Excel 2007 and later), offloading UDF computations to a Windows HPC cluster (Excel 2010 and later), and for the 64-bit versions of Excel 2010 and 2013.

Most managed UDF assemblies developed for Excel Services can be exposed to the Excel client with no modification. (Please contact me if you are interested in this feature.)

The latest Most managed UDF assemblies developed for Excel Services can be exposed to the Excel client with no modification.

The latest release - Excel-DNA version 0.30 - implements support for RTD-based asynchronous worksheet functions (Excel 2002 and later). The asynchronous support is designed to (optionally) integrate with the .NET 4.0 Task-based operations, as well as the Reactive Extensions library, allowing IObservables to be exposed as 'live' worksheet UDFs - (thus 'RxExcel'). The language-specific support for asynchronous functions in C# 5, Visual Basic 11 and F# 2.0 can be easily integrated with the Excel-DNA asynchronous interfaces.

Important Links

The home page for Excel-DNA is at http://www.excel-dna.net.

The documentation is still sparse, but if you need any help, try the main Excel-DNA support forum on Google Groups, http://groups.google.com/group/exceldna, where an extensive history of discussions can found and searched through.

You are also welcome to contact me (Govert) directly at govert@icon.co.za with questions, comments or suggestions.

Getting Started

Download the latest release, and work through the Getting Started page.

And view some additional pointers, including a step-by-step guide to making your first C# add-in, on the work-in-progress Documentation page.

External Links

If you are a VBA developer interesting in moving to .NET, you should start with Patrick O'Beirne's detailed VBA to Excel-DNA migration guide.

Next, check out the brilliant step-by-step tutorial series by Ross McLean:
As a comprehensive example using many of the Excel-DNA features, be inspired by the Financial Analytics Suite (FinAnSu), an open-source C# add-in built by Bryan McKelvey.

Or browse through the variety of samples and tutorials elsewhere:
Projects using Excel-DNA
And if you get stuck or have any questions, don't hesitate to ask on http://groups.google.com/group/exceldna.

Related Projects

  • NetOffice is a set of version-independent assemblies to allow Office integration through the COM automation interface. The NetOffice libraries can be used from an Excel-DNA add-in to ease version-independent Excel add-in development, and ease compatibility with VBA.
  • Visual Studio Tools for Office (VSTO) is Microsoft's preferred plan for integrating .NET with Office. It is mainly aimed at making it easy for Visual Studio developers to create solutions integrated with the Office applications. In contrast, Excel-DNA is (eventually) aimed at Excel end-users, as a compelling replacement for VBA, completely independent of Visual Studio.
  • Add-in Express is a commercial alternative to VSTO for users with Visual Studio. It support making add-ins for the various Office products, not just Excel, and has helpful wizards and graphics designers.
  • Jens Thiel's ManagedXll is an established, commercial product to easily create .xll libraries in .NET. If ManagedXll were free, Excel-DNA would not exist.
  • For making Excel Add-Ins in Python, have a look at PyXLL.
  • There are a number of C/C++ libraries and tools that make creating .xlls easier than using the Excel SDK directly:
    • I initially used the XLW open-source library.
    • The XLL+ toolkit is a highly regarded commercial option.
    • Keith Lewis has some modern C++ libraries for making .xlls, available on CodePlex at http://xll.codeplex.com/.

Performance

Information about the performance of Excel-DNA user-defined functions can be found on the ExcelDna Performance page.

Formal Support Agreements

Corporate users of Excel-DNA, using the library as part of their mission critical infrastructure, may be interested in a more formal support arrangement. I offer an annual subscription-based technical support agreement to such companies. For more details, please contact me by email at govert@icon.co.za.

Donations

Financial support for the Excel-DNA project encourages future development and is greatly appreciated. Transactions are processed by PayPal.
Donate via PayPal

Updated Wiki: Home

$
0
0

Introduction

Excel-DNA is an independent project to integrate .NET into Excel. I hope it will be useful to Excel users who currently write VBA code for functions and macros, and would like to start using .NET. Also interested would be C/C++ based .xll add-in developers who want to use the .NET framework to develop their add-ins.

The Excel-DNA Runtime is free for all use, and distributed under a permissive open-source license that also allows commercial use.

Excel-DNA is developed using .NET, and users have to install the freely available .NET Framework runtime. The integration is by an Excel Add-In (.xll) that exposes .NET code to Excel. The user code can be in text-based (.dna) script files (C#, Visual Basic or F#), or compiled .NET libraries (.dll). Excel-DNA supports both the .NET runtime version 2.0 (which is used by .NET versions 2.0, 3.0 and 3.5) and version 4. Add-ins can target either version of the runtime, and concurrent loading of both runtime versions into an Excel instance is supported.

Excel versions '97 through 2010 can be targeted with a single add-in. Advanced Excel features are supported, including multi-threaded recalculation (Excel 2007 and later), registration-free RTD servers (Excel 2002 and later) and customized Ribbon interfaces (Excel 2007 and 2010). There is support for integrated Custom Task Panes (Excel 2007 and later), offloading UDF computations to a Windows HPC cluster (Excel 2010 and later), and for the 64-bit versions of Excel 2010 and 2013.

Most managed UDF assemblies developed for Excel Services can be exposed to the Excel client with no modification. (Please contact me if you are interested in this feature.)

The latest release - Excel-DNA version 0.30 - implements support for RTD-based asynchronous worksheet functions (Excel 2002 and later). The asynchronous support is designed to (optionally) integrate with the .NET 4.0 Task-based operations, as well as the Reactive Extensions library, allowing IObservables to be exposed as 'live' worksheet UDFs - (thus 'RxExcel'). The language-specific support for asynchronous functions in C# 5, Visual Basic 11 and F# 2.0 can be easily integrated with the Excel-DNA asynchronous interfaces.

Important Links

The home page for Excel-DNA is at http://www.excel-dna.net.

The documentation is still sparse, but if you need any help, try the main Excel-DNA support forum on Google Groups, http://groups.google.com/group/exceldna, where an extensive history of discussions can found and searched through.

You are also welcome to contact me (Govert) directly at govert@icon.co.za with questions, comments or suggestions.

Getting Started

Download the latest release, and work through the Getting Started page.

And view some additional pointers, including a step-by-step guide to making your first C# add-in, on the work-in-progress Documentation page.

External Links

If you are a VBA developer interesting in moving to .NET, you should start with Patrick O'Beirne's detailed VBA to Excel-DNA migration guide.

Next, check out the brilliant step-by-step tutorial series by Ross McLean:
As a comprehensive example using many of the Excel-DNA features, be inspired by the Financial Analytics Suite (FinAnSu), an open-source C# add-in built by Bryan McKelvey.

Or browse through the variety of samples and tutorials elsewhere:
Projects using Excel-DNA
And if you get stuck or have any questions, don't hesitate to ask on http://groups.google.com/group/exceldna.

Related Projects

  • NetOffice is a set of version-independent assemblies to allow Office integration through the COM automation interface. The NetOffice libraries can be used from an Excel-DNA add-in to ease version-independent Excel add-in development, and ease compatibility with VBA.
  • Visual Studio Tools for Office (VSTO) is Microsoft's preferred plan for integrating .NET with Office. It is mainly aimed at making it easy for Visual Studio developers to create solutions integrated with the Office applications. In contrast, Excel-DNA is (eventually) aimed at Excel end-users, as a compelling replacement for VBA, completely independent of Visual Studio.
  • Add-in Express is a commercial alternative to VSTO for users with Visual Studio. It support making add-ins for the various Office products, not just Excel, and has helpful wizards and graphics designers.
  • Jens Thiel's ManagedXll is an established, commercial product to easily create .xll libraries in .NET. If ManagedXll were free, Excel-DNA would not exist.
  • For making Excel Add-Ins in Python, have a look at PyXLL.
  • There are a number of C/C++ libraries and tools that make creating .xlls easier than using the Excel SDK directly:
    • I initially used the XLW open-source library.
    • The XLL+ toolkit is a highly regarded commercial option.
    • Keith Lewis has some modern C++ libraries for making .xlls, available on CodePlex at http://xll.codeplex.com/.

Performance

Information about the performance of Excel-DNA user-defined functions can be found on the ExcelDna Performance page.

Formal Support Agreements

Corporate users of Excel-DNA, using the library as part of their mission critical infrastructure, may be interested in a more formal support arrangement. I offer an annual subscription-based technical support agreement to such companies. For more details, please contact me by email at govert@icon.co.za.

Donations

Financial support for the Excel-DNA project encourages future development and is greatly appreciated. Transactions are processed by PayPal.
Donate via PayPal

Updated Wiki: Getting Started

$
0
0

Getting Started with ExcelDna

Do this first:

  • The .NET Framework 2.0 Runtime or a later version must be installed. The .NET Framework Version 2.0 Redistributable Package is available from Microsoft.
  • Get the most recent release of ExcelDna: Download Excel-DNA version 0.30, unzip in a convenient directory.
  • Macro security in Excel must not be 'Very High' or 'High' (setting to Medium is fine -- it will prompt whether to enable each macro library). To use the .NET macros you will have to 'Enable' at the prompt.

1. Create a user-defined function in Visual Basic

  • Make a copy of ExcelDna.xll in a convenient directory, calling the copy Test1.xll.
  • Create a new text file, called Test1.dna (the same prefix as the .xll file), with contents:

<DnaLibrary><![CDATA[

        Public Module MyFunctions


            Function AddThem(x, y)
                AddThem = x + y
            End Function


        End Module
    ]]></DnaLibrary>
  • Load Test1.xll in Excel (either File->Open or Tools->Add-Ins and Browse...).
  • You should be prompted whether to Enable Macros, click Enable.
  • Enter =AddThem(4,2) into a cell - you should get 6. (Under some localized versions of Excel the parameters are separated by a ';', so you'd say =AddThem(4; 2) instead).
  • There should also be an entry for AddThem in the function wizard, under the category Test1.

Troubleshooting
  • If you are not prompted to Enable Macros and nothing else happens, your security level is probably on High. Set it to Medium.
  • If you get a message indicating the .Net 2.0 runtime could not be loaded, you might not have the .NET Framework 2.0 installed. Install it.
  • If Excel crashes with an unhandled exception, an access violation or some other horrible error, either during loading or when running the function, please let me know. This shouldn't happen, and I would like to know if it does.
  • If a window appears with the title 'ExcelDna Error Display' then there were some errors trying to compile the code in the .dna file. Check that you have put the right code into the .dna file.
  • If Excel prompts for Enabling Macros, and then the function does not work and does not appear in the function wizard, you might not have the right filename for the .dna file. The prefix should be the same as the .xll file and it should be in the same directory.
  • Excel is only able to load add-ins, including .xll add-ins, if VBA is installed. (This is under the Office Shared Tools option when installing Office.) Check that VBA is installed by pressing Alt+F11 to open the VBA editor. If it does not open, add VBA to your Office installation.
  • Otherwise, if something goes wrong, let me know, or post on the discussion list.

2. Creating a user-defined function in C#

Change the contents of Test1.dna to:

<DnaLibraryLanguage="CS"><![CDATA[

        using ExcelDna.Integration;
	
                public class MyFunctions
                {
                        [ExcelFunction(Description="Joins a string to a number", Category="My functions")]
                        public static string JoinThem(string str, double val)
                        {
                                return str + val;
                        }
                }
    ]]></DnaLibrary>
  • Reload the .xll, either from File->Open or in Tools->Add-Ins.
  • Check with the formula =JoinThem("abc", 123)
  • If the first example worked, this one should too.

3. Making the functions from a compiled library available

ExcelDna can also load any compiled .NET library. Public static functions with a compatible signature are exported to Excel.
  • Create a file called TestLib.cs containing the following code:
using ExcelDna.Integration;
			
publicclass MyFunctions
{
        [ExcelFunction(Description="Multiplies two numbers", Category="Useful functions")]
        publicstaticdouble MultiplyThem(double x, double y)
        {
                return x * y;
        }
}
  • You need to reference the ExcelDna.Integration.dll assembly (the ExcelFunction attribute is defined there). Copy the file ExcelDna.Integration.dll next to your source file, or reference it in your project. You need not redistribute this file - a copy is embedded as a resource in the redistributable .xll
  • Compile TestLib.cs to TestLib.dll: from the command-line: c:\windows\microsoft.net\framework\v2.0.50727\csc.exe /target:library /reference:ExcelDna.Integration.dll TestLib.cs
  • Modify Test1.dna to contain:
<DnaLibrary><ExternalLibraryPath="TestLib.dll"/></DnaLibrary>
  • Reload the .xll and check =MultiplyThem(2,3) (or =MultiplyThem(2; 3) on some versions).
  • If you are compiling your assembly to target .NET 4, you need to tell Excel-DNA to load the right version of the CLR:
<DnaLibraryRuntimeVersion="v4.0"><ExternalLibraryPath="TestLib.dll"/></DnaLibrary>
Viewing all 143 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>