Как создать COM-объект 1С (V8.COMConnector) без регистрации comcntr.dll в системе?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе интеграции различных систем с 1С часто возникает задача использовать COM-соединение. Стандартный подход требует регистрации библиотеки comcntr.dll в операционной системе. Однако бывают ситуации, когда такая регистрация нежелательна или невозможна: например, из-за отсутствия прав администратора, необходимости работать с несколькими версиями платформы одновременно или при развертывании "portable" приложений.

При попытке создать COM-объект без регистрации, как правило, возникает ошибка. Проанализируем типичное сообщение об ошибке:

Внешнее исключение (System.Runtime.InteropServices.COMException): Не удалось получить фабрику класса COM для компонента с CLSID {181E893D-73A4-4722-B61D-D604B3D67D47} из-за следующей ошибки: 80004005 Неопознанная ошибка (Исключение из HRESULT: 0x80004005 (E_FAIL)).

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

Стандартный механизм: Регистрация COM-сервера

Прежде чем перейти к основному решению, давайте кратко рассмотрим стандартный путь. Обычно при установке платформы "1С:Предприятие" библиотека comcntr.dll регистрируется автоматически. Если этого не произошло, можно сделать это вручную с помощью системной утилиты regsvr32.exe, запущенной от имени администратора.

Команда выглядит так:

regsvr32 "C:\Program Files\1cv8\[версия платформы]\bin\comcntr.dll"

При выполнении этой команды в системный реестр Windows добавляются записи, которые связывают CLSID объекта V83.COMConnector с путем к файлу comcntr.dll. После этого любая программа может легко создавать COM-объекты, обращаясь к операционной системе.

Решение: Создание COM-объекта через WinAPI без регистрации

Теперь разберем основной метод, который позволяет обойтись без регистрации. Идея заключается в том, чтобы вручную выполнить все те действия, которые операционная система обычно делает автоматически, опираясь на данные из реестра. Мы будем использовать функции WinAPI для прямой загрузки DLL и создания объекта. Этот подход известен как "бесрегистрационный COM" (Registration-Free COM).

Рассмотрим процесс по шагам.

  1. Указание пути к зависимым библиотекам. Библиотека comcntr.dll не работает в вакууме. Для ее корректной работы требуется множество других DLL из той же папки bin установленной платформы 1С. Если просто скопировать comcntr.dll в другое место, она не сможет загрузить свои зависимости. Чтобы решить эту проблему, нужно явно указать системе, где искать эти файлы. Для этого используется функция WinAPI AddDllDirectory, которой передается путь к каталогу bin.

  2. Загрузка библиотеки в память. Далее мы загружаем саму библиотеку comcntr.dll в адресное пространство нашего приложения. Для этого можно использовать функцию CoLoadLibrary или LoadLibrary.

  3. Получение "фабрики классов". По стандарту COM, каждая внутрипроцессная DLL-библиотека должна экспортировать функцию DllGetClassObject. Эта функция является точкой входа для создания объектов. Мы получаем ее адрес с помощью GetProcAddress и вызываем, передав ей CLSID нужного нам объекта ({181E893D-73A4-4722-B61D-D604B3D67D47} для V83.COMConnector) и идентификатор интерфейса фабрики классов (IClassFactory). В ответ мы получаем указатель на объект-"фабрику", который умеет создавать экземпляры нашего COM-объекта.

  4. Создание экземпляра объекта. Получив фабрику, мы вызываем ее метод CreateInstance. Этот метод и создает непосредственный экземпляр COM-объекта V83.COMConnector и возвращает нам указатель на его базовый интерфейс IUnknown.

  5. Получение нужного интерфейса для работы. Интерфейс IUnknown является базовым для всех COM-объектов, но он не позволяет вызывать методы, такие как Connect. Чтобы получить доступ к ним, нужно запросить более функциональный интерфейс — IDispatch. Это делается с помощью метода QueryInterface. Интерфейс IDispatch позволяет работать с объектом в режиме позднего связывания (late binding), что идеально подходит для скриптовых языков и сред, где типы определяются во время выполнения.

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

Практический пример на Delphi

Давайте проанализируем пример кода на языке Delphi, который наглядно демонстрирует описанный выше алгоритм. Этот код выполняет все необходимые шаги для создания COM-объекта без регистрации.


