Пример COM-моста: вызов 64-битной DLL из 32-битного приложения

· Обновлено: · · COM, Разработка Windows, 32-bit, 64-bit

История изменений (3 обновлений, последнее 30 Aug 2026)

Журнал изменений этой статьи. Там, где версия до правки была заархивирована, она остаётся доступной для чтения по постоянной ссылке с DOI.

После слияния с main уточнён абзац про DllSurrogate. Утверждения статьи не менялись.
Русский текст переписан как полноценный технический перевод, а не калька с японского. Утверждения статьи не менялись.
Перед разделом 3 добавлен абзац. Если то, к чему нужно обратиться с 64-битной стороны, само является in-proc COM-сервером (DLL, зарегистрированной через InprocServer32), то достаточно добавить AppID к её CLSID и пустой DllSurrogate под этим AppID, чтобы она загрузилась в штатный dllhost.exe Windows — и писать EXE-сервер может не понадобиться. Там же отмечено, что разрядность запускаемого суррогата определяется библиотекой, а не клиентом, и что при зарегистрированном LocalServer32 суррогат не используется. Однако если вызвать нужно обычную нативную DLL, как в этой статье, то размещать в суррогате попросту нечего, и описанный далее подход с EXE-сервером остаётся необходимым. Процедура регистрации и граница между тем, что покрывает суррогат, и тем, где нужен собственный EXE, оставлены ссылками на две другие статьи. Открыть версию до этого обновления (DOI: 10.5281/zenodo.21619626)
Первая публикация
Цитирование статьи(DOI (зарегистрированный архив): 10.5281/zenodo.21619625)

Приведённые ниже DOI относятся к ранее зарегистрированным архивным версиям, которые могут отличаться от текущего текста. Для ссылки на текущий текст используйте URL этой страницы.

Го Комура (2026). Пример COM-моста: вызов 64-битной DLL из 32-битного приложения. KomuraSoft LLC. https://comcomponent.com/ru/blog/2026/01/25/002-com-case-study-32bit-to-64bit/

DOI (зарегистрированный архив)
10.5281/zenodo.21619625
DOI (последняя зарегистрированная версия)
10.5281/zenodo.22170265

Вызов 64-битной DLL из 32-битного приложения — довольно типичное требование в Windows. Особенно когда нужно оставить существующие наработки и взять только 64-битные функции, схема COM-моста часто оказывается рабочим решением.

Для кого: те, кто сопровождает существующее 32-битное приложение Windows и хочет пользоваться 64-битной DLL или библиотекой. Текст рассчитан на уровень «про COM слышал, но сам не собирал».

Среда: 64-битная Windows (x64) и среда, в которой пишут C# (Visual Studio и аналоги). Чтобы зарегистрировать COM-сервер на всю машину (под HKEY_LOCAL_MACHINE), нужны права администратора. Базовое устройство COM разобрано в статье «Что такое COM — почему устройство Windows COM до сих пор красиво».

Оглавление

  1. Исходная ситуация
  2. Как решать
  3. Ход вызова (диаграмма последовательности)
  4. Пример кода (набросок)
  5. Полный пример
  6. Итог
  7. Источники

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 19, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

1. Исходная ситуация

Существующее 32-битное приложение оставляют как есть, но нужна обработка из 64-битной DLL. Проблема в том, что 32-битный процесс не загружает 64-битную DLL. Это ограничение на уровне ОС — его не обходят трюком.

Типичная картина такая:

  • существующее 32-битное приложение — крупная наработка, быстро не мигрировать;
  • в 64-битной DLL есть новая функциональность, либо зависимость существует только в 64-битном виде;
  • со стороны 32-bit вызов нужен типизированный.

При таком сочетании путь внутри одного процесса закрыт с самого начала.

Схема исходной ситуацииСуществующему 32-битному приложению нужна обработка из 64-битной DLL, но 32-битный процесс не может загрузить 64-битную DLL. Это ограничение ОС, поэтому путь внутри одного процесса закрыт.существующее 32-битное приложениенужна обработка из 64-битной DLLв том же процессе загрузить нельзяограничение ОС, обойти нельзя

Рис. 1: 32-битный процесс не загружает 64-битную DLL, поэтому пути внутри одного процесса изначально нет.

2. Как решать

