Russian Qt Forum
Май 29, 2024, 08:36 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3 4 5   Вниз
  Печать  
Автор Тема: Совместимлсть Qt dll  (Прочитано 27998 раз)
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #15 : Июнь 26, 2014, 16:05 »

- это выглядит глупо и противоречит идее dll

идея dll - это dll в каком-либо системном каталоге, откуда её могут подгружать те кому надо, как Linux. В Windows всё немного по-другому. Если Qt каким-то образом установлен в системный каталог, то 10 Qt приложенгий могут загрузить Qt5Core из него, и скорее всего, что в памяти будет только одна копия dll. Случай же с dll, которая лежит рядом с exe - другой. Поэтому либо ОС обязана проверять сходность нашей dll со всеми теми, что уже загружены в памяти, либо просто игнорировать тот факт, что в памяти уже могут быть точно такие же dll и грузить ещё одну, нашу копию. Что на будет делать в реальности я не знаю, такой информации у меня нет, хотя я и склоняюсь к 10 копиям просто по логике.
« Последнее редактирование: Июнь 26, 2014, 16:09 от Alex Custov » Записан
alex312
Хакер
*****
Offline Offline

Сообщений: 606



Просмотр профиля
« Ответ #16 : Июнь 26, 2014, 19:35 »

Хорошо, давайте так: на 1 машине 10 Qt приложений, каждое имеет Qt5Core.dll рядом с exe. Если все 10 приложений запущены - сколько копий Qt5Core.dll будет загружено в память? Все 10? Я не знаю "правельный ответ", но очень сомневаюсь что все 10 т.к.
За 10 не скажу, но 2 приложения у меня сейчас работают каждое со своей копией Qt5Core.dll .
Записан
Serr500
Гость
« Ответ #17 : Июнь 27, 2014, 12:26 »

- выходит "всегда юзается та dll что рядом c exe - что-то слишком просто. Напр зачем тогда эта городушка http://msdn.microsoft.com/en-us/library/windows/desktop/ms682600%28v=vs.85%29.aspx
Эта "городушка" работает немного не так, как обычно думают. Если вы через LoadLibrary в коде грузите DLL с указанием абсолютного пути, то при наличии .local-файла абсолютный путь будет проигнорирован и поиск начнётся с каталога .exe-файла.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #18 : Июнь 27, 2014, 12:52 »

Думаю будет загружено 10 штук.
Почему это глупо, подскажите пожалуйста?
Пример: Qt dll-ки в памяти занимают... ну много, метров 30 (не проверял, может и больше). 10 запущенных Qt приложений - вполне реально. Расход физической памяти 300 метров (вместо 30). По нынешним временам не катастрофа, но, мягко говоря, "не по-хозяйски".

За 10 не скажу, но 2 приложения у меня сейчас работают каждое со своей копией Qt5Core.dll .
Подтверждаю для 3-х  Улыбающийся

Эта "городушка" работает немного не так, как обычно думают. Если вы через LoadLibrary в коде грузите DLL с указанием абсолютного пути, то при наличии .local-файла абсолютный путь будет проигнорирован и поиск начнётся с каталога .exe-файла.
Т.е. предполагается такой сценарий: инсталлятор куда-то слил dll-ки и, возможно, прописал path. Неск приложений оттуда грузят. Теперь dll-ки обновилось, а одно из приложений это не устраивает. И вот тогда с помощью redirection его можно "подлечить". Хтозна-шо  Плачущий

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #19 : Июнь 27, 2014, 12:57 »

Да, к чему я все это спрашиваю: у меня 4 модуля, изначально в 1 фолдере, но один из них обычно интенсивно копируется в рамках одной машины, нередко 6-8 раз. Как лучше организовать dll-ки на Вындоуз?

Спасибо
Записан
Bepec
Гость
« Ответ #20 : Июнь 27, 2014, 13:16 »

Эмм...
А как оно копируется? модуль ваш? с dll или без?
Как вариант симлинки на ваши dll али же в system32 запихать.
Записан
Serr500
Гость
« Ответ #21 : Июнь 27, 2014, 14:04 »

