Необязательный аргумент надстройки COM vs Automation, написанной на языке C#

я работаю над библиотекой надстройки COM и надстройки Excel Automation, основные коды которой написаны на C#. Я хотел бы установить необязательный аргумент для функции, и я знаю, что это законно для C# и VBA, и даже Excel WorksheetFunction. Но я нахожу, что, наконец, необязательный аргумент работает исключительно для надстройки COM и Automation, что означает, что если одна надстройка запускается первой, то работает хорошо, но необязательный аргумент другой не будет работать.

ниже пожалуйста см. пример:

в решении VS 2013 у меня есть два проекта: Один называется TestVBA и еще одна называется TestExcel.

TestVBA предназначен для надстройки COM и построен через "Excel 2013 Add-in" и есть два .cs файлы:

  1. ThisAddIn.cs

этот файл генерируется автоматически и изменена немного. Коды

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Excel;

namespace TestVBA
{
    public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }

        private ExcelVBA oExcelVBA;

        protected override object RequestComAddInAutomationService()
        {
            if (oExcelVBA == null)
            {
                oExcelVBA = new ExcelVBA();
            }
            return oExcelVBA;
        }
        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }

        #endregion
    }
}
  1. TestVBA.cs

этот файл является основным файлом расчета надстройки COM. Коды

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

using System.Reflection;


namespace TestVBA
{
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class ExcelVBA
    {
        public int TestAddVBA(int a = 1, int b = 1)
        {
            return a + b;
        }
    }
}

еще один TestExcel предназначен для надстройки автоматизации Excel и построен через C# "библиотека классов" и есть два .cs файлы:

  1. BaseUDF.cs

этот файл определяет оформление двух атрибутов. Коды

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace BaseUDF
{
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public abstract class BaseUDF
    {
        [ComRegisterFunctionAttribute]
        public static void RegisterFunction(Type type)
        {
            // Add the "Programmable" registry key under CLSID.
            Registry.ClassesRoot.CreateSubKey(
              GetSubKeyName(type, "Programmable"));
            // Register the full path to mscoree.dll which makes Excel happier.
            RegistryKey key = Registry.ClassesRoot.OpenSubKey(
              GetSubKeyName(type, "InprocServer32"), true);
            key.SetValue("",
              System.Environment.SystemDirectory + @"mscoree.dll",
              RegistryValueKind.String);
        }

        [ComUnregisterFunctionAttribute]
        public static void UnregisterFunction(Type type)
        {
            // Remove the "Programmable" registry key under CLSID.
            Registry.ClassesRoot.DeleteSubKey(
              GetSubKeyName(type, "Programmable"), false);
        }

        private static string GetSubKeyName(Type type,
          string subKeyName)
        {
            System.Text.StringBuilder s =
              new System.Text.StringBuilder();
            s.Append(@"CLSID{");
            s.Append(type.GUID.ToString().ToUpper());
            s.Append(@"}");
            s.Append(subKeyName);
            return s.ToString();
        }

        // Hiding these methods from Excel.
        [ComVisible(false)]
        public override string ToString()
        {
            return base.ToString();
        }

        [ComVisible(false)]
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        [ComVisible(false)]
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}
  1. TestExcel.cs

этот файл является основным файлом расчета надстройки Excel Automation. Коды

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Win32;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;
using Extensibility;

namespace TestExcel
{
    [Guid("7127696E-AB87-427a-BC85-AB3CBA301CF3")]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    public class TestExcel : BaseUDF.BaseUDF
    {
        public int TestAddExcel(int a = 1, int b = 1)
        {
            return a + b;
        }
    }
}

после построения, две надстройки были зарегистрированы в системе и в Excel мы можем использовать их успешно.

для надстройки автоматизации мы называем их в электронной таблице как =TestAddExcel(2,3) и =TestAddExcel() оба они работают очень хорошо и дают правильный результат 5 и 2. Однако, когда я пытаюсь вызвать надстройку COM через

Sub TestVBA_Click()

Dim addIn As COMAddIn
Dim TesthObj As Object

Set addIn = Application.COMAddIns("TestVBA")
Set TestObj = addIn.Object

Range("Output").Value2 = TestObj.TestAddVBA(2, 3)
Range("Output").Offset(1, 0).Value2 = TestObj.TestAddVBA()

End Sub

первый вызов со всеми существующими аргументами работает хорошо, но для второго с аргументы отсутствуют показывает ошибку Type mismatch.

самое интересное, когда я закрываю тестовый файл excel и открываю его снова, на этот раз я сначала тестирую надстройку COM, все еще через вышеуказанные коды VBA, оба вызова работают очень хорошо. Затем, когда я тестирую две функции электронной таблицы, которые раньше хорошо работали, только первая хороша, вторая с аргументами отсутствует =TestAddExcel() выдает #VALUE!.

было бы очень приятно, если кто-то может помочь с этим странным вопрос.

2 ответов


Я не уверен, как ссылаться на библиотеку классов без регистрации для COM? Теперь я вижу, ты используешь позднюю привязку. Я не знал, что вы можете это сделать (не думал, что это позволит вам) и подозреваю, что это проблема, она также соответствует Type mismatch ошибка.

следуйте второму решению в my канонический ответ здесь на 3 метода для вызова .Net из Excel или VBA и убедитесь, что вы зарегистрируйтесь для COM:

перейдите на вкладку " сборка "и установите флажок"зарегистрироваться для COM-взаимодействия". На данный момент у вас есть дополнительный шаг, если вы работаете в Windows Vista или выше. Visual Studio необходимо запустить с правами администратора для регистрации COM-взаимодействия. Сохраните проект и закройте Visual Studio. Затем найдите Visual Studio в меню Пуск и щелкните правой кнопкой мыши на нем и выберите "Запуск от имени администратора". Откройте проект в Visual Studio. Затем выберите "Build", чтобы построить надстройку.

enter image description here


необязательно, если выше не работает, следуйте третьему решению в моем ответе и ссылайтесь на надстройку автоматизации и используйте раннюю привязку, я протестировал это, и он отлично работает:

enter image description here

Sub TestVBA1_Click()

Dim addIn As COMAddIn
Dim TesthObj As Object

Set addIn = Application.COMAddIns("TestVBA")
Set TestObj = addIn.Object

Debug.Print TestObj.TestAddVBA(2, 3)
Debug.Print TestObj.TestAddVBA()


Dim dotNetClass As TestExcel.TestExcel
Set dotNetClass = New TestExcel.TestExcel

Debug.Print dotNetClass.TestAddExcel(7, 3)
Debug.Print dotNetClass.TestAddExcel()

End Sub

Это полный удар в темноте, но можете ли вы создать перегруженные версии метода, чтобы имитировать способ, которым вы бы это сделали, прежде чем C# имел дополнительные параметры и посмотреть, будет ли это работать?

public int TestAddExcel(int a, int b)
{
    return a + b;
}

public int TestAddExcel(int a)
{
    return a + 1;
}

public int TestAddExcel()
{
    return 2;
}