Adresse Mémoire d'une variable VB (pour les pros de l'API)

jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 - 19 févr. 2004 à 10:46
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 - 24 févr. 2004 à 17:24
Bonjour,

J'aimerais pourvoir choisir moi même l'adresse mémoire d'une variable VB. Le VB ne gérant pas les pointeurs, je me doute qu'il faut passer par une API.
Mais laquelle ?

Je sais récupérer l'adresse d'une variable VB avec "l'API" native (situé dans le runtime VB) StrPtr(str as String) as Long

Mais je voudrais pouvoir choisir moi même l'adresse d'une variable (en gros faire une allocation mémoire).

Ceci dans le but de partager une zone mémoire par plusieurs variables VB. (pointeurs)

Merci pour votre aide...
A voir également:

18 réponses

jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
19 févr. 2004 à 10:52
En fait, j'avais déjà posé cette question...
Mais sans réponse satisfaisante... :(

http://www.vbfrance.com/forum.v2.aspx?ID=60624#60624
0
crenaud76 Messages postés 4172 Date d'inscription mercredi 30 juillet 2003 Statut Membre Dernière intervention 9 juin 2006 28
19 févr. 2004 à 11:12
Tu as l'API GlobalAlloc() qui alloue une quantité de mémoire sur le Tas .. Avec GlobalFree() pour libérer bien sur, sinon, tu cours au crash de Windows

Christophe R.
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
19 févr. 2004 à 11:23
Il vaut mieux utiliser HeapAlloc ou VirtualAlloc en fonction des quantités de mémoires à allouer.
GlobalAlloc est obsolete.

Merci quand même, mais ça ne répond pas du tout à ma question...

Ma question est très simple (et prend 2 lignes de code en C/C++ ou autre langage utilisant les pointeurs) mais très dur à réaliser en VB :
Comment déclarer 2 variables (ou plus) de type String (par exemple) utilisant le même emplacement mémoire ?

On peut tourner la question différemment, mais ça revient au même...
Comment faire pointer 2 variables String sur la même zone mémoire.

Dim hHeap As Long
Dim pointer as Long 'Pointeur sur la zone mémoire
Dim lenString as long 'Taille de ma String

lenString = 500 'octets

hHeap = GetProcessHeap()
pointer = HeapAlloc(hHeap, 0, lenString)

'Comment déclarer 2 string (str1 et str2) qui vont pointer sur le buffer de 500 octets à l'adresse mémoire pointer ?

HeapFree GetProcessHeap(), 0, ptr

Bref, je pense que tu as compris le problème...

ça permettrait d'optimiser la rapidité d'un programme VB de manière considérable car le programme occuperait beaucoup moins de mémoire en RAM et n'aurait pas à allouer de la mémoire à chaque fois.
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
19 févr. 2004 à 11:24
Il vaut mieux utiliser HeapAlloc ou VirtualAlloc en fonction des quantités de mémoires à allouer.
GlobalAlloc est obsolete.

Merci quand même, mais ça ne répond pas du tout à ma question...

Ma question est très simple (et prend 2 lignes de code en C/C++ ou autre langage utilisant les pointeurs) mais très dur à réaliser en VB :
Comment déclarer 2 variables (ou plus) de type String (par exemple) utilisant le même emplacement mémoire ?

On peut tourner la question différemment, mais ça revient au même...
Comment faire pointer 2 variables String sur la même zone mémoire.

Dim hHeap As Long
Dim pointer as Long 'Pointeur sur la zone mémoire
Dim lenString as long 'Taille de ma String

lenString = 500 'octets

hHeap = GetProcessHeap()
pointer = HeapAlloc(hHeap, 0, lenString)

'Comment déclarer 2 string (str1 et str2) qui vont pointer sur le buffer de 500 octets à l'adresse mémoire pointer ?

HeapFree GetProcessHeap(), 0, pointer

Bref, je pense que tu as compris le problème...

ça permettrait d'optimiser la rapidité d'un programme VB de manière considérable car le programme occuperait beaucoup moins de mémoire en RAM et n'aurait pas à allouer de la mémoire à chaque fois.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
crenaud76 Messages postés 4172 Date d'inscription mercredi 30 juillet 2003 Statut Membre Dernière intervention 9 juin 2006 28
19 févr. 2004 à 11:28
Sauf que pour cela, tu vas faire une tripoter d'appels API, qui sont super pénalisant !!!!!!!!!
Faut bien doser, car la, je suis aps certain que tu y gagnes bcp !!

Christophe R.
0
ShareVB Messages postés 2676 Date d'inscription vendredi 28 juin 2002 Statut Membre Dernière intervention 13 janvier 2016 26
24 févr. 2004 à 09:36
salut

déjà si tu veux de l'optimisation VB super optimisée (lol) je te conseille le livre de M.Curland "Advanced Visual Basic 6"...
(il explique comment booster VB et faire des économies de mémoire, appel de pointeur de fonctions...)

ensuite dans ton cas prend l'api :
SysallocString 'si c'est un pointeur UNICODE
SysAllocStringByteLen 'si c'est un pointeur Ascii

pour eviter les bug quand tu en as plus besoin :
varstr = vbnullstring

voila

ShareVB
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
24 févr. 2004 à 10:05
Salut,

J'ai déjà utilisé ces fontions (avec SysFreeString pour libérer la mémoire) en C++ dans des controles ActiveX (sur des BSTR, qui sont des chaines de caractères Unicode correspondant aux String de VB).

Cependant, je ne trouve pas leur profil, ni dans quel fichier elles se trouvent ...

Es-tu sûr que ce sont des API que l'on peut utiliser sous VB et si oui, dans quel fichier (dll) se trouvent-elle ?

Merci pour ton aide...
0
ShareVB Messages postés 2676 Date d'inscription vendredi 28 juin 2002 Statut Membre Dernière intervention 13 janvier 2016 26
24 févr. 2004 à 10:11
salut

sure que oui :
elles sont dans oleaut32.dll

par contre je suis pas sur que l'utilisation de SysFreeString sur une zone mémoire non allouée par une API SysXXX ne fasse pas planter VB...

voila

ShareVB
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
24 févr. 2004 à 10:22
Je suis d'accord avec toi, quand je disais SysFreeString, c'était pour libérer une zone mémoire allouée par SysAllocString ou SysAllocStringLen.

Merci pour ton aide, je vais exploiter la piste que tu m'as donné et essayé de voir ce que cela donne...

Cependant, je ne suis pas sûr que cela va m'avancer beaucoup dans mon problème, car je ne vois pas commet faire pointer 2 variable String sur la même zone mémoire, peut importer si cette zone est alloué avec SysAllocString ou autre chose...
:(

Dim str1 as String
Dim str2 as String

'Allocation d'une String
str1 = SysAllocString("test d'allocation")

'Comment faire pointer str2 sur la éone mémoire de str1 ?
'??????????

'Libération de la String
SysFreeString(str1)
0
ShareVB Messages postés 2676 Date d'inscription vendredi 28 juin 2002 Statut Membre Dernière intervention 13 janvier 2016 26
24 févr. 2004 à 10:36
salut

oui effectivement j'avais pas bien compris le prb :
c'est beaucoup plus simple :
tu as un pointeur Ptr vers une zone mémoire contenant tes 500 octets.
tu as str1 et str2 = vbnullstring

tu fais
copymemory byval varptr(str1), byval ptr,4&
copymemory byval varptr(str2), byval ptr,4&

tes 2 chaines pointent maintenant vers la zone mémoire.
par contre attention à une chose : si la zone vient à etre libérée avant str1 et str2 il y a risque de plantage

pour libéré str1 et str2
zeromemory byval varptr(str1),4&
zeromemory byval varptr(str2),4&

voila

ShareVB
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
24 févr. 2004 à 10:49
Merci beaucoup...

je n'aurais pas pensée à faire "byval varptr(str1)" dans le CopyMemory pour mettre à jour l'adresse de la zone mémoire de str1.

Je vais tester et te tenir au courant.

Pour les problèmes de référence multiple que tu soulèves très justement, je vais faire un compteur de référence sur la zone mémoire pointé pour que la zone mémoire soit libérer si et seulement si il n'y a plus de référence dessus.

Je crois que je vais écrire une sorte de classe VB ou un module VB pour gérer tout cela...

Merci pour ton aide...

Jock
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
24 févr. 2004 à 11:22
Test ce bout de code dans un module....

ça marche très bien...

Par contre, ZeroMemory ne marche pas.

Il faut bien comprendre une chose importante.

Quand on déclare une variable str de type String.

Cette variable str est en fait un alias qui représente une adresse mémoire qui contient 4 octets.
Ces 4 octets contiennent eux même l'adresse du buffer recevant la chaine de caractère.

On a donc :
- l'@ de la zone mémoire de 4 octets (pointeur)
- l'@ du buffer contenu dans l'adresse mémoire de 4 octets

C'est pour cela que quand j'affiche les adresses de mes 3 variables dans mon code (str1, str2 et str3), j'ai 3 adresses différentes alors que pourtant, ces 3 variables pointent vein sur la même zone mémoire (contenant la chaine de caractère).
C'est tout à fait normal, car les 3 variables ont un emplacement différent en mémoire, mais elles contiennent toute la même adresse dans leur zone de 4 octets (adresse de la chaine de caractère).

Le copyMemory ByVal VarPtr(str2) ...... affecte bien la zone de 4 octets de str2.
Par contre, à l'affichage (Debug.Print VarPtr(str2), il semblerait que ça affiche l'adresse mémoire de la zone de 4 octets (l'adresse de la cariable str2). Car la valeur est différente pour les 3 variables alors qu'elles pointent toutes sur la même chaine de caractère (zone mémoire partagé).

Pour la désallocation, dans ma fonction de Test, pas de prob lème, Vb se charge de libérer le buffer pointé par str1 puis libère ensuite la zone de 4 octets de str1, str2 et str3.

-----------------------------------------------------------
Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, ByVal Length As Long)

Private Declare Sub ZeroMemory Lib "Kernel32" Alias "RtlMoveMemory" (dest As Any, ByVal numBytes As Long)

Public Sub TestPointer()
Dim str1 As String
Dim str2 As String
Dim str3 As String

'Alloue une zone mémoire
str1 = "buffer"

CopyMemory ByVal VarPtr(str2), ByVal VarPtr(str1), 4&
CopyMemory ByVal VarPtr(str3), ByVal VarPtr(str1), 4&
Debug.Print "str1 : adresse 0x" + hex$(VarPtr(str1)) + " valeur " + str1 Debug.Print "str2 : adresse 0x" + hex$(VarPtr(str2)) + " valeur " + str2 Debug.Print "str3 : adresse 0x" + hex$(VarPtr(str3)) + " valeur " + str3

End Sub
----------------------------------------------------------

Qu'en penses-tu ?
Vois-tu des problèmes ou des risques (car je sais que quand on manipule les pointeurs, il y a grand danger de laisser des trous de mémoire) surtout avec VB, car on les manipule difficilement d'une façon peu banale et détourné).

En tous cas, merci beaucoup pour ton aide...
Sans toi, je n'aurais pas eu le déclic...
0
ShareVB Messages postés 2676 Date d'inscription vendredi 28 juin 2002 Statut Membre Dernière intervention 13 janvier 2016 26
24 févr. 2004 à 11:55
salut

oui je vois un prb :
à la fin de la fonction il est nécessaire de mettre str2 vbnullstring et str3 vbnullstring. En effet, d'après ce que j'ai pu lire dans le livre cité plus haut : il faut impérativement supprimer les référence à une zone mémoire partagée avant que VB ne tente de libérer cette zone car il tenterait alors de libérer 3 fois la zone dans notre cas == plantage

Varptr renvoit l'addresse de du pointeur alors que Strptr renvoit l'adresse contenue dans le pointeur.

voila

ShareVB
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
24 févr. 2004 à 12:00
Excellent...

Je te remercie vraiment...

Le bouquin que tu cites à vraiment l'air génial...

Sans toi je n'aurais pas réussi à trouver la solution qui pourtant quand on y réfléchit bien n'est pas si compliqué que cela...

Bonne continuation et encore merci...

Jock
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
24 févr. 2004 à 16:07
Le vbNullString fait 2 choses :
- il libère le buffer contenant la chaine de caractère
- il met 0 dans l'adresse du buffer (zone de 4 octets)

Quand à la zone mémoire de 4 octets contenant l'adresse de la chaine de caractère, elle est libéré quand la durée de vie de la variable VB se termine (portée de la variable).

Il faut faire attention au fait que dès qu'une variable String va être détruite par VB (fin de sa portée --> durée de vie), la zone mémoire pointé contenant la chaine de caractère va être détruite et si d'autre variable String pointe dessus, elle ne pointeront sur rien et on aura à coup sur une erreur fatal de type "La mémoire ne peut pas être "written" ou "read" sous 2000/XP).
Bref, je voudrais trouver le moyen de faire le VbNullString manuellement, mais sans désallouer la chaine de caractère (sauf si plus aucune variable ne pointe dessus).
Je voudrais donc juste mettre la zone de 4 octets (pointeur) d'une variable String à 0, mais le ZeroMemory ne marche pas en faisant ByVal VarPtr(str1)..... Windows m'engueule en me disant que j'accède à une zone mémoire sans autorisation (la mémoire ne peut être "written")...

Comment faire... pour que quand la variable sera détruite par VB, la zone mémoire pointé ne soit pas libérer ?
Je n'ai pas trop de solution... il faut comme tu me l'avais dit que je mette 0 (équivalent de NULL pour les pointeurs en C/C++) dans la zone de 4 octets de la variable.
Mais ZeromMemory ne marche pas ....

Jock
0
ShareVB Messages postés 2676 Date d'inscription vendredi 28 juin 2002 Statut Membre Dernière intervention 13 janvier 2016 26
24 févr. 2004 à 17:17
salut

attention à la déclaration, la bonne est :
Private Declare Sub ZeroMemory Lib "Kernel32" Alias "RtlZeroMemory" (dest As Any, ByVal numBytes As Long)
(tu avais mis RtlMoveMemory)

maintenant comme ca marche
zeromemory byval varptr(str2),4&

voila

ShareVB
0
ShareVB Messages postés 2676 Date d'inscription vendredi 28 juin 2002 Statut Membre Dernière intervention 13 janvier 2016 26
24 févr. 2004 à 17:17
salut

attention à la déclaration, la bonne est :
Private Declare Sub ZeroMemory Lib "Kernel32" Alias "RtlZeroMemory" (dest As Any, ByVal numBytes As Long)
(tu avais mis RtlMoveMemory)

maintenant comme ca marche
zeromemory byval varptr(str2),4&

voila

ShareVB
0
jockos Messages postés 321 Date d'inscription dimanche 22 octobre 2000 Statut Membre Dernière intervention 14 mai 2005 2
24 févr. 2004 à 17:24
Merci beaucoup...
:)
0
Rejoignez-nous