Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Обработка сообщений Windows


Автор: BreakPointMAN 10.3.2006, 22:59
Всем доброго здравия желаю! smile

Кто-нибудь может четко, простым русским языком, объяснить, что есть "Application->Handle", и что есть, скажем, "Form1->Handle"? В каких случаях следует создавать карту сообщений (макросами BEGIN_MESSAGE_MAP, MESSAGE_HANDLER, END_MESSAGE_MAP), написав соответствующие обработчики, а в каких - воспользоваться событием TApplicationEvents::OnMessage? Какие, вообше говоря, сообщения могут отлавливаться последним? Часто использую и то, и другое, но глубокого понимания сего, к сожалению, нет. smile Хелп читал. Все равно остается много вопросов...

Автор: Partizan 11.3.2006, 01:27
тов. Архангельский А.Я. по этому поводу ничего не пишет?....

я лично представляю себе, что Form->Handle есть дескриптор одного из окон приложения....
Application->Handle - дескриптор потока,связанного с приложением...

Автор: BreakPointMAN 11.3.2006, 02:33
Цитата(Partizan @ 11.3.2006, 01:27 Найти цитируемый пост)
тов. Архангельский А.Я. по этому поводу ничего не пишет?....

Боюсь, что у тов. Архангельского А.Я. не очень хорошее представление об обработке сообщений Windows... Не далее, как пару дней назад, в книге "Приемы программирования в C++ Builder. Механизмы Windows, сети" © А.Я. Архангельский, М.А. Тагин обнаружил ряд грубых ошибок. Кстати, эти же ошибки замечены в "Русских справках по C++ Builder" тех же авторов. Даже не хочется думать, насколько будет корректной работа программы (и самой ОС в целом), если пишущий ее программист последует рекомендациям в книге.

К примеру, в книге (см. 3.11) рассматривается работа с буфером обмена, а точнее, перехват событий буфера обмена Windows.

Фрагмент заголовочного файла:
Код

class TForm1 : public TForm
{
...
private:
  void __fastcall OnDRAWCLIPBOARD(TWMNoParams& Message);
  void __fastcall OnCHANGECBCHAIN(TWMNoParams& Message);
public:
  __fastcall TForm1(TComponent* Owner);
  BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_DRAWCLIPBOARD, TWMNoParams,
                    OnDRAWCLIPBOARD)
    MESSAGE_HANDLER(WM_CHANGECBCHAIN, TWMNoParams,
                    OnCHANGECBCHAIN)
  END_MESSAGE_MAP(TComponent)
};


Файл реализации:
Код

#include <vcl\Clipbrd.hpp>

HWND Hclb;

void __fastcall TForm1::FormCreate(TObject *Sender)
{
 Hclb = SetClipboardViewer(Handle);
}
//---------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
 ChangeClipboardChain(Handle, Hclb);
}
//---------------------------------------------------------
void __fastcall TForm1::OnDRAWCLIPBOARD(TWMNoParams& a)
{
 RichEdit1->Visible = false;
 Image1->Visible = false;

 try
 {
  if (Clipboard()->HasFormat(CF_BITMAP))
  {
   Image1->Picture->LoadFromClipboardFormat(CF_BITMAP,
                   Clipboard()->GetAsHandle(CF_BITMAP), 0);
   Image1->Visible = true;
  }
  else
   if (Clipboard()->HasFormat(CF_TEXT))
   {
    RichEdit1->Text = Clipboard()->AsText;
    RichEdit1->Visible = true;
   }
 }
 catch (...)
 {
  SendMessage(Hclb, WM_DRAWCLIPBOARD, 0, 0);
 }
}
//---------------------------------------------------------

void __fastcall TForm1::OnCHANGECBCHAIN(TWMNoParams& a)
{
 SendMessage(Hclb, WM_CHANGECBCHAIN, 0, 0);
}


Уже на стадии описания карты сообщений тов. Архангельский сделал непростительную ошибку - в качестве второго параметра макроса MESSAGE_HANDLER для сообщения Windows WM_CHANGECBCHAIN использовал тип структуры TWMNoParams, ну и, естественно, тот же тип был использован в качестве типа параметра обработчика OnCHANGECBCHAIN. Как известно, TWMNoParams - тип сообщений Windows без параметров, т.е. тов. Архангельский попросту проигнорировал ту информацию, которая передается вместе с сообщением. А вместе с этим сообщением передается дескриптор закрываемого окна (в wParam) и дескриптор окна, следующего за закрываемым (в lParam). Эти данные нужны программе для того, чтобы корректно отреагировать на изменения в цепочке окон просмотра буфера обмена и скорректировать в случае необходимости указатель на следующее окно цепочки (Hclb в примере), если будет удалено окно, непосредственно следующее за данным. Что, конечно, совершенно не делается в данном обработчике и, мало того, нужная информация не передается по цепочке дальше. Вместо этого тов. Архангельский напихал везде нули:

Код

SendMessage(Hclb, WM_CHANGECBCHAIN, 0, 0);

Надо сказать, что подобных ляпов в книге (и в справках) много.

Автор: Ctrl_Alt_Del 12.3.2006, 16:13
Цитата(BreakPointMAN @ 10.3.2006, 22:59)
Всем доброго здравия желаю!  smile

Кто-нибудь может четко, простым русским языком, объяснить, что есть "Application->Handle", и что есть, скажем, "Form1->Handle"? В каких случаях следует создавать карту сообщений (макросами BEGIN_MESSAGE_MAP, MESSAGE_HANDLER, END_MESSAGE_MAP), написав соответствующие обработчики, а в каких - воспользоваться событием TApplicationEvents::OnMessage? Какие, вообше говоря, сообщения могут отлавливаться последним? Часто использую и то, и другое, но глубокого понимания сего, к сожалению, нет.  smile  Хелп читал. Все равно остается много вопросов...

Application->Handle - дескриптор процесса.
Form1->Handle - дескриптор окна.
Чаще сообщения отправляются все же окну. ИМХО удобнее юзать карту сообщений.

P.S. Архангельский тоже человек и ему свойственно ошибаться.

Автор: BreakPointMAN 17.3.2006, 04:20
Цитата(Defucker @ 12.3.2006, 16:13 Найти цитируемый пост)
Application->Handle - дескриптор процесса.

Думаю, что нет... В таком случае меня смущают несколько вещей:

1) есть WinAPI-функция GetWindow. Если первым её параметром указать дескриптор окна, а вторым - GW_OWNER, то функция вернет дескриптор окна-владельца либо NULL, если такого не существует. Так вот, если передать в эту функцию дескриптор любой формы (например, Form1->Handle) и указать в качестве второго параметра GW_OWNER, то функция вернет значение, равное Application->Handle;

2) есть WinAPI-функция SetWindowPos, которая изменяет размеры, позицию, положения окна в Z-последовательности и т.д., если ей передать дескриптор соответствующего окна. Если Application->Handle - не дескриптор окна, а дескриптор процесса, то почему при вызове:

Код

SetWindowPos((HWND)Application->Handle,(HWND)NULL,0,0,100,100,(UINT)HWND_TOP);


в левом верхнем углу экрана появляется окошко размером 100x100? Процесс ведь не должен вести себя как окно?

Автор: Ctrl_Alt_Del 17.3.2006, 15:14
BreakPointMAN, sorry.
Все как всегда, надо было просто в хелп заглянуть.

TApplication::Handle
Цитата

Provides access to the window handle of the main form (window) of the application.


Дескриптор главного окна приложения.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)