Hi Martin,
By default, Excel-DNA will return any unhandled exception as #VALUE to Excel.
You can insert your own handler for unhandled exceptions by calling ExcelIntegration.RegisterUnhandledExceptionHandler.
If you want to show a message in that context, it's a bit tricky, since the error handler runs on Excel's calculation thread. The Excel-DNA LogDisplay is safe to call from here though.
You could show an alert after the calculations are complete, but a modal message for every error is a bad idea for the long run.
I show how to do all of these things in the snippet below.
Regards,
Govert
module MyFunctions
open System
open ExcelDna.Integration
open ExcelDna.Logging
// The unhandled exception handler should have the type obj->obj
let private myErrorHandler (exn : obj) : obj =
// ex is typically an Exception
let ex = exn :?> Exception
// We can get hold of the calling cell, if we want to add that to the error logging
// (But directly converting the ExcelReference to an address can't (easily) be done in this context)
let caller = XlCall.Excel(XlCall.xlfCaller) :?> ExcelReference
// The LogDisplay is safe to call from a calculation context
LogDisplay.WriteLine("Error at " + caller.ToString() + " : " + ex.ToString())
// This will run as a macro after the calculation is complete, so now we can get the address of the ExcelReference:
// But one might get quite irritated if many cells had errors, and each error showed an alert...
ExcelAsyncUtil.QueueAsMacro(
fun () ->
let callerAddress = XlCall.Excel(XlCall.xlfReftext, caller, true) :?> string
XlCall.Excel(XlCall.xlcAlert, "There was an error in cell " + callerAddress + " - " + ex.Message)
|> ignore
)
// Whatever this handler function returns will be returned to the cell,
// instead of the default #VALUE error result
"ERROR!!! " + ex.Message :> obj
// A public class implementing IExcelAddIn can be used to run code when the add-in is loaded
type public MyAddIn() =
interface IExcelAddIn with
member x.AutoOpen() =
// Why can't F# do the myErrorHandler without the delegate constructore here?
ExcelIntegration.RegisterUnhandledExceptionHandler(UnhandledExceptionHandler(myErrorHandler))
// This is no longer needed if you are using Excel-DNA 0.32
ExcelAsyncUtil.Initialize()
member x.AutoClose() = ()
// Here are the regular function to register with Excel
[<ExcelFunction(Description="An F# function to say Hello")>]
let dnaHelloFs name =
"Hello from F# " + name
// This function will throw an exception, which will then be processed by the UnhandledExceptionHandler
[<ExcelFunction(Description="An F# function to test the exception handler")>]
let dnaTestFsException () : obj =
raise (InvalidOperationException "You shouldn't do this...")