Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过Excel DNA传递Excel。范围从VBA到C#_C#_Vba_Vsto_Excel Dna - Fatal编程技术网

通过Excel DNA传递Excel。范围从VBA到C#

通过Excel DNA传递Excel。范围从VBA到C#,c#,vba,vsto,excel-dna,C#,Vba,Vsto,Excel Dna,我正在研究如何正确/最佳地传递Excel。通过Excel DNA将对象从Excel中的VBA扩展到C#,然后通过传递的引用与Excel对象模型交互 示例代码: '***************** VBA code ******************** Sub test2() Dim rng As Excel.Range Set rng = Worksheets("test_output").Range("D9") Dim m

我正在研究如何正确/最佳地传递Excel。通过Excel DNA将对象从Excel中的VBA扩展到C#,然后通过传递的引用与Excel对象模型交互

示例代码:

    '***************** VBA code ********************
    Sub test2()
        Dim rng As Excel.Range
        Set rng = Worksheets("test_output").Range("D9")

        Dim myDLL As New XLServer.MyClass
        Call myDLL.test_ExcelRangePassedAsObject(rng)
        Call myDLL.test_ExcelRangePassedAsRange(rng)
    End Sub



//**************** C# Code **********************
using System;
using ExcelDna.Integration;
using ExcelDna.ComInterop;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop;
using Excel = Microsoft.Office.Interop.Excel;

namespace XLServer
{
    [ComVisible(false)]
    class ExcelAddin : IExcelAddIn
    {
        public void AutoOpen()
        {
            ComServer.DllRegisterServer();
        }
        public void AutoClose()
        {
            ComServer.DllUnregisterServer();
        }
    }    

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class MyClass                            
    {
        public void test_ExcelRangePassedAsObject(object range)
        {
            Excel.Range rng = (Excel.Range)range;
            rng.Worksheet.Cells[1, 1].Value = "Specified range was: " + rng.Address.ToString();
        }

        public void test_ExcelRangePassedAsRange(Excel.Range range)
        {
            Excel.Range rng = range;
            rng.Worksheet.Cells[2, 1].Value = "Specified range was: " + rng.Address.ToString();
        }
当我运行它时,我得到了预期的输出:
A1:指定范围为:$D$9
A2:指定范围为:$D$9

在花了大量时间在谷歌上搜索Excel的DNA问题,却什么都没想到之后,我写了这篇文章,实际上很惊讶它居然没有问题

所以我想我的问题是,对于那些在这方面有经验的人来说……这是正确的/最好的方法吗?

例如,我遇到许多类似的帖子:


…当人们处理
ExcelReference
对象时,不得不使用令人难以置信的晦涩代码将这些对象转换为
Excel.Range
对象,这几乎让人感觉我缺少了什么?

是的,这是正确的方法,只要您:

  • 确保库项目未标记为“注册COM互操作”。您不希望构建直接将.dll注册为
    XLServer.MyClass
    COM类型的COM服务器的过程,而是将.xll用作COM服务器。这将确保COM对象与其他外接程序位于同一AppDomain中

  • ComServer
    属性添加到.dna文件中的
    标记中,如下所示

  • 注意所有COM接口版本控制规则

  • 关于该主题的最佳参考文献是Mikael Katajamäki的通读文章,我想你会发现:


    现在让我们来了解一下谷歌小组讨论的背景:

    大多数exceldna内部都与excelcapi(由excelsdk定义)有关,它非常适合制作高性能的工作表udf。在此设置中,描述工作表引用的C API结构是
    ExcelDna.Integration.ExcelReference
    类型中的包装器。这是一个小型数据结构,用于封装图纸指针(称为SheetId)和引用的范围
    ExcelReference
    对象可以安全地用于多线程UDF,并且可以来回传递到C API。Excel DNA工作表函数可配置为在适当时接收
    ExcelReference
    对象作为输入

    Range
    COM对象是完全不同的东西。它是围绕这样一个表引用的COM对象包装器,受所有COM线程、生存期和其他限制的约束。Microsoft不支持在.xll中定义的UDF函数中使用COM对象模型(以及因此而产生的
    范围
    对象),虽然它基本上是有效的,但尝试在多线程函数中使用这些对象可能会导致严重的问题

    在放入Excel DNA加载项的宏或功能区回调(作为异步触发的宏,由ExcelAsyncUtil.QueueAsMacro启动)中,您可以安全地使用C API和COM对象模型

    从精简的
    ExcelReference
    对象转换为COM
    范围
    对象并不难,但这取决于是否要支持多区域范围。如果不是,那么简单如下:

    static Range ReferenceToRange(ExcelReference xlref)
    {
        string refText = (string)XlCall.Excel(XlCall.xlfReftext, xlref, true);
        dynamic app = ExcelDnaUtil.Application;
        return app.Range[refText];
    } 
    

    这个助手不是
    ExcelReference
    类型的一部分的唯一原因是Excel DNA仍然支持.NET 2.0,而有意义的COM类型统一只有在.NET 4.0之后才可用。这就是为什么我选择堆栈溢出而不是Google组的原因……这是我不了解的。平心而论,这条线索最初始于2011年,但2014年10月14日发布的问题仍然难以解决,而且他来自c#,所以我不明白为什么他不能直接获得范围参考。也许他的插件是基于DNA而不是VSTO的?这有意义吗?我只是在学习,所以没有任何线索。事实上,戈弗特现在也不知道那个家伙在说什么,因为我重读了它……谢谢你的全面回答,这正是我想要知道的。我非常想了解更多关于您提到的特定COM注意事项,如果您手头有任何链接,我将不胜感激。(“您不希望构建过程直接将.dll注册为XLServer.MyClass COM类型的COM服务器,而是将.xll用作COM服务器。这将确保COM对象与其他外接程序位于同一AppDomain中。”)假设您想要在工作表UDF和VBA中使用的COM对象之间共享某种缓存。如果UDF部件和COM对象位于同一AppDomain中,那么共享就容易多了。为COM访问单独注册.dll将导致.NET运行时在默认AppDomain中激活它,而Excel DNA加载项在其自己的AppDomain中运行。另外-Excel DNA注册不需要管理员权限。是否有任何理由不在功能区回调中使用ExcelAynscUtil.QueueAsMacro?我想同时使用COM和C API,在QueueAsMacro中对我的函数的包装调用允许我使用XlCall.Excel(XlCall.xlfGetCell,53,参考)。如果我没有使用它,我就无法找到成功调用该函数的方法。我的Ribbon/AddIn与应用程序事件挂钩,并且需要在某些处理程序中保持一点状态,因此使我的所有回调保持静态,以便在它们上使用application.Run()变得太复杂了。此外,当QueueAsMacro委托引发错误时,谁捕捉到该异常?它似乎不是我的功能区回调或ExcelIntegration.RegisterUnhandledExceptionHandler()方法。