Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.02.06;
Скачать: CL | DM;

Вниз

TForm::OnShow   Найти похожие ветки 

 
Ермак ©   (2005-01-17 21:14) [0]

Значится, встала такая проблемка. Перед открытием главной формы программы необходимо показать форму запроса логина и пароля.

Сделал эту форму и функцию для ее создания/отображения/получения данных/закрытия (пардон, что исходники на C++ Builder):

bool EntranceBox(unsigned maxlen,AnsiString& login,AnsiString& password,bool& change)
{
       Application->CreateForm(__classid(TEntranceForm), &EntranceForm);
       EntranceForm->Edit1->Text = "";
       EntranceForm->Edit2->Text = "";
       EntranceForm->Edit1->MaxLength = maxlen;
       EntranceForm->Edit2->MaxLength = maxlen;
       switch( EntranceForm->ShowModal() ){
       case mrOk:
               login = EntranceForm->Edit1->Text;
               password = EntranceForm->Edit2->Text;
               change = false;
               EntranceForm->Close();
               return true;
       case mrRetry:
               login = EntranceForm->Edit1->Text;
               password = EntranceForm->Edit2->Text;
               change = true;
               EntranceForm->Close();
               return true;
       default:
               EntranceForm->Close();
               return false;
       }
}

Поместил ее вызов в OnCreate главной формы, и ясень пень, это не заработало - после закрытия единственного окна ввода пароля Винда  завершает приложение. Недолго думая, засунул вызов в OnShow - и все стало работать прекрасно.

Затем пишу второе приложение, которое точно так же запрашивает пароль. Но... После того, как OnShow отрабатывает, главная форма почему-то закрывается. Зарывается корректно - то есть, вызывается
OnClose, все деструкторы и т.п. Если перехватывать OnCloseQuery(), то закрытие можно пресечь, но это же не выход - почему вообще форма закрываться начинает?

Приложения идентичны, правда, создаются несколько лишних мьютексов, но дело не в них - если закомментировать вызов EntranceBox(), все работает нормально.

В чем же проблема? Подскажите, уважаемые!


 
Arnold ©   (2005-01-17 22:44) [1]

Ясень пень в С++ при обработке оператора switch компилятор пробегает по всем ветвям case и обязательно в этом случае  нужно в конце каждого case ставить break. Поробуй должно вроде так работать.

switch( EntranceForm->ShowModal() ){
      case mrOk:
              login = EntranceForm->Edit1->Text;
              password = EntranceForm->Edit2->Text;
              change = false;
              EntranceForm->Close();
              return true;
             break;
       case mrRetry:
              login = EntranceForm->Edit1->Text;
              password = EntranceForm->Edit2->Text;
              change = true;
              EntranceForm->Close();
              return true;
              break;
      default:
              EntranceForm->Close();
              return false;
              break
      }


 
jack128 ©   (2005-01-18 01:43) [2]

Arnold ©   (17.01.05 22:44) [1]
так у автора же в каждой ветке switch"a по return"у стоит

Ермак ©   (17.01.05 21:14)
Поместил ее вызов в OnCreate главной формы, и ясень пень, это не заработало - после закрытия единственного окна ввода пароля Винда  завершает приложение.

Дело не в Винде, а в том как устроена VCL. Если бы ты создовал окно так EntranceForm := TEntranceForm.Create(Application){сорри за Object Pascal} то все бы заработало.
Ермак ©   (17.01.05 21:14)
Но... После того, как OnShow отрабатывает, главная форма почему-то закрывается

а вот это странно. Приведи весь обработчик OnShow..


 
Ермак ©   (2005-01-18 12:06) [3]

>Дело не в Винде, а в том как устроена VCL.

Не-а. Это я точно знаю, Рихтера хорошо читал. Пока процесс не создал ни одного окна, он работает сколько угодно. После того, как хотя бы одно окно создано, Винда считает его за главное и при его закрытии отрубает процесс. Никакие VCL-деструкторы уже не вызваются.

А насчет обработчика - вот он:

