Some more tests below.
Excel references can be either 'internal' references, cells without
sheet info, or 'external' references which contain sheet information.
In the calls we are testing, Excel is passing an 'internal' reference
to Excel-DNA, even though the sheet is explicitly named in the
argument - I guess Excel figures out that it is the 'same' sheet as
the function. Now Excel-DNA tries to convert to an ExcelReference,
which is essentially an 'external' reference which has a SheetId too.
In converting an 'internal' reference to an 'external' reference,
Excel-DNA needs to determine the current sheet's SheetId. This step
seems to be going wrong in this case.
Internally, Excel-DNA tries to get the Current sheet (in
XlCallImpl.GetCurrentSheetId12()) by calling xlSheetNm, following the
documentation here:
http://msdn.microsoft.com/en-us/library/bb687895.aspx.
Excel-DNA passes an 'external reference' with SheetId zero. The
Microsoft documentation says: "If the ID is set to zero, xlSheetNm
returns the name of the current sheet." This is not happening when our
function is registered as IsMacroType=true (this causes registration
with a # type, discussed here:
http://msdn.microsoft.com/en-us/library/bb687900.aspx,
under the heading 'Registering Worksheet Functions as Macro Sheet
Equivalents').
The tests below show what is going wrong more directly:
* Without passing in the ExcelReference as an argument, but calling
xlSheetNm directly from the function shows the underlying problem (in
the IsMacroType=true case). The functions TestDirect / TestMacroDirect
show this, with TestMacroDirect returning the wrong sheet when another
sheet is active.
* Using xlfCaller does not seem to have this problem - the sheet
returned by caller seems to correctly be the Current sheet, whether
IsMacroType=true or not.
I'd have to think carefully whether the caller's sheet is always the
right sheet to use when converting from an 'internal' reference to an
'external' reference.
I'm afraid we're getting into details of the Excel SDK and the C API
which is beyond my expertise.
Are your functions marked IsMacroType=true?
Do they have to be?
Regards,
Govert
<DnaLibrary Language="C#" RuntimeVersion="v4.0">
<![CDATA[
using System;
using ExcelDna.Integration;
public static class Test
{
[ExcelCommand(MenuName="Test RefText", MenuText ="Update")]
public static void Update()
{
dynamic xlApp = ExcelDnaUtil.Application;
xlApp.WorkSheets["Sheet2"].Activate();
xlApp.Range["Sheet1!A1"].Formula="=TestFunction(Sheet1!B1)";
xlApp.Range["Sheet1!
A2"].Formula="=TestMacroTypeFunction(Sheet1!B2)";
xlApp.Range["Sheet1!A3"].Formula="=TestDirect()";
xlApp.Range["Sheet1!A4"].Formula="=TestMacroTypeDirect()";
xlApp.Range["Sheet1!A5"].Formula="=TestCaller()";
xlApp.Range["Sheet1!A6"].Formula="=TestMacroTypeCaller()";
xlApp.WorkSheets["Sheet1"].Activate();
}
[ExcelFunction(IsMacroType=true)]
public static string TestMacroTypeFunction(
[ExcelArgument(AllowReference=true)] object cells)
{
string sheetName = (string)XlCall.Excel(XlCall.xlSheetNm, cells);
return sheetName;
}
public static string TestFunction(
[ExcelArgument(AllowReference=true)] object cells)
{
string sheetName = (string)XlCall.Excel(XlCall.xlSheetNm, cells);
return sheetName;
}
public static string TestDirect()
{
// Make an ExcelReference with SheetId = 0.
ExcelReference xlRef = new
ExcelReference(0,0,0,0,IntPtr.Zero);
// Returns the Sheet Name of the *Current* sheet
string sheetName = (string)XlCall.Excel(XlCall.xlSheetNm,
xlRef);
return sheetName;
}
[ExcelFunction(IsMacroType=true)]
public static string TestMacroTypeDirect()
{
// Make an ExcelReference with SheetId = 0.
ExcelReference xlRef = new
ExcelReference(0,0,0,0,IntPtr.Zero);
// Returns the Sheet Name of the *Current* sheet
string sheetName = (string)XlCall.Excel(XlCall.xlSheetNm,
xlRef);
return sheetName;
}
public static string TestCaller()
{
ExcelReference xlRef =
(ExcelReference)XlCall.Excel(XlCall.xlfCaller);
string sheetName = (string)XlCall.Excel(XlCall.xlSheetNm,
xlRef);
return sheetName;
}
[ExcelFunction(IsMacroType=true)]
public static string TestMacroTypeCaller()
{
ExcelReference xlRef =
(ExcelReference)XlCall.Excel(XlCall.xlfCaller);
string sheetName = (string)XlCall.Excel(XlCall.xlSheetNm,
xlRef);
return sheetName;
}
}
]]>
</DnaLibrary>