vb.net — Как создать изолированный / без COM COM между библиотеками Visual Basic и C ++ DLL?

Я должен использовать VB (COM) DLL в C ++ DLL.
Я понял, как получить доступ к VB (COM) DLL из C ++ DLL, и это работает.

Теперь у меня проблема в том, что я должен использовать изолированную COM / свободную от COM COM, потому что я не могу зарегистрировать DLL на каждом ПК, на котором она должна использоваться.

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

У меня есть VB DLL с именем AccConnVB.dll со следующим файлом AccConnVB.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0">
<assemblyIdentity
type="win32"name="AccConnVB"version="1.0.0.0" />
<clrClass
clsid="{70da7ef0-1549-4b27-9b00-ade5f37aecbe}"progid="AccConnVB.AccConnVB"threadingModel="Both"name="AccConnVB.tables" >
</clrClass>
</assembly>

И C ++ DLL с именем AccConn.dll со следующим файлом AccConn.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0">
<assemblyIdentity
type = "win32"name = "AccConn"version = "1.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"name="AccConnVB"version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>

Моя C ++ DLL #defines _WIN32_DCOM в своем stdafx.h и #imports AccConnVB.tlb с no_namespace,

Ниже приведен метод из C ++ DLL:

JNIEXPORT jint JNICALL Java_natives_AccessConnection_refreshImportZwei
(JNIEnv *env, jclass jobj, jstring jDatabase){
jint result;
CComBSTR database;

const char* nativeDatabase = env->GetStringUTFChars(jDatabase,0);
database.Append((LPCSTR) nativeDatabase);

CoInitializeEx(NULL,COINIT_MULTITHREADED);
{
ITablesPtr ptr;
HRESULT hr = ptr.CreateInstance(__uuidof(tables));
if (SUCCEEDED(hr))
{
result = (jint) ptr->refreshImportZwei(BSTR(database));
}
}
CoUninitialize();
}

Я убедился, что все работает с зарегистрированным AccConnVB.dll, но использовать его на компьютере, где он не зарегистрирован, не удается.

Файлы манифеста встраиваются посредством выполнения mt.exe в cmd.exe со следующей строкой: mt -manifest H:\AccConnVB.manifest -outputresource:H:\AccConnVB.dll;#1, для AccConn.dll и AccConn.manifest соответственно.

Ничего другого не установлено, при доступе к AccConn.dll AccConnVB.dll, AccConn.manifest и AccConnVB.manifest находятся в одной папке.

Я последовал за прохождением Вот и попробовал некоторые варианты этого, но ничего не получалось.

Спасибо всем большое заранее!

Приложение 1:

AccConn.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0">
<assemblyIdentity
type = "win32"name = "AccConn"version = "1.0.0.0" />
<file name="AccConnVB.dll">
<comClass
clsid="{70da7ef0-1549-4b27-9b00-ade5f37aecbe}"tlbid="{1CA12FB4-4A5C-41FF-A508-DCC6CE0D26CD}"progid="AccConnVB.tables" />
<typelib
tlbid="{1CA12FB4-4A5C-41FF-A508-DCC6CE0D26CD}"version="1.0" helpdir="" />
</file>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"name="AccConnVB"version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>

AccConnVB.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0">
<assemblyIdentity
type="win32"name="AccConnVB"version="1.0.0.0" />
</assembly>

Приложение 2:

OfficeConn.manifest — C ++ — DLL — (изменилось название):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<file name="OfficeConn.dll" hashalg="SHA1">
<comClass clsid="{2C0D73B5-7AA4-4D17-970D-042804E206B2}" tlbid="{DB27F83B-DD8E-4AD8-A6A3-9232A9C1692C}">
</comClass>
<typelib tlbid="{DB27F83B-DD8E-4AD8-A6A3-9232A9C1692C}" version="1.0" helpdir="" flags="HASDISKIMAGE">
</typelib>
</file>
<comInterfaceExternalProxyStub name="IOffice" iid="{19485BDA-0BAE-3527-8F9B-C90B43746B03}" tlbid="{DB27F83B-DD8E-4AD8-A6A3-9232A9C1692C}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}">
</comInterfaceExternalProxyStub>
<comInterfaceExternalProxyStub name="_offClass" iid="{1FA5D7FC-1CAE-49E0-A99E-B97E8FE3466E}" tlbid="{DB27F83B-DD8E-4AD8-A6A3-9232A9C1692C}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}">
</comInterfaceExternalProxyStub>
</assembly>