С этой главы пойдут термины, поэтому сначала минимальный словарь.

Термин Смысл
In-proc COM (DLL-сервер) COM-компонент загружают в тот же процесс, что и вызывающая сторона. Быстро, но разрядность должна совпадать, иначе загрузить нельзя
Out-of-proc COM (EXE-сервер) COM-компонент запускают как отдельный процесс. Связать можно и при разной разрядности
LocalServer COM-сервер, который работает отдельным процессом на той же машине. Путь к EXE регистрируют в ключе реестра LocalServer32
IDL / TypeLib Описание формы интерфейса (имена методов, типы аргументов) — IDL — и его двоичный вид (TypeLib). Нужны, чтобы обе стороны смотрели на один и тот же контракт
Маршалинг Упаковка аргументов и возвращаемых значений в форму, которую можно передать через границу процесса. Обратная операция — демаршалинг
Proxy / Stub Код-посредник, который реально делает маршалинг. Со стороны вызова стоит Proxy, со стороны сервера — Stub
WOW6432Node Место на 64-bit Windows, где физически лежит содержимое реестра для 32-битных приложений. Одинаковое имя ключа на стороне 32-bit и 64-bit означает разное содержимое

Базовое решение — разнести стороны через Out-of-proc COM (EXE-сервер). 64-битную DLL вызывает 64-битный COM-сервер (EXE), а 32-битное приложение пользуется ею через COM.

Базовая схема COM-моста32-битное приложение через COM вызывает EXE 64-битного COM-сервера, а этот сервер внутри вызывает 64-битную DLL — разнесение по разным процессам.вызывает через COMвызывает внутри32-битное приложение64-битный COM-сервер (EXE)64-битная DLL

Рис. 2: 64-битную DLL держат в 64-битном EXE-сервере, а 32-битное приложение пользуется этим сервером через COM.

Порядок такой:

  1. Подготовить 64-битный COM LocalServer (EXE) и внутри него вызывать 64-битную DLL.
  2. Опубликовать типы общим COM-интерфейсом (IDL/TypeLib).
  3. 32-битное приложение вызывает COM типизированно (обмен через Proxy/Marshal).

Есть и оговорки.

  • Регистрация 32-bit и 64-bit раздельная (включая WOW6432Node)
  • Для собственных структур нужно отдельно проектировать маршалинг
  • Есть накладные расходы IPC, поэтому с частыми вызовами осторожнее

Иными словами, стандартный путь — вынести 64-битную обработку в отдельный процесс и связать стороны мостом через COM.

Три шага сборки мостаГотовят 64-битный COM LocalServer и внутри вызывают 64-битную DLL, публикуют типы интерфейса через IDL и TypeLib, после чего 32-битное приложение вызывает их типизированно.подготовить 64-битный COM LocalServerопубликовать типы в IDL / TypeLib32-битное приложение вызывает типизированнообмен через Proxy / Marshal

Рис. 3: Мост собирается в три шага: LocalServer, публикация типов, типизированный вызов.

Если на 64-битной стороне нужно использовать уже готовый in-proc COM-сервер (DLL, которую регистрируют через InprocServer32), EXE-сервер иногда можно не писать. К CLSID добавляют AppID, а в ключ этого AppID записывают пустую строку DllSurrogate — тогда DLL загружается в штатный суррогатный процесс Windows (для 64-битной DLL это System32\dllhost.exe), и 32-битному клиенту она видна как out-of-proc COM-сервер в отдельном процессе. Путь к EXE в LocalServer32 при этом не регистрируют: наоборот, если LocalServer32 есть, суррогат не используется. В обратную сторону (64-битное приложение вызывает 32-битную COM DLL) механизм тот же: разрядность запускаемого суррогата задаёт сторона DLL, а не клиент. Но если, как в этой статье, вызвать нужно обычную нативную DLL, размещать в суррогате нечего — COM-сервера нет, — поэтому дальше нужен способ с EXE-сервером. Порядок регистрации — в пункте 3.5 статьи Ловушки регистрации и bitness при разработке COM/OCX/ActiveX (там исходят из 32-битной DLL, поэтому меняется только view, в который пишут значение AppID); где суррогата достаточно, а где нужен свой EXE — в разделе 5.2 статьи Как сегодня поступать с ActiveX / OCX - таблица решений: оставить, обернуть или заменить.

