Правильная вигрузка dll

Тема в разделе "WASM.BEGINNERS", создана пользователем 984259h, 30 мар 2010.

  1. PowerASM

    PowerASM New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2010
    Сообщения:
    59
    984259h
    Просто смотрите что у Вас получается.
    выполняется FreeLibrary из-за чего вызывается DllMain.PROCESS_DETACH
    далее сразу же устанавливается Event и уничтожается
    Если это происходит не под отладчиком, то система автоматически перед уничтожением переключается на поток ожидающий этот Event. Отладчик же блокирует автоматическое переключение потоков и второй поток под отладчиком получает управление только когда Event вообще уже уничтожен.
    Одно из возможных решений. Перенесите CloseHandle(hShutdownEvent); в Thread_func.
     
  2. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    PowerASM
    я уже так делал как вы говорите эффект тот же
     
  3. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    к стати при запуске этого екзе сразу 4 потока (почему 4-ри ?) через 10 секунд вылетает MessageBoxA и остается 1 поток (если не нажав MessageBoxA то есть поток должен остановится до нажатия кнопки ) после чего ( через некоторое время, я так понял что системой аварийно завершается )
     
  4. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    PowerASM
    спасибо как вы говорили на счет "(поставить Sleep между Set и Close, либо SwitchToThread)" поставил Sleep(1000) ну в "Перенесите CloseHandle(hShutdownEvent); в Thread_func." а также поставил CloseHandle(hThreadMainConn);
    вот только с потоками немного не ясно почему их 4ри
     
  5. valterg

    valterg Active Member

    Публикаций:
    0
    Регистрация:
    19 авг 2004
    Сообщения:
    2.105
    Я тут с завистью облизываюсь на ваши эксперименты, т.к. давно хочу поработать с потоками. Но пока обхожусь без. Решил посмотреть сколько потоков в простой программе на Дельфи. Их 2 - 1 видимо обработчик Виндовых сообщений, второй - собственно обработка событий самого Дельфи. У вас наверное 3-й штатный поток - это обработка эвентов... Т.е. нет никакой мистики.
     
  6. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    valterg
    Ну если шаманить то картина такая получается я загружаю библиотеку получаю уведомление аттач и сразу создаю поток (который крутится в цикле ожидая события на завершения с задержкой 100 миллисек. -для обработки след. кода). Естественно сам процесс это поток 1 + загрузка либы (LoadLibraryA) + 1 и мой созданный + 1 в сумме = 3 пока все ок. Теперь мне необходимо выгрузить длл с ап процесса и тут следующая ситуация. Создается поток для выгрузки (FreeLibrary), сначала получаю уведомление на детач устанавливаю событие на завершения потока созданого на аттач либы после чего жду 1 сек на проработку. Мой поток возвращает на управление то есть пока все норм.Как только с детач выхожу и процесс должен завершится получается deadlock так как правильно сделать что код корректно завершился ?
     
  7. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    984259h
    Скорее всего это ожидание освобождения критической секции LdrpLoaderLock, так как вы делаете запрежённые действия.
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    *запрещённые
     
  9. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    Clerk
    Я не совсем Вас понял.
    Вы имеете ввиду что нельзя делать вызов CreateThread на длл аттач (из -за чего и
    ) ?
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    984259h
    Если вы создадите поток из InitRoutine модуля, то он будет ждать освобождения указанной выше кс. А это произойдёт когда текущий поток вернётся из длл, а далее из загрузчика, который перед этим освободит кс.
     
  11. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    Clerk
    А Вы не подскажите как правильно код организовать в моем случае буду очень благодарен.
     
  12. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    984259h
    Вы не решение задачи опишите, а задачу непосредственно, мне лень читать этот весь бред.
     
  13. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Всю тему не смотрели – лишь быстро прокомментируем кусок кода из #18:
    >nEvent = WaitForMultipleObjects(1,&hShutdownEvent,FALSE,100);
    Здесь нет необходимости делать таймаут 100мс (если это делается в целях какого-то другого эксперимента, тогда пренебрегай этим).

    >case DLL_PROCESS_DETACH:
    >SetEvent(hShutdownEvent);
    Вот здесь выставляешь события для другого потока, да. Однако после сигнализации ты ничего не ждёшь и просто возвращаешь TRUE из DllMain – может получиться так, что длл выгрузится до того, как выполняющий код в функции Thread_func поток завершится. Т.е. память, занимаемая функцией Thread_func, освободится – и при попытке исполнить что-либо оттуда произойдёт нарушение доступа.
    Не слишком хорошей идеей для решения этой проблемы могло бы стать ожидание в DllMain на hThreadMainConn после сигнализации hShutdownEvent – здесь, в зависимости от внутренней реализации лоадера, мы можем получить или не получить дедлок, поскольку при завершении потока должна быть вызвана DllMain(DLL_THREAD_DETACH), а она полагается нереентерабельной и вход в неё охраняется [ага, видим – в первом случае ты получаешь как раз это]. Ещё одним решением могло бы стать введение дополнительного события – OkayToUnloadEvent – на котором бы стоило ожидать внутри DllMain после сигнализации hShutdownEvent. Событие OkayToUnloadEvent в этом случае необходимо было бы сигнализировать при выходе из Thread_func с помощью внешней по отношению к dll функции SetEventAndExitThread(), которая сигнализирует событие и вызывает 'ExitThread()', не возвращаясь в вызываемый код. В качестве третьего варианта можем предложить бампнуть счётчик загрузок при создании потока из себя (вызовом LoadLibrary(self)), а при выходе из этого потока использовать FreeLibraryAndExitThread() – в отличие от гипотетической SetEventAndExitThread() эта функция рельно существует. Следует учитывать, что в последнем случае exe теряет способность точно контролировать момент выгрузки dll – при существовании рабочего потока она будет удалена из адресного пространства не после вызова FreeLibrary(), а лишь тогда, когда рабочий поток вызовет FreeLibraryAndExitThread().
    Общая рекомендация – строить код таким образом, чтобы просто не возникало ситуаций, когда dll неявно создаёт потоки и при этом может быть свободно выгружена.
     
  14. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    Sol_Ksacap
    Я уже об этом думал и делал после установки еванта Sleep(1000) или SwitchToThread() как говорил PowerASM.
    А если код с++ не представлять что это единое целое а представить что он состоит нескольких строк asm тогда как нельзя мне кажется говорить (
    )
     
  15. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    >Sleep(1000) или SwitchToThread()
    Не делай этого. Для правильно построенного кода подобное не понадобится. Для неправильного – лишь уменьшит вероятность проявления проблемы, но не решит её. Редкая, трудновоспроизводимая проблема хуже, чем легковоспроизводимая.

    Код (Text):
    1. nEvent = WaitForMultipleObjects(1,&hShutdownEvent,FALSE,100);
    2. (1) call [__imp_WaitForMultipleObjects]
    3. (2) mov [ebp + 8], eax
    Представь, что рабочий поток сейчас выполнил строку (1) и в недрах ядра ожидает сигнализации объекта. В это время основной поток выполняет код в DllMain для случая DLL_PROCESS_DETACH: сигнализирует событие и выходит из DllMain, после чего dll убирается из адресного пространства процесса. Через некоторое время рабочий поток продолжает выполнение – выполняет то и это, пока не придёт к выходу из функции WaitForMultipleObjects, после чего он должен будет продолжить выполнение строчки (2). А на этом месте уже пусто. Или хуже. Допустим, пока рабочий поток стремился к выходу из WaitForMultipleObjects, была загружена ещё одна dll и на месте строки (2) – совсем другой код. Окей, это понятно – говорим сие лишь к тому, что как код не представляй (си\асм\етц) – итог один.
     
  16. 984259h

    984259h New Member

    Публикаций:
    0
    Регистрация:
    25 авг 2007
    Сообщения:
    194
    Clerk
    задача такая
    Нужно что бы на подгрузку длл создавался бекконнект (тоесть когда длл загрузилась она постоянно пыталась соединится с определенный адресом ) а также что бы можно было выгрузить длл с процесса.
     
  17. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    984259h
    http://www.wasm.ru/forum/viewtopic.php?id=31189 ?