Как избежать проблем с несколькими версиями CRT в Windows (повторный визит в ад dll?)

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

[TL; DR] Версия:

Возможно ли / легко создать оболочку dll для VS2005 CRT, которая затем делегирует все вызовы VS2013 CRT?

Проще ли понизить версию сборки VS2013 так, чтобы она использовала VS2005 CRT?

Или обе эти идеи просто безумны?

Наша ситуация:

Наши приложения C ++ созданы с использованием современных версий компиляторов C ++ (VS2013, gcc 4.8 в зависимости от целевой платформы) - для некоторых из наших зависимостей, которые мы используем, потребуется современная версия, поскольку они используют C ++ 11.

Наши приложения также используют связывание времени выполнения (.dll или .so) для упаковки различных компонентов приложения.

В Windows, чтобы упростить жизнь, мы компилируем с использованием / MD (или / MDd для отладки), т.е. используем CRT в dll с использованием многопоточной версии - любые зависимости, которые мы создаем, перекомпилируются для использования той же CRT.

Использование одного и того же CRT для всех зависимостей (в отдельной dll) означает, что мы избегаем проблем, если память выделяется в одной dll и освобождается в другой, поскольку используется та же куча.

Наша проблема

У нас есть одна зависимость, которая предоставляется третьей стороной (я не буду называть их здесь и позорить их, но вы знаете, кто вы!) В виде предварительно скомпилированной dll, а не в качестве источника.

Он был скомпилирован с использованием VS2005 (MSVC8) в Windows и использует MSVC8 crt.

Их предыдущая версия этой зависимости работала нормально. Их api для этой зависимости правильно обрабатывал выделение и освобождение памяти, поэтому, даже несмотря на то, что он использовал другую версию CRT по сравнению с остальной частью нашего приложения, это не было проблемой.

К сожалению, их новая («улучшенная»!) Версия интенсивно использовала шаблоны C ++ в своем API - эти шаблоны расширяются в нашем вызывающем коде и приводят к попыткам удалить память, выделенную в их dll, из нашего вызывающего кода. Поскольку в двух областях используются разные кучи, это очень проблематично.

Возможные решения:

Чтобы решить эту проблему, мы можем увидеть следующие возможные решения

1] Попросите поставщика переписать (мы просили об этом, и это долгосрочное решение, но не произойдет в ближайшее время)

2] Попросите поставщика повторно скомпилировать с помощью VS2013, чтобы у нас была одинаковая CRT с обеих сторон (очевидно, этого не произойдет - спросили).

3] Используйте VS2005 CRT для всего нашего кода (мы не можем просто использовать VS2005 для создания нашего кода, поскольку у нас есть требование для поддержки C ++ 11)

4] Установите шайбу VS2005 CRT, которую ожидает сторонняя dll, т. Е. Создайте что-то похожее на VS2005 CRT, но на самом деле использующее VS2013 CRT.

5] Оберните стороннюю dll - то есть создайте dll, скомпилированную с VS2005, которая содержит все вызовы сторонней зависимости - и обеспечьте правильную обработку памяти, чтобы она работала с нашими другими (с использованием VS2013 CRT) dll

И напоследок вопрос:

Вариант 5], вероятно, будет наиболее трудоемким (но с наибольшей вероятностью успеха) - в основном это вариант 1], но под нашим контролем, поэтому нам не нужно ждать третьей стороны.

Однако, прежде чем перейти к этому пути, я подумал, что попрошу посмотреть, сделали ли другие что-нибудь похожее на 3] или 4] или какое-то другое решение, о котором мы не думали.

Вариант 4] (создание версии CRT с оболочкой) кажется, возможно, самым простым, поскольку я полагаю, что большая часть работы по обратной совместимости уже будет выполнена в VS2013 CRT - так что это всего лишь случай выяснения деталей и просмотра 2005 версия вызова версии 2013 года - во многих случаях я полагаю, что даже подпись идентична, так что это просто неявная запись.

Однако, когда я просмотрел через Google, я не смог найти ни одного примера, чтобы кто-либо создавал shim dll для проблем несовместимости версий CRT - так что, возможно, это намного сложнее, чем я думаю (или мой google fu сильно не хватает).

Поэтому подумал, что я просто спрошу, делал ли кто-нибудь что-нибудь подобное / знает, почему это действительно глупая идея?


person Alex Perry    schedule 16.04.2014    source источник
comment
Вы пробовали использовать loadlibrary для загрузки dll 2005 года и выполнения вызовов таким образом?   -  person cup    schedule 16.04.2014
comment
О, не думал об этом - вполне может сработать - просто переопределите операторы new / delete и каким-то образом сделайте так, чтобы они вызывали версию VS2013 или VS2005 в зависимости от ситуации.   -  person Alex Perry    schedule 16.04.2014
comment
спасибо - да, похоже на жизнеспособное решение и намного проще, чем прокладывать шайбу на всю эрт   -  person Alex Perry    schedule 16.04.2014


Ответы (1)


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

Ключевым моментом является то, что реализация STL изменилась, и это шаблоны. DLL почти наверняка содержит как встроенные, так и не встроенные вызовы VS2005 STL. Если вы замените VS2005 на VS2013 CRT, их DLL будет иметь сочетание встроенных вызовов VS2005 и не встроенных VS2013. Несомненная катастрофа. Это предполагает, что у VS2013 CRT даже есть необходимые версии без встроенной памяти.

Тем не менее, вы можете указать свои собственные new и delete в своем коде. Они могут перейти к соответствующим версиям VS2005, которые вы получите во время выполнения через GetProcAddress. Этого могло бы возможно быть достаточно - никаких гарантий.

person MSalters    schedule 16.04.2014
comment
Спасибо - забыл о STL-стороне вещей - вы правы, это нарушает условия сделки. Вероятно, будет предпринята попытка выбора во время выполнения, указав new / delete, как предлагается. Если это не удается, просто заверните вещь и готово ... - person Alex Perry; 17.04.2014