3. Ход вызова (диаграмма последовательности)

Ниже — ход вызова, когда 32-битное приложение обращается к обработке в 64-битной DLL.

Обрабатывает зарегистрированная подсистема маршалинга COM64-битная DLL64-bit COM Server(EXE)COM Stub(сторона 64-bit)RPC/IPC(межпроцессное взаимодействие)COM Proxy(сторона 32-bit)32-битный клиент64-битная DLL64-bit COM Server(EXE)COM Stub(сторона 64-bit)RPC/IPC(межпроцессное взаимодействие)COM Proxy(сторона 32-bit)32-битный клиентМаршалинг параметровДемаршалинг параметровМаршалинг возвращаемого значенияДемаршалинг возвращаемого значенияICalcService.Add(1, 2)Сериализованные данныеПередача через границу процессовAdd(1, 2)Вызов нативной функцииРезультат: 3Результат: 3Сериализованный результатПередача через границу процессовРезультат: 3

Рис. 4: Вызов 32-битного приложения доходит до 64-битного сервера и 64-битной DLL через Proxy, межпроцессное взаимодействие и Stub; результат возвращается тем же путём.

Важно:

  • 32-битное приложение вызывает типизированно через интерфейс ICalcService
  • среда выполнения COM пересекает границу процессов через зарегистрированную Proxy/Stub DLL, маршалер библиотеки типов, стандартный маршалер и т. п.
  • из-за накладных расходов межпроцессного взаимодействия лучше собирать работу в более крупные порции, чем гонять мелкие вызовы
Как думать о гранулярности вызововУ межпроцессного взаимодействия есть накладные расходы, поэтому частые мелкие вызовы накапливаются, а при укрупнении порций влияние меньше.накладные расходы межпроцессного взаимодействияна мелких повторных вызовах накапливаютсяпри укрупнении порций влияние меньшепредпочитать этот вариант

Рис. 5: Каждый переход через границу процессов имеет свою цену, поэтому вызовы лучше укрупнять.

4. Пример кода (набросок)

4.1. Общий интерфейс, сервер и клиент

Ниже — набросок идеи. Чтобы это заработало, нужна регистрация из пункта 4.2.

// Общий интерфейс (аналог IDL)
[ComVisible(true)]
[Guid("7A4B5B23-0A2F-4D2B-9D4D-8A2A92B8B001")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICalcService
{
    int Add(int a, int b);
}

// 64-bit COM LocalServer (сторона EXE)
[ComVisible(true)]
[Guid("1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("KomuraSoft.CalcService")]
public class CalcService : ICalcService
{
    public int Add(int a, int b)
    {
        // Здесь вызывается 64-битная DLL
        return a + b;
    }
}

// Сторона 32-битного приложения (клиент)
Type t = Type.GetTypeFromProgID("KomuraSoft.CalcService");
var calc = (ICalcService)Activator.CreateInstance(t);
int result = calc.Add(1, 2);

В таком виде сторона 32-bit работает типизированно. COM внутри использует Proxy/Stub и сам делает вызов через IPC.

Атрибут [ProgId("KomuraSoft.CalcService")] стоит затем, чтобы клиент мог найти сервер через Type.GetTypeFromProgID("KomuraSoft.CalcService"). ProgID — всего лишь «человекочитаемый псевдоним»; сервер на самом деле находят по регистрации CLSID, о которой ниже.

От ProgID до сервераProgID, который указывает клиент, — лишь человекочитаемый псевдоним; по нему берут CLSID, а реальный сервер находят по регистрации CLSID.ProgID (человекочитаемый псевдоним)регистрация CLSIDсервер найден

Рис. 6: ProgID — входной псевдоним; на сервер указывает регистрация CLSID.

4.2. Минимальная процедура регистрации

COM устроен так: среда выполнения COM берёт зарегистрированный в реестре CLSID и запускает сервер. Незарегистрированный код не заработает никогда (Type.GetTypeFromProgID вернёт null или CreateInstance даст REGDB_E_CLASSNOTREG). Для EXE-сервера (LocalServer) нужны, по сути, только три ключа.

Что регистрируют Ключ Значение
Соответствие ProgID → CLSID HKEY_CLASSES_ROOT\KomuraSoft.CalcService\CLSID {1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11}
CLSID → путь к EXE HKEY_CLASSES_ROOT\CLSID\{1C9B6F4D-…}\LocalServer32 Полный путь к EXE 64-битного COM-сервера
Обратный поиск CLSID → ProgID HKEY_CLASSES_ROOT\CLSID\{1C9B6F4D-…}\ProgID KomuraSoft.CalcService

И здесь же ловушка, вокруг которой построена эта статья. В документации Microsoft прямо сказано: HKEY_LOCAL_MACHINE\SOFTWARE\Classes общий для 32-битных и 64-битных приложений, а подраздел CLSIDInterface и т. п.) на стороне 32-bit и 64-bit разный (физически 32-битная копия лежит в WOW6432Node). Ключ ProgID достаточно записать один раз — его видят обе стороны. Регистрацию CLSID нужно писать и в 32-bit view, и в 64-bit view, иначе 32-битный клиент сервер не найдёт.

Что в реестре общее, а что раздельноеКлюч ProgID прямо под Classes достаточно записать один раз — его видят и 32-bit, и 64-bit. Регистрацию под CLSID нужно писать и в 32-bit view, и в 64-bit view; если нет стороны 32-bit, 32-битный клиент сервер не увидит.ключ ProgID (прямо под Classes)виден с обеих сторонрегистрация под CLSIDписать в 64-bit viewписать в 32-bit viewфизически это WOW6432Nodeбез этого 32-bit не видит

Рис. 7: Ключ ProgID общий, а ветка CLSID своя для каждого view 32-bit/64-bit, поэтому регистрируют в обоих.

Надёжный способ — командная строка с правами администратора и /reg:32 /reg:64 у команды reg (сам прописывать Wow6432Node в путь Microsoft не рекомендует).

:: Запускать в командной строке с правами администратора
set CLSID={1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11}
set PROGID=KomuraSoft.CalcService
set SERVER=C:\Program Files\KomuraSoft\CalcServer.exe

:: 1) ProgID → CLSID (прямо под HKLM\SOFTWARE\Classes общее для 32/64)
reg add "HKLM\SOFTWARE\Classes\%PROGID%\CLSID" /ve /d "%CLSID%" /f

:: 2) CLSID → LocalServer32 и ProgID (под CLSID 32/64 раздельные, писать в оба)
::    В значение LocalServer32 путь к исполняемому файлу кладут вместе с кавычками.
::    Если написать /d "%SERVER%", кавычки съест разбор аргументов reg.exe,
::    и в значении останется C:\Program Files\... Как командную строку COM
::    режет это по пробелу и сначала ищет C:\Program.exe
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\LocalServer32" /ve /d "\"%SERVER%\"" /f /reg:64
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\ProgID"        /ve /d "%PROGID%"     /f /reg:64
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\LocalServer32" /ve /d "\"%SERVER%\"" /f /reg:32
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\ProgID"        /ve /d "%PROGID%"     /f /reg:32

:: Проверить сохранённое значение. Правильно, если видно "C:\Program Files\..." с кавычками
reg query "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\LocalServer32" /ve /reg:64

Кавычки в LocalServer32 — не вопрос хорошего тона. Без кавычек C:\Program Files\... можно прочитать как «запустить C:\Program, а Files\... передать аргументом». Если у кого-то есть право положить C:\Program.exe, запустится оно. Для пути с пробелами кавычки обязательны.

Как кавычки в LocalServer32 меняют разборЕсли путь в LocalServer32 сохранить без кавычек, его можно разрезать по пробелу, и в среде, где можно положить C:\Program.exe, запустится оно. Если сохранить вместе с кавычками, стартует задуманный EXE.сохранить без кавычекможно разрезать по пробелуможет сначала стартовать C:\Program.exeсохранить вместе с кавычкамистартует задуманный EXE

Рис. 8: Если путь с пробелами зарегистрировать без кавычек, появляется возможность запустить другой исполняемый файл.

Снятие с регистрации — просто удалить те же ключи.

set CLSID={1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11}
set PROGID=KomuraSoft.CalcService

