"Klaus Petersen" <ng@spectual.ra.bnaa.dk> wrote in message
news:4198f4e8$0$33740$14726298@news.sunsite.dk...
>> Der findes en mere avancerede måde, hvor call-thunken bliver lave
>> dynamisk
>> på runtime - men det kan typisk ikke svare sig.
>
> Kender du metoden?
Ja.
Den er dog mere relevant i forbindelse på steder hvor der ikke kan føre en
void pointer med, og hvor man ofte skal lave en mapning fra en funktion til
et objekt.
Det er f.eks. anvendt i flere biblioteker hvor man har lavet en
objekt-orienteret indpakning af vinduer til MS-Windows (bl.a. Borland OWL og
Microsoft WTL).
Her vil man sende en Window message til et objekt - gerne i konstant, kort
tid.
> Den kunne jeg godt tænke mig at høre mere om.
Man allokerer et stykke hukommelse, som man fylder med passende op-koder
(assembler instruktioner) og gemmer passende ekstra information sammen med
koden.
Den funktion (f.eks. CreateThread) som kræver adressen på en call-back
metode får så bare en adresse til det netop allokerede og initialiserede
hukommelse.
Altså man laver simpelt hen en funktion pr. objekt på runtime
Nedenstående er noget kode jeg har skrevet for en del år siden, der kunne
mappe fra WNDPROC til et "Window" objekt.
Det er ikke let læseligt - men effektivt
// This structure _must_ be packed
#if defined(__BORLANDC__) && (0x0564 == __BORLANDC__)
// Borland C++Builder V6.0
#pragma option push -a1
#elif defined(__INTEL_COMPILER) && (500 == __INTEL_COMPILER || 600 ==
__INTEL_COMPILER || 700 == __INTEL_COMPILER) && defined(_WIN32)
// Intel C++ for Windows V5.0, V6.0 or V7.x
#pragma pack(push, 1)
#elif defined(_MSC_VER)
// Microsoft Visual C++V7.1 (.NET 2003)
#pragma pack(push, 1)
#endif
class InstanceThunk
{
public:
InstanceThunk(Window* wnd, WNDPROC wndproc)
{
call = 0xE8u; // CALL rel32
#if defined(__BORLANDC__) && (0x0564 == __BORLANDC__)
// Borland C++Builder V6.0
offset = offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
proc);
#elif (defined(__INTEL_COMPILER) && (500 == __INTEL_COMPILER || 600 ==
__INTEL_COMPILER || 600 == __INTEL_COMPILER) && defined(_WIN32)) ||
defined(__COMO__)
// Intel C++ for Windows V5.0, V6.0 or V7.1
// Comeau C++ for Windows
// offsetof is not supported by Intel C++
offset = 8; //offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
proc);
#elif (defined(_MSC_VER))
// Microsoft Visual C++ 7.1 (.NET 2003)
offset = 8; //offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
proc);
#endif
proc = wndproc;
window = wnd;
// POP ECX
//
// Pop return address of call into ecx (address of member "proc")
//
code[0] = 0x59u;
// MOV EDX, [ECX+4]
//
// load "window" into edx
//
code[1] = 0x8B;
code[2] = 0x51u;
code[3] = 0x04u;
// JMP [ECX]
//
// jump to window function provided
code[4] = 0xFFu;
code[5] = 0x21u;
}
WNDPROC WndProc()
{
return reinterpret_cast<WNDPROC>(this);
}
private:
unsigned char call;
int offset;
WNDPROC proc;
Window* window;
unsigned char code[6];
private:
InstanceThunk(const InstanceThunk&);
InstanceThunk& operator=(const InstanceThunk&);
};
#if defined(__BORLANDC__) && (0x0564 == __BORLANDC__)
// Borland C++Builder V6.0
#pragma option pop
#elif defined(__INTEL_COMPILER) && (500 == __INTEL_COMPILER || 600 ==
__INTEL_COMPILER || 700 == __INTEL_COMPILER) && defined(_WIN32)
// Intel C++ for Windows V5.0, V6.0 og V7.x
#pragma pack(pop)
#elif defined(_MSC_VER)
// Microsoft Visual C++V7.1 (.NET 2003)
#pragma pack(pop)
#endif
Venlig hilsen
Mogens Hansen