Могу ли я использовать компилятор Visual Studio 2010 С++ с Visual Studio 2008 С++ Runtime Library?

У меня есть приложение, которое должно работать в Windows 2000. Я также хотел бы использовать Visual Studio 2010 (в основном из-за изменения определения ключевого слова auto). Тем не менее, я немного привязан, потому что мне нужно приложение, чтобы работать на более старых ОС, а именно:

  • Windows 2000
  • RTM для Windows XP
  • Windows XP SP1

Библиотека времени исполнения Visual Studio 2010 зависит от API EncodePointer / DecodePointer, который был представлен в Windows XP SP2.

Если использование альтернативной библиотеки времени выполнения возможно, будет ли этот код прерывания, который полагается на функции С++ 0x, добавленные в VS2010, например std::regex?

Ответ 1

Решение Suma выглядело довольно многообещающим, но оно не работает: символы __imp__*@4 должны быть указателями для функций, а чем сами функции. К сожалению, я не знаю, как заставить Visual С++ выплевывать указатель с таким названием... (ну, __declspec(naked) в сочетании с __stdcall делает трюк, но тогда я не знаю, как испускать указатель).

Если использование ассемблера при времени сборки в порядке, решение довольно тривиально - соберите следующий код с FASM и ссылку на созданный объектный файл и недопустимые ссылки EncodePointer/DecodePointer в exe:

use32
format ms coff

section ".data" data
public [email protected]
[email protected] dd dummy

public [email protected]
[email protected] dd dummy

section ".text" code
dummy:
mov eax, [esp+4]
retn 4

Ответ 2

Самое простое решение - просто установить Platform Toolset в настройках проекта в VS2010 - v900, который будет использовать библиотеки Visual Studio 2008 и компилятор. Это также означает, что вы теряете функции С++ 0x, такие как auto, но, честно говоря, работа с этим с некоторыми typedef, вероятно, проще, чем создание собственной версии CRT или других более сложных решений. Кроме того, просто используйте VS2008! Я не знаю, есть ли другие функции С++ 0x, которые имеют решающее значение для вашего приложения, но вы не упомянули - кроме std::regex, который, я думаю, все еще находится в наборе инструментов v900 в пространстве имен технических отчетов 1 (std::tr1::regex).

Просто из впечатления, которое я получаю, я бы предсказал, что неудобство получения библиотек VS2010 для работы на XP SP1 больше, чем удобство функций С++ 0x, поэтому в целом это не стоило бы.

Ответ 3

Вы не можете использовать CRT 2008, но вы можете предотвратить привязку новых функций DecodePointer/EncodePointer из ядра. Легко заменить новые функции на заглушки.

Можно попытаться выполнить следующее: Поместите код, подобный этому, в источник main.cpp:

extern "C" {

  void *__stdcall _imp__DecodePointer(void *x) {return x;}
  void *__stdcall _imp__EncodePointer(void *x) {return x;}

};

Забастовкa >

Вышеуказанное не работает. Хотя основная идея звучит, исполнение должно быть немного иным. Как описано snemarch в комментарии и еще один ответ, __imp__ не может быть вызовом функции, только указателем на него. Поскольку, по-видимому, невозможно сгенерировать указатель непосредственно компилятором, вам необходимо собрать следующий код с помощью MASM и ссылку на созданный файл объекта.

.model flat

.data
[email protected] dd dummy
[email protected] dd dummy
EXTERNDEF [email protected] : DWORD
EXTERNDEF [email protected] : DWORD

.code
dummy proc
mov eax, [esp+4]
ret 4
dummy endp

end

Символы из проекта имеют предпочтение против любых символов из библиотек. Библиотеки DLL связаны с использованием .lib-частей, которые содержат только __imp__ "векторы", прыгающие в реальные функции. Заменяя __imp__ "векторы", вы не касаетесь ссылки DLL, вы заменяете часть .lib. Я проверил, что нет никакой зависимости exe от DecodePointer/EncodePointer.

Фон

Статически связанная библиотека привносит в приложение только используемые функции. Можно найти, какую конкретную функцию CRT привносят в этот новый API с помощью расширенного выполнения компоновщика:

Found [email protected]
  Referenced in LIBCMT.lib(crtmboxw.obj)
  Referenced in LIBCMT.lib(invarg.obj)
  Referenced in LIBCMT.lib(handler.obj)
  Referenced in LIBCMT.lib(onexit.obj)
  Referenced in LIBCMT.lib(cmiscdat.obj)
  Referenced in LIBCMT.lib(tidtable.obj)
  Referenced in LIBCMT.lib(hooks.obj)
  Referenced in LIBCMT.lib(winsig.obj)
  Referenced in LIBCMT.lib(rand_s.obj)

Found [email protected]
  // ... same list, only order differs ... 

Это показывает, что новые API-интерфейсы используются в некоторых CRT для обеспечения большей безопасности некоторых функций, которые, как считается, обеспечивают частые атаки.

