Здравствуйте! У меня есть одна программа (exe, соответственно). Написана на чистом API. Ее нужно переделать в dll (для запуска другим приложением, вроде плагина, поэтому просто запуск exe не подходит). Переделал. Запускается, работает все нормально. Но работает модально!!! То есть после вызова библиотечной функции, выполнение хост-программы (которая вызывает данную функцию) останавливается (она ни на что не реагирует). А надо не так. Хост-программа должна вызвать несколько функций из нескольких библиотек и остаться рабочей. В тело функции, которую я вызываю (библиотечной), я скопировал функцию WinMain из exe. Окно создается так: Код (Text): ... aReturn = RegisterClassEx(&wcex); //регистрация класса ... hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, szTitle, WS_CAPTION + WS_SYSMENU + WS_EX_CLIENTEDGE+DS_3DLOOK+WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); //создание окна Все отрабатывает нормально, проблема с петлей обработки сообщений. Так сделано в exe. Если это оставляю в dll - работает так, как я сказал выше (т.е. пока не закроешь окно, созданное в библиотечной функции, хост-программа стоит). Код (Text): ShowWindow(GhWnd,SW_MINIMIZE); UpdateWindow(GhWnd); ShowWindow(GhWnd,SW_HIDE); while(GetMessage( &msg, NULL, 0x00, 0x00)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; Я подумал, что это может быть связано с потоками. Попробовал сделать так: Код (Text): MSG msg;//Глобальная .... void MessageLoop(){ while(GetMessage( &msg, NULL, 0x00, 0x00)) { TranslateMessage(&msg); DispatchMessage(&msg); } } .... ThrId2=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoop, NULL, 0, NULL); Запускается правильно (производится вызов библиотечной функции, окошко (созданное данной функцией) сворачивается в трей, хост-приложение продолжает работу нормально), но окно, созданное библиотекой не может обрабатывать команды!!! Происходит ошибка при щелчке на значке в трее. Спасает только снятие процесса хост-приложения. Если петлю совсем убрать - также работает, как и с созданием потока. Но тут и так понятно... Запускаю так (пример на Delphi): Код (Text): try hndDLLHandle := loadLibrary ( 'somelib.dll' ); if hndDLLHandle <> 0 then begin @TMess := getProcAddress ( hndDLLHandle, 'somefunc' ); if addr ( TMess ) <> nil then begin if TMess<2 then begin MessageBox(0,'Ok!','Мастер изменений',MB_OK+MB_ICONINFORMATION); end; end; end; finally freeLibrary ( hndDLLHandle ); Подскажите, пожалуйста, как можно это побороть. Заранее благодарен за ценные советы.
Cigan И не знаю... Я вроде с тредами пробовал, но с ними никогда раньше не работал, могу и ошибиться при написании. Если можешь - приведи, пожалуйста, пример для DLL... Только запуск (который на Delphi, как пример) лучше не трогать (вероятно, запускать прийдется не только моему приложению). Модифицировать можно только DLL.
ksu_ant попробуй так: Код (Text): DWORD MessageLoop(LPVOID) { while(GetMessage( &msg, NULL, 0x00, 0x00)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } [edited] хотя тут не в этом дело. Просто функция потока принимает один параметр.
rmn Аналогично Так не захотела компилироваться: Код (Text): DWORD MessageLoop(LPVOID) Написал так: Код (Text): DWORD MessageLoop(LPVOID aReserved) В конце библиотечной функции делаю так: Код (Text): ShowWindow(GhWnd,SW_MINIMIZE); UpdateWindow(GhWnd); ShowWindow(GhWnd,SW_HIDE); ThrId2=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoop, NULL, 0, NULL); return msg.wParam; Может в конце чего-нибудь неправильно
Функции потока передается 4-й параметр CreateThread. Подробнее в msdn Попробуй такой вариант (не проверял): Код (Text): HWND GhWnd = NULL; DWORD ThreadProc(LPVOID lpParam); // вызывается из хоста void _declspec(dllexport) SomeFunc() { hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, NULL, 0, NULL); } DWORD ThreadProc(LPVOID lpParam) { MSG msg; GhWnd = CreateWindow(...); ShowWindow(GhWnd, MINIMIZE); ShowWindow(GhWnd, SW_HIDE); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessge(&msg); } return 0; }
наверно выходит 2 вложеных цикла обработки сообщений и когда запустился 1й(скопированный из винмэйн) до второго уже не доходит
rmn Эффект тот же, причем он аналогичен тому случаю, при котором петли вообще нет. Troller Не понял. Петля у меня одна... Или ты что-то другое имел ввиду?
rmn Кстати, эффект не совсем тот же. Раньше при щелчке или наведении указателя мыши на значок в трее хост-программа вылетала и ее надо было снимать в процессах (зацикливалась ошибка). Сделал так, как предложили Вы, - программа просто вылетает и все (один раз). Код такой: Код (Text): DWORD MessageLoop(LPVOID lpParam) { MSG msg; HINSTANCE hInstance; hInstance=theDLLModuleHandle; if(!InitApplication(hInstance)) return FALSE; InitCommonControls(); if (!InitInstance(hInstance, nCmdShow)) return FALSE; ShowWindow(GhWnd,SW_MINIMIZE); UpdateWindow(GhWnd); ShowWindow(GhWnd,SW_HIDE); while(GetMessage( &msg, NULL, 0x00, 0x00)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } int SomeFunc() { //Вызывается из хоста ...//Инициализация, работа, не связанная с окнами. ThrId2=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLoop, NULL, 0, &anz2); return 0; } Не знаю, в чем может быть проблема. Четвертый параметр CreateThread пуст, но я не могу сообразить что нужно передать в данном случае. У меня, надо отметить, уже создается один поток, он ловит определенные сообщения. Он создается до операций с окнами. Там четвертый параметр - событие. Здесь - не пойму что написать. Может в этом причина? Может быть они не уживаются?
Вот еще нашел схожую проблему. http://groups.google.com/group/micr...9250c3d861f/bfe48bcb36140e97#bfe48bcb36140e97 Там так и не нашлось решение. Прикрепляю тестовую dll и программу загрузки, созданную по мотивам данной проблемы. Если раскомментировать строчки в dll, которые делают окно видимым - программа вылетает.
А можно узнать зачем тебе петля обработки сообщений? Не проще сделать вывод как ты говоришь модального диалога из ресурсов, а сообщения обрабатывать в WinProc этого диалога. Так значительно проще. Сделай не регистрацию класса с последующим созданием окна, а вызов DialogBoxParam. И не увидел у тебя реализацию работы с SystemTray.
GMax Петля - для того, чтобы не изменять много кода. Он уже давно отлажен и трогать его страшно Там есть (в реальной программе) муторный алгоритм прорисовки grid (с рисованием разных иконок в сетке, в зависимости от определенных параметров). Боюсь, при переделке прийдется серьезно менять код, а этого не хотелось бы. Тем более, уже и спортивный интерес появился - неужели никто не писал так? Это же штатный способ, а работать не хочет. На Builder, Delphi я нашел в сети решения, например так: http://www.delphimaster.ru/cgi-bin/forum.pl?id=1166094492&n=5&toprint=1 но они на классах этих сред, а не на API в чистом виде, так что не понятно в чем все-таки особенность... А трея не видно потому что его нет ) Он есть в реальном коде. Это же пример и я намеренно опустил все, что не связано с появлением проблемы. Вот так. Может кто еще сможет подсказать?
Хех... Новый год, наверное, дает знать о себе Проблема решена!!! Откликнувшимся - СПАСИБО огромное! Проблема состояла в том, что я выгружал DLL (в коде программы запуска функции это видно), а этого, естественно, делать нельзя, не выйдя из библиотечного потока.