@Fred ... GetGadgetItemText

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
eddy
Messages : 67
Inscription : mer. 09/avr./2008 2:08

@Fred ... GetGadgetItemText

Message par eddy »

J'aurai besoin des lumières de Fred.

Là je bloque complètement. Ca concerne les custom gadgets.

J'essaye d'étendre la fonction GetGadgetItemText
Je sais comment récupérer le pointer vers la fonction en question.

Mais toutes les fonctions CallFunctionFast échouent.
Je devine que c'est la récupération du text qui pose problème.
- CallFunctionFast ne retourne pas un poinbter vers une String (c'est sûr).
- donc je suppose qu'il faut le résultat soit un paramètre en sortie.

J'ai essayé divers combinaison :
:arrow: CallCFunctionFast
:arrow: CallFunctionFast
:arrow: *res.string
:arrow: res.character()

Code : Tout sélectionner

CallCFunctionFast(*GetGadgetItemText, *gadget.PBGadget, Position, Column,  *result.String ?????)
eddy
Messages : 67
Inscription : mer. 09/avr./2008 2:08

Message par eddy »

Un petit exemple pour faire des tests et mieux comprendre le problème :

Code : Tout sélectionner

CompilerIf Defined(GADGET_VT, #PB_Structure)=#False
   Structure GADGET_VT  ; PB_GadgetVT
      GadgetType.i      ; gadget type (used by GadgetType command)
      SizeOf.i          ; Size of structure
      
      *GadgetCallback
      *FreeGadget
      *GetGadgetState
      *SetGadgetState
      *GetGadgetText
      *SetGadgetText
      *AddGadgetItem2
      *AddGadgetItem3
      *RemoveGadgetItem
      *ClearGadgetItemList
      *ResizeGadget
      *CountGadgetItems
      *GetGadgetItemState
      *SetGadgetItemState
      *GetGadgetItemText
      *SetGadgetItemText
      *OpenGadgetList2
      *GadgetX
      *GadgetY
      *GadgetWidth
      *GadgetHeight
      *HideGadget
      *AddGadgetColumn
      *RemoveGadgetColumn
      *GetGadgetAttribute
      *SetGadgetAttribute
      *GetGadgetItemAttribute2
      *SetGadgetItemAttribute2
      *SetGadgetColor
      *GetGadgetColor
      *SetGadgetItemColor2
      *GetGadgetItemColor2
      *SetGadgetItemData
      *GetGadgetItemData
   EndStructure
CompilerEndIf
CompilerIf Defined(GADGET, #PB_Structure)=#False
   Structure GADGET     ; PB_Gadget
      hwnd.i            ; gadget window handle
      *VT.GADGET_VT     ; gadget commands
      *GadgetData       ; gadget data           (used by SetGadgetData command)
      *OldCallback      ; window CALLBACK       (used by purebasic CALLBACK)
      Dates.i[4]        ; .....
   EndStructure
CompilerEndIf

If OpenWindow(0, 0, 0, 222, 200, "test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
   ListIconGadget(10, 10, 10, 200, 220, "header", 100)
   AddGadgetColumn(10, 1, "header2", 100)
   AddGadgetItem(10, 0, "items..."+#LF$+"item")
   
   *g.GADGET=IsGadget(10)
   Debug *g\hwnd
   Debug *g\VT\GetGadgetItemText
   Debug Len(GetGadgetItemText(10, 0, 0)) ; <--8
   Debug CallCFunctionFast(*g\VT\GetGadgetItemText, *g, 0, 0, *res) ; <--8
   Debug *res  ; <-- 0 ??
   
   Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
EndIf

PAPIPP
Messages : 534
Inscription : sam. 23/févr./2008 17:58

Message par PAPIPP »

Cela fonctionne en partie chez moi avec une autre bogue (bug en français)
J'ai ajouté quelques éléments pour étudier le Pb et j'ai trouvé ceci
ci-dessous .

Code : Tout sélectionner

Macro Quote
  "
EndMacro

Macro debn(n)
  Debug quote#n# = quote + Str(n)
EndMacro

Macro debc(C)
  Debug quote#C# = quote + C
EndMacro

Macro debf(F)
  Debug quote#F# = quote + StrF(f)
EndMacro

Macro debd(D)
  Debug quote#D# = quote + StrD(D)
EndMacro

Macro debQ(Q)
  Debug quote#Q# = quote + StrQ(Q)
EndMacro

Macro debH(H)
  Debug quote#H# = quote + Hex(H)
EndMacro

Macro debHq(Hq)
  Debug quote#Hq# = quote + HexQ(Hq)
EndMacro

Procedure.s hex_viewl(*adres.l, long.l)
  hext$ = ""
  cart$ = ""
  For i = 0 To long
    num.c = PeekC(*adres + i)
    cart$ = cart$ + Chr(num)
    
    hexs.s = Hex(num) + " "
    If Len(hexs) = 2
      hexs = "0" + hexs
    EndIf
    hext$ + hexs
  Next
  ProcedureReturn hext$ + "    " + cart$
EndProcedure

Procedure hex_view(*adress, long)
  residu.i = long%16
  ilong = long/16
  For i = 0 To ilong
    ;Debug Hex(*adress + (i*16))
    ;Debug hex_viewl (*adress + (i*16), 15)
    Debug "$" + Hex(*adress + (i*16)) + "   " + hex_viewl(*adress + (i*16), 15)
  Next
EndProcedure
; C.s="Pierre_machin"
; debc(c)
CompilerIf Defined(GADGET_VT, #PB_Structure) = #False
  Structure GADGET_VT  ; PB_GadgetVT
    GadgetType.i      ; gadget type (used by GadgetType command)
    SizeOf.i          ; Size of structure
    
    *GadgetCallback
    *FreeGadget
    *GetGadgetState
    *SetGadgetState
    *GetGadgetText
    *SetGadgetText
    *AddGadgetItem2
    *AddGadgetItem3
    *RemoveGadgetItem
    *ClearGadgetItemList
    *ResizeGadget
    *CountGadgetItems
    *GetGadgetItemState
    *SetGadgetItemState
    *GetGadgetItemText
    *SetGadgetItemText
    *OpenGadgetList2
    *GadgetX
    *GadgetY
    *GadgetWidth
    *GadgetHeight
    *HideGadget
    *AddGadgetColumn
    *RemoveGadgetColumn
    *GetGadgetAttribute
    *SetGadgetAttribute
    *GetGadgetItemAttribute2
    *SetGadgetItemAttribute2
    *SetGadgetColor
    *GetGadgetColor
    *SetGadgetItemColor2
    *GetGadgetItemColor2
    *SetGadgetItemData
    *GetGadgetItemData
  EndStructure
CompilerEndIf
CompilerIf Defined(GADGET, #PB_Structure) = #False
  Structure GADGET     ; PB_Gadget
    hwnd.i            ; gadget window handle
    *VT.GADGET_VT     ; gadget commands
    *GadgetData       ; gadget data           (used by SetGadgetData command)
    *OldCallback      ; window CALLBACK       (used by purebasic CALLBACK)
    Dates.i[4]        ; .....
  EndStructure
CompilerEndIf

If OpenWindow(0, 0, 0, 222, 200, "test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ListIconGadget(10, 10, 10, 200, 220, "header", 100)
  AddGadgetColumn(10, 1, "header2", 100)
  AddGadgetItem(10, 0, "items 10_0_0.." + #LF$ + "item 10_0_1")
  
  *g.GADGET = IsGadget(10)
  Debn (*g\hwnd)
  Debn (*g\VT\GetGadgetItemText)
  Debn (Len(GetGadgetItemText(10, 0, 0))) ; <--8
  Debug *g\VT\GetGadgetItemText

  resul=CallCFunctionFast(*g\VT\GetGadgetItemText, *g, 0, 0, *res)
   Debn (resul)
  Debug CallCFunctionFast(*g\VT\GetGadgetItemText, *g, 0, 0, *res); <--8
  
  Debug " ******* ci-dessous resultat surprenant car resultat de getgadgetitemtext alors que la macro  debn traite les val nurériques *******"
  Debn (CallCFunctionFast(*g\VT\GetGadgetItemText, *g, 0, 0, *res)); <--8
  Debug  GetGadgetItemText(10, 0 ,0)
  debc (GetGadgetItemText(10,0,0))
 ; *** si l'on exécute l'instruction ci-dessous aussi erronée que la précédente on a un plantage par"the debugged executable quit unexpectedly" ****** 
; DebC ((CallCFunctionFast(*g\VT\GetGadgetItemText, *g, 0, 1, *res))); <--8
  Debug  GetGadgetItemText(10, 0 ,1)
  debc (GetGadgetItemText(10,0,1))

  Debug *res  ; <-- 0 ??
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
;*****************Résultats obtenus *******************************
; [09:52:45] *g\hwnd = 1050280
; [09:52:45] *g\VT\GetGadgetItemText = 4207254
; [09:52:45] Len(GetGadgetItemText(10, 0, 0)) = 14
; [09:52:45] 4207254
; [09:52:45] resul = 3808912
; [09:52:45] 3808912
; [09:52:45]  ******* ci-dessous resultat surprenant car resultat de getgadgetitemtext alors que la Macro  debn traite LES val nurériques *******
; [09:52:45] items 10_0_0..
; [09:52:45] items 10_0_0..
; [09:52:45] GetGadgetItemText(10,0,0) = items 10_0_0..
; [09:52:45] item 10_0_1
; [09:52:45] GetGadgetItemText(10,0,1) = item 10_0_1
; [09:52:45] 0
gnozal
Messages : 832
Inscription : mar. 07/déc./2004 17:35
Localisation : France
Contact :

Message par gnozal »

Selon le fichier généré par PB en ASM, la solution est dans ECX :

Code : Tout sélectionner

If OpenWindow(0, 0, 0, 222, 200, "test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
  ListIconGadget(10, 10, 10, 200, 220, "header", 100) 
  AddGadgetColumn(10, 1, "header2", 100) 
  AddGadgetItem(10, 0, "items..."+#LF$+"item") 
  
  
  !EXTRN _PB_GetGadgetItemText2@16
  ;
  !MOV    Eax,[_PB_StringBasePosition]
  !PUSH   Eax
  !PUSH   Eax
  !PUSH   dword 1  ; colonne
  !PUSH   dword 0  ; ligne
  !PUSH   dword 10 ; gadget
  !CALL  _PB_GetGadgetItemText2@16
  !LEA    Ecx,[v_a$] ; variable
  !POP    Edx
  !CALL   SYS_AllocateString
  
  Debug a$ ; <=
  
  
  Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow 
EndIf
eddy
Messages : 67
Inscription : mer. 09/avr./2008 2:08

Message par eddy »

Merci
Toutes mes CustomGadgets bloquaient sur cette question. 8O

Comment tu as trouvé ça ?
Avatar de l’utilisateur
kernadec
Messages : 1606
Inscription : ven. 25/avr./2008 11:14

Message par kernadec »

bonjour
avec une telle astuce
ou est passée l'ergonomie du Basic ??
qui justement devrait éviter ce genre de patch
au revoir
eddy
Messages : 67
Inscription : mer. 09/avr./2008 2:08

Message par eddy »

C'est parce qu'on entre dans le moteur de PB que ca devient compliqué.
- Ca n'a aucune utilité pour les débutants en BASIC mais plutôt pour ceux qui débute en ASM
- Je ne cherche pas un truc cross-platform.

Mais l'ergonomie de PB est là, on peut mixé de l'ASM avec du code basic.
Heuresement PB ne se résume pas au basic sinon je ne l'aurai jamais choisi. :wink:


Je suis entrain de personnaliser le ListiconGadget
Image
Cls
Messages : 620
Inscription : mer. 22/juin/2005 8:51
Localisation : Nantes

Message par Cls »

Très intéressant ça !

Tu fais un code libre ou tu le gardes au chaud ?
eddy
Messages : 67
Inscription : mer. 09/avr./2008 2:08

Message par eddy »

Bah c'est libre.

Mais je suis bloqué sur ce problème de renvoie de text.
Apparemment c'est un cas que PB ne gère pas et ProcedureReturn ne marche pas.

J'ai le même problème avec d'autres CustomGadgets que j'ai codé.
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

@Eddy

Je ne sais pas exactement ce que tu veux mais j'avais déjà eu un problème sur un retour de chaîne et Gnozal avait donné quelques précisions intéressantes : "Mémé kiffe les orties"
eddy
Messages : 67
Inscription : mer. 09/avr./2008 2:08

Message par eddy »

ça doit être quelque chose comme ça
parce que j'ai des ACCESS ERROR en début de procédure à cause d'un paramètre fantôme
et en fin de procédure.
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

J'ai pas senti sur le forum anglais une envie de t'aider de la part de Fred/Freak.

J'ai regardé mais avec le pointeur du gadget de PB je n'arrive à rien.

Pour le code asm posté par Gnozal, voici ce que je comprend

Code : Tout sélectionner

!EXTRN _PB_GetGadgetItemText2@16
  ;
  !MOV    Eax,[_PB_StringBasePosition]
  !PUSH   Eax
  !PUSH   Eax
  !PUSH   dword 1  ; colonne
  !PUSH   dword 0  ; ligne
  !PUSH   dword 10 ; gadget
  !CALL  _PB_GetGadgetItemText2@16
  !LEA    Ecx,[v_a$] ; variable
  !POP    Edx
  !CALL   SYS_AllocateString 

La fonction appelée est _PB_GetGadgetItemText2@16 qui a donc 4 paramètres Long (4 x 4 = 16, qui correspond au 16 après le @) alors que la fonction PB accepte au plus 3 paramètres (3 x 4 = 12). De toute évidence il y a plusieurs fonctions GetGadgetItemText car celle-ci se fini par 2 (_PB_GetGadgetItemText2), ce qui fait que je ne sais pas vraiment sur quoi pointe *g\VT\GetGadgetItemText, peut-être une table (?) donc sans explication, on arrive pas à grand chose. L'utilisation des autres fonctions GetGadgetItemText (avec un nombre de paramètres différent) dépend peut-être du contexte tel que décrit dans le SDK ci-dessous.

Pour revenir au code asm, le premier Push eax est fait pour mémoriser le pointeur _PB_StringBasePosition qui donne le pense le début de la zone libre du buffer d'écriture des chaînes (mais bon ?), cette valeur est récupére par le POP edx.
Le deuxième PUSH eax (on empile le pointeur _PB_StringBasePosition) est un des paramètre de la fonction _PB_GetGadgetItemText2@16, les autre PUSH correspondent comme Gnozal l'a écrit aux paramètres propres de la fonction. PB va utiliser le pointeur pour écrire la chaîne dans le buffer (enfin je pense) et ce pointeur aura ensuite une valeur différente d'avant l'appel de la fonction. Mais comme on a empilé la valeur initiale, c'est cette valeur qui pointera le début de la chaine écrite sur le buffer.

Ensuite, pour attribuer à la variable a$ le contenu de la chaine lue, PB va allouer de la mémoire pour cette opération en utilisant l'appel de fonction !CALL SYS_AllocateString qui admet deux paramètres :
ECX reçoit l'adresse de la variable a$, qu'elle soit locale ou globale
EDX récupère le pointeur _PB_StringBasePosition avant écriture du buffer

La fonction admet je pense un troisième paramètre qui est masqué qui est la taille de la chaine retournée dans eax par le CALL _PB_GetGadgetItemText2@16

C'est que j'ai compris mais c'est comme tout, beaucoup d'incertitudes

Pour que tout soit clean, il faut ensuite détruire la mémoire attribuée pour la chaine comme ceci (dès que c'est possible)

Code : Tout sélectionner

PUSH   dword [v_a$]
CALL  _SYS_FreeString@4


La doc SDK de PB dit ceci (voir ci-dessous) mais là encore, rien de rien pour utiliser les macro Polink


VI. Managing strings
--------------------

Managing strings in PureBasic 4.0 and above isn't obvious anymore. If a function use strings but doesn't
returns string, there is not problem at all. Now when it returns string, there is different case:

1) The function doesn't has string parameter

It's the easiest one, and you can use the SYS_GetOutputBuffer() or SYS_GetOutputBufferESP() macro
in LCC.

SYS_GetOutputBuffer(char *Output, int NeededLength, char *NbParameters)

With this command you ask PureBasic to returns a string buffer of 'NeededLength' (in characters, which means
than it's the same value in unicode or not) and store the pointer value in 'Output'. 'NbParameters' is a
string number which indicates how many parameters the function has.

ex: SYS_GetOutputBuffer(Output, 100, "2")

Once you get this buffer, just write the string result in it and you're done.

Note: the 'NeededLength' should be the exact returned string length. It doesn't count the null terminating character

WARNING: When using LCC, there is sometimes an issue when the function doesn't have any parameters, and is very short.
LCC then optimize it by using only registers and then SYS_GetOutputBuffer() will fails. In this case, you can generate
the .asm code and check the procedure start, if ebp is used or not. If not, you will have to use SYS_GetOutputBufferESP()
and put the offset number. It very rare case, but can happen.


2) If the function has some string parameters

You still have to use the above functions, but before you may need to to call SYS_GetParameterIndex() and SYS_ResolveParameter()
if you need to use the string parameters after having called SYS_GetOutputBuffer(). Why that ? Because if one of your
parameter is a composed string (like a$+b$), it will reside on the internal buffer. When you request some length (let's say
a big length), it can be reallocated, which means than your string pointers won't be correct anymore. SYS_GetParameterIndex() will
get the index in the buffer, if the string is in the buffer (or return 0 else). SYS_ResolveParameter() will rebuild the
string pointer once SYS_GetOutputBuffer() will be called.

A typical C code will look like that:

M_PBFUNCTION void PB_LSet(const TCHAR *String, int Length)
{
[...]

ParameterIndex = SYS_GetParameterIndex(String);

SYS_GetOutputBuffer(Cursor, StringLength, "2");

if (ParameterIndex)
String = SYS_ResolveParameter(ParameterIndex);

[...]
}

Now, sometimes you can't know the size of the result string (or it will be too long to compute it. In this can, you
can request a fixed size and adjust it at the end with the SYS_ReduceStringSize(Length) function. 'Length' is the
number of byte to reduce the buffer. If you have requested a buffer of 4096 with SYS_GetOutputBuffer() and your
string do only 4000 bytes, you will have to reduce it from 96 bytes ie: SYS_ReduceStringSize(96).
Répondre