void __fastcall TFormMain::FormShow(TObject *Sender)
{
       try{
       HINSTANCE hashlib = LoadLibrary("hash.dll");
       void __stdcall (*hashinit)() =
               (void __stdcall (*)())GetProcAddress(hashlib,"HashInit");
       hashinit();
       HashString = (void __stdcall (*)(char*,void*,unsigned))
               GetProcAddress(hashlib,"HashString");
       if( !HashString ) throw 1;
       }
       catch(...)
       {
               MessageBox(Handle,"Модуль hash.dll отсутствует или поврежден!",
               "Ошибка",MB_OK|MB_ICONERROR);
               TerminateThread(GetCurrentThread(),1);
       }
       user[0] = 0;

       base = new AuTrade::DriverAccess();
       TIniFile* ini = new TIniFile(".\\acslocal.ini");
       AnsiString path = ini->ReadString("LOCAL BASE","path","?");
       delete ini;
exclusive:
       HANDLE mutex = CreateMutex(0,TRUE,"AuTradeBaseAccess");
       if( GetLastError() == ERROR_ALREADY_EXISTS )
       {
               CloseHandle(mutex);
               if( MessageBox(Handle,"Следует закрыть все другие окна, работающие \
с этой базой!","Ошибка",MB_RETRYCANCEL|MB_ICONWARNING) == ID_RETRY )
                       goto exclusive;
               else
                       TerminateThread(GetCurrentThread(),1);
       }
       AuTrade::ShopOpen(path.c_str());
       if( !AuTrade::ShopState() )
       {
               MessageBox(Handle,"Невозможно открыть или создать базу данных \
по пути, указанному в acslocal.ini!","Ошибка",MB_OK|MB_ICONERROR);
               TerminateThread(GetCurrentThread(),1);
       }
       base->Products = AuTrade::ShopProducts();
       base->Suppliers = AuTrade::ShopSuppliers();
       base->Actions = AuTrade::ShopActions();
       base->Acts = AuTrade::ShopActs();
       base->Invoices = AuTrade::ShopInvoices();
       base->Main = AuTrade::ShopMain();

       AnsiString login, password;
       bool change_password;
entrance:
       if( !EntranceBox(15,login,password,change_password) )
                       goto terminate;

       if( password == "" ) password = " ";
       char p[16];
       HashString(password.c_str(),p,15);
       p[15] = 0;

       try{
               shop = base->Main->GetAccess(login.c_str(),p,0);
               products = base->Products->GetAccess(login.c_str(),p,0);
               suppliers = base->Suppliers->GetAccess(login.c_str(),p,0);
               actions = base->Actions->GetAccess(login.c_str(),p,0);
               acts = base->Acts->GetAccess(login.c_str(),p,0);
               invoices = base->Invoices->GetAccess(login.c_str(),p,0);
       }
       catch(AuTrade::ErrorUnknownLogin)
       {
               MessageBox(Handle,"Пользователя с таким именем не существует.",
                       "Неверное имя пользователя",MB_OK|MB_ICONERROR);
               goto entrance;
       }
       catch(AuTrade::ErrorWrongPassword)
       {
               MessageBox(Handle,"Старый пароль введен неверно.",
                       "Неверный пароль",MB_OK|MB_ICONERROR);
               goto entrance;
       }

       OpenProductPart();
       ApplySettings();

       return;
terminate:
       AuTrade::ShopClose();
       CloseHandle(mutex);
       TerminateThread(GetCurrentThread(),1);
}

Кстати, интересно, что из FormShow программу никак иначе не прервешь, кроме TerminateThread(GetCurrentThread(),1), стандартные средства, натипа exit (аналог halt) вызывают ошибку: "невозможно изменить вс-во Visible".


 
Ермак ©   (2005-01-18 12:32) [4]

EntranceForm := TEntranceForm.Create(Application)

Попробовал так сделать. Проблема исчезла! Но либо я дурак, либо одно из двух...

Вернул обратно Application.CreateForm - и оно тоже работает! Фигня какая-то... Открыты два окна Билдера с похожими программами - в одной работает, в другой нет! Потом меняю строчку - работает, меняю обратно - снова работает! Честное слово, со вчерашнего вечера к клаве не прикасался...

Объянение одно: глюкавость IDE, которая чего-то вовремя не пересобрала, либо в отладочном режиме накосячила. У Билдера такое бывает, к сожалению, в отличие от Дельфи. Надо на VC переходить...

Ну ладно, проблема решилась. Спасибо!


 
KSergey ©   (2005-01-18 14:04) [5]

> [3] Ермак ©   (18.01.05 12:06)
> >Дело не в Винде, а в том как устроена VCL.
> Не-а. Это я точно знаю, Рихтера хорошо читал. Пока процесс
> не создал ни одного окна, он работает сколько угодно. После
> того, как хотя бы одно окно создано, Винда считает его за
> главное (?) и при его закрытии отрубает процесс. Никакие VCL-деструкторы
> уже не вызваются.

Бред!

Впрочем, если использовать такие решения

TerminateThread(GetCurrentThread(),1);

то, конечно, можно многое поиметь, в том числе - и невызов деструкторов VCL


 
jack128 ©   (2005-01-18 18:06) [6]

KSergey ©   (18.01.05 14:04) [5]
Это я точно знаю, Рихтера хорошо читал

то что ты рихтера читал - это хорошо, но наверника в плохом переводе. Мне такие встечались.

Процесс завершается в ТРЕХ(!!!) случаях
1) Завершаются все его потоки(это нормальный вариант)
2) Вызов ExitProcess
3) TerminateProcess


 
jack128 ©   (2005-01-18 18:08) [7]

jack128 ©   (18.01.05 18:06) [6]
KSergey ©   (18.01.05 14:04) [5]
Это я точно знаю, Рихтера хорошо читал

Сорри, естественно эту фразу сказал не Сергей, а Ермак


 
Дмитрий В. Белькевич   (2005-01-23 02:43) [8]

Так должно работать:

Application.Initialize;
PasswordDlg := TPasswordDlg.Create(Application);
if PasswordDlg.ShowModal <> mrOK then //нажали Cancel
 begin
  PasswordDlg.Free;
  exit;
 end;
Application.CreateForm(TForm1, Form1); //основная форма
for i := 0 to Screen.FormCount - 1 do
 Internat.Execute(Screen.Forms[i]); //переводим на другой язык
Application.Run;



Страницы: 1 вся ветка

Текущий архив: 2005.02.06;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.148 c
14-1106121963
syte_ser78
2005-01-19 11:06
2005.02.06
Пример с книги Delphi 3 не работает на Delphi 6


1-1106565979
Mutniy
2005-01-24 14:26
2005.02.06
Почему в компоненте не находит ресурс ?


4-1103011815
Архитектор
2004-12-14 11:10
2005.02.06
InternetSetOption


1-1106501507
Knoxville
2005-01-23 20:31
2005.02.06
Многоязычная программа


14-1106047306
Stanislav
2005-01-18 14:21
2005.02.06
Не стирается DVD-RW