Подскажите, пожалуйста, как, находясь в DLL, получить HMODULE этой DLL? Проблема в том, что в этой DLL нужно пользовать custom ресурсы, а соответствующие вызовы API FindResource, LoadResource, SizeofResource требуют HMODULE. Если вместо HMODULE пользовать NULL или использовать GetModuleHandle(NULL), то возвращается HMODULE вызывающего DLL процесса, а не самой DLL. Вызывать
GetModuleHandle("Путь")
тоже нельзя, т.к. положение текущего каталога относительно каталога с DLL неизвестно. Абсолютный путь к DLL заранее тоже не известен.
Использовать HMODULE, который передается в DLLMain, в моем случае тоже не получается.
Так как же поиметь HMODULE DLL, находясь в самой DLL? Или как поиметь custom ресурс, который в этой же DLL?
Здравствуйте Polosaty, Вы писали:
P>Подскажите, пожалуйста, как, находясь в DLL, получить HMODULE этой DLL? Проблема в том, что в этой DLL нужно пользовать custom ресурсы, а соответствующие вызовы API FindResource, LoadResource, SizeofResource требуют HMODULE. Если вместо HMODULE пользовать NULL или использовать GetModuleHandle(NULL), то возвращается HMODULE вызывающего DLL процесса, а не самой DLL. Вызывать P>
P>GetModuleHandle("Путь")
P>
P>тоже нельзя, т.к. положение текущего каталога относительно каталога с DLL неизвестно. Абсолютный путь к DLL заранее тоже не известен. P>Использовать HMODULE, который передается в DLLMain, в моем случае тоже не получается. P>Так как же поиметь HMODULE DLL, находясь в самой DLL? Или как поиметь custom ресурс, который в этой же DLL?
Используй DllMain:
HINSTANCE hInst;
...
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
hInst = hinstDll;
}
...
use hInst in program
...
Здравствуйте Polosaty, Вы писали:
P>Подскажите, пожалуйста, как, находясь в DLL, получить HMODULE этой DLL? Проблема в том, что в этой DLL нужно пользовать custom ресурсы, а соответствующие вызовы API FindResource, LoadResource, SizeofResource требуют HMODULE. Если вместо HMODULE пользовать NULL или использовать GetModuleHandle(NULL), то возвращается HMODULE вызывающего DLL процесса, а не самой DLL. Вызывать P>
P>GetModuleHandle("Путь")
P>
P>тоже нельзя, т.к. положение текущего каталога относительно каталога с DLL неизвестно. Абсолютный путь к DLL заранее тоже не известен. P>Использовать HMODULE, который передается в DLLMain, в моем случае тоже не получается. P>Так как же поиметь HMODULE DLL, находясь в самой DLL? Или как поиметь custom ресурс, который в этой же DLL?
Специально для таких случаев сделал функцию GetCurrentInstance (по аналогии с GetCurrentThread и GetCurrentProcess). Возвращает HINSTANCE модуля, из которого была вызвана эта функция.
Здравствуйте Alex Fedotov, Вы писали:
AF>Специально для таких случаев сделал функцию GetCurrentInstance (по аналогии с GetCurrentThread и GetCurrentProcess). Возвращает HINSTANCE модуля, из которого была вызвана эта функция.
AF>
Здравствуйте Alex Fedotov, Вы писали:
AF>Здравствуйте Polosaty, Вы писали:
P>>Подскажите, пожалуйста, как, находясь в DLL, получить HMODULE этой DLL? Проблема в том, что в этой DLL нужно пользовать custom ресурсы, а соответствующие вызовы API FindResource, LoadResource, SizeofResource требуют HMODULE. Если вместо HMODULE пользовать NULL или использовать GetModuleHandle(NULL), то возвращается HMODULE вызывающего DLL процесса, а не самой DLL. Вызывать P>>
P>>GetModuleHandle("Путь")
P>>
P>>тоже нельзя, т.к. положение текущего каталога относительно каталога с DLL неизвестно. Абсолютный путь к DLL заранее тоже не известен. P>>Использовать HMODULE, который передается в DLLMain, в моем случае тоже не получается. P>>Так как же поиметь HMODULE DLL, находясь в самой DLL? Или как поиметь custom ресурс, который в этой же DLL?
AF>Специально для таких случаев сделал функцию GetCurrentInstance (по аналогии с GetCurrentThread и GetCurrentProcess). Возвращает HINSTANCE модуля, из которого была вызвана эта функция.
AF>
Здравствуйте Владимир Гренадеров, Вы писали:
ВГ>А DllMain чем хуже? Или я не врубился?
Ничем не хуже. Наоборот, даже лучше. Однако, иногда (в моей практике — однажды) бывают ситуации, когда на DllMain надеяться нельзя. Например, я делал статическую библиотеку, у которой уже был прописан интерфейс. То есть ни добраться до параметра DllMain, ни добавить параметр в свою функцию я не мог. Пришлось извратиться.
Здравствуйте Владимир Гренадеров, Вы писали:
ВГ>Здравствуйте Alex Fedotov, Вы писали:
AF>>Здравствуйте Polosaty, Вы писали:
P>>>Подскажите, пожалуйста, как, находясь в DLL, получить HMODULE этой DLL? Проблема в том, что в этой DLL нужно пользовать custom ресурсы, а соответствующие вызовы API FindResource, LoadResource, SizeofResource требуют HMODULE. Если вместо HMODULE пользовать NULL или использовать GetModuleHandle(NULL), то возвращается HMODULE вызывающего DLL процесса, а не самой DLL. Вызывать P>>>
P>>>GetModuleHandle("Путь")
P>>>
P>>>тоже нельзя, т.к. положение текущего каталога относительно каталога с DLL неизвестно. Абсолютный путь к DLL заранее тоже не известен. P>>>Использовать HMODULE, который передается в DLLMain, в моем случае тоже не получается. P>>>Так как же поиметь HMODULE DLL, находясь в самой DLL? Или как поиметь custom ресурс, который в этой же DLL?
ВГ>Сильно !!!
Согласен
ВГ>А DllMain чем хуже? Или я не врубился?
Если посмотреть на 4 строки выше, то там есть одно предложение из самого первого письма с вопросом:
Использовать HMODULE, который передается в DLLMain, в моем случае тоже не получается.
Ну так получилось, что не могу я в моей ситуации поиметь HMODULE из DLLMain
Здравствуйте Alex Fedotov, Вы писали:
AF>Здравствуйте Alex Fedotov, Вы писали:
AF>>Специально для таких случаев сделал функцию GetCurrentInstance (по аналогии с GetCurrentThread и GetCurrentProcess). Возвращает HINSTANCE модуля, из которого была вызвана эта функция.
AF>>
Здравствуйте Polosaty, Вы писали:
ВГ>>А DllMain чем хуже? Или я не врубился? P>Если посмотреть на 4 строки выше, то там есть одно предложение из самого первого письма с вопросом: P>
P>Использовать HMODULE, который передается в DLLMain, в моем случае тоже не получается.
P>
P>Ну так получилось, что не могу я в моей ситуации поиметь HMODULE из DLLMain
А-а... Ступил что-то я...
P.S. А все-таки, почему DllMain не пашет (вдруг и уменя такое произойдет?), или ты
LoadLibraryEx юзаешь ?
Здравствуйте Владимир Гренадеров, Вы писали:
ВГ>Здравствуйте Polosaty, Вы писали:
ВГ>>>А DllMain чем хуже? Или я не врубился? P>>Если посмотреть на 4 строки выше, то там есть одно предложение из самого первого письма с вопросом: P>>
P>>Использовать HMODULE, который передается в DLLMain, в моем случае тоже не получается.
P>>
P>>Ну так получилось, что не могу я в моей ситуации поиметь HMODULE из DLLMain
ВГ>А-а... Ступил что-то я...
ВГ>P.S. А все-таки, почему DllMain не пашет (вдруг и уменя такое произойдет?), или ты ВГ>LoadLibraryEx юзаешь ?
DllMain пашет. Все гораздо хуже. У меня ее нет
Это один из случаев, когда HMODULE получить в DllMain нельзя. Можно было, конечно, определить DllMain, но... "нормальные герои всегда идут в обход" .
Второй случай, который привел Alex Fedotov — это когда Вы делаете статическую библиотеку, которая будет прилинкована неизвестно к чему, да еще и интерфейсы определены заранее и передача HMODULE ни в один из вызовов этой библиотеки не предусмотрена.
В общем, DllMain работает, только вот до HMODULE иногда не удается добраться.
Здравствуйте Polosaty, Вы писали:
P>Подскажите, пожалуйста, как, находясь в DLL, получить HMODULE этой DLL? Проблема в том, что в этой DLL нужно пользовать custom ресурсы, а соответствующие вызовы API FindResource, LoadResource, SizeofResource требуют HMODULE. Если вместо HMODULE пользовать NULL или использовать GetModuleHandle(NULL), то возвращается HMODULE вызывающего DLL процесса, а не самой DLL. Вызывать P>
P>GetModuleHandle("Путь")
P>
P>тоже нельзя, т.к. положение текущего каталога относительно каталога с DLL неизвестно. Абсолютный путь к DLL заранее тоже не известен. P>Так как же поиметь HMODULE DLL, находясь в самой DLL?
А почему нельзя? Ведь про каталог ничего не сказано в описании данной функции. Она case independently определяет, загружена ли библиотека с таким именем, без учета пути. По-моему (мне так кажется, и у Рихтера о том вроде написано, хотя не нашел сейчас), что чтоб узнать адрес либы внутри исполняемого модуля, надо знать только имя библиотеки, и не нужно путь к ней. А потом, по HMODULE получается полный путь, откуда она загружена (GetModuleFileName).
Здравствуйте Kaa, Вы писали:
Kaa>Здравствуйте Polosaty, Вы писали:
P>>Подскажите, пожалуйста, как, находясь в DLL, получить HMODULE этой DLL? Проблема в том, что в этой DLL нужно пользовать custom ресурсы, а соответствующие вызовы API FindResource, LoadResource, SizeofResource требуют HMODULE. Если вместо HMODULE пользовать NULL или использовать GetModuleHandle(NULL), то возвращается HMODULE вызывающего DLL процесса, а не самой DLL. Вызывать P>>
P>>GetModuleHandle("Путь")
P>>
P>>тоже нельзя, т.к. положение текущего каталога относительно каталога с DLL неизвестно. Абсолютный путь к DLL заранее тоже не известен. P>>Так как же поиметь HMODULE DLL, находясь в самой DLL? Kaa>А почему нельзя? Ведь про каталог ничего не сказано в описании данной функции. Она case independently определяет, загружена ли библиотека с таким именем, без учета пути. По-моему (мне так кажется, и у Рихтера о том вроде написано, хотя не нашел сейчас), что чтоб узнать адрес либы внутри исполняемого модуля, надо знать только имя библиотеки, и не нужно путь к ней. А потом, по HMODULE получается полный путь, откуда она загружена (GetModuleFileName).
Kaa>Я ошибаюсь?
Наверняка сказать, что Вы ошибаетесь, не могу, не знаю точно. Но логика у меня такая.
Представьте себе, что 2 разных приложения запускаются из разных каталогов. Совершенно случайно в составе обоих приложений оказались DLL с одним и тем же именем, и лежат эти DLL каждая в каталоге со своим EXE, т.е. каждая в своем. Если бы ОС было "наплевать" на путь к DLL, то что бы Вам вернул GetModuleHandle, когда обе DLL загружены?
Здравствуйте Polosaty, Вы писали:
P>Здравствуйте Kaa, Вы писали:
Kaa>>А почему нельзя? Ведь про каталог ничего не сказано в описании данной функции. Она case independently определяет, загружена ли библиотека с таким именем, без учета пути. По-моему (мне так кажется, и у Рихтера о том вроде написано, хотя не нашел сейчас), что чтоб узнать адрес либы внутри исполняемого модуля, надо знать только имя библиотеки, и не нужно путь к ней. А потом, по HMODULE получается полный путь, откуда она загружена (GetModuleFileName).
Kaa>>Я ошибаюсь?
P>Наверняка сказать, что Вы ошибаетесь, не могу, не знаю точно. Но логика у меня такая. P>Представьте себе, что 2 разных приложения запускаются из разных каталогов. Совершенно случайно в составе обоих приложений оказались DLL с одним и тем же именем, и лежат эти DLL каждая в каталоге со своим EXE, т.е. каждая в своем. Если бы ОС было "наплевать" на путь к DLL, то что бы Вам вернул GetModuleHandle, когда обе DLL загружены?
Вот написал такое и сам засомневался и полез в Рихтера. А там на стр. 54 IV издания сказано, что GetModuleHandle проверяет адресное пространство только того процесса, который ее вызвал. Тогда вопрос формулируется по-другому: если приложение загружает несколько разных DLL, которые имеют одинаковое имя, но лежат в разных каталогах, то что вернет GetModuleHandle?
Вообще-то обходиться без имени просто надежнее. Вдруг вздумается когда-нибудь переобозвать DLL, а аргумент функции GetModuleHandle при пересборке поменять забудете... Хотя это, конечно, за уши притянуто.
Кроме того, в Рихтере есть еще такое замечание: "если же файл системой не найден, функция возвращает NULL." Непонятно, что стоит за словами "файл системой не найден".
А метод, предложенный Alex Fedotov, работает всегда. И не только для DLL. И, как я понял, не только для исполняемого модуля (впрочем, как и GetModuleHandle). Но что еще выгодно отличает его от GetModuleHandle (если, конечно, я правильно врубился) — можно даже имени файла, спроецированного на адресное пространство процесса, не знать, а его HMODULE Вы получите.
Здравствуйте Polosaty, Вы писали:
P>Наверняка сказать, что Вы ошибаетесь, не могу, не знаю точно. Но логика у меня такая. P>Представьте себе, что 2 разных приложения запускаются из разных каталогов. Совершенно случайно в составе обоих приложений оказались DLL с одним и тем же именем, и лежат эти DLL каждая в каталоге со своим EXE, т.е. каждая в своем. Если бы ОС было "наплевать" на путь к DLL, то что бы Вам вернул GetModuleHandle, когда обе DLL загружены?
Ну, ОС такое допускает. Вернут будет первый из найденных "инстансов". Адреса загрузки DLL начинаются с 0x10000000. Будет выдан адрес первой найденной DLL. Если уж думать о том, что их может быть более одной, то все плохо. Тогда надо этого либо не допускать, либо проверять на наличие нескольких экземпляров. Но наличие нескольких экземпляров — не пресекается.
Прогони в отладчике такой пример (имена либ измени на свой манер, но чтоб пути разные были )
Как видишь, все четко определяется, но находится первая библиотека, и находится она только по имени, без учета каталога. Так что, в этом случае какраз ОС "наплевать"
Kaa>Как видишь, все четко определяется, но находится первая библиотека, и находится она только по имени, без учета каталога. Так что, в этом случае какраз ОС "наплевать"
Да, похоже, что ты прав . Но после твоего примера становится понятно, что метод от Alex Fedotov надежнее .
Здравствуйте Polosaty, Вы писали:
P>Вообще-то обходиться без имени просто надежнее. Вдруг вздумается когда-нибудь переобозвать DLL, а аргумент функции GetModuleHandle при пересборке поменять забудете... Хотя это, конечно, за уши притянуто.
Это точно. Большинство приложений линкуются со своими библиотеками статически, поэтому случаев на общем фоне не так много. Хотя предположить такое можно, и есть задачи, которые к этому иногда приводят.
P>Кроме того, в Рихтере есть еще такое замечание: "если же файл системой не найден, функция возвращает NULL." Непонятно, что стоит за словами "файл системой не найден".
Это значит, что в адресное пространство процесса файл с таким именем не "замапплен".
P>А метод, предложенный Alex Fedotov, работает всегда. И не только для DLL. И, как я понял, не только для исполняемого модуля (впрочем, как и GetModuleHandle).
Никто не ставит под сомнение метод мэтра. Просто есть стандартное средство проверить, что загружено в адресное пространство процесса, причем совершенно все равно, ккого типа это файл. При умолчании расширения .dll подразумевается, но там может быть все что угодно: от .exe до .txt
Здравствуйте Alex Fedotov, Вы писали:
AF>Здравствуйте VladD2, Вы писали:
VD>>Таки надо FAQ написать по этому делу.
AF>Ну путь кто-нибудь еще для Alpha и IA64 напишет, тогда можно и FAQ.
Ну, для IA64 ты наверное и сам сможешь, а для Alpha-ы уже поздновато.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: HMODULE в DLL
От:
Аноним
Дата:
24.02.02 17:14
Оценка:
Здравствуйте Alex Fedotov, Вы писали:
AF>Специально для таких случаев сделал функцию GetCurrentInstance (по аналогии с GetCurrentThread и GetCurrentProcess). Возвращает HINSTANCE модуля, из которого была вызвана эта функция.
AF>
Здравствуйте Аноним, Вы писали:
AF>>Специально для таких случаев сделал функцию GetCurrentInstance (по аналогии с GetCurrentThread и GetCurrentProcess). Возвращает HINSTANCE модуля, из которого была вызвана эта функция.
А>Мне кажется, что во второй функции лучше использовать GetThreadContext. Получится переносимее.
Во-первых, в таком случае она перестанет решать поставленную задачу, а именно возвращает HINSTANCE модуля, из которого была вызвана эта функция. Вместо этого она будет возвращать HINSTANCE модуля в котором она сама находится, что тоже неплохо.
Во-вторых, структура CONTEXT сама по себе зависит от платформы, так что выигрыш в переносимости не очень большой.
Здравствуйте Alex Fedotov, Вы писали:
AF>Во-первых, в таком случае она перестанет решать поставленную задачу, а именно возвращает HINSTANCE модуля, из которого была вызвана эта функция. Вместо этого она будет возвращать HINSTANCE модуля в котором она сама находится, что тоже неплохо.
Да, про это я не подумал.
AF>Во-вторых, структура CONTEXT сама по себе зависит от платформы, так что выигрыш в переносимости не очень большой.
Здравствуйте SergH, Вы писали:
AF>>Во-первых, в таком случае она перестанет решать поставленную задачу, а именно возвращает HINSTANCE модуля, из которого была вызвана эта функция. Вместо этого она будет возвращать HINSTANCE модуля в котором она сама находится, что тоже неплохо.
SH>Да, про это я не подумал.
Кстати, о переносимости. Только что узнал, причем читая книгу Рихтера про .Net.
Оказывается, VC 7.0 поддерживат intrinsic-функцию с именем _ReturnAddress, которая возвращает адрес возврата из текущей функции. С ее помощью можно обойтись и без ассемблера.
Но самое интересное в том, что на VC 6.0 она тоже поддерживается (уж не знаю, начиная с какого SP), так что вот этот код без проблем компилируется и работает на моем VC 6.0 SP5 + Processor Pack.
Здравствуйте Alex Fedotov, Вы писали:
AF>>Специально для таких случаев сделал функцию GetCurrentInstance (по аналогии с GetCurrentThread и GetCurrentProcess). Возвращает HINSTANCE модуля, из которого была вызвана эта функция.
Здравствуйте Kaa, Вы писали:
Kaa>В каких случаях мой вариант не будет работать?
Вопрос снимается. Функция при загрузке dll в другой адрес имеет адрес относительно адреса, указанного при сборке dll, а не относительно того, в который dll была загружена. (Как мутно выразился )
Здравствуйте Alex Fedotov, Вы писали:
AF>Здравствуйте SergH, Вы писали:
AF>>>Во-первых, в таком случае она перестанет решать поставленную задачу, а именно возвращает HINSTANCE модуля, из которого была вызвана эта функция. Вместо этого она будет возвращать HINSTANCE модуля в котором она сама находится, что тоже неплохо.
SH>>Да, про это я не подумал.
AF>Кстати, о переносимости. Только что узнал, причем читая книгу Рихтера про .Net.
AF>Оказывается, VC 7.0 поддерживат intrinsic-функцию с именем _ReturnAddress, которая возвращает адрес возврата из текущей функции. С ее помощью можно обойтись и без ассемблера.
AF>Но самое интересное в том, что на VC 6.0 она тоже поддерживается (уж не знаю, начиная с какого SP), так что вот этот код без проблем компилируется и работает на моем VC 6.0 SP5 + Processor Pack.
AF>
AF>Так что переносимость в пределах поддерживаемых MS платформ обеспечена (а для других задача не имеет смысла).
Мне понравилось. Попробовал. У меня на VC6 SP5 без Processor Pack скомпилялось без проблем. На моей W2K работает тоже без проблем. А вот на W98SE срабатывает _ASSERTE(mem.Type == MEM_IMAGE);. Можно ли это победить?
AF>>Так что переносимость в пределах поддерживаемых MS платформ обеспечена (а для других задача не имеет смысла).
P>Мне понравилось. Попробовал. У меня на VC6 SP5 без Processor Pack скомпилялось без проблем. На моей W2K работает тоже без проблем. А вот на W98SE срабатывает _ASSERTE(mem.Type == MEM_IMAGE);. Можно ли это победить?
AF>>>Так что переносимость в пределах поддерживаемых MS платформ обеспечена (а для других задача не имеет смысла).
P>>Мне понравилось. Попробовал. У меня на VC6 SP5 без Processor Pack скомпилялось без проблем. На моей W2K работает тоже без проблем. А вот на W98SE срабатывает _ASSERTE(mem.Type == MEM_IMAGE);. Можно ли это победить?
AF>А что там в поле Type оказалось?
Здравствуйте Alex Fedotov, Вы писали:
AF>Здравствуйте Polosaty, Вы писали:
AF>>>А что там в поле Type оказалось?
P>>MEM_PRIVATE
AF>Э... Ну если адрес правильный возвращается, просто убери этот ASSERT и все.
Я совсем убирать не стал, в релизе сам уберется. Сделал на всякий случай
Недавно встретил еще один любопытный подход. Выглядит он примерно так: есть некая dll, назовем ее lib1.dll. Для того, чтобы добраться до HINSTANCE, присутствует такая конструкция:
HINSTANCE hRes=LoadLibrary("Lib1.dll");
т.е. делается LoadLibrary самой себя. Как я понимаю, dll не может быть повторно загружена в адресное пространство процесса, т.е. данный вызов только возвращает HINSTANCE. Есть ли недостатки у такого подхода (не считая экзотики типа одноименных библиотек, загруженных из разных каталогов).
Здравствуйте, Polosaty, Вы писали:
P>Недавно встретил еще один любопытный подход. Выглядит он примерно так: есть некая dll, назовем ее lib1.dll. Для того, чтобы добраться до HINSTANCE, присутствует такая конструкция:
P>
P>HINSTANCE hRes=LoadLibrary("Lib1.dll");
P>
P>т.е. делается LoadLibrary самой себя. Как я понимаю, dll не может быть повторно загружена в адресное пространство процесса, т.е. данный вызов только возвращает HINSTANCE. Есть ли недостатки у такого подхода (не считая экзотики типа одноименных библиотек, загруженных из разных каталогов).
а DllMain будет отрабатывать второй раз? если так, то лучше LoadLibraryEx c LOAD_LIBRARY_AS_DATAFILE