2010-05-03 6 views
6

У меня есть программа, в которую я добавляю эффекты полноэкранного пост-обработки. У меня нет источника для программы (это проприетарно, хотя разработчик отправил мне копию отладочных символов, формат .map). У меня есть код для написанных и работающих эффектов, никаких проблем.Избегайте переполнения стека в библиотеке обертки

Моя проблема теперь связана с двумя.

Я попробовал два метода до сих пор:

использовать объезды, чтобы изменить таблицу импорта оригинальной программы. Это отлично работает и гарантированно стабильно, но пользователь, с которым я разговаривал, не устраивает его, он требует установки (за исключением извлечения архива), и возникает вопрос, исправляется ли программа с помощью Detours в соответствии с условиями лицензионного соглашения. Итак, этот вариант отсутствует.

Другой вариант - традиционная замена DLL. Я обернул OpenGL (opengl32.dll), и мне нужна программа для загрузки моей DLL вместо системной копии (просто отбросьте ее в папку программы с правильным названием, это легко).

Мне тогда нужна моя DLL для загрузки фреймворка Cg и времени выполнения (который зависит от OpenGL) и нескольких других вещей. Когда Cg загружается, он вызывает некоторые из моих функций, которые вызывают функции Cg, и я склонен получать переполнения стека и бесконечные циклы. Мне нужно иметь возможность включать DLL-библиотеки Cg в подкаталог и по-прежнему использовать их функции (не уверены, возможно ли, чтобы таблица импорта DLL-файлов указывала на DLL в подкаталоге), или мне нужно динамически связать их (что я ' d скорее не делать, просто для упрощения процесса сборки), что-то, чтобы заставить их ссылаться на файл системы (а не на мою пользовательскую замену).

Вся цепь: Программа загружает DLL A (с именем opengl32.dll). DLL A загружает Cg.dll и динамически ссылки (GetProcAddress) в sysdir/opengl32.dll. Теперь мне нужно Cg.dll также ссылаться на sysdir/opengl32.dll, не DLL A.

Как это сделать? Редактировать: Как это сделать легко без использования GetProcAddress? Если ничего не работает, я готов вернуться к этому, но я бы предпочел, если это вообще возможно.

Редактировать 2: Я просто наткнулся на функцию SetDllDirectory в документах MSDN (на совершенно несвязанный поиск). На первый взгляд это похоже на то, что мне нужно. Это правильно, или я ошибаюсь? (выкл., чтобы опробовать его сейчас)

Редактировать 3: Я решил эту проблему, выполнив несколько иначе. Вместо того, чтобы отбрасывать OpenGL32.dll, я переименовал свою DLL в DInput.dll. Преимущество не только в том, что нужно экспортировать одну функцию вместо более 120 (для программы, Cg и GLEW), мне не нужно беспокоиться о возвращающихся функциях (я могу ссылаться на OpenGL, как обычно) , Чтобы войти в звонки, мне нужно перехватить, я использую «Объемы». В целом, он работает намного лучше. Этот вопрос, тем не менее, по-прежнему остается интересной проблемой (и, надеюсь, будет полезен для всех, кто пытается сумасшедшие вещи в будущем). Оба ответа хороши, поэтому я еще не уверен, что выбрать ...

+0

Для всех, кто сталкивается с этим вопросом в будущем, лучшие варианты (которые я закончил с помощью некоторого времени позже) - это ** не использовать Detours **. Это глючит, особенно в WoW64, и отсутствует базовые функции, такие как рекурсия. [EasyHook] (http://easyhook.codeplex.com/) намного превосходит функции, стабильность/производительность и общую обработку. – ssube

ответ

1

SetDllDirectory возможно не будет работы. Вероятно, Cg.dll просто ссылается на OpenGL.dll. Когда ОС загружает Cg.dll, он видит, что уже есть модуль, загруженный с этим именем (ваш), поэтому он связывает Cg с этим, а не собирается искать другую копию. То есть порядок поиска, который модифицирует SetDllDirectory, даже не вступает в игру, потому что ОС не выполняет никаких поисков.

Я подозреваю, что ваш лучший выбор действительно будет заключаться в том, чтобы выявлять звонки в вашу библиотеку. Когда вы обнаруживаете это, вместо того, чтобы выполнять свою собственную обработку, переадресовывайте вызов непосредственно в настоящую библиотеку OpenGL, к которой у вас есть ссылка из-за вызова LoadLibrary, а затем GetProcAddress для каждой из функций библиотеки.

+0

Есть ли у вас предложения по наиболее простому способу их обнаружения? Я не сталкивался с этой проблемой раньше, поэтому я не знаком с лучшим способом справиться с этим. Добавление фрагмента к началу каждой функции для вызова реального в конкретном состоянии не является проблемой, но что лучше всего проверить? – ssube

+1

На самом деле, у меня была мысль. Было бы эффективным и эффективным использовать простое глобальное логическое значение? В начале моей функции установите флажок 'if (cameBack) {вызовите realFunc; } else {cameBack = true; } ', затем установите значение false, когда выполняется выполнение. Это похоже на работу. Мой код, насколько мне известно, не должен быть потокобезопасным (у программы есть один поток рендеринга и один поток, который вообще относится к OpenGL, из моей отладки). – ssube

+1

Глобальная переменная - это именно то, что я бы использовал для первой попытки. Если вам нужно несколько потоков, вы можете попробовать локальное хранилище вместо обычных глобалов. Если одна из функций, которые вы перехватываете, заканчивается вызовом * другой * функции OpenGL, которую вы * также * хотите перехватить, тогда вы можете использовать глобальные переменные, зависящие от конкретной функции, а не только одну. –

1

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

Многочисленные зависящие от погоды сторонние компоненты в вашей системе уже проявили - и насколько подделка этих проявлений может представлять собой нарушение лицензии.

Для решения проблем с версиями dll Windows XP получила технологию, называемую контекстами активации. Иногда известный как бок о боке сборки, или даже что-то ужасное, как Application Isolation

Резюмируя много чтения в небольшое пространство: манифестов являются кусками данных XML, которые могут описать сборку, или описывают зависимость от сборок. Сборка - это манифест, плюс его dll.

Причина этого заключается в том, что сборка может принимать простую dll. «comctl32.dll» и его номер версии (v6), и создать вещь с более большим уникальным именем, так что несколько версий простой dll можно будет установить в одном месте безопасно. Ассембли предназначены для установки в C:\Windows\WinSxS.

Когда файл манифеста описывает DLL в сборке, его вызывает манифест сборки. И обычно имеет другое имя для dll.

Когда файл манифеста описывает сборки, используемые dll или exe, его называют манифестом приложения и обычно встраивается как ресурс RT_MANIFEST - в EXE с идентификатором res из 1 в Dll с идентификатором res 2 - или на диске в виде файла с именем «appname.exe.manifest»/«dllname.dll.2.manifest». Application manifesters определяют предмет, называемый контекстом активации, который в основном представляет собой пространство имен, которое окна будут искать для вещей. Каждый манифест создает контекст активации. Каждый контекст активации имеет сопоставление простых имен dll для сборок.

Таким образом, если вы создаете сборку с файла opengl32.dll и создать контекст активации для App.exe ссылающегося (локальный opengl32.dll) файл, а затем, возможно, все остальные DLLки, можно (и будут) продолжать использовать файлы system opengl32.dll, несмотря на то, что имена очень похожи. coff.

Проблема заключается в том, что res-id манифеста приложения - 1 - означает, что он используется для создания контекста активации по умолчанию процесса - так что ВСЕ DLL, у которых нет собственных явных манифестаций (Cg?), Будут искать пространство процесса по умолчанию и найти, что opengl32.dll

Таким образом, вы должны создать манифесты для каждого DLL, которые уже не встраивать один, убедившись, что просто не ссылаться на ваш opengl32.dll узла, который должен позволить затем вернитесь к порядку поиска по умолчанию и найдите его в обычном расположении system32.

это означает, что ваш файл opengl32.dll не может находиться в папке exe, так как эта папка ищет dll перед system32 (тот факт, что вы полагаетесь на подключение).

Мы сохраняем довольно простой порядок поиска, который берется системой при поиске сборок. сначала он ищет в WinSxS. Ваш Opengl32.dll не будет там, установка будет трудной проблемой. Затем он ищет в папке exe для подкаталога с именем сборки, затем он ищет в папке exe для манифеста сборки непосредственно.

Это означает, что вы можете создать сборку - называется что-то вроде: «OpenGLHook» и ваша структура папок будет выглядеть следующим образом:

\appfolder\ 
    app.exe 
    app.exe.manifest     - contains a dependentAssembly node to OpenGLHook 
    OpenGLHook\OpenGLHook.manifest - contains a file name=opengl32.dll 
    OpenGLHook\opengl32.dll   - your hook dll 
    yourimpl.dll      - your implementation dll that linkgs to cg.dll 
    cg.dll       - cg libraries 
    cg.dll.2.manifest     - a stub manifest you put together to ensure cg 
             doesnt use the app default activation ctx. 

Um, удачи?