OfficeConnVB.manifest — VB-DLL — (изменил название):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity name="OfficeConnVB" version="1.0.0.0" publicKeyToken="38d072ba2818144d" processorArchitecture="msil">
</assemblyIdentity>
<clrClass clsid="{2c0d73b5-7aa4-4d17-970d-042804e206b2}" progid="OfficeConnVB.offClass" threadingModel="Both" name="OfficeConnVB.offClass" runtimeVersion="">
</clrClass>
<clrSurrogate clsid="{453B8C28-201B-3705-8CF1-C492C7B259EA}" name="Microsoft.Office.Interop.Outlook.OlDefaultFolders">
</clrSurrogate>
<clrSurrogate clsid="{B5181856-6837-3E65-AF7B-5020DD408339}" name="Microsoft.Office.Interop.Outlook.OlItemType">
</clrSurrogate>
<clrSurrogate clsid="{ECE70AEA-B928-3392-AE59-01373B29D3DA}" name="Microsoft.Office.Interop.Outlook.OlImportance">
</clrSurrogate>
<clrSurrogate clsid="{D74B5B88-8D75-3D21-A9BA-F6DBDC905F75}" name="Microsoft.Office.Interop.Word.WdSaveOptions">
</clrSurrogate>
<file name="OfficeConnVB.dll" hashalg="SHA1">
</file>
</assembly>

2

Решение

Вы делаете странно распространенную ошибку, ожидая, что Windows решит проблему курицы и яйца. Краткое слово о том, как манифест работает, может помочь.

Windows загружает содержимое манифеста, когда загружает исполняемый файл, записи добавляются во внутреннюю таблицу поиска. Всякий раз, когда приложение сначала запрашивает создание COM-объекта, основным вызовом является CoCreateInstance (), который предоставляет guid CLSID, оно сначала обращается к этой таблице поиска. Если CLSID совпадает, то запись сообщает ему, какая DLL должна быть загружена. Если совпадений нет, то возвращается к традиционному поиску в реестре.

Курица и яйцо в том, что ваша DLL еще не загружена. Таким образом, его записи манифеста еще не активны.

Яйцо должно прийти первым, <clrClass> запись должна идти в манифест, который вы встраиваете в исполняемый файл C ++. Как это:

  <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="AccConn" version="1.0.0.0" />
<file name="foobar.dll"/>
<clrClass ...etc>
</clrClass>
</assembly>

Статья MSDN это здесь.

3

Другие решения

Вы должны использовать идентификатор ресурса # 2 для DLL, поэтому измените выполнение mt.exe, чтобы использовать # 2 вместо # 1. По крайней мере, это так для собственных DLL, я не уверен, что так должно быть для управляемых DLL, так что попробуйте.

Вы должны переместить все, что касается библиотеки VB.NET, за исключением зависимости, в манифест VB.NET, поскольку это подходящее место для хранения этой информации.

Вы должны использовать узлы clrClass вместо узлов comClass для классов .NET COM.

Вам может потребоваться сгенерировать библиотеку типов (tlbexp.exe) и объявить ее в манифесте (по желанию, вы также можете встроить ее в DLL, но я советую не делать этого, если сама DLL большая), если вы хотите, чтобы ваши классы и интерфейсы, подлежащие проверке и маршалированию потребителями библиотеки типов, например VBA, VC ++ #import директива и генераторы кода в целом. Кроме того, вам может потребоваться объявить экспортированные интерфейсы в манифесте, если вы создаете объекты вне VB.NET, которые реализуют его экспортированные интерфейсы и которые должны быть упорядочены.

Если ваша библиотека единственный генератор объектов, которые реализуют экспортируемые интерфейсы используется в той же квартире, вам не нужно ни генерировать, ни объявлять библиотеку типов. Я думаю. NET реализует IMarshal, так что этот конкретный сценарий работает без библиотеки типов.


AccConn.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"name="AccConn"version="1.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"name="AccConnVB"version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>

AccConnVB.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"name="AccConnVB"version="1.0.0.0" />
<file name="AccConnVB.dll" />
<clrClass clsid="{70da7ef0-1549-4b27-9b00-ade5f37aecbe}"name="AccConnVB.tables"progid="AccConnVB.AccConnVB"threadingModel="Both" />
</assembly>

РЕДАКТИРОВАТЬ: в соответствии с обновлением вашего вопроса.

У вас нет элемента зависимости в манифесте C ++, поэтому он не знает о сборке VB.NET по-COM без регистрации.

Кажется, вы объявляете библиотеку типов VB.NET в манифесте C ++.

Кажется, вы объявляете comClass в манифесте C ++, который объявлен как clrClass в манифесте VB.NET. Не делай этого!

1

По вопросам рекламы [email protected]