Форум программистов, компьютерный форум CyberForum.ru
CyberForum.ru - форум программистов и сисадминов > > >
Восстановить пароль Регистрация
 
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
03.12.2012, 15:06     Узнать о закрытии внешней программы   #1
Я запускаю внешнюю программу при помощи ShellExecute. Как узнать, что внешняя программа закрывается? Можно ли вообще перехватывать любые события, происходящие в другой программе (если так же это моя программа)? Данными обмениваться необязательно. Очень нет времени изучать OLE или DDE. Нужно просто, чтобы первая программа узнала о завершении второй.
AdAgent
Объявления
03.12.2012, 15:06     Узнать о закрытии внешней программы
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.12.2012, 15:06     Узнать о закрытии внешней программы
Посмотрите здесь:

C++ Builder Выполнение кода при закрытии программы
C++ Builder сохранение данных об объектах при закрытии программы
C++ Builder Перехватить событие из внешней программы
C++ Builder Сохранение в текстовом документе при закрытии программы
C++ Builder Как мне сделать так, чтобы данный текстовый файл был открыт один раз при запуске программы и закрыт при закрытии программы?
mimicria
return (true);
1837 / 971 / 41
Регистрация: 19.04.2011
Сообщений: 2,034
03.12.2012, 15:38     Узнать о закрытии внешней программы   #2
Способов куча:
1. Искать окно FindWindow
2. Использовать WaitForSingleObject
3. Использовать GetProcessTimes (конкретно lpExitTime)
Я когда была необходимость запустить стороннюю программу и дождаться её завершения, не предпринимая никаких действий в процессе работы, использовал вместо ShellExecute() spawnlp() с параметром P_WAIT
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
04.12.2012, 14:09  [ТС]     Узнать о закрытии внешней программы   #3
Цитата Сообщение от mimicria Посмотреть сообщение
Я когда была необходимость запустить стороннюю программу и дождаться её завершения, не предпринимая никаких действий в процессе работы, использовал вместо ShellExecute() spawnlp() с параметром P_WAIT
А как не блокировать работу первой программы?
WaitForSingleObject - все равно блокирует насколько я понял. А FindWindow нужно вызывать самому (или опрашивать таймером, что не вариант).
BRcr
Модератор
3064 / 1667 / 107
Регистрация: 03.02.2011
Сообщений: 4,174
Записей в блоге: 6
04.12.2012, 17:24     Узнать о закрытии внешней программы   #4
Укажи параметр P_NOWAIT вместо P_WAIT. Кто справку-то читать будет?
Ddv122
Почемучка)
1221 / 281 / 11
Регистрация: 23.12.2010
Сообщений: 1,911
Записей в блоге: 1
04.12.2012, 21:35     Узнать о закрытии внешней программы   #5
Извините, не сюда написал)
Но Спасибо за spawnlp()
AdAgent
Объявления
04.12.2012, 21:35     Узнать о закрытии внешней программы
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
07.12.2012, 14:00  [ТС]     Узнать о закрытии внешней программы   #6
Цитата Сообщение от BRcr Посмотреть сообщение
Укажи параметр P_NOWAIT вместо P_WAIT
А как узнать о завершении программы то?)
BRcr
Модератор
3064 / 1667 / 107
Регистрация: 03.02.2011
Сообщений: 4,174
Записей в блоге: 6
07.12.2012, 14:49     Узнать о закрытии внешней программы   #7
Если подвешивать свою программу нельзя, тогда только опрашивать таймером или вынести ожидание в поток, других вариантов не ведаю.
При этом ты до сих пор не сообщил, почему это вдруг таймер не вариант...
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
07.12.2012, 16:08  [ТС]     Узнать о закрытии внешней программы   #8
Цитата Сообщение от BRcr Посмотреть сообщение
почему это вдруг таймер не вариант...
Включать таймер в программе А и проверять в нем FindWindow пробграммы B? Какой интервал задавать, чтобы не грузить систему? Не будет ли такого, что окна B уже не существует, но еще не выполнены операции деструктора B? Где гарантии, что пока программа B ищется на жестком диске и загружается в оперативную память сработает таймер в программе A? Все это наводит на мысли о ненадежности и нестабильности на разных компьютерах.
У Вас есть опыт, как это организовывается при помощи таймера, чтобы все было окей?

