Установка BDE из собственного инсталятора
От: sublihim Россия  
Дата: 04.12.08 15:32
Оценка:
Доброго времени суток!
Вот вкратце моя проблема:
Есть написанный на С++ инсталлятор. В процессе работы необходимо оттуда запустить установку BDE. запускаю стандартно:



if ( ! CreateProcess(        NULL,
                             Path_BDE_SETUP,
                             NULL,
                             NULL,
                             TRUE,
                             NORMAL_PRIORITY_CLASS,
                             NULL,
                             NULL,
                             &si,
                             &pi)
      )
    {
    MessageBeep( MB_ICONERROR );
    }

    WaitForSingleObject( pi.hProcess, INFINITE );

    CloseHandle( pi.hThread );
    CloseHandle( pi.hProcess );




все бы хорошо, но на WaitForSingleObject — весь процесс замирает, пока не "срублю" поток инсталлятора, тогда и продолжается установка BDE. Я так понял, это происходит из-за того, что инсталшилд вначале стартует виртуальную дос-машину, зачем-то (я смотрел по pi.hProcess ) и WaitForSingleObject ловит его хендл и впадает в бесконечное ожидание...
Кто-нибудь сталкивался с подобным?

Решил сделать по-другому:
"Выковырял" BdeInst.dll, гружу и вызываю DllRegisterServer — и все-бы хорошо, но под WinXP SP3 — возникает ошибка во время регистрации, пишет, что не хватает места на диске и спрашивает, продолжить ли? Когда соглашаешься — то дальше все идет нормально. Но неприятно пугает пользователей. Может кто-нибудь и с этим сталкивался?

09.12.08 01:20: Перенесено модератором из 'C/C++. Прикладные вопросы' — Кодт
bde установка dllregisterserver waitforsingleobject
Re: Установка BDE из собственного инсталятора
От: Аноним  
Дата: 04.12.08 16:27
Оценка:
Здравствуйте, sublihim, Вы писали:

S>все бы хорошо, но на WaitForSingleObject — весь процесс замирает, пока не "срублю" поток инсталлятора, тогда и продолжается установка BDE. Я так понял, это происходит из-за того, что инсталшилд вначале стартует виртуальную дос-машину, зачем-то (я смотрел по pi.hProcess ) и WaitForSingleObject ловит его хендл и впадает в бесконечное ожидание...

S>Кто-нибудь сталкивался с подобным?

Там сам инсталлер 16 разрядный, поэтому в досовской машине. У нас проблема ожидания решается отслеживанием окошка установки BDE, а не процесса.
Re: Установка BDE из собственного инсталятора
От: sublihim Россия  
Дата: 08.12.08 06:02
Оценка:
Проблема решилась следующим образом:


if ( ! CreateProcess(        NULL,
                             Path_BDE_SETUP,
                             NULL,
                             NULL,
                             TRUE,
                             NORMAL_PRIORITY_CLASS,
                             NULL,
                             NULL,
                             &si,
                             &pi)
      )
    {
      // GetLastError
    }
    else
    {
        DWORD exitCode;
        MSG msg;
        do
        { 
            WaitForSingleObject(pi.hProcess, 10);

            if ( (PeekMessage(&msg, m_hWnd, 0, 0, PM_REMOVE)) && (msg.message == WM_PAINT) )
            {
                ::TranslateMessage(&msg);
                ::DispatchMessage(&msg);
            }
            GetExitCodeProcess(pi.hProcess, &exitCode);
        } while ( exitCode == STILL_ACTIVE );      
    }
Re[2]: Установка BDE из собственного инсталятора
От: sublihim Россия  
Дата: 08.12.08 06:14
Оценка:
Здравствуйте, sublihim, Вы писали:

S>Проблема решилась следующим образом:



S>
S>if ( ! CreateProcess(        NULL,
S>                             Path_BDE_SETUP,
S>                             NULL,
S>                             NULL,
S>                             TRUE,
S>                             NORMAL_PRIORITY_CLASS,
S>                             NULL,
S>                             NULL,
S>                             &si,
S>                             &pi)
S>      )
S>    {
S>      // GetLastError
S>    }
S>    else
S>    {
S>        DWORD exitCode;
S>        MSG msg;
S>        do
S>        { 
S>            WaitForSingleObject(pi.hProcess, 10);

S>            if ( (PeekMessage(&msg, m_hWnd, 0, 0, PM_REMOVE)) && (msg.message == WM_PAINT) )
S>            {
S>                ::TranslateMessage(&msg);
S>                ::DispatchMessage(&msg);
S>            }
S>            GetExitCodeProcess(pi.hProcess, &exitCode);
S>        } while ( exitCode == STILL_ACTIVE );      
S>    }

S>


PS. надо только сменить NORMAL_PRIORITY_CLASS на CREATE_SEPARATE_WOW_VDM
Re[2]: Установка BDE из собственного инсталятора
От: Аноним  
Дата: 08.12.08 06:31
Оценка:
S>
S>            WaitForSingleObject(pi.hProcess, 10);
S>


Лучше MsgWaitForMultipleObject вместо этого таймаута
Re[3]: Установка BDE из собственного инсталятора
От: sublihim Россия  
Дата: 08.12.08 06:54
Оценка:
Здравствуйте, Аноним, Вы писали:

A>Лучше MsgWaitForMultipleObject вместо этого таймаута

почему, аргументируйте?
Re[4]: Установка BDE из собственного инсталятора
От: Аноним  
Дата: 08.12.08 07:07
Оценка:
A>>Лучше MsgWaitForMultipleObject вместо этого таймаута
S>почему, аргументируйте?
1) Более быстрым просыпанием потока при приходе оконного сообщения.
2) Отсутствием отжора процессора на пустой цикл каждые 10 мсек.
3) Polling — быдлокодерство ( изза 1) и 2) )
Re[5]: Установка BDE из собственного инсталятора
От: Кодт Россия  
Дата: 08.12.08 22:53
Оценка:
Здравствуйте, Аноним, Вы писали:

A>>>Лучше MsgWaitForMultipleObject вместо этого таймаута

S>>почему, аргументируйте?
А>1) Более быстрым просыпанием потока при приходе оконного сообщения.
А>2) Отсутствием отжора процессора на пустой цикл каждые 10 мсек.
А>3) Polling — быдлокодерство ( изза 1) и 2) )

Вообще, любой модальный цикл должен быть как-то предъявлен пользователю как модальный.
А то разница между Wait и MsgWait (или тупым поллингом) лишь в том, замёрзнет окошко или не замёрзнет.

Удобно предъявлять модальность... да, конечно: модальным диалогом!
Одна беда: ::DialogBox (или надстройка над ним, obj.DoModal), помимо дисабления нижележащих окон, крутит собственный цикл. А создавать немодальный диалог и вручную превращать его в модальный — много возни.

Поэтому я предпочёл бы сделать так:
1) вынес процедуру вызова дочернего процесса в отдельный поток
2) создал бы модальный диалог (с кнопкой "Cancel вдребезги пополам")
3) познакомил бы диалог и тред между собой (или даже пусть диалог из OnInitDialog запустит тред, отдав ссылку на себя)
4) по "Вдребезги" диалог посылает треду эвент, и тот прекращает ждать процесса (WaitForMultipleObjects), и делает ему TerminateProcess
5) в конце работы тред посылает диалогу сообщение о закрытии

А если всё это кажется слишком сложным, то у нас есть ещё один способ показать модальность. Это песочные часы!
1) включаем песочные часы
2) дисаблим окно приложения
3) запускаем процесс
4) устраиваем прокачку, всё, как описано выше с MsgWait...
5) энаблим окно обратно
6) восстанавливаем курсор в исходное положение
Минус в том, что при зависании дочернего процесса остаётся висеть (хотя и не замерзает) основной процесс. И чтобы разрулить ситуацию, придётся запускать таскменеджер.


Да, кстати.
Оба подхода — с модальным диалогом и с песочными часами — прекрасно оформляются для повторного использования.
Точка кастомизации — это создание и утилизация хэндла синхрообъекта.
Причём создавать и утилизировать можно за пределами собственно модальной процедуры

API будет выглядеть вот так
BOOL WaitWithDialog( // возвращает false, если пользователь прервал работу
  HANDLE hToWait, // кого ждём
  HWND hwndParent, // родительское окно для диалога
  LPCTSTR strText, LPCTSTR strCaption, // содержание диалога
  BOOL bHasCancelButton // ну и собственно, есть ли чудо-кнопка
);

void WaitWithCursor(
  HANDLE hToWait, // кого ждём
  HWND hwnd // какое окно (точнее, его owner'а) дисаблить
);

Тогда
CreateProcess(.......);
if(!WaitWithDialog(pi.hProcess, hwnd, _T("Installing BDE... Please wait"), _T("My Cool Installer"), true))
  TerminateProcess(pi.hProcess);
CloseHandle(pi.hProcess);
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.