Обертка сторонней DLL

У меня есть сторонняя DLL, которую необходимо динамически загружать с помощью LoadLibrary() и которая использует соглашение о вызовах __cdecl. Мне нужно иметь возможность использовать dll из VB6, поэтому я создал собственную DLL-оболочку, которая использует соглашение о вызовах __stdcall и экспортирует необходимые функции.

Теперь появилось дополнительное требование, и я изо всех сил пытаюсь понять, как с ним справиться; завернутая DLL предоставляет API для другого приложения, и мне нужно одновременно подключиться к двум экземплярам приложения. Это проблема, так как DLL не имеет концепции сеанса, типичное взаимодействие будет выглядеть так:

tpc_connect("service1")
// Do some stuff
tpc_disconnect()

и то, что я должен быть в состоянии сделать, это

session1 = tpc_connect("service1")
session2 = tpc_connect("service2")
// Do some stuff with session1
// Do some stuff with session2
tpc_disconnect(session1)
tpc_disconnect(session2)

Основная проблема, как я вижу, заключается в том, что один процесс может быть подключен только к одной службе, поэтому первое решение, которое я попробовал, состояло в том, чтобы переместить оболочку DLL в отдельный процесс, создав внепроцессный COM-сервер с использованием ATL. У меня сейчас проблема в том, что я получаю только один экземпляр COM-сервера.

Итак, мои вопросы (наконец): есть ли способ принудительно создать новый экземпляр COM-сервера ATL? Это лучший подход к проблеме или кто-то может придумать лучший способ решить эту проблему.

Спасибо Джексон


person Jackson    schedule 23.04.2009    source источник


Ответы (2)


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

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

Вот что я сделал:

  • Добавьте в оболочку функции для создания и уничтожения экземпляров библиотеки.

  • Измените все остальные функции, чтобы они брали указатель на экземпляр используемой библиотеки.

  • В функции создания экземпляра сначала попытайтесь создать жесткую ссылку на исходную DLL, используя случайное имя файла (например, используйте CreateHardLink). Если это не поможет, сделайте настоящую копию DLL со случайным именем. Вам не нужно использовать расширение DLL, если вы этого не хотите. Динамически загрузите эту копию DLL и указателей функций и верните указатель на внутреннюю структуру.

  • В функции уничтожения просто выгрузите DLL и удалите ее.

  • Лучше всего создать копию во временном каталоге, чтобы было очевидно, что ее можно удалить в случае сбоя, хотя я не уверен, есть ли ограничения в Vista и позже на загрузку DLL из временного каталога.

Это все работает идеально для меня.

person brofield    schedule 23.04.2009
comment
Завершил внедрение оболочки - я попытался использовать CreateHardLink вместо копии, но у меня это не сработало, поэтому в конце я использовал полную копию DLL. - person Jackson; 24.04.2009
comment
CreateHardLink работает только тогда, когда на диске NTFS цель находится в том же разделе, что и источник. В моей оболочке я сначала пробую CreateHardLink, так как это позволит избежать копирования файла и будет быстрым, однако, если это не удается, я делаю настоящую копию. Рад, что это помогло вам. - person brofield; 27.04.2009

если вам нужно только 2 сеанса, вы можете сделать копию исходной dll и назвать ее как-то иначе. они в вашей dll-оболочке экспортируют два отдельных вызова (по одному для каждой dll). поэтому у вас будет:

session1 = tcp_connect("whatever")      'this points to dll1.dll
session2 = tcp_connect2("whatever")     'this points to a copy of dll1 called dll2.dll

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

-Дон

person Don Dickinson    schedule 23.04.2009