У меня есть приложение, которое должно воздействовать на Windows 2000. Я также хотел бы использовать Visual Studio 2010 (главным образом из-за изменения формулировки auto
ключевое слово). Однако я нахожусь в чем-то вроде, связывают, потому что мне нужно приложение, чтобы смочь воздействовать на более старую ОС, а именно:
Библиотека времени выполнения 2010-х Visual Studio зависит от EncodePointer / DecodePointer
API, который был представлен в Windows XP SP2.
Если пользование альтернативной библиотекой времени выполнения возможно, будет это взламывать код, который полагается на C++ 0x опции, добавленные в VS2010, как std::regex
?
Решение Сумы выглядело многообещающе, но оно не работает: символы __imp__*@4
должны быть указателями на функции, а не сами функции. К сожалению, я не знаю, как заставить Visual C++ выдавать указатель с такой генерацией имени... (ну, __declspec(naked)
в сочетании с __stdcall
делает свое дело , но тогда я не знаю, как выдать указатель).
Если использование ассемблера во время сборки допустимо, решение довольно тривиально — соберите следующий код с помощью FASM и свяжите с созданным объектным файлом, и вуаля — никаких ссылок EncodePointer/DecodePointer в exe:
use32
format ms coff
section ".data" data
public __imp__DecodePointer@4
__imp__DecodePointer@4 dd dummy
public __imp__EncodePointer@4
__imp__EncodePointer@4 dd dummy
section ".text" code
dummy:
mov eax, [esp+4]
retn 4
Вариант 1 - создайте измененную версию среды выполнения 2010, которая перенаправляет вызовы проблемного API в предоставленную вами библиотеку DLL. Я не знаю, насколько это будет легко или сложно - надеюсь, это всего лишь небольшая настройка таблицы символов, но это зависит от формата файла - и, конечно, вы, скорее всего, столкнетесь с оговоркой о реверс-инжиниринге лицензии. .
Вариант 2 - Сравните экспортированные символы в двух разных версиях библиотек времени выполнения. Если символы совпадают, у вас хорошие шансы на совместимость, но никаких гарантий. Возможно даже, что форматы файлов lib разные.
Вариант 3 - Проверьте, можете ли вы получить доступ к источникам среды выполнения через MSDN или аналогичный, особенно для создания исправленной версии.
Вариант 4. Проверьте, можете ли вы использовать компилятор 2010, но более старый компоновщик, возможно, настроенный в ваших решениях как настраиваемый шаг сборки. Опять же, это зависит от того, имеют ли файлы obj и lib один и тот же формат, но вы можете написать небольшую утилиту для исправления простых различий, таких как номера версий в заголовке. У старого компоновщика не должно возникнуть проблем с компоновкой в старой среде выполнения - при условии, что объекты нового компилятора совместимы с ним.
Вариант 5 - создать в 2010 году библиотеки DLL, которым не нужна собственная среда выполнения, но которые загружаются и размещаются приложением, созданным с использованием более старого компилятора.Выполнение требования «без времени выполнения» для ваших DLL может означать, что многие ваши библиотеки, конечно же, должны быть встроены в хост-приложение, и вам может потребоваться предоставить свои собственные интерфейсы (через хост-приложение) для библиотечных функций, которые вам нужны для работы. with - особенно материал о распределении памяти.
Варианты, которые стоит проверить, но я уверен, что вы уже подумали обо всех их - извините, я понятия не имею, будут ли какие-либо из них работать - или они будут почти работать, но будут периодически вызывать проблемы.
Это было бы намного проще, если бы вам разрешили использовать DLL. По сути, напишите EXE, который вообще не требует функций времени выполнения C, используя функцию компоновщика / ENTRYPOINT. После того, как вы проверили, что ваши основные предварительные требования выполнены, и сообщили о любых проблемах пользователю с помощью только предоставляемых Windows API, доступных во всех целевых ОС (например, MessageBox), затем вызовите LoadLibrary, чтобы запустить DLL, которая содержит основную часть вашей логики. . Эта DLL может использовать среду выполнения VS2010 как обычно. Вы даже можете избежать развертывания двух отдельных файлов, распаковав DLL из ресурса, содержащегося в вашем основном .EXE, при запуске. (Вы можете сделать это полностью в памяти, не записывая .DLL на диск, но не в том случае, если вы хотите воспользоваться загрузчиком Windows PE для исправления всего вашего импорта).
Создайте .LIB, который реализует недостающую функциональность, и свяжите его перед KERNEL32.LIB.
Вам нужно будет использовать параметр компоновщика /NODEFAULTLIB:kernel32.lib, чтобы вы могли поместить свой w2kcompat.lib перед kernel32.lib.
Обычный способ решения этой проблемы - создать собственную версию CRT. Инструкции для него можно найти здесь . Вам просто нужно отредактировать код, чтобы игнорировать EncodePointer
и DecodePointer
. (Для этого уже должен быть #define
.)
Есть еще две незначительные вещи, которые вам нужно сделать:
C: \ Microsoft Visual Studio 9.0 \ VC \ lib
в качестве первого пути для поиска. (Я предполагаю, что вы использовали каталог установки по умолчанию, в противном случае измените при необходимости.) Это должно позволить вашей программе работать как в Windows 2000, так и в более поздних версиях.
Самое простое решение - просто установить для набора инструментов платформы в настройках проекта в VS2010 значение v900, при котором будут использоваться библиотеки и компилятор Visual Studio 2008. Это также означает, что вы теряете функции C ++ 0x, такие как auto
, но, честно говоря, обойти это с некоторыми typedef
, вероятно, проще, чем создавать свою собственную версию CRT или другие более сложные решения. В качестве альтернативы просто используйте VS2008! Я не знаю, есть ли другие функции C ++ 0x, которые имеют решающее значение для вашего приложения, но вы не упомянули, кроме std :: regex
, который, как мне кажется, все еще присутствует в наборе инструментов v900. в пространстве имен технического отчета 1 ( std :: tr1 :: regex
).
Исходя из моего впечатления, я могу предсказать, что неудобство запуска библиотек VS2010 на XP SP1 больше, чем удобство функций C ++ 0x, так что в целом это того не стоит.
Вы не можете использовать 2008 CRT, но можете запретить связывание новых функций DecodePointer / EncodePointer из ядра. Заменить новые функции заглушками довольно просто.
Можно попробовать следующее: Поместите такой код в исходный код main.cpp:
extern "C" {
void *__stdcall _imp__DecodePointer(void *x) {return x;}
void *__stdcall _imp__EncodePointer(void *x) {return x;}
};
Вышеупомянутое не работает. Хотя основная идея верна, исполнение должно быть немного другим. Как описано snemarch в комментарии и в другом ответе , __ imp __
не может быть вызовом функции, только указателем на нее. Поскольку создание указателя напрямую компилятором не представляется возможным, вам необходимо собрать следующий код с помощью MASM и связать его с созданным объектным файлом.
.model flat
.data
__imp__EncodePointer@4 dd dummy
__imp__DecodePointer@4 dd dummy
EXTERNDEF __imp__EncodePointer@4 : DWORD
EXTERNDEF __imp__DecodePointer@4 : 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 __imp__EncodePointer@4
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 __imp__DecodePointer@4
// ... same list, only order differs ...
Это показывает, что новые API используются в некоторых CRT для обеспечения большей безопасности для некоторых функций, которые, как считается, обеспечивают частые векторы атак. .
Приложив некоторые усилия, можно было бы использовать LoadLibrary / GetProcAddress для обеспечения реальной функциональности, которую предлагает ОС, но я не думаю, что это действительно что-то принесет. Функции времени выполнения, которые используют DecodePointer / EncodePointer, на самом деле не нуждаются в нем для обеспечения какой-либо кодировки, все, что им нужно, - это симметричное кодирование. Вам действительно не нужна повышенная безопасность (среда выполнения VS 2008 также не предоставит вам ее).
Надеюсь, вас не ждут другие препятствия - у меня нет доступа к системе Win2k или XP pre SP2, поэтому я не могу попробовать. Если есть какие-либо флаги заголовка exe, препятствующие даже попытке запустить exe в таких системах, их должно быть легко изменить.