Ранняя привязка библиотеки COM C # в VBA

Хотя это длинный вопрос, часть кодирования и тестирования должна быть действительно легко воспроизведена.

Я создал два отдельных Class Libraries в C# и я думаю, что я столкнулся с проблемой столкновения имен, вызванной существующими ключами реестра из моих предыдущих проектов и испытаний.

Вот мои два classа:

 using System; using System.Runtime.InteropServices; namespace Test { [InterfaceType(ComInterfaceType.InterfaceIsDual), Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")] public interface ITest { // body } [ClassInterface(ClassInterfaceType.None)] [Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")] [ProgId("Test.TestClass")] public class TestClass : ITest { // body } } 

а также

 using System; using System.Runtime.InteropServices; using ADODB; namespace Test { [InterfaceType(ComInterfaceType.InterfaceIsDual), Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")] public interface IConnection { // body } [ClassInterface(ClassInterfaceType.None)] [Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")] [ProgId("Test.Connection")] public class Connection : IConnection { // body } } 

Я выставил .Net Components для COM следующим образом:
Чтобы получить доступ к assemblyм из Excel, я добавил ссылки ADODB на сборку, пометил make make COM COM и зарегистрировался для com interop . Кроме того, я добавил ссылки на каждый файл *.tlb ( 2 файла для двух проектов ), поэтому я могу получить к ним доступ с использованием раннего связывания и использовать VBA Intellisense .

Я выполнил ту же процедуру на другом компьютере, и я могу использовать раннее связывание, используя class Connection as.

Я думаю, что есть некоторые старые ключи реестра, которые я не удалял на своей исходной машине, что не позволит мне использовать Connection качестве имени classа в VBE. Я вручную просмотрел свой реестр и удалил все, что мог подумать о моем проекте.

Я также полностью удалил проект и использовал стороннее программное обеспечение для сканирования реестра для отсутствующих dll однако это не помогло: /

Удалены все ранее зарегистрированные идентификаторы GUID и применяются новые, каждый раз, когда я создал новый проект (на всякий случай )

Созданы новые проекты с использованием разных пространств имен и имен classов ( using ADODB; ) Я не смог использовать раннее связывание еще, как этот Test.Connection поэтому я предполагаю, что у меня есть проблема столкновения имен . Я подозреваю, что имя classа Connection вызывает его, хотя я не уверен на 100%.

Test.TestClass имен Test.TestClass в VBA:

Я могу объявлять и использовать экземпляры типа TestClass двумя способами, используя раннее связывание:

 Dim x as Test.TestClass Dim x as TestClass 

Теперь, перейдя в VBE Object Explorer F2, TestClass правильно отображается по сравнению с другими библиотеками и общей идеей использования COM.

Проводник объектов TestClass

Однако, когда я хочу использовать библиотеку Test.Connection я не могу использовать раннюю привязку, следуя той же схеме, что и TestClass потому что сгенерированный файл *.tlb автоматически изменяет ( переименовывает ) ProgId's . Поэтому вместо этого я должен привязать его так

 Dim x As Test.Test_Connection Dim x As Test_Connection 

и Object Explorer отображает имена, используя _ (подчеркивание), а не . (точки), что легко объяснить, почему это происходит – продолжайте читать 🙂

не может использовать раннее связывание

В его нынешнем виде я уверен, что это не среда VBE, которая меняет имена, чтобы избежать столкновений. Это генератор VS ‘ *.tlb .

Я пошел в папку сборки и открыл оба файла *.tlb в Notepad++ . Я ясно вижу, что *.tlb для библиотеки Test.Connection уже содержит имена с Test.TestClass отличие от Test.TestClass который имеет . s

Я попытался вручную отредактировать файл *.tlb но как его смешанный двоичный файл, он имеет некоторый эффект, но также заставляет Excel перестать отвечать на некоторые странные способы, поэтому я должен избегать этого метода.

Я думаю, что я хорошо объяснил, в чем проблема и откуда она взялась. Теперь мой вопрос:
Существуют ли какие-либо атрибуты для использования в коде C #, чтобы сообщить генератору *.tlb не переопределять мои данные ProdId ?
Существуют ли альтернативные способы манипулирования файлами *.tlb ?
Является ли эта проблема name collision и ее можно избежать без изменения имени classа Connection ?

Прошу прощения за такой длинный вопрос, но я уже копаю и копаю уже почти неделю, и я все еще не могу это решить.

Примечание. В VBA (или VBE Object Explorer), используя IntelliSense ctrl + space , похоже, что ни Connection ни Recordset не использовались. Поскольку они еще не зарезервированы в среде VBE, я считаю, что это связано с самой моей библиотекой.

В качестве ссылки на то, почему эта проблема была поднята здесь, см. Раздел VBA, эквивалентный использованию C # или импорт VB.NET, создающий псевдонимы
Большое спасибо за уделенное время!

Не избегайте фокусировки на ProgId. Вы на самом деле не используете его, диалоги, которые вы сделали на скриншоте, показывают фактические имена classов, а не ProgId.

Получение имени classа, переименованного в «Test_Connection», является нормальным поведением для экспортера библиотеки типов. Он будет делать это каждый раз, когда обнаруживает конфликт с другим интерфейсом или именем classа с тем же именем. Вы, безусловно, увеличиваете вероятность этого, также имея зависимость от ADODB, он также имеет class Connection. Очень тривиальное решение – просто переименовать свой собственный тип.

Ваш fragment кода не может воспроизвести эту проблему. Но, конечно, он неполный, мы не можем видеть, что вы действительно делаете в коде. Вы введете зависимость от ADODB, если какой-либо из ваших общедоступных методов использует тип из этой библиотеки типов. Также обратите внимание, что есть ненулевые шансы, что это произойдет случайно. Возможно, вы написали метод, который предназначен для использования вашего собственного типа подключения, но компилятор разрешил его для типа ADODB.

Важным инструментом для отладки этого является Oleview.exe, запустите его из командной строки Visual Studio. Сначала создайте библиотеку типов для сборки C # с помощью Tlbexp.exe. Затем используйте File + View Typelib, вы увидите содержимое библиотеки типов, выраженное в синтаксисе IDL. У вас мало проблем с распознаванием сопоставления типов C # с объявлениями IDL.

Обратите внимание на директивы importlib в верхней части файла. Они должны выглядеть так:

 // TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D} importlib("mscorlib.tlb"); // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046} importlib("stdole2.tlb"); 

Там должны быть только те двое. Первый импортирует типы .NET, определяя _Object. Второй импортирует стандартные типы COM, такие как IDispatch. Если вы видите дополнительные здесь, вы увеличиваете вероятность столкновения имен.

Этот IDL также дает вам возможность решить проблему, в случае, если она неразрешима, вы можете отредактировать ее, чтобы назвать типы так, как вы хотите. Сохраните его в .idl-файле. И скомпилируйте его с помощью midl.exe / tlb для создания библиотеки типов с вашими предпочтительными именами. Обратите внимание, что это не то, что вам нужно делать часто.