Т.е. предполагается такой сценарий: инсталлятор куда-то слил dll-ки и, возможно, прописал path. Неск приложений оттуда грузят. Теперь dll-ки обновилось, а одно из приложений это не устраивает. И вот тогда с помощью redirection его можно "подлечить". Хтозна-шо  Плачущий
Следствие недостаточно продуманной архитектуры первых версий Windows...  В замешательстве Потом придумали WinSxS...
Записан
OKTA
Гость
« Ответ #22 : Июнь 27, 2014, 14:22 »

Да копия у каждого приложения, копия!

Иначе что, сделал QLibrary::unload () и все, крах системы?  Смеющийся Смеющийся Смеющийся Смеющийся

Если нужна только одна dll-ка, то берем системное API и нагло насилуем библиотеку какого-нибудь одного приложения  Смеющийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #23 : Июнь 27, 2014, 17:44 »

Эмм...
А как оно копируется? модуль ваш? с dll или без?
Как вариант симлинки на ваши dll али же в system32 запихать.
Нет уж, в system32 ничего пихать не будем  Злой
Допустим простейший вариант: кладем  все рядом с exe. Тогда придется вдаваться в не очень удобные объяснения типа  "Вы ж все что начинается с "Q" тоже копируйте" + расход памяти.

Конечно копированием одного exe все равно не обойтись, поэтому пользователи уже приучены копировать фолдер Resources, это не вызовет никаких вопросов. Заметно лучше было бы слить dll-ки туда, но тогда нет никаких гарантий что там они найдутся первыми. Кстати пробовал подсунуть др Qt5Core.dll - он ее хватает и вякает что плохая.

А лучше всего было бы создать фолдер с именем DLL и туда все лить - но опять-таки, как обеспечить надежную "находимость"?

Да копия у каждого приложения, копия!

Иначе что, сделал QLibrary::unload () и все, крах системы?  Смеющийся Смеющийся Смеющийся Смеющийся
unload уменьшает счетчик ссылок, неоднократно встречал это упоминание

Если нужна только одна dll-ка, то берем системное API и нагло насилуем библиотеку какого-нибудь одного приложения  Смеющийся
Каким образом? Изложите план насилия  Улыбающийся
Записан
OKTA
Гость
« Ответ #24 : Июнь 27, 2014, 19:27 »

Ведется подсчет ссылок внутри процесса и выгрузится он из этого процесса, а не из памяти.
А вот статейка про то самое  Улыбающийся
http://www.codeproject.com/Tips/139349/Getting-the-address-of-a-function-in-a-DLL-loaded
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #25 : Июнь 28, 2014, 09:55 »

Ведется подсчет ссылок внутри процесса и выгрузится он из этого процесса, а не из памяти.
А вот статейка про то самое  Улыбающийся
http://www.codeproject.com/Tips/139349/Getting-the-address-of-a-function-in-a-DLL-loaded
Не вижу никакой связи этой статьи с данной темой Улыбающийся Ладно, подведем итоги. Я понял так:

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

В результате можно иметь сколько угодно одинаковых копий - напр для одинаковых dll файлов лежащих в разных местах рядом с разными exe. Выходит это гарантирует запуск. Чтобы обеспечить использование одной копии - надо что-то делать с path, чтобы находили один и тот же файл.

Если dll с нужным именем уже в памяти процесса - ну здравый смысл говорит что она и будет использована (хотя Вындоуз - хз). А "совместимость Qt dll" решается до боли просто: разными именами dll (напр Qt4Core.dll и  Qt5Core.dll), никакого другого "идентификатора версии" они не имеют (нет его и в манифестах что в ресурсах).

Правильно ли я понял? Какие др мнения?

Спасибо
Записан
OKTA
Гость
« Ответ #26 : Июнь 30, 2014, 09:35 »

В статье как раз описано, как получить доступ к методам dll, загруженной в другой процесс....
Dll не берется из памяти, если такая же уже загружена... Она всегда берется с диска.. Почитайте ради интереса статейки.
http://www.rsdn.ru/?article/baseserv/InjectDll.xml http://www.rsdn.ru/article/baseserv/apicallsintercepting.xml
Там описаны методы внедрения dll в память процесса из которых понятно, что каждый процесс (без внешнего вмешательства) берет библиотеку с диска, а не из памяти... Вы представьте в голове простейший вариант - если бы dll бралась из памяти (при условии, что какой-от процесс с такой библиотекой уже запущен), то достаточно было бы написать приложение одно, которое просто загружает все нужные хакеру dll и запускать его перед стартом всех остальных интересующих процессов... Такой глупости не может быть, хотя она и была... вот кусок из одной из статей..

