How to use a VCL class member-function as a Win32 callback.

By: mykle hoban

Abstract: This article describes how to substitue a global or static-member function for an actual member-function when using Win32 callbacks.

Question

How do make one of my VCL class member-functions act as a Win32 callback function?

Answer

This problem is a lot easier to solve than most people think. Most of the time, you will see callbacks implemented either as static members or global functions with the class instance pointer set as extra data (to the window or lParam or whatever). The VCL provides two undocumented functions that are designed to do exactly what we want: use member-functions as callbacks. Those functions are MakeObjectInstance and FreeObjectInstance.

Example:


//---------Function Protypes from Forms.hpp----------------
//extern PACKAGE void * __fastcall MakeObjectInstance(Controls::TWndMethod Method);
//extern PACKAGE void __fastcall FreeObjectInstance(void * ObjectInstance);
//---------------------------------------------------------

//------------------------------Unit1.h--------------------------------------
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
  void __fastcall FormClick(TObject *Sender);
private:	// User declarations
  void *oldproc;
  void *newproc;
  void __fastcall myproc(TMessage &msg);
public:		// User declarations
  __fastcall TForm1(TComponent* Owner);
  __fastcall ~TForm1();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
//-----------------------End Unit1.h-----------------------------------------

//-----------------------Unit1.cpp-------------------------------------------
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  newproc = MakeObjectInstance(myproc);
  oldproc = (void *)SetWindowLong(Handle,GWL_WNDPROC,(LONG)newproc);
}
//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
  SetWindowLong(Handle,GWL_WNDPROC,(LONG)oldproc);
  FreeObjectInstance(newproc);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::myproc(TMessage &msg)
{
  if (msg.Msg == WM_LBUTTONUP)
    ShowMessage("click");
  msg.Result = CallWindowProc((FARPROC)oldproc,Handle,msg.Msg,msg.WParam,msg.LParam);
}
void __fastcall TForm1::FormClick(TObject *Sender)
{
  ShowMessage("click_event");
}
//---------------------------------------------------------------------------
//-----------------------End Unit1.cpp---------------------------------------

Server Response from: ETNASC03