С некоторыми усилиями можно было бы использовать LoadLibrary/GetProcAddress, чтобы обеспечить реальную функциональность, предлагаемую ОС, но я не думаю, что это действительно принесло бы что-нибудь. Функции времени выполнения, которые используют DecodePointer/EncodePointer, действительно не нуждаются в этом, чтобы обеспечить любую кодировку, все, что им нужно, - это кодирование симметричным. Вам не нужна повышенная безопасность (среда выполнения VS 2008 тоже не даст вам).

Я надеюсь, что вас не ждут другие препятствия - у меня нет доступа к системе Win2k или XP pre SP2, поэтому я не могу попробовать. Если есть какие-либо флаги заголовков exe, препятствующие даже попытке запуска exe в таких системах, их легко изменить.

Ответ 4

Поскольку Visual Studio поставляется с поддержкой MASM (см. "Свойства проекта" → "Настройка сборки" ), может оказаться полезным следующий перевод кода snemarch в MASM:

.model flat

.data
[email protected] dd dummy
[email protected] dd dummy
EXTERNDEF [email protected] : DWORD
EXTERNDEF [email protected] : DWORD

.code
dummy proc
mov eax, [esp+4]
ret 4
dummy endp

end

И не забудьте установить Linker- > System- > Minimum Required Version to 5.0 (по умолчанию 5.1) для запуска в Windows 2000.

Ответ 5

Обычная работа для этой проблемы заключается в создании собственной пользовательской версии CRT. Для этого есть инструкции здесь. Вам просто нужно отредактировать код, чтобы игнорировать EncodePointer и DecodePointer. (Для этого уже должен быть #define.)

Есть еще две незначительные вещи, которые вам нужно сделать:

  • Перейдите в папку Linker- > Additional Library Directories и установите C:\Microsoft Visual Studio 9.0\VC\lib в качестве первого пути поиска. (Я предполагаю, что вы использовали установочный каталог по умолчанию, иначе измените его соответствующим образом.)
  • Измените версию подсистемы в заголовке PE на 5,00 (используйте бесплатный CFF Explorer Suite, если у вас нет другого инструмента удобный для него).

Это должно позволить вашей программе работать в Windows 2000, а также в более поздних версиях.

Ответ 6

Вариант 1 - создать измененную версию среды выполнения 2010 года, которая перенаправляет вызовы API проблемы в поставляемую вами DLL. Я не знаю, как легко или сложно это быть - надеюсь, только незначительная настройка таблицы символов, но это зависит от формата файла - и вы, скорее всего, столкнетесь с обратным инженерным предложением лицензии, конечно.

Вариант 2 - Сравните экспортированные символы в двух разных версиях исполняемых файлов. Если символы одинаковы, у вас есть хорошие шансы на совместимость - хотя никаких гарантий нет. Его даже возможно, что форматы файлов lib отличаются.

Вариант 3 - Проверьте, можете ли вы получить доступ к источникам времени выполнения через MSDN или аналогичные, в частности, для создания исправленной версии.

Вариант 4 - Проверьте, можно ли использовать компилятор 2010 года, но более старый компоновщик, возможно, настроенный в ваших решениях как шаг пользовательской сборки. Опять же, это зависит от того, являются ли файлы obj и lib одинаковыми форматами файлов, но вы можете написать небольшую утилиту для исправления простых различий, таких как номера версий в заголовке. У старшего компоновщика не должно возникнуть проблем с компоновкой в ​​более старой среде исполнения - при условии, что objs из нового компилятора совместимы с ним.

Вариант 5 - сборка DLL в 2010 году, которая не требует их собственной среды выполнения, но которая загружается и размещается приложением, созданным с использованием более старого компилятора. Разумеется, достижение требования "нет времени выполнения" для ваших DLL может означать, что многие из ваших библиотек должны быть встроены в хостинг-приложение, и вам может потребоваться предоставить свои собственные интерфейсы (через приложение-хост) к библиотечным функциям, которые вам нужны для работы с - особенно материал выделения памяти.

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

Ответ 7

Это будет намного проще, если вам разрешено использовать DLL. В принципе, напишите EXE, который вообще не требует функций выполнения C, используя функцию компоновщика /ENTRYPOINT. После того как вы проверили, что ваши основные предпосылки выполнены, и сообщили о каких-либо проблемах пользователю с помощью только API-интерфейсов Windows, доступных на всех целевых ОС (например, MessageBox), затем вызовите LoadLibrary, чтобы запустить DLL, которая содержит основную часть вашей логики, Эта DLL может использовать среду выполнения VS2010, как обычно. Вы даже можете избежать развертывания двух отдельных файлов, распаковывая DLL из ресурса, содержащегося в вашем основном .EXE при запуске. (Вы можете сделать это полностью в памяти, не записывая .DLL на диск, но не если вы хотите воспользоваться загрузчиком Windows PE, чтобы исправить все ваши импорт).

Ответ 8

Создайте .LIB, который реализует недостающую функциональность и связывает ее перед KERNEL32.LIB.

Вам нужно будет использовать опцию компоновщика /NODEFAULTLIB:kernel32.lib, чтобы вы могли поместить ваш w2kcompat.lib перед kernel32.lib.