IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Macros et VBA Excel Discussion :

Function StrPtr(Ptr As String) As LongPtr - Comportement, documentation, explications


Sujet :

Macros et VBA Excel

  1. #1
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut Function StrPtr(Ptr As String) As LongPtr - Comportement, documentation, explications
    Bonjour,

    La fonction objet de ce sujet étant cachée par Microsoft, il n'existe pas de documentation à ce sujet.

    Après m'être un peu penché sur la question (doc unofficial), il s'agit d'une fonction créée pour réaliser des appels à la fonction Unicode (MyUnicodeCall de la librairie "MyUnicodeDll.Dll" par exemple).
    Ne possédant pas cette dll sur mon pc, je ne me suis pas encore documentée à son propos.

    Néanmoins, sans connaitre ses origines, la fonction StrPtr possède certaines "qualités" que je souhaite découvrir avec vous (mes tests n'étant pas toujours bien orientés...).

    A titre d’élargissement, il sera peut-être intéressant, en fin de topic, de se pencher sur ces consœurs VarPtr et ObjPtr.

    Je vais donc poser ma première question :
    Comment StrPtr fonctionne (en gros) ?
    [cette notion de pointeurs est encore hyper floue pour moi]

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Salut.

    Bonne idée, on pourra alimenter la faq...

    La fonction MyUnicodeCall.dll est prise en exemple dans le lien que tu cites, mais elle n'existe pas. Le nom utilisé est simplement là pour illustrer le code, on aurait pu tout aussi bien utiliser toto.dll...
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  3. #3
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Notion de pointeurs...
    Pas si simple.
    Cette image trouvée sur wikipédia :
    Pièce jointe 270758
    Nous indique que a est un pointeur vers la variable b.

    Si j'ai bien saisi, un pointeur est donc une variable contenant l'adresse d'une autre variable.
    C'est donc l'équivalant d'une variable passée ByRef dans une fonction?

    Si j'ai bien compris, donc, StrPtr renvoie le pointeur de la variable qu'on lui a passé, et, par conséquent, l'adresse de cette variable.
    Est ce cela?

    Si oui, cela expliquerait les résultats (curieux) de ce petit test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Sub AvecVbUnicode()
    Dim S As String, S1 As String, i As Integer
    For i = 1 To 10
        S = "": S1 = ""
        S = StrConv(S, vbFromUnicode)
        Debug.Print StrPtr(S) & " -- " & StrPtr(S1)
    Next
    End Sub
    résultats :
    202728940 -- 202827308
    202826908 -- 202728940
    202827308 -- 202826908
    202728940 -- 202827308
    202826908 -- 202728940
    202827308 -- 202826908
    202728940 -- 202827308
    202826908 -- 202728940
    202827308 -- 202826908
    202728940 -- 202827308
    On voit que les retours se "croisent"

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Si les pointeurs t'intéressent, tu peux aller faire un tour sur http://chgi.developpez.com/pointeur/ (C'est du C/C++, mais les notions sont là).
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  5. #5
    Invité
    Invité(e)
    Par défaut
    bonjour,
    les pointeur étaient la tasse de thé du langage C, le références elles sont apparues avec le C++!
    la différence est de taille.

    les référence pointe sur l'adresse de base d'un objet? disons que j'ai une un onglet Excel à l'adresse FFA625. set gonglet=FFA625 me donne accès à toutes le méthodes et propriété de l'onglet!

    si j'utilise un pointeur Onglet -> [FFA625: AA123456789] je me retrouve avec un tableau d'adresse mémoire équivalente à l'occupation mémoire de l'onglet en question!

    disons qu'un Integer fait 4 octet dim A as integer me retourne une référence la l'adresse base de [A] alors qu'un pointeur me retourne un table de 4 octets [Octets3],[Octets2],[Octets1],[Octets0]

    quand tu utilise mid(txt,10,1) tu utilise d'une certaine manière un pointeur sur un string a->txt[10]

  6. #6
    Expert confirmé
    Homme Profil pro
    aucune
    Inscrit en
    Avril 2016
    Messages
    7 563
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : aucune

    Informations forums :
    Inscription : Avril 2016
    Messages : 7 563
    Par défaut
    Salut
    Le mot "MyUnicodeCall.dll" n'est là que pour dire : toute fonction dont un ou plusieurs paramètres sont à être reçus sous forme de pointeur vers une chaîne unicode

    StrPtr permet l'obtention d'un pointeur vers une chaîne Unicode
    StrPtr est très utile pour passer par exemple et entre autres ses deux premiers paramètres à la fonction NetShareGetInfo de la librairie Netapi32.dll ****

    **** précisions que ces fonctions se contentaient jusqu'à NT de'un pointeur vers une chaîne ANSI.

  7. #7
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    @Pierre : merci!
    Lu et compris.
    Assimilé, on verra ça par la suite

    @dysorthographie :
    Bonjour Robert,
    Oui, en effet. Tout cela est d'ailleurs "aperçu" dans le lien de Pierre au chapitre 6.

    @Unparia :
    Bonjour Jacques,

    StrPtr permet l'obtention d'un pointeur vers une chaîne Unicode
    Cela signifie que StrPtr créé un pointeur vers la chaîne Unicode passée en paramètre et retourne un LngPtr.
    Ce LngPtr représente quoi? L'adresse du pointeur?
    C'est THE BIG question pour moi...
    Une fois cette question résolue (pour moi), on pourra voir ensemble des utilisations pratiques de cette fonction.

    StrPtr est très utile pour passer par exemple et entre autres ses deux premiers paramètres à la fonction NetShareGetInfo de la librairie Netapi32.dll
    Connais pas cette fonction. Vais me renseigner de suite...

  8. #8
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Bonjour,

    J'ai commencé les tests proposés par Jacques.
    N'hésitez surtout pas à critiquer vertement les tests si ceux-ci vous paraissent farfelus/stupides/inutiles.
    Merci d'avance.

    Tout d'abord le test sur des String "vides" :
    Soit a = vbNulString, b = "", et c variable String déclarée mais non alimentée.
    Peut-on faire la différence entre les 3?
    Et bien on peut différencier a et b, b et c, mais a et c sont identiques en tout point.
    Ce dernier test, entre a et c, nous permet tout de même de savoir/confirmer/établir (rayer les mentions inutiles) que, lors du dimensionnement d'une variable String, elle vaut vbNullString.

    Ce test, le voici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Sub StrPtr_vbNullString()
    Dim a As String, b As String, c As String
     
      a = vbNullString
      b = ""
      MsgBox ("la chaîne a est-elle """"égale"""" à la chaîne b ? ---> ") & (a = b) & vbCrLf & _
      "car a = " & """" & a & """" & " et que b = également " & """" & b & """"
      MsgBox ("la chaîne a est-elle """"égale"""" à la chaîne c ? ---> ") & (a = c) & vbCrLf & _
      "car a = " & """" & a & """" & " et que c = également " & """" & c & """"
      MsgBox ("strptr(a) est-il égal à strptr(b) ? ----> ") & (StrPtr(a) = StrPtr(b)) & vbCrLf & _
      "car strptr(a) retourne " & StrPtr(a) & " tandis que strptr(b) retourne " & StrPtr(b)
      MsgBox ("strptr(a) est-il égal à strptr(c) ? ----> ") & (StrPtr(a) = StrPtr(c)) & vbCrLf & _
      "car strptr(a) retourne " & StrPtr(a) & " et que strptr(c) retourne " & StrPtr(c)
      MsgBox ("... ET Logiquement... strptr(b) est-il égal à strptr(c) ? ----> ") & (StrPtr(b) = StrPtr(c)) & vbCrLf & _
      "car strptr(b) retourne " & StrPtr(b) & " tandis que strptr(c) retourne " & StrPtr(c)
    End Sub
    Je vais poursuivre avec les tests sur variable tableau.

  9. #9
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Bonjour Jacques,

    Ton second test proposé concerne les variables tableaux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Sub Test_Tablo()
        ReDim toto(1) As String
        Debug.Print StrPtr(toto(0))
        toto(0) = ""
        Debug.Print StrPtr(toto(0))
        ReDim Preserve toto(1)
        Debug.Print StrPtr(toto(0))
        ReDim toto(1)
        Debug.Print StrPtr(toto(0))
        toto(0) = ""
        Debug.Print StrPtr(toto(0))
    End Sub
    Ce test confirme pour moi le comportement de ReDim et du mot clé Preserve.
    On peut donc, si j'ai bien compris ce test, savoir, à tout moment d'un code dynamique, si le tableau est alimenté.
    Est ce bien cela l'objet du test?

    Lorsque toto(0) n'est pas alimenté (lignes 3 et 9), StrPtr(toto(0)) vaut toujours 0. Peut-on en conclure quelque chose?

    Une fois sur deux, les lignes 5, 7 et 11 donnent la même valeur pour StrPtr, la seconde fois les valeurs sont identiques pour les lignes 5 et 7 mais la 11 est différente?
    Comportement normal?

    J'ai donc voulu tester sur "plus grande échelle", comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    Sub Coll_String_Simple()
    Dim Coll As Collection
    Dim S As String
    Dim Msg As String
    Dim N As Long
    Dim I As Long
    Dim T As Single
     
    N = 100000
    Msg = "Nombre de tours de boucle : " & Format(N, "# ###")
     
    On Error Resume Next 'permet de zapper l'erreur de Coll.Add si la clé existe déjà
    '1er test :
        'Nombre de pointeurs pour la chaîne "a"
    Set Coll = New Collection
    T = Timer
    For I = 1 To N
        Coll.Add StrPtr("a"), CStr(StrPtr("a"))
    Next I
    Msg = Msg & vbCrLf & vbCrLf & "1er test : " & vbCrLf & _
        "Nombre de pointeurs pour la chaîne ""a"", sans passer par une variable" & vbCrLf & _
        "==> " & Coll.Count & " en " & Timer - T & " sec."
     
    '2nd test :
        'Nombre de pointeurs pour une chaîne vide (S non remplit)
    Set Coll = New Collection
    T = Timer
    For I = 1 To N
        Coll.Add StrPtr(S), CStr(StrPtr(S))
    Next I
    Msg = Msg & vbCrLf & vbCrLf & "2eme test : " & vbCrLf & _
        "Nombre de pointeurs pour une chaîne vide (variable S sans affectation de valeur)" & vbCrLf & _
        "==> " & Coll.Count & " en " & Timer - T & " sec."
     
    '3eme test :
        'Nombre de pointeurs pour la chaîne ""
        'la variable S est affectée de sa valeur une fois, avant la boucle
    Set Coll = New Collection
    T = Timer
    S = ""
    For I = 1 To N
        Coll.Add StrPtr(S), CStr(StrPtr(S))
    Next I
    Msg = Msg & vbCrLf & vbCrLf & "3eme test : " & vbCrLf & _
        "Nombre de pointeurs pour la chaîne """"" & vbCrLf & _
        "La variable S est affectée de sa valeur une fois, avant la boucle" & vbCrLf & _
        "==> " & Coll.Count & " en " & Timer - T & " sec."
     
    '4eme test :
        'Nombre de pointeurs pour la chaîne "a"
        'la variable S est affectée de sa valeur à chaque tour de boucle
    Set Coll = New Collection
    T = Timer
    For I = 1 To N
        S = "a"
        Coll.Add StrPtr(S), CStr(StrPtr(S))
    Next I
    Msg = Msg & vbCrLf & vbCrLf & "4eme test : " & vbCrLf & _
        "Nombre de pointeurs pour la chaîne ""a""" & vbCrLf & _
        "La variable S est affectée de sa valeur à chaque tour de boucle" & vbCrLf & _
        "==> " & Coll.Count & " en " & Timer - T & " sec."
     
    '5eme test :
        'Nombre de pointeurs pour la valeur 0
        'la variable S est affectée de sa valeur à chaque tour de boucle
    Set Coll = New Collection
    T = Timer
    For I = 1 To N
        S = 0
        Coll.Add StrPtr(S), CStr(StrPtr(S))
    Next I
    Msg = Msg & vbCrLf & vbCrLf & "5eme test : " & vbCrLf & _
        "Nombre de pointeurs pour la valeur 0" & vbCrLf & _
        "La variable S est affectée de sa valeur à chaque tour de boucle" & vbCrLf & _
        "==> " & Coll.Count & " en " & Timer - T & " sec."
     
    '6eme test :
        'Nombre de pointeurs pour la valeur 0
        'la variable S est affectée de sa valeur une fois, avant la boucle
    Set Coll = New Collection
    T = Timer
    S = 0
    For I = 1 To N
        Coll.Add StrPtr(S), CStr(StrPtr(S))
    Next I
    Msg = Msg & vbCrLf & vbCrLf & "6eme test : " & vbCrLf & _
        "Nombre de pointeurs pour la valeur 0" & vbCrLf & _
        "la variable S est affectée de sa valeur une fois, avant la boucle" & vbCrLf & _
        "==> " & Coll.Count & " en " & Timer - T & " sec."
     
    MsgBox Msg
    End Sub
    Est ce probant? Ce test nous apprend quelque chose?
    Cela semble confirmer le "une fois sur deux"...

  10. #10
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Pour être tout à fait honnête, je ne comprends pas encore l'intérêt de cette fonction, mis à part pour tester une variable String. Et donc, à part pour le contrôle d'une saisie utilisateur, je n'en vois pas trop le but.
    Je vais continuer à errer dans les tests, peut être que l'un d'entre eux me mettra sur une piste...

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 34
    Par défaut
    Bonjour,

    Si le sujet vous interpelle encore, il me semble que toute cette polémique autour de l'utilité et usage de StrPtr est résolue, entre autres sujets du même ordre, ici:
    https://docs.microsoft.com/fr-fr/off...ions-of-office

    @+
    Paolo

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 34
    Par défaut
    Il y a aussi le lien suivant, qui donne quelques informations utiles au fonctionnement entre varPtr et strPtr...
    https://renenyffenegger.ch/notes/dev...ons/xPtr/index

    Bonne continuation

    Paolo

  13. #13
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut
    Bonjour paoloadv, le forum,

    Si le sujet vous interpelle encore
    Interpeller est le bon mot.
    C'est un sujet qui n'attire pas les foules car la notion de pointeurs n'est pas utile dans 99% des codes VBA.
    Les pointeurs ne deviennent intéressant, à mon sens, que lors de l'appel d'API et, de fait, de portabilité des applications 32 bits <=> 64 bits.
    Pour ne pas "alourdir" inutilement cette réponse, je placerais les codes exemples trouvés sur le Net dans une seconde réponse...

    En ce qui concerne les fonctions, voici ce qu'il convient de savoir :
    Source principale : https://bytecomb.com/vba-internals-s...ters-in-depth/
    1. VarPtr :
      Retourne l'adresse de (pointe vers) la variable. Ce qui est stocké à cette adresse dépend du type de variable.
    2. StrPtr :
      • Prend explicitement un argument String.
        Si vous transmettez un autre type de donnée (Long par exemple), StrPtr va effectuer automatiquement une conversion et donc, votre pointeur "pointera" sur une chaîne créée temporairement et détruite au retour de cette fonction.
      • Effectue automatiquement une "redirection" et obtient l'adresse du 5ème octet d'un BSTR (La structure BSTR commence par un entier 32 bits qui indique la longueur (en octets) du tampon de caractères).
        A noter, toutefois, qu'il peut y avoir plusieurs "redirection", dans le cas ou la chaîne est stockée dans un Variant...
    3. ObjPtr :
      Obtient l'adresse de l'objet en mémoire. Comme avec StrPtr, cette fonction peut effectuer plusieurs niveaux de redirection si la variable est un Variant ByRef.
      La fonction prend un argument de type Unknown. Toute variable qui n'est pas un type d'objet déclenchera une erreur de compilation "incompatibilité de type".

    A noter : Il n'existe pas de fonction, en VBA, permettant l'obtention d'un pointeur vers une variable tableau.
    Pour réaliser cela, il convient d'utiliser l'API : Declare Function VarPtrArray Lib "msvbvm60" Alias "VarPtr" (arr() As Any) As Long

    A noter 2 : Il existe également la fonction de conversion CLngPtr qui convertit une expression simple en un type de données LongPtr.

    Parlons un peu de l'appel des apis.
    Certaines d'entre elles n'ont pas besoin de conversion 32-64 bits. Par exemple, l'api Beep fonctionne sans Pointeur ni Handle, qu'avec des arguments de type Long, et donc fonctionnera aussi bien sur les 2 systèmes.
    Declare PtrSafe Function Beep Lib "kernel32" Alias "Beep" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long****

    D'autres api, utilisant soit des pointeurs soit des Handle, ont besoin de conversion.
    C'est le cas de FindWindowExA (par exemple) (Cette fonction récupère un handle vers une fenêtre dont le nom de classe et le nom de fenêtre correspondent aux chaînes spécifiées. La fonction recherche les fenêtres enfants, en commençant par celle qui suit la fenêtre enfant spécifiée. cf : https://docs.microsoft.com/fr-fr/win...ectedfrom=MSDN)
    En 32 bits :
    Private Declare Function FindWindowEx Lib "USER32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
    En 64 bits :
    Private Declare PtrSafe Function FindWindowEx Lib "USER32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr

    Le type de données LongPtr est un Type de données "polymorphe", c'est à dire "qui est un type de données 4 octets sur les versions 32 bits et un type de données de 8 octets sur les versions 64 bits".

    Fort de tout ceci, je me demande à quoi sert la compilation conditionnelle...

    La fonction FindWindowExA, déclarée comme suit, fonctionnera sur les 2 systèmes, à condition de déclarer les variables "Handle" de type LongPtr.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Private Declare PtrSafe Function FindWindowEx Lib "USER32" _
                                      Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, _
                                       ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
     
    Sub Test()
    Dim hWndParent As LongPtr, sParentClassName As String
    Dim hWndChild As LongPtr, sChildClassName As String, sChildWindow As String

    **** L'attribut PtrSafe indique juste aux versions 64 bits que la fonction est "safe" pour les pointeurs et handle. Elle est facultative pour les versions 32 bits, mais ne gène en rien si elle est explicitement indiquée.

  14. #14
    Membre Expert
    Avatar de pijaku
    Homme Profil pro
    Inscrit en
    Août 2010
    Messages
    1 817
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Août 2010
    Messages : 1 817
    Billets dans le blog
    10
    Par défaut Codes de tests et d'exemples trouvés sur Internet
    Les codes suivants ne sont pas de moi, mais leurs auteurs sont tous référencés.
    Certains nécessitent des déclarations aux API. Je vous place donc en premier lieu l'entête du Module standard.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    'ENTETE
    Option Explicit
     
    Private Declare Sub PutMem4 Lib "msvbvm60.dll" (Destination As Any, Value As Any)
    Private Declare PtrSafe Function GetMem4 Lib "msvbvm60.dll" (ByVal addr As Long, ByRef retval As Any) As Long
    Private Declare Function VarPtrArray Lib "msvbvm60" Alias "VarPtr" (arr() As Any) As Long
    Private Declare Sub Mem_Copy Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Sub testPtr()
    Dim aPtr As LongPtr, bPtr As LongPtr, tempPtr As LongPtr, a As Long, b As Long, aRetval As Long, bRetval As Long, aL As Long, bL As Long, c As Long
        a = 1
        b = 2
        aPtr = VarPtr(a)
        bPtr = VarPtr(b)
        aL = GetMem4(aPtr, aRetval)
        bL = GetMem4(bPtr, bRetval)
        Debug.Print "La valeur pointée par aPtr est " & aRetval, "Pointée à l'adresse (CLngPtr(aPtr)) : " & CLngPtr(aPtr), "avec VarPtr(a) : " & VarPtr(a), "a = " & a
        Debug.Print "La valeur pointée par bPtr est " & bRetval, "Pointée à l'adresse (CLngPtr(bPtr)) : " & CLngPtr(bPtr), "avec VarPtr(b) : " & VarPtr(b), "b = " & b
        ' On échange les adresses pointées par aPtr et bPtr
        tempPtr = aPtr
        aPtr = bPtr
        bPtr = tempPtr
        aL = GetMem4(aPtr, aRetval)
        bL = GetMem4(bPtr, bRetval)
        Debug.Print "La valeur pointée par aPtr est " & aRetval, "Pointée à l'adresse (CLngPtr(aPtr)) : " & CLngPtr(aPtr), "avec VarPtr(a) : " & VarPtr(a), "a = " & a
        Debug.Print "La valeur pointée par bPtr est " & bRetval, "Pointée à l'adresse (CLngPtr(bPtr)) : " & CLngPtr(bPtr), "avec VarPtr(b) : " & VarPtr(b), "b = " & b
    End Sub

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    Sub StringPointerExample()
    'https://bytecomb.com/vba-scalar-variables-and-pointers-in-depth/
    ' Platform-independent method to return the full zero-padded
    ' hexadecimal representation of a pointer value
    Const PTR_LENGTH As Long = 4
    Dim strVar As String, ptrVar As LongPtr, ptrBSTR As LongPtr
        strVar = "Hello"
        ptrVar = VarPtr(strVar)
        Mem_Copy ptrBSTR, ByVal ptrVar, PTR_LENGTH
        Debug.Print "ptrVar  : 0x"; HexPtr(ptrVar, PTR_LENGTH); _
                           " : 0x"; Mem_ReadHex(ptrVar, PTR_LENGTH)
        Debug.Print "ptrBSTR : 0x"; HexPtr(ptrBSTR, PTR_LENGTH)
        Debug.Print "StrPtr(): 0x"; HexPtr(StrPtr(strVar), PTR_LENGTH)
        Debug.Print "Memory  : 0x"; Mem_ReadHex(ptrBSTR - 4, LenB(strVar) + 6)
    End Sub
    Function HexPtr(ByVal Ptr As LongPtr, PTR_LENGTH As Long) As String
        HexPtr = Hex$(Ptr)
        HexPtr = String$((PTR_LENGTH * 2) - Len(HexPtr), "0") & HexPtr
    End Function
    Function Mem_ReadHex(ByVal Ptr As LongPtr, ByVal Length As Long) As String
        Dim bBuffer() As Byte, strBytes() As String, i As Long, ub As Long, b As Byte
        ub = Length - 1
        ReDim bBuffer(ub)
        ReDim strBytes(ub)
        Mem_Copy bBuffer(0), ByVal Ptr, Length
        For i = 0 To ub
            b = bBuffer(i)
            strBytes(i) = IIf(b < 16, "0", "") & Hex$(b)
        Next
        Mem_ReadHex = Join(strBytes, "")
    End Function
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    Sub PtrExample()
    'https://bytecomb.com/vba-internals-getting-pointers/
    Dim lLong As Long, sString As String, oCollection As Collection, aDoubles(10) As Double, vDate As Variant
    Dim ptrToLong As LongPtr, ptrToStringVar As LongPtr, ptrToBSTR As LongPtr, ptrToObjVar As LongPtr, ptrToObject As LongPtr
    Dim ptrToArray As LongPtr, ptrToArrayData As LongPtr, ptrToVarVar As LongPtr, ptrToDate As LongPtr
        lLong = 42
        sString = "Hello"
        Set oCollection = New Collection
        aDoubles(0) = 3.14159
        vDate = Now
        ' Pointer to Long variable, which is also the actual Long value
        ptrToLong = VarPtr(lLong)
        Debug.Print "VarPtr(lLong) : " & ptrToLong
        ' Pointer to String variable
        ptrToStringVar = VarPtr(sString)
        Debug.Print "VarPtr(sString) : " & ptrToStringVar
        ' Pointer to actual string content
        ptrToBSTR = StrPtr(sString)
        Debug.Print "StrPtr(sString) : " & ptrToBSTR
        ' Pointer to Object variable
        ptrToObjVar = VarPtr(oCollection)
        Debug.Print "VarPtr(oCollection) : " & ptrToObjVar
        ' Pointer to actual object in memory
        ptrToObject = ObjPtr(oCollection)
        Debug.Print "ObjPtr(oCollection) : " & ptrToObject
        ' Pointer to array variable
        ptrToArray = VarPtrArray(aDoubles)
        Debug.Print "VarPtrArray(aDoubles) : " & ptrToArray
        ' Pointer to the start of the actual array content
        ptrToArrayData = VarPtr(aDoubles(0))
        Debug.Print "VarPtr(aDoubles(0)) : " & ptrToArrayData
        ptrToArrayData = VarPtr(aDoubles(10))
        Debug.Print "VarPtr(aDoubles(10)) : " & ptrToArrayData
        ' Pointer to Variant variable
        ptrToVarVar = VarPtr(vDate)
        Debug.Print "VarPtr(vDate) : " & ptrToVarVar
        ' Pointer to actual Date value, at offset 8 of VARIANT struct
        ptrToDate = ptrToVarVar + 8
        Debug.Print "ptrToVarVar + 8 (ptrToDate) : " & ptrToDate
    End Sub

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    Sub main() ' {https://renenyffenegger.ch/notes/development/languages/VBA/functions/xPtr/index
    Dim long_1 As Long, long_2 As Long, addr_1 As LongPtr, addr_2 As LongPtr, val_addr_1 As LongPtr, val_addr_2 As LongPtr
    Dim L_1 As Long, L_2 As Long
        long_1 = 12345678
        long_2 = 42
      ' Determine the addresses of long_1 and long_2:
        addr_1 = VarPtr(long_1)
        addr_2 = VarPtr(long_2)
      ' The addresses are 4 bytes apart and decreasing. Apparently,
      ' they're allocated on the stack:
        Debug.Print "addr_1 = " & addr_1
        Debug.Print "addr_2 = " & addr_2
      ' Get the value in memory that the addresses of the
      ' variables point at:
        L_1 = GetMem4(addr_1, val_addr_1)
        L_2 = GetMem4(addr_2, val_addr_2)
      ' Not surprisingly, these values correspond to the
      ' values that were assigned to the variables:
        Debug.Print "val_addr_1 = " & val_addr_1, "L_1 = " & L_1
        Debug.Print "val_addr_2 = " & val_addr_2, "L_2 = " & L_2
      ' Manipulate the memory that the addresses point at:
        PutMem4 addr_1, 123
      ' Get the value in memory
        val_addr_1 = GetMem4(addr_1, long_1)
      ' Manipulate the memory that the addresses point at:
        PutMem4 addr_2, 456
      ' Get the value in memory
        val_addr_2 = GetMem4(addr_2, long_2)
      ' The values of the variables were changed:
        Debug.Print "long_1 = " & long_1 ' 123
        Debug.Print "long_2 = " & long_2 ' 456
    End Sub ' }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    Sub DarkVader1()
    'https://www.developpez.net/forums/d870138/autres-langages/general-visual-basic-6-vbscript/vb-6-anterieur/trucs-astuces-quelques-observations-varptr-and-co/
    'Une adresse unique par espace de stockage - 2,4 ou 8 octets - String fixe ou non à part
    'Stockage par id dentique aux énumérations !?
    'Peut-être une voie pour modifier une constante en cours d'exécution ?
        Const k1  As Byte = 1
        Const k2 As Long = 2
        Const k3 As Double = 3
        Const k4 As Double = 3
        Const k5 As Integer = 3
        Const k6 As Long = 3
        Const k7 As String * 2 = "3"
        Const k8 As String = "3"
        Const k9 As String = "3"
        Const k10  As Byte = 155
     
        Debug.Print "Const k1 As Byte", VarPtr(k1)
        Debug.Print "Const k2 As Long", VarPtr(k2)
        Debug.Print "Const k3 As Double", VarPtr(k3)
        Debug.Print "Const k4 As Double", VarPtr(k4)
        Debug.Print "Const k5 As Integer", VarPtr(k5)
        Debug.Print "Const k6 As Long", VarPtr(k6)
        Debug.Print "Const k7 As String *", VarPtr(k7)
        Debug.Print "Const k8 As String", VarPtr(k8)
        Debug.Print "Const k9 As String", VarPtr(k9)
        Debug.Print "Const k10 As Byte", VarPtr(k10)
    End Sub
    Sub DarkVader2()
    'RAS : 2 adresses différentes pointant sur un SAFEARRAY
    Dim myTab1() As Long, myTab2() As Long
        ReDim myTab1(5)
        ReDim myTab2(5)
        Debug.Print VarPtrArray(myTab1())
        Debug.Print VarPtrArray(myTab2())
    End Sub
    Sub DarkVader3()
    'Comportement inattendu : Une adresse unique pour tous les tableaux quelquesoit le type !!!
    'Eviter d'utiliser les pointeurs sur les tableaux prédimensionnés semble de bon sens ou utiliser des tableaux redimensionnables.
    Dim t1(5) As Integer, t2(1) As Long, t3(1) As Byte, t4(1) As Single, t5(1) As Double, t6(1) As Long, t7(1) As Integer
        Debug.Print "t1(5) As Int", VarPtrArray(t1())
        Debug.Print "t2(1) As Lng", VarPtrArray(t2())
        Debug.Print "t3(1) As Byt", VarPtrArray(t3())
        Debug.Print "t4(1) As Sng", VarPtrArray(t4())
        Debug.Print "t5(1) As Dbl", VarPtrArray(t5())
        Debug.Print "t6(1) As Lng", VarPtrArray(t6())
        Debug.Print "t7(1) As Int", VarPtrArray(t7())
    End Sub
    Sub DarkVader4()
    Dim myTab1() As Long, myTab2() As Long, nn1 As Long, nn2 As Long
        ReDim myTab1(5) As Long
        ReDim myTab2(5, 2) As Long
        nn1 = Not (Not myTab1())
        nn2 = Not (Not myTab2())
        Debug.Print "Pointeur NotNot(myTab1()) nn1 : " & Format(nn1, "00 000 000"), "( <>" & VarPtrArray(myTab1()) & ")"
        Debug.Print "Pointeur NotNot(myTab2()) nn2 : " & Format(nn2, "00 000 000"), "( <>" & VarPtrArray(myTab2()) & ")"
     
    Dim headerInfos1(1) As Integer, headerInfos2(1) As Integer
    ' Copier uniquement les données voulues (mais cela pourrait-être l'intégralité d'un safearray)
        If nn1 Then GetMem4 nn1, headerInfos1(0)
        If nn2 Then GetMem4 nn2, headerInfos2(0)
        Debug.Print "Le tableau1 a " & headerInfos1(0) & " dim"
        Debug.Print "Le tableau2 a " & headerInfos2(0) & " dim"
    End Sub
    Sub DarkVader5()
    Dim t1(1) As Long, t2(2) As Long, ptr1 As Long, ptr2 As Long, adr1 As Long, adr2 As Long
    'Si le pointeur d'un tableau fixe est commun à tous les tableaux,
    ' chaque tableau fixe est évidemment stocké à une adresse différente (encore heureux).
    ' Il importe donc de récupérer l'adresse et non le pointeur dans les cas particuliers énumérés précédemment.
        ptr1 = VarPtrArray(t1())
        ptr2 = VarPtrArray(t2())
        GetMem4 ByVal ptr1, adr1
        GetMem4 ByVal ptr2, adr2
        Debug.Print ptr1, adr1
        Debug.Print ptr2, adr2
        ' UTILISATION CORRECTE
        ptr1 = VarPtrArray(t1())
        GetMem4 ByVal ptr1, adr1
        ptr2 = VarPtrArray(t2())
        GetMem4 ByVal ptr2, adr2
        Debug.Print ptr1, adr1
        Debug.Print ptr2, adr2
    End Sub
    Sub DarkVader6()
    Dim s As String, o As Object, ptrS As Long, ptrO As Long, ptrd As Long, ptrS2 As Long
    Dim d As Object, toto As String
        toto = "toto"
        Set d = CreateObject("Scripting.Dictionary")
        ptrS = StrPtr(s)
        ptrS2 = StrPtr(toto)
        ptrO = ObjPtr(o)
        ptrd = ObjPtr(d)
        Debug.Print ptrS2, ptrS, ptrO, ptrd
    End Sub
    Bon amusement!

Discussions similaires

  1. [String] Comportement bizarre
    Par michaeljeru dans le forum SL & STL
    Réponses: 4
    Dernier message: 27/01/2008, 18h37
  2. probleme de retour de string dans une function
    Par the_magik_mushroom dans le forum Langage
    Réponses: 3
    Dernier message: 07/08/2007, 03h19
  3. [Dates] date string function
    Par taffMan dans le forum Langage
    Réponses: 4
    Dernier message: 28/09/2006, 14h17
  4. Passer un String en parametre a une "function"
    Par ze veritable farf dans le forum Général JavaScript
    Réponses: 12
    Dernier message: 28/08/2006, 12h26
  5. function stripslashes() avec des string
    Par rigel dans le forum Langage
    Réponses: 2
    Dernier message: 04/07/2006, 08h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo