Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1709 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  [C++ pour les hommes, les vrais] : les Delegates

 


 Mot :   Pseudo :  
 
 Page :   1  2  3
Page Précédente
Auteur Sujet :

[C++ pour les hommes, les vrais] : les Delegates

n°899898
chrisbk
-
Posté le 16-11-2004 à 16:04:22  profilanswer
 

(y zy connaissent rien sur blabla, alors je m'adresse directement a l'elite)
 
Messieurs dames, bonjour, le cours du jour sera : comment faire des delegates en C++.
 
Le probleme que nous avons tous rencontré un jour, c'est une fonction demandant une Callback en entrée dans la main gauche, et une fonction membre qui serait parfaite pour ce role dans l'autre.
Drame : ca ne marche pas, car une fonction membre C++ demande en plus le 'this' de l'objet.
 
Que faire ? L'idéal serait un truc a la c#, un pointeur de fonction comprenant aussi le this, mais le tout sous forme d'unique pointeur de fonction. La technique decrite ici, que j'appelerais technique Colgate car j'ai eu l'idée en me brossant les dents, repond a ses attentes grace au "dynamic code generation" que j'ecris en anglais car l'anglais, ca pootre plus.
 
l'idée est d'intercaler entre un pointeur de fonction et la cible un code intermediaire servant a rebondir vers la cible. Ledit code intermediaire comprends simplement deux instructions asm fort banales : mov et jmp.
 

Code :
  1. 0xaddr   mov ecx, thisDeL'objet
  2. 0xaddr2  jmp (addresseFonctionMembre - addr2)


 
C'est tout.
 
Par convention le this est generalement foutu dans ecx, donc on le fait, et on fait un jmp a la place d'un call pour pas changer la pile. le jmp prends une valeur relative donc on la recalcule en live.
 
Le plus rigolo, c'est que, vive le C++, on peut tout balancer ca dans une...structure, sans toucher du tout a l'asm, ou peu.
 

Code :
  1. #pragma pack(1) //Important de faire sauter l'alignement, sinon le code de la structure va etre pourri
  2. struct Delegate
  3. {
  4. public:
  5.   Delegate(void *tThis, void *addrFonction)
  6.   {
  7.      movOpcode1 = ...; //remplacer ici par les bons opcodes, je les ai pas sous la main
  8.      movOpcode2 = ...;
  9.      thisPtr    = tThis;
  10.      jmpopcode  = ...;
  11.      disp = (unsigned int)addrFonction - (unsigned int)(&jmpOpcode);
  12.   }
  13. private:
  14.   unsigned char movOpcode1;
  15.   unsigned char movOpcode2;
  16.   unsigned int  thisPtr;
  17.   unsigned char jmpopcode;
  18.   unsigned int disp;
  19. }
  20. #pragma pack()


 
et voila le travail.
le probleme est de retrouver l'adresse de la fonction membre sous forme de void *, taz avait refilé une interessante solution a coup d'union. On peut meme rajouter une couche de template par dessus, et la, vla le bonheur :

Code :
  1. #pragma pack(1)
  2. template<typename T>
  3. struct Delegate
  4. {
  5. public:
  6.   Delegate(void *tThis, T fonction)
  7.   {
  8.      union truc
  9.      {
  10.         T fonction2;
  11.         unsigned int addr;
  12.      }
  13.      truc machin;
  14.      machin.fonction = fonction;
  15.      movOpcode1 = ...;
  16.      movOpcode2 = ...;
  17.      thisPtr    = tThis;
  18.      jmpopcode  = ...;
  19.      disp = truc.addr - (unsigned int)(&jmpOpcode);
  20.   }
  21. private:
  22.   unsigned char movOpcode1;
  23.   unsigned char movOpcode2;
  24.   unsigned int  thisPtr;
  25.   unsigned char jmpopcode;
  26.   unsigned int disp;
  27. }
  28. #pragma pack()
  29. ...
  30. class A
  31. {
  32. public:
  33.   void prout() {std::cout<<"maman, caca "<<toto;}
  34.   int toto;
  35. };
  36. typedef __stdcall void (*truc) MaFonction;
  37. A *bidule = new A;
  38. Delegate del = new Delegate(bidule, A::prout);
  39. MaFonction chose = (MaFonction) &del;
  40. chose();


 
 
Pour ensuite utiliser ca comme callback, il suffit de caster l'adresse de cette structure en pointeur de fonction (si, si) et vala.
 
enfin j'ai pas encore essayé mais ca devrait marcher au poil.
 
Notez le stdcall. De nombreuses api sont en cdcel, et pas en stdcall, ce qui necessitera un peu de réecriture au niveau du code (passage du mov en autre chose). Je laisse ca en exerice pour le lecteur [:icon7]
 
merci de votre attention


