Hej Hajer
Lige et lille spørgsmål fra en C/C++ novice. Jeg tror der er et eller andet
jeg ikke er med på men her følger et forsøg på at forklare.
Så vidt jeg har forstået af glut-eksemplerne så sendes en funktionpointer
med til glutDisplayFunc. Det sker ved at der i ens c-fil er defineret en
metode, lad os kalde den foo, og i eksemplerne
siger man så glutDisplayFunc(foo) eller noget i den stil. Hvorfor kan man
ikke i dette tilfælde bruge C++'s syntaks til at oprette funktionspointere
og så sende sådan en med. Altså noget med
void (FooClass::*pointer2foo)(void);
pt2Foo = FooClass::foo;
....hvor man så sendte pt2Foo med?
Mvh Jesper
"Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
news:blhjhe$9ov$1@news.cybercity.dk...
>
> "Jonas Meyer" <someone@microsoft.com> wrote in message
> news:blhhhi$ee2$1@munin.diku.dk...
> > "Mogens Hansen" <mogens_h@dk-online.dk> wrote in message
> > news:blhfje$43q$1@news.cybercity.dk...
> > > Udgangspunktet for den løsning er at opgaven _ikke_ ligeså let kan
> klares
> > > med en simpel c-funktion.
> >
> > Jeg forstår det ikke så.
>
> Ok.
>
> >
> > Hvad er det for et problem vi prøver at løse? Mit gæt er at vi vil have
en
> > funktion kaldt på et objekt, istedet for en c funktion - Men den hersens
> > thunk hvad er det?
>
> Et eksempel fra den virkelige verden:
>
> Når man laver en C++ objekt-orienteret wrapper af det C baserede Win32
API,
> vil man typisk have en klasse Button (som arver fra Window), som man kan
> lave mange objekter af.
> Når der bliver klikket på et Button _objekt_ skal der kaldes en
> _member_-funktion, således at man nemt kan skelne mellem om det er "Ok"
> eller "Cancel", der er trykket på.
> Win32 API'et kender ikke noget til Button klassen og de forskellige Button
> objekter, og kan derfor ikke kalde nogen member-funktion direkte.
> Win32 API'et kan kun kalde en C-funktion (WinProc) med information om
> hvilket vindue (HWND) der er trykket på. Et eller andet sked i C++ wrapper
> biblioteket skal der ske en konvertering fra HWND til Button objekt.
> Dette kan naturligvis gøres med en tabel (std::map<HWND, Button*>), men
det
> kan gøres hurtigere (konstant, kort tid) med en call-thunk.
> Hvis C-callback funktionen ikke på en eller anden måde havde information
med
> til at skelne mellem objekterne (som man reelt kan med HWND i Win32
API'et)
> var der få andre muligheder end at bruge en call-thunk.
>
> Dette kan findes i biblioteker som Borland OWL og Microsoft ATL.
>
> > Blot en peger til det objekt?
>
> Og en lille stump assembler kode.
>
> > hvornår bliver den lavet og allokeret? og
> > hvorhenne?
>
> Koden er et datamedlem i Window klassen - helt seriøst
> Der ligger f.eks. et char-array, hvor man skriver pointeren til objektet
og
> nogle fornuftige op-coder (oversat assembler).
> Der bliver altså lavet en ny funktion for hvert objekt !
>
> <C++ kode fra et af mine egne biblioteker>
> class InstanceThunk
> {
> public:
> InstanceThunk(Window* wnd, WNDPROC wndproc)
> {
> call = 0xE8u; // CALL rel32
> #if defined(__BORLANDC__) && (0x0550 == __BORLANDC__ || 0x0551 ==
> __BORLANDC__)
> // Borland C++Builder V5.0
> offset = offsetof(InstanceThunk, code) - offsetof(InstanceThunk,
> proc);
> #elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 500) &&
> defined(_WIN32)) || defined(__COMO__)
> // Intel C++ for Windows V5.0
> // Comeau C++ for Windows
> // offsetof is not supported by Intel C++
> 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(void)
> {
> 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&);
> };
>
> template <class WND_T>
> class CustomWindow : public Window
> {
> public:
> CustomWindow(LPCTSTR lpWindowName, DWORD dwStyle,
> int x, int y, int nWidth, int nHeight,
> HWND hWndParent, HMENU hMenu, LPVOID lpParam);
> ~CustomWindow();
>
> // ...
> static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
> LPARAM lParam);
>
> // ...
>
> private:
> InstanceThunk instanceThunk;
>
> private:
> CustomWindow(const CustomWindow&);
> const CustomWindow& operator=(const CustomWindow&);
> };
>
>
> template <class WND_T>
> inline CustomWindow<WND_T>::CustomWindow(LPCTSTR lpWindowName, DWORD
> dwStyle,
> int x, int y, int nWidth, int nHeight,
> HWND hWndParent, HMENU hMenu, LPVOID lpParam) :
> Window(WND_T::CreateWindow_(lpWindowName, dwStyle, x, y, nWidth,
nHeight,
> hWndParent, hMenu, lpParam)),
> instanceThunk(this, reinterpret_cast<WNDPROC>(WndProc))
> {
> ::SetWindowLong(*this, GWL_WNDPROC,
> reinterpret_cast<DWORD>(instanceThunk.WndProc()));
> }
>
>
>
>
> <C++ kode fra et af mine egne biblioteker>
>
> Venlig hilsen
>
> Mogens Hansen
>
>