Цитировать
Так как перехват практически всегда связан с модификацией памяти (либо кода перехватываемой функции, либо таблиц импорта/экспорта), то для его осуществления необходимо учитывать особенности архитектуры памяти WinNT и Win9X.

Каждому процессу (начиная с Windows 95) выделяется собственное виртуальное адресное пространство. Для 32-разрядных процессов его размер составляет 4 Гб. Это адресное пространство разбивается на разделы, функциональное назначение и свойства которых довольно сильно отличаются у семейств ОС WinNT и Win9Х.

Адресное пространство любого процесса в Win9Х можно разделить на три раздела:

Младшие два гигабайта (00400000-7FFFFFFF) – код и данные пользовательского режима (в диапазоне 00000000-003FFFFF расположены разделы для выявления нулевых указателей и для совместимости с программами DOS и Win16);
Третий гигабайт – для общих файлов, проецируемых в память (MMF), и системных DLL.
Четвёртый гигабайт – для кода и данных режима ядра (здесь располагается ядро операционной системы и драйверы).
Старшие два гигабайта являются общими для всех процессов. Основные системные DLL – kernel32.dll, advAPI32.dll, user32.dll и GDI32.dll загружаются в третий гигабайт. По этой причине эти четыре библиотеки доступны всем процессам в системе. Поскольку этот гигабайт общий, они существуют во всех процессах по одним и тем же адресам. Из соображений безопасности Microsoft запретила запись в область, куда они загружаются. Если же запись туда всё же произвести (а это возможно из режима ядра или недокументированными методами), то изменения произойдут во всех процессах одновременно.

В WinNT общих разделов у процессов нет, хотя системные библиотеки по-прежнему во всех процессах загружаются по одинаковым адресам (но теперь уже в область кода и данных пользовательского режима). Запись в эту область разрешена, но у образов системных библиотек в памяти стоит атрибут «копирование при записи» (copy-on-write). По этой причине попытка записи, например, в образ kernel32.dll приведёт к появлению у процесса своей копии изменённой страницы kernel32.dll, а на остальных процессах это никак не отразится.

Все эти различия существенно влияют на способы реализации перехвата функций, расположенных в системных DLL.

Перехваты можно разделить на два типа: локальные (перехват в пределах одного процесса) и глобальные (в масштабах всей системы).
Записан
OKTA
Гость
« Ответ #27 : Июнь 30, 2014, 09:55 »

А еще есть такая книжечка "Windows для профессионалов". Вот выдержки из нее
Цитировать
Выполнение EXE-модуля
При запуске EXE-файла загрузчик операционной системы создает для его процесса
виртуальное адресное пространство и проецирует на него исполняемый модуль. Далее загрузчик анализирует раздел импорта и пытается спроецировать все необходимые DLL на адресное пространство процесса.
Поскольку в разделе импорта указано только имя DLL (без пути), загрузчику приходится самому искать ее на дисковых устройствах в компьютере пользователя. Поиск DLL осуществляется в следующей последовательности.
1. Каталог, содержащий EXE-файл.
2. Текущий каталог процесса.
3. Системный каталог Windows.
4. Основной каталог Windows.
5. Каталоги, указанные в переменной окружения PATH.
Учтите, что на процесс поиска библиотек могут повлиять и другие факторы
(см. главу 20). Проецируя DLL-модули на адресное пространство, загрузчик проверяет в каждом из них раздел импорта. Если у DLL есть раздел импорта (что обычно и
бывает), загрузчик проецирует следующий DLL-модуль. При этом загрузчик ведет учет
загружаемых DLL и проецирует их только один раз, даже если загрузки этих DLL требуют и другие модули.
Если найти файл DLL не удается, загрузчик выводит одно из двух сообщений

А вот про счетчики еще из той же книжечки:

Цитировать
На самом деле LoadLibrary и LoadLibraryEx лишь увеличивают счетчик числа пользователей указанной библиотеки, а FreeLibrary и FreeLibraryAndExitThread его уменьшают. Так, при первом вызове LoadLibrary для загрузки DLL система проецирует образ DLL-файла на адресное пространство вызывающего процесса и присваивает единицу счетчику числа пользователей этой DLL. Если поток того же процесса вызывает
LoadLibrary для той же DLL еще раз, DLL больше не проецируется; система просто
увеличивает счетчик числа ее пользователей — вот и все.
Чтобы выгрузить DLL из адресного пространства процесса, FreeLibrary придется
теперь вызывать дважды: первый вызов уменьшит счетчик до 1, второй — до 0. Обнаружив, что счетчик числа пользователей DLL обнулен, система отключит ее. После
этого попытка вызова какой-либо функции из данной  DLL приведет к нарушению
доступа, так как код по указанному адресу уже не отображается на адресное пространство процесса.
Система поддерживает в каждом процессе свой счетчик DLL, т. е. если поток
процесса А вызывает приведенную ниже функцию, а затем тот же вызов делает поток
в процессе В, то MyLib.dll проецируется на адресное пространство обоих процессов,
а счетчики числа пользователей DLL в каждом из них приравниваются 1.
HINSTANCE hinstDll = LoadLibrary("MyLib.dll");
Если же поток процесса В вызовет далее:
FreeLibrary(hinstDll);
счетчик числа пользователей DLL в процессе В обнулится, что приведет к отключению DLL от адресного пространства процесса В. Но проекция DLL на адресное пространство процесса А не затрагивается, и счетчик числа пользователей DLL в нем
остается прежним.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #28 : Июнь 30, 2014, 11:31 »

Dll не берется из памяти, если такая же уже загружена... Она всегда берется с диска..
MSDN пишет http://msdn.microsoft.com/en-us/library/windows/desktop/ms682586%28v=vs.85%29.aspx
Цитировать
If a DLL with the same module name is already loaded in memory, the system checks only for redirection and a manifest before resolving to the loaded DLL, no matter which directory it is in. The system does not search for the DLL.
Здесь важно "same module name" - это должен быть "именно тот файл" (а не др хоть и идентичный)   

Проверим на той же Qt5Core.dll запустив 2 Qt приложения. Утилита listDLLs.exe показывает
Цитировать
Test1.exe pid: 3768
Command line: "C:\QT_Training\Test1\Win32\Debug\Test1.exe"

Base                Size      Path
0x0000000050080000  0x7ec000  C:\Qt\5.2.0\msvc2012\bin\Qt5Cored.dll


windowflags.exe pid: 4984
Command line: "C:\Qt\5.2.0\msvc2012\examples\widgets\widgets\windowflags\debug\windowflags.exe"

Base                Size      Path
0x0000000050080000  0x7ec000  C:\Qt\5.2.0\msvc2012\bin\Qt5Cored.dll
Base одинаковый, в памяти одна копия. Положите dll рядлм с каждым exe - будут 2 копии.

Почитайте ради интереса статейки.
А Вы их сами внимательно читали? Улыбающийся Давайте попробуем вместе
Цитировать
Система поддерживает в каждом процессе свой счетчик DLL, т. е. если поток
процесса А вызывает приведенную ниже функцию, а затем тот же вызов делает поток
в процессе В, то MyLib.dll проецируется на адресное пространство обоих процессов,
а счетчики числа пользователей DLL в каждом из них приравниваются 1.
Нема квешнзов, dll используется ОДНА, "проекций" может быть сколько угодно

Цитировать
Если же поток процесса В вызовет далее:
FreeLibrary(hinstDll);
счетчик числа пользователей DLL в процессе В обнулится, что приведет к отключению DLL от адресного пространства процесса В. Но проекция DLL на адресное пространство процесса А не затрагивается, и счетчик числа пользователей DLL в нем остается прежним.
Тоже все ясно, dll в памяти пока ею пользуется хоть один процесс
Записан
OKTA
Гость
« Ответ #29 : Июнь 30, 2014, 12:23 »

MSDN говорит о загрузке библиотеки внутри одного процесса, а не среди нескольких.

Цитировать
Здесь важно "same module name" - это должен быть "именно тот файл" (а не др хоть и идентичный) 

- это просто имя файла библиотеки и ничего больше. Соответственно, следуя Вашей логике, система Windows не может содержать в памяти несколько библиотек с одинаковыми именами...
И почему это приложение отказывается стартовать, если не видит библиотеки на диске, хоть и приложение с такой же библиотекой будет одновременно работать?
Записан
Страниц: 1 [2] 3 4 5   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.067 секунд. Запросов: 22.