---------------
NP: HTTP Error 764 Stupid coder found
mood
Publicité
Posté le 16-11-2004 à 16:04:22  profilanswer
 

n°899900
skeye
Posté le 16-11-2004 à 16:06:07  profilanswer
 

J'ai rien compris...[:chacal_one333]


---------------
Can't buy what I want because it's free -
n°899902
Joel F
Real men use unique_ptr
Posté le 16-11-2004 à 16:22:13  profilanswer
 

euh .... y a des trucs templates qui font ca proprement tu sais :o
 
EDIT : COPITEUR :kaola:
 
http://www.codeproject.com/cpp/SoloGenericCallBack.asp


Message édité par Joel F le 16-11-2004 à 16:27:33
n°899909
chrisbk
-
Posté le 16-11-2004 à 16:29:16  profilanswer
 

copiteur ? mon cul, c'est du 100% trouvé par moi, maintenant la technique dite du "thunkt est pas neuve en elle meme[:itm]


---------------
NP: HTTP Error 764 Stupid coder found
n°899926
HelloWorld
Salut tout le monde!
Posté le 16-11-2004 à 16:38:33  profilanswer
 

Cette technique s'appelle le thunking et est à la base de l'encapsulation Win32 dans des libs comme OWL ou ATL. Elle ne fonctionne pas sur certains processeurs récents (flag NX) & certains noyaux Linux / XP SP2 car la mémoire allouée n'a pas le droit en exécution...


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
n°899936
Lam's
Profil: bas.
Posté le 16-11-2004 à 16:48:49  profilanswer
 

HelloWorld a écrit :

Elle ne fonctionne pas sur certains processeurs récents (flag NX) & certains noyaux Linux / XP SP2 car la mémoire allouée n'a pas le droit en exécution...


Je lui ai déjà dit, mais il m'a dit qu'il s'en foutait et que depuis qu'il faisait des Delegates Colgate, son sexe avait triplé de volume.
 
Bref, je crois qu'il serait mieux à faire du Java et du SQL, et laisser la vraie programmation aux spécialistes. :o  
 

n°899944
chrisbk
-
Posté le 16-11-2004 à 17:02:23  profilanswer
 

Lam's a écrit :

Je lui ai déjà dit, mais il m'a dit qu'il s'en foutait et que depuis qu'il faisait des Delegates Colgate, son sexe avait triplé de volume.


 
j't'ai repondu :o


---------------
NP: HTTP Error 764 Stupid coder found
n°899946
HelloWorld
Salut tout le monde!
Posté le 16-11-2004 à 17:04:38  profilanswer
 

Y'a pas de solution portable, déjà à cause de l'asm. Mais en spécifique c'est faisable, à condition d'allouer de la mémoire exécutable avec VirtualAlloc + VirtualProtectEx( PAGE_EXECUTE ).


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
n°899950
Taz
bisounours-codeur
Posté le 16-11-2004 à 17:10:54  profilanswer
 

heink ? boost::function et boost::bind c'est bien plus souple

n°899993
HelloWorld
Salut tout le monde!
Posté le 16-11-2004 à 17:45:17  profilanswer
 

Tu peux filer une boost::function comme callback à une fonction C ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
mood
Publicité
Posté le 16-11-2004 à 17:45:17  profilanswer
 

n°900003
chrisbk
-
Posté le 16-11-2004 à 18:01:21  profilanswer
 

HelloWorld a écrit :

Y'a pas de solution portable, déjà à cause de l'asm.


 
chui pas trop un mec qui se soucie de la portabilité [:joce]
et ici y'a pu d'asm mais que des opcodes, donc c portable sur tout compatibl eintel x86 :o
 
 

HelloWorld a écrit :


 Mais en spécifique c'est faisable, à condition d'allouer de la mémoire exécutable avec VirtualAlloc + VirtualProtectEx( PAGE_EXECUTE ).


 
bin oui [:spamafote]


Message édité par chrisbk le 16-11-2004 à 18:02:46

---------------
NP: HTTP Error 764 Stupid coder found
n°900011
HelloWorld
Salut tout le monde!
Posté le 16-11-2004 à 18:09:09  profilanswer
 

Et les conventions d'appel ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
n°900012
chrisbk
-
Posté le 16-11-2004 à 18:13:33  profilanswer
 

HelloWorld a écrit :

Et les conventions d'appel ?


 
comme dit dans le texte, __stdcall  
pour __cdecl va falloir gruger un brin


---------------
NP: HTTP Error 764 Stupid coder found
n°900013
Taz
bisounours-codeur
Posté le 16-11-2004 à 18:16:14  profilanswer
 

tu ferais quand même mieux de typer plus fortement
 
Delegate(void *tThis, T fonction)
 
->
 
