Registration Free COM и OLE DB

Все что ни делается, все к лучшему …

Предыстория
В конце лета 2016-го, мой любимый рабочий ноутбук начал выносить мозг внезапными выключениями. К октябрю это окончательно задрало и я решил что пришло время осуществить свою мечту притворить в реальность мысли о новом рабочей лошадке. Которая сможет заменить и ноутбук и десктоп, собранный в 2008 году. В начале ноября новый компьютер был собран. Его дури хватило на то, чтобы за четыре дня зарелизить собственного клиента для FB3 🙂

После этого началась настройка новой системы для ежедневной рутинной работы.

По теме
Основная проблема, которая сопровождает разработку и тестирование IBProvider-a на одном компьютере — это конфликты регистрационных записей в реестре Windows. Нужно постоянно помнить, какая сборка сейчас зарегистрирована. Это напрягает и периодически приводит к ошибкам типа «тесты подхватили не ту DLL».

Решение у этой проблемы уже давно есть — в манифест исполняемого файла (EXE) тестов следует добавить записи, позволяющие создавать COM-объекты с использованием технологии «Registration Free COM». Добавил.

И тут внезапно оказалось, что стандартный пул подключений OLE DB не поддерживает провайдеры «зарегистрированные» таким образом. Создавать-то он их может. Но подключения не кэширует — ему нужны дополнительные данные о провайдере из реестра, которых, понятное дело, там нет.

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

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

Если интересно посмотреть своими глазами, то нужно установить все компоненты IBProvider-а (32бита или 64бита — это без разницы) и перейти в каталог «c:\Program Files\LCPI\IBProvider.3\TestCode\ActiveX\IBP\oledb_test».

Для 32битных и 64битных тестов были сформированы файлы с дополнительными данными для манифестов:

  • manifests\ibprovider_w32.manifest
  • manifests\ibprovider_w64.manifest

Содержимое файла ibprovider_w32.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <file name = "private\lcpi.ibprovider_v3_vc15_w32_prof_i.dll">
   <comClass progid="LCPI.IBProvider.3.Private.vc15.release" clsid="{1ED1A41E-5D9F-4EAC-9A8A-E3BAA4BE4901}" threadingModel = "Both" />
  </file>
  <file name = "private\lcpi.ibprovider_v3_vc15_w32_prof_d.dll">
   <comClass progid="LCPI.IBProvider.3.Private.vc15.debug" clsid="{2F9837F6-EE9F-4841-A8D3-D0D6803A917C}" threadingModel = "Both" />
  </file>

  <file name = "private\lcpi.oledb_services_v1_vc15_w32_prof_i.dll">
   <comClass progid="LCPI.OleDbServices.DataInitManager.Local.1.Private.vc15.release" clsid="{1329FCE3-50CB-4036-AC2F-A98C9651940F}" threadingModel = "Both" />
  </file>
  <file name = "private\lcpi.oledb_services_v1_vc15_w32_prof_d.dll">
   <comClass progid="LCPI.OleDbServices.DataInitManager.Local.1.Private.vc15.debug" clsid="{5E8359F3-6D19-4EA9-80EC-7588C2D43698}" threadingModel = "Both" />
  </file>
</assembly>

Содержимое файла ibprovider_w64.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <file name = "private\lcpi.ibprovider_v3_vc15_w64_prof_i.dll">
   <comClass progid="LCPI.IBProvider.3.Private.vc15.release" clsid="{C010F775-31CB-457A-9B2F-ED6FA1A686F5}" threadingModel = "Both" />
  </file>
  <file name = "private\lcpi.ibprovider_v3_vc15_w64_prof_d.dll">
   <comClass progid="LCPI.IBProvider.3.Private.vc15.debug" clsid="{213E7754-8C67-41C8-9CD4-B92B882D2399}" threadingModel = "Both" />
  </file>

  <file name = "private\lcpi.oledb_services_v1_vc15_w64_prof_i.dll">
   <comClass progid="LCPI.OleDbServices.DataInitManager.Local.1.Private.vc15.release" clsid="{C5E11739-40A5-4A00-B8F9-9EDF5BFD4207}" threadingModel = "Both" />
  </file>
  <file name = "private\lcpi.oledb_services_v1_vc15_w64_prof_d.dll">
   <comClass progid="LCPI.OleDbServices.DataInitManager.Local.1.Private.vc15.debug" clsid="{2FF3E7C9-5D84-458E-9030-1A7165278A1F}" threadingModel = "Both" />
  </file>
</assembly>

Как видим, здесь определены различные релизные и отладочные сборки провайдера и пула подключений.

ProgID-ы можно назначать какие угодно.

CLSID-ы должны быть теми, которые поддерживает DLL. В случае IBProvider-а CLSID-ы можно найти в файлах:

  • sdk/ibprovider/v03/lcpi_sdk__ibprovider__v03__clsids.cpp
  • sdk/ibprovider/v03/lcpi_sdk__ibprovider__v03__private_clsids.cpp

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

Во втором файле определены CLSID, уникальные для каждой сборки (компилятор+редакция+платформа+конфигурация).

Для автоматизации модификации манифеста исполняемого файла тестов в проектный файл тестовой системы были добавлены следующие записи:

  <Target Name="BeforeBuild">
    <Error Text="WindowsSDK80Path not defined!" Condition="'$(WindowsSDK80Path)' == ''" />
  </Target>
  <Target Name="AfterBuild">
    <Message Importance="High" Text="Try to modify the assembly manifest" />
    <Exec 
     Condition="'$(Platform)'=='x64'"
     Command="&quot;$(WindowsSDK80Path)bin\x86\mt.exe&quot; -updateresource:$(TargetPath);#1 -manifest ..\..\manifests\ibprovider_w64.manifest" />
    <Exec 
     Condition="'$(Platform)'=='Win32'"
     Command="&quot;$(WindowsSDK80Path)bin\x86\mt.exe&quot; -updateresource:$(TargetPath);#1 -manifest ..\..\manifests\ibprovider_w32.manifest" />
  </Target>

Теперь в каталоге (target) со сгенерированными исполняемым файлами тестов создаем подкаталог «private» и копируем в него сборки провайдера и пула подключений:

  • lcpi.ibprovider_v3_vc15_w32_prof_d.dll
  • lcpi.ibprovider_v3_vc15_w32_prof_i.dll
  • lcpi.ibprovider_v3_vc15_w64_prof_d.dll
  • lcpi.ibprovider_v3_vc15_w64_prof_i.dll
  • lcpi.oledb_services_v1_vc15_w32_prof_d.dll
  • lcpi.oledb_services_v1_vc15_w32_prof_i.dll
  • lcpi.oledb_services_v1_vc15_w64_prof_d.dll
  • lcpi.oledb_services_v1_vc15_w64_prof_i.dll

Всё, можно запускать тесты, которые не будут зависеть от реестра:

target\ibp_oledb_test_vc15_x64_Release.exe /thread_count 8 /log_file_prefix fb30_fb.direct_ram_w64_d3 /auto /log_dir ..\_log\__ReleaseTests1s\ /new_db_location «inet4://localhost/d:\database\ram\» /cn_str «provider=LCPI.IBProvider.3.Private.vc15.release;location=inet4://localhost/d:\database\ram\ibp_test_fb30_d3_2.gdb;user id=GAMER;password=vermut;ctype=win1251;icu_library=icuuc30.dll;temp_file_dir=d:\database\ram\temp;dbclient_type=fb.direct» /oledb_svc_cmp «LCPI.OleDbServices.DataInitManager.Local.1.Private.vc15.release» /test ds* /test sess* /test odbc* /test cmd* /test column* /test array.write* /test array.read* /test array*001* /test icr* /test rowset* /test schema.002* /test schema.004* /test schema.005* /test schema.008* /test schema.009* /test schema.010* /test octet* /test blob*large*65536*1251* /test array*1251* /test charset*1251* /test *4053*

Открываем диспечер задач, чтобы проверить результаты наших трудов, и видим:

Гармония и полная умиротворенность.

Leave a Comment