Отложенная загрузка и прерывание выполнения работы
От: sax0n Украина  
Дата: 05.01.09 17:42
Оценка:
всех с НГ.
Такой вот вопросец есть: линкую DLL (Д) статически к своей программе.
программа (П) представляет собой плагин (ДЛЛ).
Если не находится Д, то при старте появляется чудная системная надпись о том, что Д е была найдена и плагин вываливается.
Мне же нужно убрать эту надпись и показать просто свое сообщение и завершить работу плагина.
Второе я сделать могу: через отложенную загрузку я могу сначала в DllMain проверить, можно ли загрузить Д и реагирую в зависимости от результата, но после этого все равно появляется системная надпись, что бы я не возвращал в DllMain
//Отложеннгая загрузка
#include <DelayImp.h>
#pragma comment(lib, "Delayimp.lib")
#pragma comment(lib,"my.lib")


BOOL APIENTRY DllMain( HINSTANCE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    hDllInstance = hModule;
    if (ul_reason_for_call == DLL_PROCESS_ATTACH)
    {
        HMODULE hlib = LoadLibrary(L"my.dll");
        if(!hlib)
        {
            MessageBoxA(0, "Error", "", 0);
            //lpReserved = NULL;
            return NULL;
        }
        //FreeLibrary(hlib);
    }
    return NULL; //Здесь пробовал разные значения вовзвращать...
}

По сути нужно прервать загрузку плагина, чтобы он не пытался загрузить Д.
Re: Отложенная загрузка и прерывание выполнения работы
От: Mager Украина  
Дата: 05.01.09 17:50
Оценка:
Здравствуйте, sax0n, Вы писали:

Не знаю, пробовали ли Вы уже ето, но мне такое помогало:
Достаточно вписать Вашу либу в список Properties->Linker->Input->Delay Loaded DLLs

Потом при старте проверить, есть ли она, если нет, то не обращаться больше к ней.
У меня такое работало.

Вот только не знаю, может оно так на LoadLibrary(L"my.dll") гавкает...
Тогда пробуйте как-нибудь по-другому проверять, есть ли библиотека нужная на нужном месте (может, файл с таким именем проверьте)
Re: Отложенная загрузка и прерывание выполнения работы
От: x64 Россия http://x64blog.name
Дата: 05.01.09 18:08
Оценка:
Я ни хрена не понял, что ты хочешь, но вызывать LoadLibrary() в DllMain() нельзя.
JID: x64j@jabber.ru
Re[2]: Отложенная загрузка и прерывание выполнения работы
От: sax0n Украина  
Дата: 05.01.09 18:24
Оценка:
Для Mager:
На LoadLibrary оно не гавкает. Ну, как-то проверить я смогу, есть ДЛЛ или нет... это неважно сейчас.
А вот что значит "не обращаться больше к ней"?
У меня по всему коду распиханы вызовы функций из этой ДЛЛ.
При чем при отложенной загрузке вываливается уже после DllMain, но до вызова плагина из хост-приложения.
Т.е. есть вызов DLL_PROCESS_ATTACH. я проверил ДЛЛ, вернул FALSE, т.к. нет той ДЛЛ. и сразу идет вызов DLL_PROCESS_DETACH. уже ПОСЛЕ выхода из DllMain вылетает системное сообщение. как такое может вообще быть?

Для x64:
есть сторонняя ДЛЛ, lib к ней и заголовочные файлы. это все я подключаю к своей ДЛЛ.
Так вот мне нужно при старте проверять, есть ли эта стороянняя ДЛЛ. и если нет, говорить это юзеру и завершать работу плагина (моей ДЛЛ) так, чтобы не появилось системное сообьщение об ошибке загрузки ДЛЛ.
Re[3]: Отложенная загрузка и прерывание выполнения работы
От: x64 Россия http://x64blog.name
Дата: 05.01.09 19:08
Оценка:
S>есть сторонняя ДЛЛ, lib к ней и заголовочные файлы. это все я подключаю к своей ДЛЛ.

Это называется "статическая линковка" и при отсутствии той DLL ты и будешь наблюдать то самое системное сообщение, это нормально.

S>Так вот мне нужно при старте проверять, есть ли эта стороянняя ДЛЛ. и если нет, говорить это юзеру и завершать работу плагина (моей ДЛЛ) так, чтобы не появилось системное сообьщение об ошибке загрузки ДЛЛ.


Ok, рассказываю. Вот для этого нужно использовать динамическую линковку, т.е. загрузку DLL по требованию через LoadLibrary() и иже с ними. Но вызывать LoadLibrary() в DllMain() — это большая ошибка, о чём, кстати, сказано в документации. Решение в твоём случае такое. В своей DLL тебе нужно предусмотреть функцию-экспорт типа Initialize(). Задача этой функции как раз и заключается в вызове LoadLibrary() на стороннюю DLL. Суть в том, что Initialize() должна быть вызвана кем-то, кто использует твою DLL (например, сразу после загрузки твоей DLL, т.е. после того, как отработает твоя DllMain()).