reg delete "HKLM\SOFTWARE\Classes\CLSID\%CLSID%" /f /reg:64
reg delete "HKLM\SOFTWARE\Classes\CLSID\%CLSID%" /f /reg:32
reg delete "HKLM\SOFTWARE\Classes\%PROGID%" /f

Плюс сам EXE при старте должен представиться COM: «этот CLSID — мой». В C/C++ это CoRegisterClassObject, в .NET Framework — RegistrationServices.RegisterTypeForComClients. Реестр доводит COM только до запуска EXE. Если представления нет, EXE стартует, а объект создать нельзя — сбой, который трудно сразу понять.

Регистрация в реестре и представление EXEРеестр доводит COM только до запуска EXE. Объект можно создать лишь после того, как стартовавший EXE представится как ответственный за этот CLSID. Без представления EXE стартует, а объект не создаётся.без представлениярегистрация в реестреCOM запускает EXEEXE представляется как ответственный за CLSIDобъект можно создатьстартует, но создать нельзя

Рис. 9: Реестр отвечает за запуск EXE; дальше без представления самого EXE объект не создать.

Если нужно только попробовать при разработке, ту же структуру можно записать в HKCU\SOFTWARE\Classes вместо HKLM — права администратора не нужны (HKEY_CLASSES_ROOT — составной вид HKLM и HKCU). Но HKCU\SOFTWARE\Classes\CLSID тоже раздельный для 32-bit и 64-bit, так что писать в оба view всё равно нужно.

4.3. В .NET Framework и в .NET (5 и новее) это делается по-разному

Код выше на C#, но процедура сильно зависит от того, какое .NET вы берёте. Если смешать — застрянете.

  .NET Framework .NET (Core 3.0 / 5 и новее)
Инструмент регистрации Есть RegAsm.exe (но он создаёт регистрацию InprocServer32 для in-proc, так что LocalServer32 всё равно пишут сами) Инструмента уровня RegAsm нет
Обычная публикация в COM Атрибуты на сборке и RegAsm <EnableComHosting>true</EnableComHosting> даёт *.comhost.dll, регистрируют через regsvr32 (только in-proc)
Генерация TypeLib (.tlb) Можно через TlbExp / RegAsm /tlb Не поддерживается. IDL пишут руками и компилируют MIDL (начиная с .NET 6 готовый .tlb можно встроить в comhost)
Указание CLSID Можно опустить Для класса, который создаёт COM, CLSID нужно указать явно
Поведение AnyCPU Доступен клиентам и 32-bit, и 64-bit Сопровождающий *.comhost.dll по умолчанию 64-bit, поэтому доступен только 64-битному клиенту

Схема этой статьи (EXE-сервер) в .NET (5 и новее) лежит вне стандартного EnableComHosting, поэтому регистрацию пишут сами. Официальный образец Microsoft — OutOfProcCOM; если собирать на стороне .NET, с него и начинают.

Как собирать EXE-сервер на .NET (5 и новее)Схема EXE-сервера этой статьи в .NET 5 и новее лежит вне стандартного EnableComHosting, поэтому регистрацию пишут сами; отправная точка — официальный образец OutOfProcCOM.EXE-сервер на .NET (5 и новее)вне стандартного EnableComHostingрегистрацию пишут самиотправная точка — официальный образец OutOfProcCOM

Рис. 10: EXE-сервер на .NET (5 и новее) лежит вне стандартных средств, поэтому регистрацию пишут самостоятельно.

5. Полный пример

Концепцию выше в реально запускаемом виде мы выложили на GitHub.

Call64bitDLLFrom32bitProc - GitHub

В репозитории есть:

  • Call64bitDLLFrom32bitProc/ — 64-bit COM LocalServer (EXE)
  • X64DLL/ — 64-битная DLL (сама обработка)
  • X86App/ — 32-битный клиент (WinForms)
  • scripts/ — скрипты регистрации и снятия с регистрации COM-сервера

Если собрать и зарегистрировать по README, можно убедиться, что 32-битный процесс действительно вызывает 64-битную DLL.

6. Итог

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

