Проблема с окнами при переписывании из exe в dll

Тема в разделе "WASM.WIN32", создана пользователем ksu_ant, 3 янв 2007.

  1. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    Здравствуйте!
    У меня есть одна программа (exe, соответственно). Написана на чистом API.
    Ее нужно переделать в dll (для запуска другим приложением, вроде плагина, поэтому просто запуск exe не подходит).
    Переделал.
    Запускается, работает все нормально. Но работает модально!!! То есть после вызова библиотечной функции, выполнение хост-программы (которая вызывает данную функцию) останавливается (она ни на что не реагирует). А надо не так. Хост-программа должна вызвать несколько функций из нескольких библиотек и остаться рабочей.
    В тело функции, которую я вызываю (библиотечной), я скопировал функцию WinMain из exe.
    Окно создается так:
    Код (Text):
    1. ...
    2. aReturn = RegisterClassEx(&wcex); //регистрация класса
    3. ...
    4. hWnd = CreateWindowEx(  WS_EX_CLIENTEDGE,
    5.                         g_szClassName,
    6.                         szTitle,
    7.                         WS_CAPTION + WS_SYSMENU + WS_EX_CLIENTEDGE+DS_3DLOOK+WS_MINIMIZEBOX,
    8.                         CW_USEDEFAULT,
    9.                         CW_USEDEFAULT,
    10.                         CW_USEDEFAULT,
    11.                         CW_USEDEFAULT,
    12.                         NULL,
    13.                         NULL,
    14.                         hInstance,
    15.                         NULL);          //создание окна
    Все отрабатывает нормально, проблема с петлей обработки сообщений. Так сделано в exe. Если это оставляю в dll - работает так, как я сказал выше (т.е. пока не закроешь окно, созданное в библиотечной функции, хост-программа стоит).
    Код (Text):
    1. ShowWindow(GhWnd,SW_MINIMIZE);
    2. UpdateWindow(GhWnd);
    3. ShowWindow(GhWnd,SW_HIDE);
    4.  
    5. while(GetMessage( &msg, NULL, 0x00, 0x00))
    6. {
    7.    TranslateMessage(&msg);
    8.    DispatchMessage(&msg);
    9. }
    10. return msg.wParam;
    Я подумал, что это может быть связано с потоками.
    Попробовал сделать так:
    Код (Text):
    1. MSG  msg;//Глобальная
    2. ....
    3. void MessageLoop(){
    4.     while(GetMessage( &msg, NULL, 0x00, 0x00))
    5.     {
    6.         TranslateMessage(&msg);
    7.         DispatchMessage(&msg);
    8.     }
    9. }
    10. ....
    11. ThrId2=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoop, NULL, 0, NULL);
    Запускается правильно (производится вызов библиотечной функции, окошко (созданное данной функцией) сворачивается в трей, хост-приложение продолжает работу нормально), но окно, созданное библиотекой не может обрабатывать команды!!! Происходит ошибка при щелчке на значке в трее. Спасает только снятие процесса хост-приложения.
    Если петлю совсем убрать - также работает, как и с созданием потока. Но тут и так понятно...
    Запускаю так (пример на Delphi):
    Код (Text):
    1.   try
    2.     hndDLLHandle := loadLibrary ( 'somelib.dll' );
    3.     if hndDLLHandle <> 0 then
    4.     begin
    5.       @TMess := getProcAddress ( hndDLLHandle, 'somefunc' );
    6.       if addr ( TMess ) <> nil then
    7.       begin
    8.         if TMess<2 then begin
    9.           MessageBox(0,'Ok!','Мастер изменений',MB_OK+MB_ICONINFORMATION);
    10.         end;
    11.       end;
    12.      end;
    13.   finally
    14.     freeLibrary ( hndDLLHandle );
    Подскажите, пожалуйста, как можно это побороть.
    Заранее благодарен за ценные советы.
     
  2. Cigan

    Cigan New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2003
    Сообщения:
    54
    Адрес:
    Моск.обл
    А создание нового треда не пойдет?
     
  3. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    Cigan
    И не знаю... :dntknw: Я вроде с тредами пробовал, но с ними никогда раньше не работал, могу и ошибиться при написании.
    Если можешь - приведи, пожалуйста, пример для DLL...
    Только запуск (который на Delphi, как пример) лучше не трогать (вероятно, запускать прийдется не только моему приложению). Модифицировать можно только DLL.
     
  4. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    ksu_ant
    попробуй так:
    Код (Text):
    1. DWORD MessageLoop(LPVOID)
    2. {
    3.     while(GetMessage( &msg, NULL, 0x00, 0x00))
    4.     {
    5.         TranslateMessage(&msg);
    6.         DispatchMessage(&msg);
    7.     }
    8.     return 0;
    9. }
    [edited]
    хотя тут не в этом дело. Просто функция потока принимает один параметр. :)
     
  5. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    rmn
    Аналогично :dntknw:
    Так не захотела компилироваться:
    Код (Text):
    1. DWORD MessageLoop(LPVOID)
    Написал так:
    Код (Text):
    1. DWORD MessageLoop(LPVOID aReserved)
    В конце библиотечной функции делаю так:
    Код (Text):
    1. ShowWindow(GhWnd,SW_MINIMIZE);
    2. UpdateWindow(GhWnd);
    3. ShowWindow(GhWnd,SW_HIDE);
    4. ThrId2=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoop, NULL, 0, NULL);
    5. return msg.wParam;
    Может в конце чего-нибудь неправильно :dntknw:
     
  6. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    rmn
    А вот здесь, если можно, по-подробнее...
     
  7. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Функции потока передается 4-й параметр CreateThread. Подробнее в msdn :)

    Попробуй такой вариант (не проверял):
    Код (Text):
    1. HWND GhWnd = NULL;
    2.  
    3. DWORD ThreadProc(LPVOID lpParam);
    4.  
    5. // вызывается из хоста
    6. void _declspec(dllexport) SomeFunc()
    7. {
    8.     hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, NULL, 0, NULL);
    9. }
    10.  
    11. DWORD ThreadProc(LPVOID lpParam)
    12. {
    13.     MSG msg;
    14.     GhWnd = CreateWindow(...);
    15.     ShowWindow(GhWnd, MINIMIZE);
    16.     ShowWindow(GhWnd, SW_HIDE);
    17.    
    18.     while(GetMessage(&msg, NULL, 0, 0))
    19.     {
    20.         TranslateMessage(&msg);
    21.         DispatchMessge(&msg);
    22.     }
    23.     return 0;
    24. }
     
  8. Troller

    Troller New Member

    Публикаций:
    0
    Регистрация:
    3 авг 2006
    Сообщения:
    6
    наверно выходит 2 вложеных цикла обработки сообщений и когда запустился 1й(скопированный из винмэйн) до второго уже не доходит
     
  9. Troller

    Troller New Member

    Публикаций:
    0
    Регистрация:
    3 авг 2006
    Сообщения:
    6
    т.е. наоборот - скопированный из винмэйн это второй
     
  10. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    rmn
    Эффект тот же, причем он аналогичен тому случаю, при котором петли вообще нет.
    Troller
    Не понял. Петля у меня одна... Или ты что-то другое имел ввиду?
     
  11. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    rmn
    Кстати, эффект не совсем тот же.
    Раньше при щелчке или наведении указателя мыши на значок в трее хост-программа вылетала и ее надо было снимать в процессах (зацикливалась ошибка).
    Сделал так, как предложили Вы, - программа просто вылетает и все (один раз).
    Код такой:
    Код (Text):
    1. DWORD MessageLoop(LPVOID lpParam)
    2. {
    3. MSG  msg;
    4. HINSTANCE hInstance;
    5.  
    6. hInstance=theDLLModuleHandle;
    7. if(!InitApplication(hInstance))
    8.       return FALSE;
    9. InitCommonControls();
    10. if (!InitInstance(hInstance, nCmdShow))
    11.    return FALSE;
    12. ShowWindow(GhWnd,SW_MINIMIZE);
    13. UpdateWindow(GhWnd);
    14. ShowWindow(GhWnd,SW_HIDE);
    15. while(GetMessage( &msg, NULL, 0x00, 0x00))
    16. {
    17.     TranslateMessage(&msg);
    18.     DispatchMessage(&msg);
    19. }
    20. return 0;
    21. }
    22.  
    23. int SomeFunc() {      //Вызывается из хоста
    24. ...//Инициализация, работа, не связанная с окнами.
    25. ThrId2=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoop, NULL, 0, &anz2);
    26. return 0;
    27. }
    Не знаю, в чем может быть проблема.
    Четвертый параметр CreateThread пуст, но я не могу сообразить что нужно передать в данном случае.
    У меня, надо отметить, уже создается один поток, он ловит определенные сообщения. Он создается до операций с окнами. Там четвертый параметр - событие. Здесь - не пойму что написать.
    Может в этом причина? Может быть они не уживаются?
     
  12. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    Вот еще нашел схожую проблему.
    http://groups.google.com/group/micr...9250c3d861f/bfe48bcb36140e97#bfe48bcb36140e97
    Там так и не нашлось решение. :dntknw:
    Прикрепляю тестовую dll и программу загрузки, созданную по мотивам данной проблемы.
    Если раскомментировать строчки в dll, которые делают окно видимым - программа вылетает.
     
  13. GMax

    GMax Member

    Публикаций:
    0
    Регистрация:
    3 июл 2006
    Сообщения:
    218
    А можно узнать зачем тебе петля обработки сообщений?
    Не проще сделать вывод как ты говоришь модального диалога из ресурсов, а сообщения обрабатывать в WinProc этого диалога. Так значительно проще.
    Сделай не регистрацию класса с последующим созданием окна, а вызов DialogBoxParam.
    И не увидел у тебя реализацию работы с SystemTray.
     
  14. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    GMax
    Петля - для того, чтобы не изменять много кода. Он уже давно отлажен и трогать его страшно :)
    Там есть (в реальной программе) муторный алгоритм прорисовки grid (с рисованием разных иконок в сетке, в зависимости от определенных параметров). Боюсь, при переделке прийдется серьезно менять код, а этого не хотелось бы.
    Тем более, уже и спортивный интерес появился - неужели никто не писал так?
    Это же штатный способ, а работать не хочет.
    На Builder, Delphi я нашел в сети решения, например так: http://www.delphimaster.ru/cgi-bin/forum.pl?id=1166094492&n=5&toprint=1 но они на классах этих сред, а не на API в чистом виде, так что не понятно в чем все-таки особенность...
    А трея не видно потому что его нет :)) Он есть в реальном коде.
    Это же пример и я намеренно опустил все, что не связано с появлением проблемы.
    Вот так.
    Может кто еще сможет подсказать?
     
  15. ksu_ant

    ksu_ant New Member

    Публикаций:
    0
    Регистрация:
    28 сен 2005
    Сообщения:
    273
    Хех...
    Новый год, наверное, дает знать о себе :)
    Проблема решена!!!
    Откликнувшимся - СПАСИБО огромное!
    Проблема состояла в том, что я выгружал DLL (в коде программы запуска функции это видно), а этого, естественно, делать нельзя, не выйдя из библиотечного потока.