Тут проблема может быть в том, что твоя DLL — это тоже плагин, который грузится строго определённым образом, т.е. вызвать твою Initialize() просто некому. Здесь возможно другое решение, если нужно, я расскажу в следующий раз.
JID: x64j@jabber.ru
Re[4]: Отложенная загрузка и прерывание выполнения работы
От: sax0n Украина  
Дата: 05.01.09 19:23
Оценка:
Как называются все эти процессы я-то знаю.
А вот сделать с этим ничего не могу
Вариант не подходит. Мой только плагин, доступа к хост-приложению нет.
Есть только подключенный lib и все. Так что никто не вызовет Initialize().
Хост загружается и инициализирует все плагины через dllmain (process attach)
если плагин падает (как в моем случае), он не отображается даже в списке у хоста.
На данный момент выходит, что мне нужно сделать так, чтобы вообще ничего не появилось на екране. все остальное я сделать смогу.
Отложенная загрузка дает возможность получить управление до того, как лоадер попробует загрузить стороннюю ДЛЛ. Но, как сказать ему, что мне уже не нужны услуги этой ДЛЛ и ее не нужно запускать, т.к. я выгружаюсь?
Re[5]: Отложенная загрузка и прерывание выполнения работы
От: x64 Россия http://x64blog.name
Дата: 05.01.09 19:45
Оценка:
S>Хост загружается и инициализирует все плагины через dllmain (process attach)

Немного не корректное выражение, ну да ладно. Хорошо, тогда такие ещё вопросы:

1. Каким образом хост-процесс использует твою DLL? Т.е. просто загружает по LoadLibrary() и далее твоя DLL живёт сама по себе и делает что хочет? Наверно, всё же какие-то функции (или методы классов, например) твоей DLL вызываются хост-процессом позже?

2. В чём хотя бы примерно суть твоей DLL? Что она делает? И что за хост-процесс, для чего он вкратце?
JID: x64j@jabber.ru
Re[6]: Отложенная загрузка и прерывание выполнения работы
От: sax0n Украина  
Дата: 05.01.09 20:15
Оценка:
Это плагин для Photoshop.
При старте ему я так понимаю делается LoadLibrary.
А потом при вызове непосредственно из Фотошопа вызывается экспортируемая функция.
проблема в том, что "падает" оно после ДллМейн, но до вызова из Фотошопа.
Что дает отложенная загрузка? то, что ДЛЛ будет загружена в адресное пространство в момент первого обращения к одной из ее функций?
проблема в том, что я вызываю функции сторонней ДЛЛ в функции, до которой дело даже не доходит.
т.е. выходит из DllMain, а потом пытается подгрузить стороннюю ДЛЛ.
ДЛЛ эта хранит несколько функций (расчетов). вызывается далеко, в глубине от всех обсуждаемых событий
Re[7]: Отложенная загрузка и прерывание выполнения работы
От: x64 Россия http://x64blog.name
Дата: 05.01.09 21:53
Оценка:
S>Это плагин для Photoshop.
S>При старте ему я так понимаю делается LoadLibrary.
S>А потом при вызове непосредственно из Фотошопа вызывается экспортируемая функция.

Ну всё понятно тогда.

S>проблема в том, что "падает" оно после ДллМейн, но до вызова из Фотошопа.


Ну разумеется, это из-за статической линковки.

S>Что дает отложенная загрузка? то, что ДЛЛ будет загружена в адресное пространство в момент первого обращения к одной из ее функций?


Если кратко, то да. Но я не вижу причины использовать delay loading в твоём случае.

S>проблема в том, что я вызываю функции сторонней ДЛЛ в функции, до которой дело даже не доходит.


Я вообще не понимаю проблемы. Прежде всего, убери ты эту статическую линковку, она вообще противопоказана в твоём случае (исключительно потому что 3rdparty.dll может не быть). Для этого сотри все упоминания о 3rdparty.lib из настроек проекта, далее закомментируй в коде все вызовы из неё и после успешной сборки убедись, что твоя DLL ничего из неё не импортирует. Для этого проверь таблицу импортов своей DLL с помощью Dependency Walker. Теперь разкомментируй все вызовы в коде из 3rdparty.dll и замени их на вызовы по указателям, которые ты получишь через GetProcAddress(). Перед этими вызовами поставь проверку на NULL соответствующего указателя и, если он равен NULL, тогда вызывай функцию, которая сделает LoadLibrary() на 3rdparty.dll и получит указатели на каждую нужную тебе функцию через GetProcAddress(). Работу с функциями из 3rdparty.dll вынеси в отдельный исходный файл, это будет т.н. wrapper.

Ещё раз повторяю: не вижу никакой проблемы, просто откажись от статической линковки и замени её динамической через LoadLibrary(). То, что я написал выше, единственный грамотный и документированный путь. Delay loading есть суть тоже самое, только с той разницей, что при своей реализации у тебя появляется гибкость, а также чёткое понимание как оно работает.
JID: x64j@jabber.ru
Re[8]: Отложенная загрузка и прерывание выполнения работы
От: sax0n Украина  
Дата: 06.01.09 07:26
Оценка:
x64>Я вообще не понимаю проблемы. Прежде всего, убери ты эту статическую линковку, она вообще противопоказана в твоём случае (исключительно потому что 3rdparty.dll может не быть). Для этого сотри все упоминания о 3rdparty.lib из настроек проекта, далее закомментируй в коде все вызовы из неё и после успешной сборки убедись, что твоя DLL ничего из неё не импортирует. Для этого проверь таблицу импортов своей DLL с помощью Dependency Walker. Теперь разкомментируй все вызовы в коде из 3rdparty.dll и замени их на вызовы по указателям, которые ты получишь через GetProcAddress(). Перед этими вызовами поставь проверку на NULL соответствующего указателя и, если он равен NULL, тогда вызывай функцию, которая сделает LoadLibrary() на 3rdparty.dll и получит указатели на каждую нужную тебе функцию через GetProcAddress(). Работу с функциями из 3rdparty.dll вынеси в отдельный исходный файл, это будет т.н. wrapper.

x64>Ещё раз повторяю: не вижу никакой проблемы, просто откажись от статической линковки и замени её динамической через LoadLibrary(). То, что я написал выше, единственный грамотный и документированный путь. Delay loading есть суть тоже самое, только с той разницей, что при своей реализации у тебя появляется гибкость, а также чёткое понимание как оно работает.


В моем случае это не выход. слишком большие затраты времени на создание враппера.
...просто там на самом деле не х0 вызовов в коде, а х000. и лучше отказаться от самой проверки ДЛЛ, чем создавать враппер и переписывать код.
Мне нужно как-то из ДллМеин прекратить загрузку ДЛЛ. при чем в момент process_detach.
просто на данном этапе резонне сделать ресурс с этой ДЛЛ и при старте проверять наличие ДЛЛ в системе и сохранять из ресурса файл, чем переписывать все.
я понимаю, что прекратить загрузку ДЛЛ из самой ДЛЛ — это негуманно. но, отчаянные времена требуют отчаянных мер
Re[9]: Отложенная загрузка и прерывание выполнения работы
От: Mager Украина  
Дата: 06.01.09 07:46
Оценка:
Здравствуйте, sax0n, Вы писали:


S>В моем случае это не выход. слишком большие затраты времени на создание враппера.

S>...просто там на самом деле не х0 вызовов в коде, а х000. и лучше отказаться от самой проверки ДЛЛ, чем создавать враппер и переписывать код.
S>Мне нужно как-то из ДллМеин прекратить загрузку ДЛЛ. при чем в момент process_detach.
S>просто на данном этапе резонне сделать ресурс с этой ДЛЛ и при старте проверять наличие ДЛЛ в системе и сохранять из ресурса файл, чем переписывать все.
S>я понимаю, что прекратить загрузку ДЛЛ из самой ДЛЛ — это негуманно. но, отчаянные времена требуют отчаянных мер

1) Если правильно написать враппер, то ничего и переписывать не придется
2) Еще есть delay loading
Re[9]: Отложенная загрузка и прерывание выполнения работы
От: x64 Россия http://x64blog.name
Дата: 06.01.09 15:16
Оценка:
S>В моем случае это не выход. слишком большие затраты времени на создание враппера.
S>...просто там на самом деле не х0 вызовов в коде, а х000.

Это что за DLL такая, в которой, если я правильно понял, несколько тысяч экспортов? Или имеется в виду несколько тысяч вызовов, а самих функций намного меньше? Ну тогда здесь поможет что-то типа авторефакторинга. Предположим, что функций всего десяток, а вызовов ну тысяч 5, к примеру, и допустим ещё что все вызовы размазаны по разным исходным файлам. Тут можно либо отдельную утилитку консольную написать для обработки исходников, либо воспользоваться тупо фичей "Replace In Files", которая в Visual Studio. В любом случае, всё действо сводится к следующему алгоритму:

1. Заменить все вызовы вида

int iRet = 3rdpartyFunctionXxx (arg1, arg2, ...);


на

int iRet = gp3rdpartyFunctionXxx (arg1, arg2, ...);


Этот шаг нужно проделать столько раз, сколько всего функций используется из 3rdparty.dll.

2. Для каждой функции определить её тип примерно так:

typedef
int
(*3rdpartyFunctionPtr1) (
  type1 arg1,
  type2 arg2);

typedef
double
(*3rdpartyFunctionPtr2) (
  type1 arg1);

...

typedef
char*
(*3rdpartyFunctionPtrN) (
  type1 arg1);


3. В твоей функции, которая вызывается первой из Photoshop'а собрать все указатели на функции из 3rdparty.dll, т.е. сделать сначала LoadLibrary() и, затем, GetProcAddress() столько раз сколько нужно.

4. Все указатели на функции собрать в каком-либо исходном .cpp-файле, для их хранения используй тупо глобальные переменные. А в тех исходниках, где функции непосредственно используются, вставить такое:

extern 3rdpartyFunctionPtr1 gp3rdpartyFunctionXxx1;
extern 3rdpartyFunctionPtr2 gp3rdpartyFunctionXxx2;
extern 3rdpartyFunctionPtr3 gp3rdpartyFunctionXxx3;
extern 3rdpartyFunctionPtr4 gp3rdpartyFunctionXxx4;
...
extern 3rdpartyFunctionPtrN gp3rdpartyFunctionXxxN;


Ну в общем-то и всё. Вообще, что-то подобное нужно было сделать с самого начала, а не городить статическую линковку, писать десятки (если не сотни) тысяч строк кода, а потом кричать мол "надо переделывать, надо переделывать!".
JID: x64j@jabber.ru
Re[2]: Отложенная загрузка и прерывание выполнения работы
От: Аноним  
Дата: 07.01.09 00:47
Оценка:
Здравствуйте, x64, Вы писали:

x64>Я ни хрена не понял, что ты хочешь, но вызывать LoadLibrary() в DllMain() нельзя.


Если нельзя, но очень хочется или очень надо, то можно... но, предварительно завернув сей вызов в CreateThread... иначе — DeadLock
Re[3]: Отложенная загрузка и прерывание выполнения работы
От: sax0n Украина  
Дата: 07.01.09 08:11
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Если нельзя, но очень хочется или очень надо, то можно... но, предварительно завернув сей вызов в CreateThread... иначе — DeadLock


Но, как отменить загрузку статически прилинкованной ДЛЛ?
Re[4]: Отложенная загрузка и прерывание выполнения работы
От: std.denis Россия  
Дата: 11.01.09 15:42
Оценка:
S>Но, как отменить загрузку статически прилинкованной ДЛЛ?
может попробовать найти "my.dll" в том же порядке, как это делает LoadLibrary?

Вообще, имхо, правильно Mager говорит, что нужно использовать отложенную загрузку DLL-ок.

Я не знаток как пишутся плагины для фотошопа, но наверняка плагину, уже после загрузки его DLL-ки, можно как-то отказать фотошопу. Поэтому можно включить Delayed-loading, убрать всякие вызовы функций из "my.dll" внутри DllMain, и написать свою обработку ситуации ошибки загрузки DLL. Для этого возможно нужно будет покопаться внутри vc\include\delayhlp.cpp

Хотя я все же думал, что есть некая точка инициализации — Init/Load/Startup или фабрика класса, внутри которой можно проверить наличие всех нужных компонентов и в случае чего сказать "меня тут нет"..
Re[5]: Отложенная загрузка и прерывание выполнения работы
От: x64 Россия http://x64blog.name
Дата: 11.01.09 16:36
Оценка:
SD>Хотя я все же думал, что есть некая точка инициализации — Init/Load/Startup...

Так в том-то и дело что она есть, вот здесь
Автор: sax0n
Дата: 05.01.09
автор пишет об этом:

При старте ему я так понимаю делается LoadLibrary.
А потом при вызове непосредственно из Фотошопа вызывается экспортируемая функция.


И не нужны тут никакие delayed loading и прочая хрень. Почему автор уцепился именно за DL —
JID: x64j@jabber.ru
Re[6]: Отложенная загрузка и прерывание выполнения работы
От: sax0n Украина  
Дата: 11.01.09 18:22
Оценка:
На данный момент я нахожусь в такой ситуации:
есть плагин. при запуске фотошопа определяется, какой тип плагина загружается (посредством loadlibrary). когда в меню ФШ выберают запуск плагина, вызывается експорт-функция плагина. плагин использует статической линковкой еще одну ДЛЛ.

это все факт, который на данный момент менять я не буду. спасибо большое за помощь, но ответы в стиле "переписать/создать враппер..." прошу не предлагает, со всем уважением к всем участника форума.

И в такой ситуации мне нужно сделать так, чтобы при loadlibrary моего плагина, я мог определить, есть ли дополнительная ДЛЛ или нет. и как-то остановить загрузку статической ДЛЛ и вообще всего плагина.
да, это немного некрасиво выходит. и вообще неправильно. это я знаю.
нужно просто отменить инициализацию плагина как ДЛЛ, и отменить загрузку статической ДЛЛ.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.