понедельник, 28 декабря 2009 г.

Wrappers...

Враппер в WinAPI - довольно таки нужная и интересная штука. Америку, конечно, не открою, но пару слов о том, что это такое, сказать все же надо. По-моему, некоторые уже начинают забывать основной смысл этого слова.

Во первых, враппер - это только обертка объекта, поэтому влезать в этот объект с целью понавешать на него максимально много функций и свойств, предполагающих буквально автономную его работу во всех возможных ситуациях не надо, пусть этим занимается кто-то еще, кому интересен сам процесс, а не результат.
class CWindowWrapper{
protected:
HWND hwnd;
public:
operator HWND( void )const{ return hwnd; }
CWindowWrapper( HWND hwnd = HWND_DESKTOP ):
hwnd( hwnd ){
}
LRESULT SendMessage( UINT uMsg, WPARAM wParam, LPARAM lParam )const{
return ::SendMessage( hwnd, uMsg, wParam, lParam );
}
};
Пара строк - и враппер готов.
Теперь им можно свободно пользоваться в любой ситуации, когда требуется HWND, причем без особых затрат на внедрение:
...
LRESULT OnCommand( WORD ID, WORD Notify, const CWindowWrapper& Ctrl ){
 switch( Notify ){
  case EN_CHANGE:
   Ctrl.SendMessage( ... )
   break;
 }
}
...

switch( uMsg ){
 ...
 case WM_COMMAND:
  return OnCommand( LOWORD( wParam ), HIWORD( wParam ), (HWND)lParam ); 
 ...
}
return ::DefWindowProc( hwnd, uMsg, wParam, lParam );

Конечно, пока этот объект только копирует функционал своего подопытного, пользы от него мало. Вот здесь-то и выплывает второе свойство врапперов - адаптация к среде разработки, т.е. враппер - это такой объект, который позволяет избавиться от рутинных дел, а не просто перевести API через ООП.
class CWindowWrapper{
 ...
 INT GetWindowTextLength( void )const{
  return ::GetWindowTextLength( hwnd );
 }
 INT GetWindowText( LPTSTR lpString, INT nMaxCount )const{
  return ::GetWindowText( hwnd, lpString, nMaxCount );
 }
 std::W( string ) GetWindowText( void )const{
  std::W( string )Buffer;
  INT Length;
  //
  if( Length = GetWindowTextLength() ){
   Buffer.resize( Length );
   GetWindowText( &*Buffer.begin() , Length );
  }
  return Buffer;
 }
 ...
};
GetWindowText с использованием STL-контейнера - полезный метод? Несомненно.

Последнее свойство - враппер не должен быть один. То есть, конечно, он может быть и один, но он не должен один решать слишком много задач, иначе враппер из маленькой шестеренки большого механизма превратится в неповоротливый коленвал, которому возможно и достанется в нем своя роль, но только один раз, и только до первой же поломки, после которой, взвесив затраты на переборку, умные авторы все же предпочтут от него просто отказаться.
class CEditWrapper : public CWindowWrapper{
public:
 CEditWrapper( HWND hwnd = HWND_DESKTOP ):
  CWindowWrapper( hwnd ){
  }
 ...
 BOOL CanUndo( void )const{
  return SendMessage( EM_CANUNDO, 0, 0 ) ? TRUE : FALSE;
 }
 ...
};
Удобно, не правда ли? Когда потребуется к примеру RichEdit, наследовать его от Edit уже не составит труда.

А если понадобится совершить какое-то специфическое действие, например: добавить в список Combo значение из поля ввода Combo?
Да просто создаем враппер под эту задачу:
class CMyComboWrapper : public CComboBoxWrapper{
public:
 CMyComboWrapper( HWND hwnd = HWND_DESKTOP ):
  CComboBoxWrapper( hwnd ){
  }
 ...
 CEditWrapper MyComboEdit( void )const{
  COMBOBOXINFO ComboBoxInfo;
  //
  ComboBoxInfo.cbSize = sizeof( ComboBoxInfo );
  GetComboBoxInfo( &ComboBoxInfo );
  return ComboBoxInfo.hwndItem;
 }
 LRESULT MyAdd( void )const{
  return AddString( MyComboEdit().GetWindowText().c_str() );
 }
 ...
};
Несложные манипуляции и предельно прозрачный код: не задача нас решает, а мы её :)

Вобщем, не забываем что на самом деле должны уметь делать эти маленькие помошники, как с их помощью решаются задачи и сколько реально должно стоить их внедрение.

Удачи!

Комментариев нет:

Отправить комментарий