Подходит Не подходит
Само 32-битное приложение переписать нельзя (стоимость переделки не окупается) Сторону 32-bit можно пересобрать в 64-bit (это самый короткий путь)
Вызовы крупной гранулярности (один вызов — одно изображение, один файл и т. п.) Мелкие вызовы десятки тысяч раз, часто и по одному элементу (накладные расходы IPC начинают доминировать)
Обмениваются числами, строками, массивами — типами, которые удобно маршалировать Гоняют туда-сюда сырые указатели или сложные собственные структуры
Хочется, чтобы при падении обработки на стороне 64-bit само приложение осталось живым (разделение процессов здесь плюс) Не хочется писать восстановление после сбоя или перезапуска сервера
Нужен типизированный вызов (IntelliSense и проверка на этапе компиляции) Хватает разовой пакетной обработки, достаточно передать данные через стандартный ввод-вывод или файлы

Обратная сторона последней строки: всегда стоит рассмотреть простой вариант «сделать 64-битную обработку обычным консольным EXE и обмениваться аргументами и файлами». COM-мост имеет смысл, когда нужно сохранить типизированные вызовы и когда сервер с состоянием вызывают многократно.

Развилка между COM-мостом и простым вариантомЕсли нужны типизированные вызовы или сервер с состоянием, который вызывают многократно, работает COM-мост. Если хватает разовой пакетной обработки, стоит рассмотреть простой вариант: консольный EXE и обмен аргументами и файлами.данетНужны типизированные вызовы или состояние?COM-мостконсольный EXE, аргументы и файлы

Рис. 11: Нужны ли типизированные вызовы и сохранение состояния — развилка между мостом и простым вариантом.

Дальше удобно идти в таком порядке.

  1. Сначала клонировать образец из главы 5, собрать и зарегистрировать по README и получить у себя один работающий пример.
  2. Взять одну функцию своей 64-битной DLL, добавить один метод в интерфейс вроде ICalcService из образца и прогнать этот вызов.
  3. Когда пройдёт — измерить число вызовов и объём данных за один вызов. Решение «укрупнить гранулярность» (несколько вызовов свернуть в один) лучше принять здесь: меньше придётся возвращаться.

7. Источники

  • Обзор Component Object Model (COM) https://learn.microsoft.com/en-us/windows/win32/com/component-object-model–com–portal
  • Регистрация COM LocalServer32 https://learn.microsoft.com/en-us/windows/win32/com/localserver32
  • Основы интерфейсов COM https://learn.microsoft.com/en-us/windows/win32/com/the-component-object-model
  • COM Interop (использование из .NET) https://learn.microsoft.com/en-us/dotnet/standard/native-interop/cominterop
  • Перенаправитель реестра WOW64 (HKLM\SOFTWARE\Classes общий, ветка CLSID раздельная для 32/64) https://learn.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys
  • Публикация компонентов .NET (Core / 5 и новее) в COM https://learn.microsoft.com/en-us/dotnet/core/native-interop/expose-components-to-com

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Можно ли напрямую вызвать 64-битную DLL из 32-битного приложения?
Нет. 32-битный процесс не может загрузить 64-битную DLL. Это ограничение на уровне ОС, а не то, что обходится трюком. Путь внутри одного процесса закрыт с самого начала, поэтому 64-битную обработку нужно вынести в отдельный процесс.
Как пользоваться функциями 64-битной DLL из 32-битного приложения?
Стандартный путь — разнести стороны через Out-of-proc COM (EXE-сервер). 64-битную DLL вызывает 64-битный COM LocalServer (EXE), а 32-битное приложение пользуется ею типизированно через COM-интерфейс. Типы публикуют общим COM-интерфейсом (IDL/TypeLib), а среда выполнения COM пересекает границу через Proxy/Stub и межпроцессное взаимодействие.
На что смотреть в схеме COM-моста?
На три вещи. Регистрация 32-bit и 64-bit раздельная (включая WOW6432Node). Для собственных структур нужно отдельно проектировать маршалинг. Из-за накладных расходов IPC осторожнее с частыми мелкими вызовами: лучше собирать работу в более крупные порции, чем гонять поток мелких обращений.
Есть ли пример, который реально запускается?
Да. В репозитории Call64bitDLLFrom32bitProc на GitHub выложен полный набор: 64-битный COM LocalServer (EXE), 64-битная DLL, 32-битный клиент (WinForms) и скрипты регистрации и снятия с регистрации COM-сервера. Если собрать и зарегистрировать по README, можно убедиться, что 32-битный процесс действительно вызывает 64-битную DLL.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог