Как имитировать несколько экземпляров глобальных переменных в поведении приложения статической библиотеки, но с использованием библиотеки DLL?

У нас есть приложение, написанное на C / C ++, которое разбито на один EXE и несколько DLL. Каждая из этих DLL использует одну и ту же статическую библиотеку (utilities.lib).

Любая глобальная переменная в статической библиотеке утилит фактически будет иметь несколько экземпляров во время выполнения в приложении. Будет одна копия глобальной переменной на каждый модуль (например, DLL или EXE), с которым был связан utilities.lib.

(Все это хорошо известно, но стоит рассказать немного о том, как статические библиотеки ведут себя в контексте DLL.)

Теперь мой вопрос ... Мы хотим изменить utilities.lib, чтобы он стал DLL. Он становится очень большим и сложным, и мы хотим распространять его в форме DLL, а не в форме .lib. Проблема в том, что для этого приложения мы хотим сохранить текущее поведение, при котором каждая DLL приложения имеет собственную копию глобальных переменных в библиотеке утилит. Как бы вы это сделали? На самом деле нам это не нужно для всех глобальных переменных, только для некоторых; но это не имело бы значения, если бы мы получили его для всех.


Наши мысли:

  1. В библиотеке не так много глобальных переменных, которые нас интересуют, мы могли бы обернуть каждую из них аксессором, который выполняет какой-нибудь забавный трюк, пытаясь выяснить, какая DLL вызывает ее. Предположительно, мы можем пройти вверх по стеку вызовов и выудить HMODULE для каждой функции, пока не найдем ту, которая не utilities.dll. Затем мы могли бы вернуть другую версию в зависимости от вызывающей DLL.
  2. Мы могли бы поручить вызывающим абонентам установить определенную глобальную переменную (возможно, также локальную для потока) перед вызовом любой функции в utilities.dll. Затем DLL утилит может использовать это значение глобальной переменной для определения вызывающего контекста.
  3. Мы могли бы найти способ загружать utilities.dll несколько раз во время выполнения. Возможно, нам нужно будет сделать несколько переименованных копий во время сборки, чтобы каждая DLL приложения могла иметь свою собственную копию DLL утилит. Это, в первую очередь, сводит на нет некоторые преимущества использования DLL, но есть и другие приложения, для которых такое поведение в стиле «статической библиотеки» не требуется и которые все равно выиграют, если utilities.lib станет utilities.dll.

person pauldoo    schedule 02.07.2009    source источник


Ответы (2)


Вам, вероятно, лучше всего просто экспортировать дополнительные функции utilities.dll для выделения и освобождения структуры, содержащей переменные, а затем заставить каждую из ваших других рабочих DLL вызывать эти функции во время выполнения, когда это необходимо, например, на этапах DLL_ATTACH_PROCESS и DLL_DETACH_PROCESS в DllEntryPoint (). Таким образом, каждая DLL получает свою собственную локальную копию переменных и может передавать структуру обратно функциям utilities.dll в качестве дополнительного параметра.

Альтернативой является просто объявить отдельные переменные локально внутри каждой рабочей DLL напрямую, а затем передать их в utilities.dll в качестве параметров ввода / вывода, когда это необходимо.

В любом случае, у вас нет utilities.dll, попробуйте выяснить контекстную информацию самостоятельно. Это не сработает.

person Remy Lebeau    schedule 02.07.2009
comment
Таким образом, каждая DLL получает свою собственную локальную копию переменных и может передавать структуру обратно функциям utilities.dll в качестве дополнительного параметра. - Будет ли это явным параметром, который нам нужно будет добавить к каждой из наших функций? Или есть способ пропустить это под капотом? Я предполагаю, что вы имеете в виду явный параметр. - person pauldoo; 03.07.2009
comment
Да, это должен быть явный параметр. - person Remy Lebeau; 08.07.2009

Если бы я делал это, я бы исключил все глобальные переменные с сохранением состояния - я бы экспортировал COM-объект или простой класс C ++, содержащий все необходимое состояние, и каждый экспорт DLL стал бы методом вашего класса.

Ответы на ваши конкретные вопросы:

  1. Вы не можете надежно выполнить такую ​​трассировку стека - из-за таких оптимизаций, как оптимизация хвостового вызова или FPO вы не можете определить, кто вам звонил, во всех случаи. Вы обнаружите, что ваша программа будет работать при отладке, работать в основном в выпуске, но иногда дает сбой.
  2. Я думаю, вам будет сложно управлять этим, и это также требует, чтобы ваша библиотека не могла повторно входить в систему с другими модулями в вашем процессе - например, если вы поддерживаете обратные вызовы или события в другие модули.
  3. Это возможно, но вы полностью отрицали смысл использования DLL. Вместо переименования вы можете копировать в отдельные каталоги и загружать по полному пути.
person Michael    schedule 02.07.2009