function FixinMagic(): TResult;
var
  FullFilePath, FileDir: String;
  FileName: String;
  NewID: TGUID;
  LibHandle: THandle;
  AddDllDirectory: TAddDllDirectory;
  DllGetClassObject: TDllGetClassObject;
  res: THandle;
  Factory: IClassFactory;
  unk: IUnknown;
  Obj: IDispatch;
  hkernel32: THandle;
  ErrorCode: Cardinal;
  ErrorDescription: String;
begin
  Result.Result := false;
  // Указываем полный путь к comcntr.dll
  FullFilePath := 'C:\Program Files\1cv8\8.3.25.1336\bin\comcntr.dll';
  FileDir := ExtractFilePath(FullFilePath);
  // CLSID для V83.COMConnector
  NewID := StringToGUID('{181E893D-73A4-4722-B61D-D604B3D67D47}');

  // Получаем доступ к функции AddDllDirectory из kernel32.dll
  hkernel32 := GetModuleHandle(Pchar('kernel32.dll'));
  if hkernel32 = 0 then
    hkernel32 := LoadLibrary(Pchar('kernel32.dll'));
  // ... (проверка ошибок) ...
  @AddDllDirectory := GetProcAddress(hkernel32, 'AddDllDirectory');

  // Шаг 1: Добавляем каталог с зависимостями в пути поиска
  res := AddDllDirectory(Pchar(FileDir));
  // ... (проверка ошибок) ...

  // Шаг 2: Загружаем библиотеку
  LibHandle := CoLoadLibrary(Pchar(FullFilePath),true);
  // ... (проверка ошибок) ...

  // Получаем адрес функции DllGetClassObject
  @DllGetClassObject := GetProcAddress(LibHandle, 'DllGetClassObject');
  // ... (проверка ошибок) ...

  // Шаг 3: Получаем фабрику классов
  res := DllGetClassObject(NewID, IClassFactory, Factory);
  // ... (проверка ошибок) ...

  // Шаг 4: Создаем экземпляр объекта
  res := Factory.CreateInstance(nil, IUnknown, unk);
  // ... (проверка ошибок) ...

  // Шаг 5: Получаем интерфейс IDispatch
  res := unk.QueryInterface(IDispatch, Obj);
  // ... (проверка ошибок) ...

  // Возвращаем готовый объект
  Result.Data := Obj;
  Result.Result := true;
end;

procedure TForm2.Button1Click(Sender: TObject);
var
  MagicResult: TResult;
  Connector1C, Connection1C: OleVariant;
begin
  MagicResult := FixinMagic();
  if MagicResult.Result = false then
  begin
    ShowMessage(MagicResult.ErrorDescription);
    exit;
  end;

  // Используем полученный объект
  Connector1C := MagicResult.Data;
  try
    Connection1C := OleVariant(Connector1C).Connect('Srvr="Localhost";Ref="Empty"');
    ShowMessage(Connection1C.Метаданные.Версия);
  finally
  end;
end;

Как мы видим, после вызова функции FixinMagic мы получаем в переменной Connector1C рабочий COM-объект и можем вызывать его методы, например, Connect, для подключения к информационной базе.

Альтернативные подходы и важные нюансы

Рассмотренный метод — не единственный способ работы с COM без регистрации. Рассмотрим другие варианты и важные моменты.

Манифесты приложений (Registration-Free COM)

Более современным и предпочтительным способом является использование манифестов приложений. Это специальные XML-файлы, которые поставляются вместе с исполняемым файлом программы. В манифесте декларативно описываются все используемые COM-компоненты, их CLSID и пути к DLL. При запуске такого приложения операционная система создает для него изолированный контекст активации, используя информацию из манифеста вместо глобального системного реестра. Этот подход чище и не требует написания низкоуровневого кода.

Веб-сервисы (HTTP)

Хорошей альтернативой COM-взаимодействию является использование веб-сервисов. Этот подход более универсален, не зависит от платформы и операционной системы (клиент может быть написан на любом языке и работать под Linux или macOS). Он избавляет от сложностей, связанных с регистрацией, версиями и разрядностью COM-компонентов, но требует публикации веб-сервисов на стороне 1С.

Ключевые моменты, на которые стоит обратить внимание

← На главную