void Delegate(T * const that, void (T::*function)()

n°900015
chrisbk
-
Posté le 16-11-2004 à 18:17:37  profilanswer
 

Taz a écrit :

tu ferais quand même mieux de typer plus fortement
 
Delegate(void *tThis, T fonction)
 
->
 
void Delegate(T * const that, void (T::*function)()


 
c'etait un exemple vite torché, par contre je conteste le void de retour et mon template avait pas pour but de substituer au type de "this" mais a celui du ptr de fonction


---------------
NP: HTTP Error 764 Stupid coder found
n°900024
Joel F
Real men use unique_ptr
Posté le 16-11-2004 à 18:31:43  profilanswer
 

HelloWorld a écrit :

Tu peux filer une boost::function comme callback à une fonction C ?


 
Je le fait toute la journée :o

n°900051
chrisbk
-
Posté le 16-11-2004 à 18:53:13  profilanswer
 

tu pourrais poster un exemple ?

n°900054
Taz
bisounours-codeur
Posté le 16-11-2004 à 19:03:50  profilanswer
 

t'es trop flemmard pour lire leur excellente documentation et leurs exemples ?

n°900055
chrisbk
-
Posté le 16-11-2004 à 19:07:06  profilanswer
 

je trouve pas dans leur excellent exemple une excellente facon de mapper une excellente fonction membre sur une excellente callback type C. Mais faut dire que je suis excellement naze, la

n°900057
Joel F
Real men use unique_ptr
Posté le 16-11-2004 à 19:13:02  profilanswer
 

chrisbk a écrit :

tu pourrais poster un exemple ?


 
Demain depuis le boulot  [:joel f]

n°900108
Taz
bisounours-codeur
Posté le 16-11-2004 à 20:25:30  profilanswer
 

mais les callback C, c'est naz ...

n°900110
chrisbk
-
Posté le 16-11-2004 à 20:26:32  profilanswer
 

Taz a écrit :

mais les callback C, c'est naz ...


 
oué d'accord, mais je sais pas si t'as vu, c'est un peu le but de ce bordel d'au dessus

n°900114
Taz
bisounours-codeur
Posté le 16-11-2004 à 20:29:28  profilanswer
 

mais dans une API C bien foutue, y a toujours un param supplémentaire void* data ...

n°900116
chrisbk
-
Posté le 16-11-2004 à 20:30:48  profilanswer
 

Taz a écrit :

mais dans une API C bien foutue, y a toujours un param supplémentaire void* data ...


 
Certes, mais tu peux rapelle qu'une fonction public pour gerer la callback, alors

n°900126
Taz
bisounours-codeur
Posté le 16-11-2004 à 20:38:47  profilanswer
 

static tu veux dire

n°900128
chrisbk
-
Posté le 16-11-2004 à 20:41:38  profilanswer
 

Taz a écrit :

static tu veux dire


 
oué non, jme suis empatouillé, j'ai rien dit [:itm]
 
 
 
 

n°900132
Lam's
Profil: bas.
Posté le 16-11-2004 à 20:45:29  profilanswer
 

emberlificoté tu veux dire

n°900134
chrisbk
-
Posté le 16-11-2004 à 20:47:26  profilanswer
 

je m'empatouille en m'enberfilicotant et c'est mon choix

n°900138
Taz
bisounours-codeur
Posté le 16-11-2004 à 20:50:36  profilanswer
 

cela dit c'est vraiment du hack
 
quand tu fais du type-punning avec une union, techniquement, ton compilo à le droit d'optimiser et donc ça marcherait pas

n°900141
chrisbk
-
Posté le 16-11-2004 à 20:52:10  profilanswer
 

Taz a écrit :

cela dit c'est vraiment du hack
 
quand tu fais du type-punning avec une union, techniquement, ton compilo à le droit d'optimiser et donc ça marcherait pas


 
Oui, mais comme tu vois, j'en suis pas un hack pres, alors si pour retrouver la valeur fo passer par un memcpy crado ou un coup d'asm inline, ca me fait pas peur [:franck75] (l'union marche tres bien, merci)

n°900155
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 16-11-2004 à 21:14:58  profilanswer
 

chrisbk a écrit :


Le probleme que nous avons tous rencontré un jour, c'est une fonction demandant une Callback en entrée dans la main gauche, et une fonction membre qui serait parfaite pour ce role dans l'autre.
Drame : ca ne marche pas, car une fonction membre C++ demande en plus le 'this' de l'objet.


personnellement, je contourne le problème en déclarant la fonction en static [:joce]


---------------
J'ai un string dans l'array (Paris Hilton)
n°900156
chrisbk
-
Posté le 16-11-2004 à 21:16:49  profilanswer
 

Harkonnen a écrit :

personnellement, je contourne le problème en déclarant la fonction en static [:joce]


 
heuh, merci, hans [:petrus75]
ca resouds pas tout hein ? :o

n°900166
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 16-11-2004 à 21:32:31  profilanswer
 

chrisbk a écrit :

heuh, merci, hans [:petrus75]
ca resouds pas tout hein ? :o


ben non, le problème est que je ne peux plus accéder aux données membres non static de ma classe.
mais dans ce cas, je file en paramètre à la Callback le pointeur this, et j'appelle cette Callback à partir d'une fonction static (qui est en fait la vraie callback) :spamafote:


---------------
J'ai un string dans l'array (Paris Hilton)
n°900169
chrisbk
-
Posté le 16-11-2004 à 21:34:56  profilanswer
 

Harkonnen a écrit :

ben non, le problème est que je ne peux plus accéder aux données membres non static de ma classe.
mais dans ce cas, je file en paramètre à la Callback le pointeur this, et j'appelle cette Callback à partir d'une fonction static (qui est en fait la vraie callback) :spamafote:


 
methode taz de plus haut ca :o
 
mais spa tjs possible (genre les callback des fenetres windows. A part foutre dans le GWL_USERDATA en priant pour que personne vienne foutre sa merde, t'as une solution fine ?)

n°900227
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 16-11-2004 à 22:49:42  profilanswer
 

chrisbk a écrit :


mais spa tjs possible (genre les callback des fenetres windows. A part foutre dans le GWL_USERDATA en priant pour que personne vienne foutre sa merde, t'as une solution fine ?)


oui, je balance le this dans les propriétés des fenêtres, SetProp et GetProp roulaize :o
http://msdn.microsoft.com/library/ [...] erties.asp
 
edit: en plus, le GWL_USERDATA c'est le mal, car pour une fenêtre ou un controle que tu n'as pas créé toi même, tu peux pas être sur qu'il ne soit pas déja "occupé"


Message édité par Harkonnen le 16-11-2004 à 22:51:04

---------------
J'ai un string dans l'array (Paris Hilton)
n°900234
Jubijub
Parce que je le VD bien
Posté le 16-11-2004 à 22:58:17  profilanswer
 

Poste inutile du gars qui se dit que ca doit etre bien de comprendre ce que vous racontez...le seul truc que g pigé parce que je le savais déjà, c qu'en static t'a pas accès aux variables d'instances (ce qui est la logique meme de la chose)...


---------------
Jubi Photos : Flickr - 500px
n°900243
chrisbk
-
Posté le 16-11-2004 à 23:04:07  profilanswer
 

tu veux comprendre quoi ? t'as deja fait du C++ ?

n°900265
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 16-11-2004 à 23:18:29  profilanswer
 

Jubijub a écrit :

Poste inutile du gars qui se dit que ca doit etre bien de comprendre ce que vous racontez...le seul truc que g pigé parce que je le savais déjà, c qu'en static t'a pas accès aux variables d'instances (ce qui est la logique meme de la chose)...


bah, stout simple :??:
la problématique est la suivante : une fonction callback est une fonction appelée par le système en réponse à un évènement précis. cette fonction doit respecter une certaine signature.
le problème avec le C++, c'est que chaque méthode de classe possède un premier argument caché : le pointeur de l'objet (le this). donc, la signature de la callback n'est pas respectée, et ça ne marche pas !
les seules fonctions C++ qui ne possèdent pas de this en 1er paramètres, sont les fonctions static. malheureusement, tu ne peux pas accéder aux données membres à partir des fonctions static.
d'où la bidouille du père bk (bidouille qui me rappelle certains hacks du temps ou je codais des démos, quand on se faisait chier à calculer des adresses relatives pour éviter de foutre en l'air le registre de pile, et pour gagner quelques cycles :D)


---------------
J'ai un string dans l'array (Paris Hilton)
n°900269
chrisbk
-
Posté le 16-11-2004 à 23:21:14  profilanswer
 

spa une bidouille, stun thunk [:mmmfff]
et ton compilo C++ t'en genere plein sans que tu le voyes :o

n°900273
Taz
bisounours-codeur
Posté le 16-11-2004 à 23:26:38  profilanswer
 

c'est pas ça du tout. les fonctions membres non-static ne sont tout simplement pas des fonctions comme les autres fonctions libres. Si y avait que cette histoire de this implicite, on se marrerait bien.

mood
Publicité
Posté le   profilanswer
 

 Page :   1  2  3
Page Précédente

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  [C++ pour les hommes, les vrais] : les Delegates

 

Sujets relatifs
Vraie rencontre pour vrais gens :o[Perl/Tk] Les VRAIS curseurs de souris de windows, ou ki sont??
Comment évaluer, en gros, les jours/hommes d'un dev à réaliser ? 
Plus de sujets relatifs à : [C++ pour les hommes, les vrais] : les Delegates


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR