Ecrire en mémoire avec VB6

Résolu
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 - 29 mars 2011 à 16:22
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 - 30 mars 2011 à 15:47
Boujour à tous

Je voudrais essayer d'ecrire en mémoire, un tableau sous format ASCII, et en LPSTR, de façon à pouvoir le lire avec une DLL standard.

J'ai créé avec beaucoup de mal ce code, mais cela ne marche pas

Si quelqu'un avait la gentillesse de me donner un coup de pouce

Private Declare Function HeapAlloc Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function HeapFree Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long
Private Declare Function GetProcessHeap Lib "kernel32" () As Long
Private Declare Sub CopyMemoryWrite Lib "kernel32" Alias "RtlMoveMemory" (Destination As Long, ByVal Source As String, ByVal Length As Long)
Private Declare Sub ShowArrayString Lib "TheDll.dll" (ByRef ArrayPtr As ArrayStruct)

Private Sub Form_Load()
 
 Dim TheArray(10) As String
 Dim ArrayString As ArrayStruct
 Dim ArrayLen As Integer
 Dim OffsetPtr As Long
 Dim hHeap As Long
 Dim ArrayAscii As String
 
 ChDir App.Path
 CurDir Left(App.Path, 3)
  
 For i = 1 To UBound(TheArray())
  TheArray(i) = "Sentence n° " + Str(i)
  ArrayLen = ArrayLen + Len("Sentence n° " + Str(i))
 Next
 
 ArrayString.Size = UBound(TheArray())
 hHeap = GetProcessHeap()
 ArrayString.Ptr = HeapAlloc(hHeap, 0, ArrayLen)
 OffsetPtr = ArrayString.Ptr
 
 For i = 1 To UBound(TheArray())
  ArrayAscii = StrConv(TheArray(i), vbFromUnicode)
  CopyMemoryWrite OffsetPtr, ArrayAscii, LenB(ArrayAscii)
  OffsetPtr = OffsetPtr + LenB(ArrayAscii)
 Next
 
 ShowArrayString ArrayString
 HeapFree GetProcessHeap(), 0, ArrayString.Ptr
 
End Sub


Je vous remercie et vous souhaite une bonne soirée

15 réponses

Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
30 mars 2011 à 15:03
Tu seras embetté, VB et PB gèrent pas leurs tableaux de Stirngs de manière similaire...

possible de faire :

TheDLL.pb
EnableExplicit

Procedure.i GetStringArray(*pSA.i, Count.i, Array List.s(1))
  Define.i i
  If Count = 0
    Define.i pSA = PeekI(*pSA);
    Count = PeekI(pSA+16);
    pSA = PeekI(pSA+12);  
    ReDim List(Count)
    For i = 0 To Count -1
        List(i) = PeekS(PeekI(pSA+i*4))
    Next
  Else
    ReDim List(Count)
    For i = 0 To Count -1
      List(i) = PeekS(*pSA + 24 * i)
    Next
  EndIf  
  ProcedureReturn Count
EndProcedure

ProcedureDLL Show_StringArray(*pSA, Count.i = 0)
  Dim List.s(0)
  Count.i = GetStringArray(*pSA, Count, List())
  Define i
  Define Sentence.s = ""
  For i = 0 To Count -1
    Sentence = Sentence + List(i) + #CRLF$
  Next
  MessageRequester(Str(Count) + " elements", Sentence)      
EndProcedure 


; Dim xsPlanets.s(8)
; xsPlanets(0) = "Mercure"
; xsPlanets(1) = "Venus"
; xsPlanets(2) = "Terre"
; xsPlanets(3) = "Mars"
; xsPlanets(4) = "Jupiter"
; xsPlanets(5) = "Saturne"
; xsPlanets(6) = "Uranus"
; xsPlanets(7) = "Neptune"
; Show_StringArray(@xsPlanets(0), 8)



PBClient.pb
EnableExplicit

Prototype Show_StringArray(*pFirst.i, Count.i)
Define LIB_TheDLL.i = OpenLibrary(#PB_Any, "TheDll")
If LIB_TheDLL 
  Define Show_StringArray_.Show_StringArray = GetFunction(LIB_TheDLL, "Show_StringArray")
EndIf
Macro Show_StringArray(x)
  Show_StringArray_(@x#(0), ArraySize(x#()))
EndMacro

Dim xsPlanets.s(8)
xsPlanets(0) = "Mercure"
xsPlanets(1) = "Venus"
xsPlanets(2) = "Terre"
xsPlanets(3) = "Mars"
xsPlanets(4) = "Jupiter"
xsPlanets(5) = "Saturne"
xsPlanets(6) = "Uranus"
xsPlanets(7) = "Neptune"
Show_StringArray(xsPlanets)

Merci les Macros^^ Même appel en PB et en VB


VBClient.bas
Private Declare Sub Show_StringArray Lib "TheDll" (ByRef vxsData() As String, Optional ByVal vnCount As Long = 0)

Sub Main()
Dim xsPlanets(7) As String
    xsPlanets(0) = "Mercure"
    xsPlanets(1) = "Venus"
    xsPlanets(2) = "Terre"
    xsPlanets(3) = "Mars"
    xsPlanets(4) = "Jupiter"
    xsPlanets(5) = "Saturne"
    xsPlanets(6) = "Uranus"
    xsPlanets(7) = "Neptune"
    Show_StringArray xsPlanets
End Sub


Ainsi tout le monde est content...

Renfield - Admin CodeS-SourceS - MVP Visual Basic & Spécialiste des RegExp
3
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
29 mars 2011 à 16:51
Salut

(vite fait, je n'ai pas trop le temps)
Tu auras du mal à écrire directement un tableau de String car les adresses des chaines sont doublement indexées.
Par contre, en passant par une structure, tu peux fournir l'adresse de la structure au lieu de celui du tableau :
Type maStructure
    myArray(10) As String)
End Type

Voir ces deux liens riches en info :
<lien 1>
<lien 2>

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
0
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 1
29 mars 2011 à 18:25
Merci mille fois JACK, je vais etudier ça
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
30 mars 2011 à 09:35
Salut Eric, comment est déclaré ArrayStruct ?

que contient cette Structure ?

For i = 1 To UBound(TheArray())
cette manie de commencer à 1....


Renfield - Admin CodeS-SourceS - MVP Visual Basic & Spécialiste des RegExp
0

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

Posez votre question
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
30 mars 2011 à 09:36
Ta dll étant mappée dans le même espace mémoire que ton programme VB (c'est le principe des dll)

tu peux lui filer des pointeurs vers tes String, elles pourront être manipulées par ta dll PB

Renfield - Admin CodeS-SourceS - MVP Visual Basic & Spécialiste des RegExp
0
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 1
30 mars 2011 à 10:59
Salut Eric, comment est déclaré ArrayStruct ?

Bonjour Reynald, j'suis tellement content de te reparler.
Je viens de tout lire, ce que m'a gentiment donné JACK, et à part une tournée générale d'aspirine, j'ai pas gagné grand chose

que contient cette Structure ?

ArrayStruct ??? mais j'ai pas d'arraystruct

Je suis evidemment toujours dans mon projet ou j'ai avancé grace à toi, et cette combine que j'avais pas comprise de pointeur de pointeur de safearray, maintenant les safearray prennent tous les jours le metro destination "porte de la DLL"
Donc pour ce coups, je voulais "tout bettement" (Tout est relatif) faire l'inverse, c'est à dire créer avec VB, un tableau le LPSTR comme peut le lire ma DLL.
Donc j'ai essayé de creer une zone memoire avec VB, et je voulais copier dedans chaque string du tableau a la queue leu leu séparée d'un chr(0), afin que ma DLL retrouve ses petits.
J'envoyais le pointeur de ma zone mémoire et en avant "guinganp" la DLL se disait qu'elle avait un de SES tableaux à lire
Mais comme dab, deja pour creer une zone memoire j'ai du mettre une journée a trouver les API "HeapAlloc & co", donc je pense que c'est bon.
Mais pour aller poser les strings, enlever leur UNICODE, et leur BSTR, etc...

For i = 1 To UBound(TheArray())
cette manie de commencer à 1....

Tu as mille fois raison...depuis 30 ans je fais ça, alors dur d'arreter de fumer

tu peux lui filer des pointeurs vers tes String, elles pourront être manipulées par ta dll PB

Comment tu sais ce que je fais
Oui mais les BSTR et UNICODE comment je les vire ???

J'ai trouvé cette fonction grace a JACK:
Function BSTRtoLPSTR(sBSTR As String, b() As Byte, lpsz As Long) As Long
 
 ' Input: a nonempty BSTR string
 ' Input: **undimensioned** byte array b()
 ' Output: Fills byte array b() with ANSI char string
 ' Output: Fills lpsz with a pointer to b() array
 ' Returns byte count, not including terminating null
 ' Original BSTR is not affected
  
 Dim cBytes As Long
 Dim sABSTR As String
  
 cBytes = LenB(sBSTR)
  
 ' ReDim array, with space for terminating null
 ReDim b(1 To cBytes + 2) As Byte
  
 ' Convert to ANSI
 sABSTR = StrConv(sBSTR, vbFromUnicode)
  
 ' Point to BSTR char array
 lpsz = StrPtr(sABSTR)
  
 ' Copy the array
 CopyMemory b(1), ByVal lpsz, cBytes + 2
  
 ' Point lpsz to new array
 lpsz = VarPtr(b(1))
  
 ' Return byte count
 BSTRtoLPSTR = cBytes
 
End Function


Mais comme dab, j'suis comme une poule avec une fourchette, j'suis pas arrivé à l'inserer dans mon code, ça crash

Private Declare Function HeapAlloc Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function HeapFree Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long
Private Declare Function GetProcessHeap Lib "kernel32" () As Long
Private Declare Sub CopyMemoryWrite Lib "kernel32" Alias "RtlMoveMemory" (Destination As Long, ByVal Source As String, ByVal Length As Long)
Private Declare Sub ShowArrayString Lib "C:\Travail\Allocation mémoire libérée par la DLL [Kcc]\TheDll.dll" (ByRef ArrayPtr As ArrayStruct)
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (b As Any, lpsz As Long, cBytes As Long)

Private Sub Form_Load()
 
 Dim TheArray(10) As String
 Dim ArrayString As ArrayStruct
 Dim ArrayLen As Integer
 Dim OffsetPtr As Long
 Dim hHeap As Long
 
 ChDir App.Path
 CurDir Left(App.Path, 3)
  
 For i = 1 To UBound(TheArray())
  TheArray(i) = "Sentence n° " + Str(i)
  ArrayLen = ArrayLen + Len("Sentence n° " + Str(i))
 Next
 
 Dim b() As Byte
 Dim lpsz As Long, lng As Long, Lpstr As Long
 
 ArrayString.Size = UBound(TheArray())
 hHeap = GetProcessHeap()
 ArrayString.Ptr = HeapAlloc(hHeap, 0, ArrayLen)
 OffsetPtr = ArrayString.Ptr

 For i = 1 To UBound(TheArray())
  Lpstr = BSTRtoLPSTR(TheArray(i), b, lpsz)
  CopyMemoryWrite OffsetPtr, Lpstr, 4
  OffsetPtr = OffsetPtr + LenB(ArrayAscii)
 Next
 
 ShowArrayString ArrayString
 HeapFree GetProcessHeap(), 0, ArrayString.Ptr
 
End Sub

Function BSTRtoLPSTR(sBSTR As String, b() As Byte, lpsz As Long) As Long
 
 ' Input: a nonempty BSTR string
 ' Input: **undimensioned** byte array b()
 ' Output: Fills byte array b() with ANSI char string
 ' Output: Fills lpsz with a pointer to b() array
 ' Returns byte count, not including terminating null
 ' Original BSTR is not affected
  
 Dim cBytes As Long
 Dim sABSTR As String
  
 cBytes = LenB(sBSTR)
  
 ' ReDim array, with space for terminating null
 ReDim b(1 To cBytes + 2) As Byte
  
 ' Convert to ANSI
 sABSTR = StrConv(sBSTR, vbFromUnicode)
  
 ' Point to BSTR char array
 lpsz = StrPtr(sABSTR)
  
 ' Copy the array
 CopyMemory b(1), ByVal lpsz, cBytes + 2
  
 ' Point lpsz to new array
 lpsz = VarPtr(b(1))
  
 ' Return byte count
 BSTRtoLPSTR = cBytes
 
End Function

0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
30 mars 2011 à 11:15
Dim ArrayString As ArrayStruct


ou as tu déclaré ArrayStruct ?

Renfield - Admin CodeS-SourceS - MVP Visual Basic & Spécialiste des RegExp
0
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 1
30 mars 2011 à 11:26
J'ai honte...a force de triturer les codes plusieurs jours, j'sais plus ou j'en suis

Tu as encore raison, j'avais mis ça dans un module
Type ArrayStruct
 Ptr As Long
 Size As Integer
End Type


Et voici la DLL, d'ailleurs j'ai une quetion importante pour moi.
Ai-je le droit de liberer la zone allouée par VB6 dans la DLL
Ou bien c'est comme pour les tableaux et il ne faut jamais faire cela, et liberer les zone mémoires par celui qui l'a créé
Structure ArrayStruct
 *Ptr.l
 Size.i
EndStructure

ProcedureDLL ShowArrayString(*TheArray.ArrayStruct)

 *OffsetPtr = *TheArray\Ptr
 
 For i = 1 To *TheArray\Size
  String$ = PeekS(*OffsetPtr,4)
  SentenceString$ + String$ + Chr(13)
  *OffsetPtr + Len(String$) + 1
 Next
 
 FreeMemory(*TheArray); <=== Ai je le droit ???
 MessageRequester("The array form EXE", SentenceString$)
 
EndProcedure 
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
30 mars 2011 à 13:20
Comme pour les tableaux ...


Non, même les tableaux peuvent etre liberés... suffit de bien lui demander.

pour la mémoire allouée, même topo...
bien lui demander et dans VB ne plus mentionner ce pointeur devenu invalide...


Renfield - Admin CodeS-SourceS - MVP Visual Basic & Spécialiste des RegExp
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
30 mars 2011 à 13:22
une raison particulière de donner une copie de cette structure, au final et non la structure allouée par VB ?

Renfield - Admin CodeS-SourceS - MVP Visual Basic & Spécialiste des RegExp
0
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 1
30 mars 2011 à 13:56
Non, même les tableaux peuvent etre liberés... suffit de bien lui demander.
pour la mémoire allouée, même topo...
bien lui demander et dans VB ne plus mentionner ce pointeur devenu invalide...

D'accord...donc faut demander correctement.
Et dans mon exemple, lui ai-je demandé assez "poliement"
FreeMemory(*TheArray);


une raison particulière de donner une copie de cette structure, au final et non la structure allouée par VB ?

Bah non
En fait je croyais bettement que c'etait obligatoire de la declarer de chaque coté afin que le ligne "ShowArrayString(*TheArray.ArrayStruct)" puisse fonctionner ...
0
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 1
30 mars 2011 à 13:58
Je dirais meme plus, en fait le tableau de string ne necessite pas de structure, c'est juste un tableau de string simple dans VB
J'ai rajouté une structure pour indiquer la longueur du tableau, et n'envoyer qu'un seul pointeur comprenant le pointeur du tableau recréé par VB en mémoire et la longueur du tableau
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
30 mars 2011 à 14:15
j'avais saisi le but de la chose....

inutile pour un tableau envoyé par VB, et don en SafeArray

utile pour un tableau qui viendrait par exemple de PureBasic ...

Renfield - Admin CodeS-SourceS - MVP Visual Basic & Spécialiste des RegExp
0
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 1
30 mars 2011 à 14:18
Un miracle s'est produit..."aaaaah les nouilles"
Je crois que j'ai compris ce que tu veux dire, tu voudrais utiliser la structure du safearray peut etre ??
0
cs_andrebernard Messages postés 404 Date d'inscription lundi 9 juin 2003 Statut Membre Dernière intervention 4 septembre 2013 1
30 mars 2011 à 15:47
Aloooooors laaaaaa !!

Dire que c'est de la programmation bas niveau serait faire offense à ton code.
C'est la valse des empereurs des fonctions
Tout y passe "les prototrucs" que j'ai toujours qu'a moitié compris, les macros (Que j'utilise jamais), etc....
J'ai l'impression d'avoir jamais touché PB

C'est court, propre, parfait....comme j'ai rien compris, je vais y'aller au feeling.
Je suppose que tu va lire les renseignements du tableau créé par VB, puisque la DLL et VB partagent le meme espace ....

Et bin !!!!! t'es le jean paul gauthier de la prog
Je vais essayer de digérer ça

Mille merci de ta precieuse aide, je vous souhaite à tous les deux une excelente journée
0
Rejoignez-nous