Hi Ian,
Firstly, within Excel-Dna *macros* (not functions) like this example,
I believe it is safe to call the Automation (COM) API just like you
would from a COM add-in or from a VBA macro. So I think it is safe to
call:
value = ExcelDnaUtil.Application.ActiveSheet.Cells(3,3).Value
If you want to use the XLL API, you can use the ExcelReference helper
class as in the example you quote. ExcelReference thinly encapsulates
a range reference as used by the API functions. The ExcelReference
constructor takes up to five arguments - RowFirst, RowLast,
ColumnFirst, ColumnLast, SheetId, so you can refer to a large array
without issue.
The SheetId here is an internal handle Excel has for each sheet. It
can be retrieved from a sheet name using the xlSheetId call, which
returns an ExcelReference containing the right SheetId, like so
xlrefSheet2 = XlCall.Excel(XlCall.xlSheetId, "Sheet2")
For a different workbook, use the standard "[BOOK1.XLSX]Sheet1" style
referencing.
With no sheetId passed to the ExcelReference constructor, the active
(front) sheet is used.
I think this answers your immediate questions.
---------------------
For most cases, your macros will be easier to write if you use the COM
API. One reason to use the SDK API is to have consistency between your
macros and your user-defined functions. There might also be
performance advantages to using the SDK API.
Using the COM API from within user-defined *functions* is not really
supported.
However, if you mark your function as IsMacroType=true, I believe you
are in the same position as VBA or an Automation add-in, so you
actually have some limited access to the COM API. As an example, I
also add a function at the bottom that calculates the sum of cells
having a given color (stolen from the OzGrid site). I have made a
wrapper and some helper functions to expose this VBA-style function
(which takes Range arguments) as an Excel-Dna function.
I'd love to know if anyone has a problem when running functions like
these which only do 'friendly' calls to the Excel Automation
interfaces. It works fine for me in limited testing. Of course, trying
to set the values of cells from within a function is not (easily)
possible, just like in VBA or Automation Add-Ins.
I've rambled on a bit. An example to look at is pasted below.
Please post back if you need more clarification.
Kind regards,
Govert
<DnaLibrary>
<Reference AssemblyPath="System.Windows.Forms.dll"/>
<![CDATA[
Imports System.Windows.Forms
Imports ExcelDna.Integration
Public Module RangeTests
<ExcelCommand(MenuName:="RangeTests", MenuText:="Show value in C3
(COM interface)")> _
Sub ShowCell_C3_COM()
Dim app as Object
Dim value as Object
app = ExcelDnaUtil.Application
value = app.ActiveSheet.Cells(3,3).Value
MessageBox.Show("The value in cell C3 is " & value)
End Sub
<ExcelCommand(MenuName:="RangeTests", MenuText:="Show value in C3
(SDK interface)")> _
Sub ShowCell_C3_SDK()
Dim xlref as ExcelReference
Dim value as Object
xlref = new ExcelReference(2,2) ' Zero-based indexing here.
value = xlref.GetValue()
MessageBox.Show("The value in cell C3 is " & value)
End Sub
<ExcelCommand(MenuName:="RangeTests", MenuText:="Show value in Sheet2!
C3 (COM interface)")> _
Sub ShowCell_Sheet2_C3_COM
Dim app as Object
Dim value as Object
app = ExcelDnaUtil.Application
value = app.WorkSheets("Sheet2").Cells(3,3).Value
MessageBox.Show("The value in cell C3 on Sheet2 is " & value)
End Sub
<ExcelCommand(MenuName:="RangeTests", MenuText:="Show value in Sheet2!
C3 (SDK interface)")> _
Sub ShowCell_Sheet2_C3_SDK
Dim xlrefSheet2 as ExcelReference
Dim xlref As ExcelReference
Dim value As Object
' Call xlSheetId to return a reference with the corrent SheetId
xlrefSheet2 = XlCall.Excel(XlCall.xlSheetId, "Sheet2")
xlref = New ExcelReference(2, 2, 2, 2, xlrefSheet2.SheetId)
value = xlref.GetValue()
MessageBox.Show("The value in cell C3 on Sheet2 is " & value)
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'A UDF test
<ExcelFunction(IsMacroType:=True)> _
Function SumColor( _
<ExcelArgument(AllowReference := True)> theColor as Object, _
<ExcelArgument(AllowReference := True)> theSumRange as Object)
Dim refColor as ExcelReference = theColor
Dim refSumRange as ExcelReference = theSumRange
SumColor = _SumColor(ReferenceToRange(refColor),
ReferenceToRange(refSumRange))
End Function
Private Function ReferenceToRange(xlref as ExcelReference) as Object
Dim app As Object = ExcelDnaUtil.Application
Dim refAddress As String
refAddress = ReferenceAddress(xlref)
ReferenceToRange = app.Range(ReferenceAddress(xlref))
End Function
Private Function ReferenceAddress(xlref As ExcelReference ) as String
Dim refRightBottom As ExcelReference
Dim addrLeftTop as String
Dim addrRightBottom as String
Dim bangIndex as Integer
addrLeftTop = XlCall.Excel(XlCall.xlfGetCell, 1, xlref)
refRightBottom = New ExcelReference(xlref.RowLast, xlref.RowLast,
xlref.ColumnLast, xlref.ColumnLast,
xlref.SheetId)
addrRightBottom = XlCall.Excel(XlCall.xlfGetCell, 1, refRightBottom)
If (addrLeftTop = addrRightBottom) Then
ReferenceAddress = addrLeftTop
Else
bangIndex = addrRightBottom.IndexOf("!")
ReferenceAddress = addrLeftTop & ":" &
addrRightBottom.Substring(bangIndex + 1)
End If
End Function
Private Function _SumColor(rColor As Object, rSumRange As Object) As
Double
''''''''''''''''''''''''''''''''''''''
'Written by Ozgrid Business Applications
'
www.ozgrid.com
'Sums cells based on a specified fill color.
''''''''''''''''''''''''''''''''''''''
Dim rCell As Object
Dim iCol As Integer
Dim vResult as Double
iCol = rColor.Interior.ColorIndex
For Each rCell In rSumRange
If rCell.Interior.ColorIndex = iCol Then
vResult = rCell.Value + vResult
End If
Next rCell
_SumColor = vResult
End Function
End Module
]]>
</DnaLibrary>