Добавлено через 1 минуту
О многопоточности думал. Но хотелось бы простой способ какой-нибудь.
BRcr
Модератор
3064 / 1667 / 107
Регистрация: 03.02.2011
Сообщений: 4,174
Записей в блоге: 6
08.12.2012, 12:17     Узнать о закрытии внешней программы   #9
Вообще-то с потоком оно и попроще будет, как на мой вкус...
Вот рабочий пример:
Код C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class TForm1
               : public TForm
{
__published: // IDE-managed Components
    TEdit *edit1;
    TButton *btn1;
    TLabel *lbl1;
    TLabel *lbl2;
    TButton *btn2;
    void __fastcall btn2Click( TObject *Sender );
private: // User declarations
public:  // User declarations
    __fastcall TForm1( TComponent *Owner );
};
// ---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
// ---------------------------------------------------------------------------
class process_await_thread
               : public TThread {
private:
 
protected:
 
public:
    HANDLE process;
    void __fastcall Execute( ) {
        WaitForSingleObject( process, INFINITE );
        Synchronize( &action );
    }
    void __fastcall action( ) {
        Form1->lbl2->Caption = "процесс завершен";
    }
    __fastcall process_await_thread( bool _suspended )
                   : TThread( _suspended ) {};
};
// ---------------------------------------------------------------------------
Код C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void __fastcall TForm1::btn2Click( TObject *Sender ) { // запуск программы
    SHELLEXECUTEINFO ei;
    String filename = "notepad.exe";
 
    SecureZeroMemory( &ei, sizeof( SHELLEXECUTEINFO ) );
    ei.cbSize = sizeof( SHELLEXECUTEINFO );
    ei.fMask |= SEE_MASK_NOCLOSEPROCESS;
    ei.lpFile = ( LPCTSTR )filename.c_str( );
    ei.nShow |= SW_SHOWDEFAULT;
 
    if ( ShellExecuteEx( &ei ) ) {
        lbl2->Caption = "процесс запущен";
        process_await_thread *thr = new process_await_thread( true );
        thr->FreeOnTerminate = true;
        thr->process = ei.hProcess;
        thr->Resume( );
    }
}
Экзешник:
Вложения
Тип файла: rar Project1.rar (468.1 Кб, 13 просмотров)
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
14.12.2012, 21:25  [ТС]     Узнать о закрытии внешней программы   #10
Почему возникает предупреждение?
[BCC32 Warning] W8111 Accessing deprecated entity '_fastcall TThread::Resume()'
BRcr
Модератор
3064 / 1667 / 107
Регистрация: 03.02.2011
Сообщений: 4,174
Записей в блоге: 6
14.12.2012, 22:02     Узнать о закрытии внешней программы   #11
Это значит, что эбаркадеровцы не гарантируют наличие данного метода в классе TThread в будущих версиях библиотеки VCL.
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
16.12.2012, 19:13  [ТС]     Узнать о закрытии внешней программы   #12
Как сделать, чтобы при закрытии процесса выполнялся метод другого объекта(класса)?
Я попробовал так:
Код C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class process_await_thread
               : public TThread {
private:
 
protected:
 
public:
    HANDLE process;
 
    void (*func_action)(void);  // новое
 
    void __fastcall Execute( ) {
        WaitForSingleObject( process, INFINITE );
        Synchronize( &func_action );
    }
 
    __fastcall process_await_thread( bool _suspended )
                   : TThread( _suspended )
                        {func_action = NULL}; // новое
};
В другом классе:
Код C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void __fastcall TForm1::btn2Click( TObject *Sender ) { // запуск программы
    SHELLEXECUTEINFO ei;
    String filename = "notepad.exe";
 
    SecureZeroMemory( &ei, sizeof( SHELLEXECUTEINFO ) );
    ei.cbSize = sizeof( SHELLEXECUTEINFO );
    ei.fMask |= SEE_MASK_NOCLOSEPROCESS;
    ei.lpFile = ( LPCTSTR )filename.c_str( );
    ei.nShow |= SW_SHOWDEFAULT;
 
    if ( ShellExecuteEx( &ei ) ) {
        
        process_await_thread *thr = new process_await_thread( true );
 
        thr->func_action = &My_Method; // где My_Method пренадлежит TForm1
 
        thr->FreeOnTerminate = true;
        thr->process = ei.hProcess;
        thr->Resume( );
    }
}
Но компилятор выдает ошибку на приведение типов в методе Synchronize. Если посмотреть возможные параметры, то Synchronize вообще хочет принимать только указатели на методы класса TThread.

Как быть? Что то меня заклинило...
BRcr
Модератор
3064 / 1667 / 107
Регистрация: 03.02.2011
Сообщений: 4,174
Записей в блоге: 6
16.12.2012, 19:22     Узнать о закрытии внешней программы   #13
И что мешает поступить просто вот так?
Код C++
1
2
3
4
    void __fastcall action( ) {
        //Form1->lbl2->Caption = "процесс завершен";
        Form1->My_Method( );
    }
