Совместное COM-взаимодействие с C# и VBA

Я не говорю о вызове VBA COM из C#... наоборот!

То, что я хотел бы сделать, это вызвать библиотеку C# с использованием VBA в MS Access без регистрации DLL. Некоторое время я играл с параллельным взаимодействием, но безуспешно, и мне наконец пришло в голову, что mdb.manifest, вероятно, не является приемлемой заменой exe.manifest (вероятно, очевидно, я знаю, но я пытался быть оптимистом).

Мой вопрос: возможно ли заставить VBA загружать параллельный COM-компонент?

Или есть другой способ использовать незарегистрированную библиотеку C# в Access?

(Прежде чем вы спросите, у меня есть следующие причины: нет абсолютно никакого способа, которым мне будет предоставлен доступ к реестру Windows моего клиента - именно поэтому он был написан в Access в первую очередь. И мне нужно будет реализовать те же функции в Приложение C# в ближайшее время, а не делать это дважды).

4 ответа

Решение

Вам не нужно владеть exe-файлом, чтобы использовать SxS, SxS - другое слово для контекста активации. Если вы можете импортировать соответствующие вызовы win32 в vba (и вы можете), то вы можете использовать контекстный API активации для загрузки файла манифеста.

Больше на предмете и некоторых примерах можно найти здесь.

Чтобы добавить к уже существующим ответам: с .NET 4.0 на самом деле довольно просто использовать C# dll в вашем проекте VBA без регистрации COM.

РЕДАКТИРОВАТЬ: я только что попробовал это с mscorlib.tlb а также mscoree.tlb которые находятся в C:\windows\Microsoft.NET\Framework\v2.0.50727- загрузка сборки, скомпилированной в 3.5--, и она работала просто отлично. Так что, очевидно, вам не нужен.NET 4.0.

Ниже приведен пример использования dll на C# в вашем проекте VBA. Это немного изменено из этого ответа.

1) Добавьте ссылки на следующий тип библиотек вашего проекта VBA (Инструменты-> Ссылки):

C:\windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb
C:\windows\Microsoft.NET\Framework\v4.0.30319\mscoree.tlb

(используйте папку Framework64, если вы используете 64-разрядную версию Office)

2) В своем проекте C# обязательно добавьте [ComVisible(true)] атрибут вашего класса:

using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace VB6FuncLib
{
    [ComVisible(true)]
    public class VB6FuncLib
    {
        public VB6FuncLib()
        { }
        public void test()
        {
            MessageBox.Show("Test Successful");
        }
    }
}

Вам не нужно проверять опцию "Зарегистрироваться для COM Interop". Это только для построения стандартного COM-объекта. Вам также не нужно проверять "Сделать сборку COM видимой", если только вы не хотите, чтобы вся сборка была видимой (это также избавило бы от необходимости COMVisible атрибуты).

3) Добавьте в свой код VBA новый модуль с этим кодом:

Sub Test()
    Dim Host As mscoree.CorRuntimeHost
    Set Host = New CorRuntimeHost
    Host.Start
    Dim Unk As IUnknown
    Host.GetDefaultDomain Unk
    Dim AppDomain As AppDomain
    Set AppDomain = Unk
    Dim ObjHandle As ObjectHandle
    Set FS = CreateObject("Scripting.FileSystemObject")
    Path = FS.GetParentFolderName(CurrentDb().Name)
    Set ObjHandle = AppDomain.CreateInstanceFrom(Path & "\VB6 Function Library.dll", "VB6FuncLib.VB6FuncLib")
    Dim ObjInstance As Object
    Set ObjInstance = ObjHandle.Unwrap
    ObjInstance.test
    Host.Stop
End Sub

4) Скопируйте DLL в ту же папку, что и ваш проект Office, и запустите подпрограмму Test() в VBA.

Заметки:

Следует отметить, что одним из ограничений этого метода является то, что он не будет работать, если файл.DLL хранится на удаленном сетевом ресурсе. Одним простым решением было бы скопировать его в одну и ту же локальную папку на каждом ПК, где он используется. Другое решение - включить двоичные файлы в приложение Access / проект VBA и экспортировать их в MS-Access. Один из способов сделать это - сохранить их в Base64 в виде таблицы или таблицы, затем преобразовать их и экспортировать в двоичном виде.

Мне удалось заставить работать раннее связывание (и, следовательно, Microsoft IntelliSense), создав библиотеку типов для работы с DLL (используя tlbexp) и добавив ссылку на TLB в моем проекте VBA, но это немного усложняет ситуацию. потому что оно требует, чтобы ваше приложение VBA знало, где находятся и DLL, и файлы TLB (а также требует, чтобы кто-то удостоверился, что они там есть).

Проблема в том, что для использования SxS вам нужно иметь исполняемый файл, чтобы настроить конфигурацию для загрузки сборки SxS. У вас нет "собственного" доступа, и хотя вы можете оставить нужную конфигурацию, чтобы она загружала ваш.NET COM материал без регистрации, это не было бы "добропорядочным гражданином".

Если вам не хватает шимминга, вы можете настроить неуправляемую DLL (или взломанную библиотеку классов C# с помощью dllexport, см., Например,) с экспортом, который загрузит платформу.NET, создаст экземпляр управляемого COMVisible DispInterface введите и верните его (метод должен вернуть IDispatch). Затем напишите объявление VBA для вашей функции экспорта DLL (объявленной как возвращающий объект). Если это не имеет смысла, вы, вероятно, не должны пытаться это делать...:) Я делал это раньше в аналогичной ситуации, и это работает, но у меня нет образца, на который можно было бы вам указать.

Библиотеки C# не являются обычными DLL. Они больше похожи на библиотеки COM, которые должны быть зарегистрированы (как элементы управления ActiveX) перед использованием; особенно при вызове из не-.NET кода.

(Если, конечно, все не изменилось...)

Другие вопросы по тегам