Form2->ShowModal() - форма теряет фокус
Что делаю:
1. Запускаю другую программу через CreateProcess(...)
2. Скрываю все формы запускаемого приложения через ShowWindow(hWnd, SW_HIDE)
3. Показываю модально Form2->ShowModal();
4. После показа формы в обработчике OnShow(...) я выполняю определенные действия вплоть то инициализации потока и ожидания работы с ним. Фактически, Form2 отображает ProgressBar операции, которую пользователь может отменить. Чтобы запретить доступ к Form1, пока не закончится обработка функции, я создал Form2->ShowModal(...)
Если просто выполнять какой-нибудь цикл после создания формы, то Form2 отображается правильно. А вот если запускать приложение, то, как я понял, она теряет фокус и что-то неправильно обрабатывает - Form2 cкрывается за Form1. Приходится кликать на Form1, чтобы показалась Form2...
Пробовал... SetFocus(), и даже SendToBack(...), а потом BringToFront(...) ... И Form2->Visible = true делал
Все без толку... вот пока на главную форму не кликнешь - не покажется модальная Form2...
{
if (HideForm)
{
Form2->Position = poDesigned;
Form2->Left = -111;
Form2->Top = -111;
} else
{
Form2->Position = poMainFormCenter;
}
Form2->ShowModal();
}
//----------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TButton* btn = (TButton*)Sender;
if (btn->Name == "btnShowModal") ShowModalForm();
<...>
}
PS: и Form1, и Form2 у меня не имеют бордюра (заголовка, сист. кнопок и т.п. вещей)
Не получается...
Как я понял, суть проблемы в том, что я запускаю из своей проги (скажем, MyProg) другую прогу (назовем, OtherProg) через CreateProcess(...), затем я через перечисление EnumWIndow(...) скрываю все окна OtherProg, используя ShowWindow(... SW_HIDE).
В итоге получается, что сначала фокус стоит на MyProg, затем при запуске он переходит в OtherProg, а так как я скрываю все окна OtherProg, то фокус не стоит ни на одном окне (приложении)... И моя Form2, показанная ShowModal() не видна, т.е. скрыта за основным окном, т.е. за формой Form1. Только после клика на главном окне (Form1) появляется Form2...
Нет,
if (CreateProcess(NULL, RUNAPPNAME, 0, 0, FALSE, 0, 0, 0, &si, &pi))
{
DWORD res = WaitForInputIdle(pi.hProcess, 3000);
if (res == WAIT_TIMEOUT)
{
TerminateProcess(pi.hProcess, 0);
} else
{
EnumWindows((WNDENUMPROC)WndEnumProc, pi.dwProcessId);
<...>
Внутри ShowModal создаётся своя петля сообщений. В этой петле в цикле вызывается метод Application.HandleMessage до тех пор, пока не будет установлено свойство ModalResult или не придёт сообщение WM_Quit. После завершения этой петли вновь разрешаются все окна, которые были разрешены до вызова ShowModal, а "модальная" форма закрывается. В отличие от системных модальных диалогов модальная форма VCL во время своей активности не посылает родительскому окну сообщение WM_EnterIdle, но благодаря тому, что "модальная" петля сообщений использует HandleMessage, будет вызываться Idle, а значит, будет возникать событие Application.OnIdle, которое позволит выполнять фоновые действия.
Написано на http://delphikingdom.ru/asp/viewitem.asp?catalogid=169
Я тож из длл-плагина не могу отобразть просто так модальную форму в основном приложении, для этого я делаю что типа:
{
private:
bool ShowDialog(xti *xte)
{
Synchronize(SShowDialog);
return Answer;
}
void __fastcall SShowDialog();
}
....
void __fastcall TXti::SShowDialog()
{
SwDialog= new TShowDialog(Application);
Answer = SwDialog->ShowModal() == mrOk;
delete SwDialog;
SwDialog = NULL;
}
...
Xti->ShowDialog(xte);
А вот насчёт
Окно уж явно не будет ни модальным ни TOPMOST и будет постоянно пропадать под другие окна.
Кстати зделать это можно
без ноликов :)
такое вряд ли поможет, т.к. форма показывается модально, и выполнение кода после TForm::ShowModal тормозится до ее закрытия
[quote=frid-karatel]
if (CreateProcess(NULL, RUNAPPNAME, 0, 0, FALSE, 0, 0, 0, &si, &pi))
{
DWORD res = WaitForInputIdle(pi.hProcess, 3000);
if (res == WAIT_TIMEOUT)
{
TerminateProcess(pi.hProcess, 0);
} else
{
EnumWindows((WNDENUMPROC)WndEnumProc, pi.dwProcessId);
<...>
[/quote]
и какие выводы по поводу HWND дает этот код, если в нем ниразу хендл ничей не указан?
Вот практически полный код моих действий:
{
DWORD pid;
GetWindowThreadProcessId(hWnd, &pid);
if (pid == (DWORD)lParam)
{
ShowWindow(hWnd, SW_HIDE);
}
return true;
}
//---------------------------------------------------------------------------
void StartOtherProg()
{
<...>
if (CreateProcess(NULL, OTHERPROGFILE, 0, 0, FALSE, 0, 0, 0, &si, &pi))
{
DWORD res = WaitForInputIdle(pi.hProcess, 3000);
if (res == WAIT_TIMEOUT)
{
TerminateProcess(pi.hProcess, 0);
} else
{
EnumWindows((WNDENUMPROC)WndEnumProc, pi.dwProcessId);
<...>
}
Form1->ShowWaitForm();
<...>
}
//---------------------------------------------------------------------------
DWORD CALLBACK OperationThread()
{
<...>
Form2->Close();
return 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ShowWaitForm()
{
<...>
Form2->ShowModal();
<...>
}
//---------------------------------------------------------------------------
void __fastcall TForm2::FormShow(TObject *Sender)
{
CloseHandle(CreateThread(0, 0, OperationThread, 0, NULL, NULL));
}
Я запускаю функцию StartOtherProg(), и до тех пор, пока запущеное мной другое приложение (окна которого скрыты) не выполнит все действия, я ожидаю...
Я еще подключаю к запускаемой программе DLL в CreateProcess:
if (p)
{
if (WriteProcessMemory(pi.hProcess, p, PROG_DLL, strlen(PROG_DLL) + 1, NULL))
В этом не может быть проблемы?
да и вообще... сначала Form2 показывается модально, затем на ее OnShow стоит Form2->Close()
Внутри ShowModal создаётся своя петля сообщений. В этой петле в цикле вызывается метод Application.HandleMessage до тех пор, пока не будет установлено свойство ModalResult или не придёт сообщение WM_Quit. После завершения этой петли вновь разрешаются все окна, которые были разрешены до вызова ShowModal, а "модальная" форма закрывается. В отличие от системных модальных диалогов модальная форма VCL во время своей активности не посылает родительскому окну сообщение WM_EnterIdle, но благодаря тому, что "модальная" петля сообщений использует HandleMessage, будет вызываться Idle, а значит, будет возникать событие Application.OnIdle, которое позволит выполнять фоновые действия.
Написано на http://delphikingdom.ru/asp/viewitem.asp?catalogid=169
Я тож из длл-плагина не могу отобразть просто так модальную форму в основном приложении, для этого я делаю что типа:
{
private:
bool ShowDialog(xti *xte)
{
Synchronize(SShowDialog);
return Answer;
}
void __fastcall SShowDialog();
}
....
void __fastcall TXti::SShowDialog()
{
SwDialog= new TShowDialog(Application);
Answer = SwDialog->ShowModal() == mrOk;
delete SwDialog;
SwDialog = NULL;
}
...
Xti->ShowDialog(xte);
А вот насчёт
Окно уж явно не будет ни модальным ни TOPMOST и будет постоянно пропадать под другие окна.
Кстати зделать это можно
без ноликов :)
Многа букафф не осилил.
Прежде чем писать - может стоит проверить то , что вы цитируете? Попытка профессиональной риторики - еще не говорит о том, что утверждения верны.
Кроме того - вынужден разочаровать - данный код работает - причем форма к которой данное свойство применяется вызывается из длл.
Не смотря, на то что по вашему мнению это невозможно. :)
З.Ы. Возможно это так же связанно с тем что модальную форму вы создаете
я всегда модальную форму создаю
надеюсь не нужно объяснять почему?
CloseHandle(...) закрывает создаваемый поток...[//QUOTE]
[QUOTE=oxotnik333;238189]да и вообще... сначала Form2 показывается модально, затем на ее OnShow стоит Form2->Close()
Form2->Close() не стоит в OnShow окна - он стоит в созданном потоке...
PS: я привел примерный код моей программы
Прежде чем писать - может стоит проверить то , что вы цитируете? Попытка профессиональной риторики - еще не говорит о том, что утверждения верны.
Кроме того - вынужден разочаровать - данный код работает - причем форма к которой данное свойство применяется вызывается из длл.
Не смотря, на то что по вашему мнению это невозможно. :)
З.Ы. Возможно это так же связанно с тем что модальную форму вы создаете
я всегда модальную форму создаю
надеюсь не нужно объяснять почему?
Уважаемый _kot во всём что я здесь написал я уверен, и без разницы как вы создаёте это окно, отображатся модально оно не будет, а вот то что я написал про VCL это правда, и несмотря на ваш большой опыт я вам бы советывал это прочитать, потому что это одна из тонкостей билдера, у него модальные окна организуются не так как в WINAPI.
ps.Я только что специально перепроверил, и так как вы сказали тоже, а вот вы даже строки не осилили, а вот и зря, так много знать - не уделять внимания мелочам.
Тем не менее, действительно если
Раньше так делал, но модальное окно не пробывал.
А вот через SetWindowPos становится поверх других окон не хочет.
А нахрена создавать и тут же убивать его???
[QUOTE=frid-karatel]
Form2->Close() не стоит в OnShow окна - он стоит в созданном потоке...
PS: я привел примерный код моей программы[/QUOTE]
А поток запускается на OnShow...
ЗЫ: архитектура явно страдает
ps.Я только что специально перепроверил, и так как вы сказали тоже, а вот вы даже строки не осилили, а вот и зря, так много знать - не уделять внимания мелочам.
Тем не менее, действительно если
Раньше так делал, но модальное окно не пробывал.
А вот через SetWindowPos становится поверх других окон не хочет.
Вот горе-то, горе. :):):)
У меня становиться - у вас не становиться.
Писать и читать никто не мешает - и о том что билдер имеет свои ньюансы в работе с окнами я знаю - по крайней мере новостью для меня это не является. Но. Окно в данном случае все равно окном остается. И установка его первым в Z-последовательности сработает в любом случае.
У меня становиться - у вас не становиться.
Писать и читать никто не мешает - и о том что билдер имеет свои ньюансы в работе с окнами я знаю - по крайней мере новостью для меня это не является. Но. Окно в данном случае все равно окном остается. И установка его первым в Z-последовательности сработает в любом случае.
_Kot в последнем вашем посте я узнал много полезного, очень очень полезный пост. Если не сложно,учитывая ваш опыт, ответе пожалуйста на мой вопрос вашим постом выше, очень надеюсь что вы ответите без гнева присущего вам в этой теме )
ps. Ни от кого ничег оне пребую )) просто действительно именно щас вдруг потребовалось зделать окно поверх, не получается пока если кто знает как ответте пожалуйста.
А поток запускается на OnShow...
ЗЫ: архитектура явно страдает
Вообще, я в своей программе поток создаю при создании первой формы (основной, т.е. Form1), ставлю его в "спящий" режим, а потом активирую. Т.е. вместо CloseHandle(CreateThread(...)) я активирую поток, соответственно, функция Form2::FormShow(...) выполняется полностью.
В потоке же я жду, пока программа выполнит все действия... Когда все ОК, я закрываю модальную форму Form2...
Итак, в чем же может быть проблема, и почему форма не показывается?
PS: может тупо сэмулировать клик на главной форме? и все... :)
ps. Ни от кого ничег оне пребую )) просто действительно именно щас вдруг потребовалось зделать окно поверх, не получается пока если кто знает как ответте пожалуйста.
Да собственно не вопрос.
Код приложения-хоста:
{
if(dmMain->cdsSelectPriceItems->FieldByName("price")->Value==0)return;
HANDLE ghMutex = CreateMutex(NULL,FALSE,"CreateFormComplex");
int Res = GetLastError();
HWND hWnd = NULL;
if(Res==ERROR_ALREADY_EXISTS || Res == ERROR_INVALID_HANDLE)
hWnd = FindWindow("TfmComplete",NULL);
else{
CloseHandle(ghMutex);
typedef HWND (__import *pLoadForm)(HWND Handler,const char* connect);
pLoadForm fLoadForm = NULL;
HINSTANCE hDll = LoadLibrary("complcomp.dll");
if(!hDll)return;
fLoadForm = (pLoadForm)GetProcAddress(hDll,"_LoadForm");
if(!fLoadForm){
ShowMessage("Not load func!");return;
}
String temp = WideCharToString(dmMain->adoConnect->ConnectionString);
hWnd = fLoadForm(this->Handle,temp.c_str());
}
SetWindowPos(hWnd,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
SendMessage(hWnd,MM_ADDITEMS,dmMain->cdsSelectPriceItems->FieldByName("priceitem")->Value,0);
}
Этот код вызывается в случае, если окно необходимо поместить на передний план - но при этом модальным оно быть не должно. Думаю что в пояснениях код не нуждается. Это код который выполняется в длл
CoInitialize(NULL);
TfmComplete *fmMn = new TfmComplete(NULL);
fmMn->SetConnect(Handler,connect);
fmMn->Show();
return fmMn->Handle;
}
Когда выполняется этот участок кода - окно отображается, но скрывается когда клик происходит по родительскому окну или любому другому.
Это код вызова формы, которая показывается как модальная:
{
//
typedef HWND (__import *pLoadForm)(HWND Handler,const char* connect);
pLoadForm fLoadForm = NULL;
HINSTANCE hDll = LoadLibrary("complcomp.dll");
if(!hDll)return;
fLoadForm = (pLoadForm)GetProcAddress(hDll,"_LoadFormAll");
if(!fLoadForm){
ShowMessage("Not load func!");return;
}
String temp = WideCharToString(dmMain->adoConnect->ConnectionString);
fLoadForm(this->Handle,temp.c_str());
FreeLibrary(hDll);
}
Соответствующая функция в длл:
CoInitialize(NULL);
TfmMain *fmMain = new TfmMain(NULL);
fmMain->SetConnect(Handler,connect);
fmMain->ShowModal();
delete fmMain;
CoUninitialize();
return 0;
}
Если же в первой функции использовать вместо
вы получите окно, которое модальным не является - но при этом находиться всегда сверху.
запускай поток на OnShow модальной формы
т.е.
ModalForm->ShowModal();
//------------------------
void __fastcall TModalForm::FormShow(TObject *Sender)
{
CreateThread(...);
}
//--------------------