Доступ к коду надстройки COM из VBA - PullRequest
0 голосов
/ 06 сентября 2010

Я создал надстройку COM для Excel 2003 с помощью Visual Studio 2005 Tools for Office. Код надстройки выглядит следующим образом:

[Guid("EAC0992E-AC39-4126-B851-A57BA3FA80B8")]
[ComVisible(true)]
[ProgId("NLog4VBA.Logger")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Logger
{
    public double Debug(string context, string message)
    {
        Trace.WriteLine(message);
        return message.Length;
    }

    [ComRegisterFunctionAttribute]
    public static void RegisterFunction(Type type)
    {
        Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
        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)
    {
        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();
    }
}

Я настроил проект для регистрации COM-взаимодействия, и я зарегистрировал DLL с:

regasm.exe /tlb NLog4VBA.dll

Когда я открываю Excel, я захожу в Инструменты -> Надстройки, нажимаю Автоматизация и добавляю NLog4VBA.Logger. Затем я могу перейти в меню «Вставка» -> «Функция», выбрать NLogVBA.Logger из списка категорий и выбрать «Отладка».

Конечный результат - это ячейка с содержимым вроде:

=Debug("My Context","My Message")

... и отображаемое значение:

10

Это все как и должно быть. В своем коде VBA я могу перейти в Сервис -> Ссылки и добавить NLog4VBA. Затем я добавляю следующий код для кнопки на моем листе:

Private Sub CommandButton1_Click()
        Application.COMAddIns("NLog4VBA.Logger").Object.Debug "My Context", "My Message"
End Sub

Это невозможно, потому что COMAddIns ("NLog4VBA.Logger") завершается с:

Run-time error '9': Subscript out of range

Может кто-нибудь сказать мне, что мне нужно сделать, чтобы метод Debug () был доступен для моего кода VBA (что для меня более полезно, чем возможность вызывать метод из ячейки)?

Я уверен, что мне здесь не хватает чего-то простого.

Отредактировано 2010/09/07: Я обновил фрагмент кода, добавив атрибут [ProgId], как предложено ниже Джимом; проблема сохраняется. Я вижу объект в реестре:

[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}]
@="NLog4VBA.Logger"

[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]

[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\InprocServer32]
@="C:\\WINDOWS\\system32\\mscoree.dll"
"ThreadingModel"="Both"
"Class"="NLog4VBA.Logger"
"Assembly"="NLog4VBA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="file:///C:/projects/nlog4vba/NLog4VBA/bin/Debug/NLog4VBA.dll"

[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\InprocServer32\1.0.0.0]
"Class"="NLog4VBA.Logger"
"Assembly"="NLog4VBA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="file:///C:/projects/nlog4vba/NLog4VBA/bin/Debug/NLog4VBA.dll"

[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\ProgId]
@="NLog4VBA.Logger"

[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\Programmable]

Кроме того, ProgID отображается в диалоговом окне надстроек:

Add-Ins dialog showing ProgID

Я до сих пор не понимаю, почему это не работает: - (

Ответы [ 2 ]

1 голос
/ 06 сентября 2010

Коллекция COMAddIns индексируется либо с помощью числового индекса, либо с помощью строки, которая является ProgId требуемого компонента. Убедитесь, что ваш ProgId на самом деле «NLog4VBA.Logger» (через атрибут ProgId в .NET) и убедитесь, что объект зарегистрирован с этим идентификатором (который вы можете легко проверить в реестре, выполнив поиск назначенного GUID).

0 голосов
/ 07 сентября 2010

Оказывается, мой код VBA был совершенно неверным; здесь это ответ вежливости Ян Карел Питерсе :

Я думаю, вам нужно сделать что-то подобное:

Private Sub CommandButton1_Click()

        'Declare an object variable using the referenced lib.
        'if all is well, intellisense will tell you what the proper object name is:
        Dim objLogger as NLog4VBA

        'Create an instance of the object
        Set objLogger = New NLog4VBA

        'Now use the object
        objLogger.Object.Debug "My Context", "My Message"
End Sub
...