Маршалинг неуправляемой dll в C # через ComInterop без регистрации DLL - PullRequest
3 голосов
/ 06 января 2012

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

[ComImport(), Guid("75E81043-CAD5-11D3-800D-00105A5E2FA0")]
public class MyObject { }

[ComImport(), Guid("75E81042-CAD5-11D3-800D-00105A5E2FA0"),
 InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface MyInterface
{
    string EncryptString([In, MarshalAs(UnmanagedType.BStr)] string bstrOrginal);    
}

Тогда позвонить:

MyInterface obj = (MyInterface)new MyObject();
string crypt = obj.EncryptString("something");

Это работает, возвращаемое значение соответствует ожидаемому. Однако, это требует, чтобы dll была зарегистрирована с regsvr32.

Я ищу способ сделать это без требования regsvr32. Предпочтительно, просто имея доступную копию dll. Стоит отметить, что у меня есть источник для неуправляемой библиотеки DLL и возможность изменять ее при необходимости.

Толчок в правильном направлении был бы очень признателен.

Ответы [ 3 ]

3 голосов
/ 06 января 2012

Я хотел сделать то же самое сам. Как упоминает Джим, можно получить адрес DllRegisterServer и вызвать его, но это все равно изменяет ваш реестр различными записями. Если вы не хотите этого делать (например, у вас могут не быть необходимых прав для записи в реестр), есть другой способ.

Любая DLL, в которой находится один или несколько внутрипроцессных COM-объектов, должна предоставлять функцию DllGetClassObject. Эта функция используется для получения экземпляра фабрики класса COM, который используется для создания объекта COM. Что вам нужно сделать, это:

  1. Загрузить библиотеку (DLL), в которой находится нужный COM-объект
  2. Найдите функцию DllGetClassObject
  3. Вызовите DllGetClassObject, передав ему CLSID нужного COM-объекта, это вернет экземпляр IClassFactory.
  4. Вызвать метод CreateInstance на фабрике классов, чтобы получить экземпляр COM-объекта.
  5. Приведите возвращенный объект к интерфейсу, который вы хотите использовать.

Обратите внимание, что при таком подходе есть драконы - это довольно низкий уровень. Если вы что-то не так сделаете, вы столкнетесь с нарушениями прав доступа или хуже. (Например, объявление вашего интерфейса должно точно соответствовать интерфейсу COM).

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

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

// Load the library. You dispose this after you are finished with
// all of your COM objects. 
var library = new LibraryModule();
library.Load("mylibrary.dll"); or whatever your dll is called

var clsid = new Guid("75E81043-CAD5-11D3-800D-00105A5E2FA0");

var myObject = (MyInterface)ComHelper.CreateInstance(library, clsid);

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

2 голосов
/ 06 января 2012

Вам необходимо настроить неуправляемую DLL для COM без регистрации.Здесь довольно полное прохождение , с множеством примеров.Среди прочего, он включает в себя использование манифестов для указания на файл, параллельные сборки и некоторое взаимодействие.

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

1 голос
/ 06 января 2012

Если ваша DLL должна быть COM-объектом, она должна быть зарегистрирована. Эта регистрация не должна выполняться regsvr32. Все, что делает regsvr32, это загружает DLL, получает адрес DllRegisterServer и вызывает его. DllRegisterServer добавляет необходимые записи в реестр, чтобы приложение могло использовать этот объект.

Если ваша DLL не обязательно должна быть COM-объектом, вы можете изменить ее так, чтобы просто экспортировать нужные вам функции и вызвать их (p).

...