Ответ 1
Существует несколько подходов к этой проблеме. Большинство из них icky, и это полностью зависит от того, какой графический API вы хотите настроить, и какие функции использует целевое приложение. Большинство приложений DirectX, GDI + и OpenGL имеют двойной или триплексный буфер, поэтому все они звонят:
void SwapBuffers(HDC hdc)
в какой-то момент. Они также генерируют сообщения WM_PAINT в очереди сообщений, когда окно должно быть нарисовано. Это дает вам два варианта.
-
Вы можете установить глобальный крючок или привязку к потоку в целевой процесс и захватить сообщения WM_PAINT. Это позволяет скопировать содержимое из контекста устройства непосредственно перед началом картины. Процесс можно найти, перечислив все процессы в системе и найдите известное имя окна или известный дескриптор модуля.
-
Вы можете ввести код в локальную копию SwapBuffers в целевой процесс. В Linux это было бы легко сделать с помощью переменной окружения LD_PRELOAD или явно вызовом ld-linux.so.2, но в Windows нет эквивалента. К счастью, у Microsoft Research есть структура, которая может сделать это для вас под названием Detours. Вы можете найти это здесь: ссылка.
Демосценовая группа Farbrausch сделала демонстрационный инструмент под названием kkapture, который использует библиотеку Detours. Их инструмент предназначен для приложений, которые не требуют ввода пользователя, поэтому они в основном запускают демонстрации с фиксированной частотой кадров, подключая все возможные функции времени, такие как timeGetTime(), GetTickCount() и QueryPerformanceCounter(). Это полностью рад. Презентацию, написанную ryg (я думаю?) Относительно внутренних элементов kkapture, можно найти здесь здесь. Я думаю, что вас интересует.
Для получения дополнительной информации о перехватах Windows см. здесь и здесь.
EDIT:
Эта идея заинтриговала меня, поэтому я использовал Detours для подключения к приложениям OpenGL и беспорядка с графикой. Вот Quake 2 с добавлением зеленого тумана:
Дополнительная информация о работе Detours, так как я использовал ее в первую очередь:
Обходные работы работают на двух уровнях. Фактический захват работает только в том же пространстве процесса, что и целевой процесс. Таким образом, у Detours есть функция для инъекции DLL в процесс и принудительного запуска DLLMain, а также функций, которые предполагается использовать в этой DLL. Когда DLLMain запущен, DLL должна вызывать DetourAttach(), чтобы указать функции для перехвата, а также функцию "обход", которая является кодом, который вы хотите переопределить.
Итак, он в основном работает следующим образом:
- У вас есть приложение для запуска, которому нужно только вызвать DetourCreateProcessWithDll(). Он работает так же, как и CreateProcessW, только с несколькими дополнительными параметрами. Это вставляет DLL в процесс и вызывает его DllMain().
- Вы реализуете DLL, которая вызывает функции Detour и настраивает функции батута. Это означает вызов DetourTransactionBegin(), DetourUpdateThread(), DetourAttach(), за которым следует DetourTransactionEnd().
- Используйте программу запуска, чтобы внедрить DLL, которую вы внедрили в процесс.
Однако есть некоторые оговорки. Когда DllMain запущен, библиотеки, которые позже импортируются с помощью LoadLibrary(), пока не отображаются. Поэтому вы не можете настроить все во время события вложения DLL. Обходной путь заключается в том, чтобы отслеживать все функции, которые были переопределены до сих пор, и попытаться инициализировать другие внутри этих функций, которые вы уже можете вызвать. Таким образом, вы обнаружите новые функции, как только LoadLibrary отобразит их в пространство памяти процесса. Я не совсем уверен, насколько хорошо это работает для wglGetProcAddress. (Возможно, у кого-то здесь есть идеи относительно этого?)
Некоторые вызовы LoadLibrary(), похоже, терпят неудачу. Я тестировал с Quake 2, а DirectSound и API waveOut по какой-то причине не удалось инициализировать. Я все еще расследую это.