Добавлено через 1 минуту
Впрочем, если это не вариант, то покажу способ с шаблонами и указателями на методы класса...
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
16.12.2012, 20:08  [ТС]     Узнать о закрытии внешней программы   #14
Цитата Сообщение от BRcr Посмотреть сообщение
И что мешает поступить просто вот так?
Я бы хотел создать один раз класс process_await_thread, добавить его в свою библиотеку и использовать его в разных программах и проектах.
BRcr
Модератор
3064 / 1667 / 107
Регистрация: 03.02.2011
Сообщений: 4,174
Записей в блоге: 6
16.12.2012, 20:50     Узнать о закрытии внешней программы   #15
Тогда так:
Код C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
template <class procs_provider>
class process_await_thread
               : public TThread {
private:
 
protected:
 
public:
    HANDLE process;
    procs_provider *a_class;
    void __fastcall( procs_provider::*action_proc )( );
 
    void __fastcall Execute( ) {
        WaitForSingleObject( process, INFINITE );
        Synchronize( &action );
    }
    void __fastcall action( ) {
        ( a_class->*action_proc )( );
    }
    __fastcall process_await_thread( bool _suspended )
                   : TThread( _suspended ) {};
};
// ---------------------------------------------------------------------------
class TForm1
               : public TForm
{
__published: // IDE-managed Components
    TMemo *memo1;
    TMemo *memo2;
    TButton *btn1;
    TComboBox *ComboBox1;
    TEdit *Edit1;
    TEdit *Edit2;
    void __fastcall btn1Click( TObject *Sender );
private: // User declarations
public:  // User declarations
    void __fastcall my_method( ) {
        ShowMessage( "in my_method" );
    }
    __fastcall TForm1( TComponent *Owner );
};
Код C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    SHELLEXECUTEINFO ei;
    String filename = "notepad.exe";
 
    SecureZeroMemory( &ei, sizeof( SHELLEXECUTEINFO ) );
    ei.cbSize = sizeof( SHELLEXECUTEINFO );
    ei.fMask |= SEE_MASK_NOCLOSEPROCESS;
    ei.lpFile = ( LPCTSTR )filename.c_str( );
    ei.nShow |= SW_SHOWDEFAULT;
 
    typedef process_await_thread <TForm1> pat_for_form1;
    if ( ShellExecuteEx( &ei ) ) {
        pat_for_form1 *thr = new pat_for_form1( true );
        thr->FreeOnTerminate = true;
        thr->process = ei.hProcess;
        thr->a_class = this;
        thr->action_proc = &TForm1::my_method;
        thr->Resume( );
    }
Синтаксис работы с указателями на функции-члены класса весьма кривой, но, увы, деваться от этого пока что некуда... разве что использовать какие-то простые вспомогательные функции в качестве интерфейса к методам класса, что тоже весьма коряво.
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
16.12.2012, 21:16  [ТС]     Узнать о закрытии внешней программы   #16
Спасибо большое, попробую.
Оффтопом:
Правильно ли я понимаю, что для работы
Код C++
1
2
 template <какой-то тип данных>
//здесь описание функции или класаа
нужно подключать не h-файл, а cpp-файл?
Я использую часто template, но подключать приходиться cpp-файлы, иначе жалуется линкер.

Например в h-файле UnitFunctions.h:
Код C++
1
2
template <class T>
void EnterRNumber(wchar_t &Key,T Obj); 
В cpp-файле UnitFunctions.cpp реализация:
Код C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template <class T>
void EnterRNumber(char &Key,T Obj)
{
    if ((Key >= '0') && (Key <= '9')) {}  // цифры
    else if (Key == 8) {}  // <-
    else if ((Key == '.') || (Key == ',')) // запятая
    {
        if (Obj->Text.Pos(DecimalSeparator)!=0) // если запятая уже есть
                Key = 0;
        else // если ещё нет
                Key = DecimalSeparator;
    }
    else if (Key == '-') // минус
    {
        int l =  Obj->Text.Length();
        if ((Obj->Text.Pos('-')==1  || l>0 )) // минус уже есть и он на первом месте
                Key = 0;
        else // если ещё нет
                Key = '-';
    }
    else Key = 0; // не цифра
}
Где-то в другом файле MainForm.cpp:
Код C++
1
2
3
4
5
6
7
//#include "UnitFunctions.h"      // так не работает
#include "UnitFunctions.cpp"     // а так работает 
 
void __fastcall TFormMain::Edit1KeyPress(TObject *Sender, wchar_t &Key)
{
    EnterRNumber(Key, (TEdit*)Sender);
}
Я что-то делаю не так, или так и должно быть?
BRcr
Модератор
3064 / 1667 / 107
Регистрация: 03.02.2011
Сообщений: 4,174
Записей в блоге: 6
16.12.2012, 21:21     Узнать о закрытии внешней программы   #17
В данном случае содержимое файла UnitFunctions.h просто не принимает участия в твоем проекте.

Объявление и определение шаблонной функции или шаблонного метода должны быть в одном файле, такое вот ограничение. А уж .cpp это будет или .h - без разницы.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.12.2012, 21:22     Узнать о закрытии внешней программы
Еще ссылки по теме:

C++ Builder Ошибка при закрытии программы в компиляторе, из-за TMediaPlayer
C++ Builder Доступ к компонентам внешней программы
C++ Builder Сохранить значения переменных при закрытии программы
znseday
Форумчанин
14 / 14 / 1
Регистрация: 20.03.2012
Сообщений: 304
16.12.2012, 21:22  [ТС]     Узнать о закрытии внешней программы   #18
Ну т.е. в cpp тоже
Код C++
1
void EnterRNumber(wchar_t &Key,T Obj)
(не то скопировал просто)
Yandex
Объявления
16.12.2012, 21:22     Узнать о закрытии внешней программы
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Опции темы

Текущее время: 13:09. Часовой пояс GMT +4.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.7 PL3
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Яндекс.Метрика