Материал из Википедии — свободной энциклопедии:
Сабклассинг — процесс переопределения оконной процедуры, которую Windows назначает по умолчанию.
Назначение технологии
Данная технология применяется в том случае, если требуется наделить окно какой-либо специфической реакцией на сообщение Windows. При помощи сабклассинга можно организовывать контроль ввода, блокировку закрытия окна. В целом самым важным здесь является то, что при необходимости программист получает полный контроль над поведением окна.
Преимущества сабклассинга
В Windows есть довольно богатый выбор элементов управления, однако вы можете столкнутся c ситуацией, когда нужно дополнить поведение элемента управления. И здесь есть затруднение: процедуру, которую Windows назначает элементу управления изменить саму по себе невозможно. Есть два пути:
Написать элемент управления заново
Воспользоваться возможностью переопределения оконной процедуры у данного элемента управления, что и является сабклассингом.
Недостатки первого подхода в том, что фактически программист вынужден заново «изобретать велосипед». Преимущество же сабклассинга в том, что он позволяет программисту сосредоточится только на действительно нужных ему Windows сообщениях, а остальные передать стандартной оконной процедуре.
Вот примерчик (из кода MiracleV8.dll ):
var Old1CWindowProc: Pointer;
function New1CWindowProc(WindowHandle: hWnd;
TheMessage: WParam;
ParamW: WParam;
ParamL: LParam): LongInt
{$IFDEF WIN32} stdcall;
{$ELSE}; export;
{$ENDIF}
var b: array[0..255] of AnsiChar;
begin
// анализируем сообщения
// тут, к примеру, реакция на нажатие пункта меню
if TheMessage = WM_COMMAND then begin
// в ParamW - идентификатор пункта, в переменную b помещаем строковое значение пункта
GetMenuString(GetMenu(WindowHandle), ParamW, @b, 256, MF_BYCOMMAND);
// генерим внешнее событие для 1С
pEvent._AddRef;
pEvent.ExternalEvent('MiracleV8_1C', 'MENUSELECT', IntToStr(ParamW) + ',' + StrPas(b));
end;
if TheMessage = WM_WINDOWPOSCHANGING then begin
// тут отслеживаем (если надо) перестройку меню, в 7.7 оно постоянно меняется
pEvent._AddRef;
pEvent.ExternalEvent('MiracleV8_1C', 'MENURECREATE', IntToStr(ParamW));
end;
// в общем, что хотим - то и творим ;)
// передаем управление родной оконной процедуре
New1CWindowProc := CallWindowProc(Old1CWindowProc, WindowHandle, TheMessage,
ParamW, ParamL);
end;
procedure TMiracleClass.SetNew1CWindowProc;
begin
// запоминаем указатель на родную оконную процедуру и переопределям на новую
Old1CWindowProc := Pointer(SetWindowLong(h1C, GWL_WNDPROC, LongInt(@New1CWindowProc)));
end;
Примечания:
h1C - хэндл главного окна 1С, полученный любым образом, например, через
интерфейс IExtWndsSupport.
pEvent - интерфейс IAsyncEvent
(оба описаны в ТСВК)