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

VB 6 et antérieur Discussion :

Passer un tableau de string à un dll c++


Sujet :

VB 6 et antérieur

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 14
    Points : 7
    Points
    7
    Par défaut Passer un tableau de string à un dll c++
    Bonjour a tous,
    Je voudrais passer un tableau de string à une dll, en gros :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Private Declare Function MyFuntion_dll Lib "MyDll"(ByVal aFile as String, ByRef rTabId() as String) as long
    Sub MyMacro
    Dim i as long
    Dim lFileName as String 
    Dim lTabRetourString(10) as String
    lFileName="C:\Users\.. \MyFile.csv"
    i=MyFunction_dll(lFileName,lTabRetourString)
    ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int __stdcall MyFunction_dll(BSTR aStringFile, SAFEARRAY** rStringTabId)
    {...}
    mais dans la dll le type BSTR ne ramène pas du tout le string du VB et si je fais un SysAllocString(OLESTR("hello")) sur mon SAFEARRAY, l'execution crash.

    D'après le tuto http://rp.developpez.com/vb/tutoriels/dll/#LXII il parle de récupérer le string VB dans la dll via un char*, ce qui marche en effet, mais dès qu'il sagit d'un tableau, le type de string ne peut être qu'un BSTR, ce qui ne marche pas du tout dans mon cas.
    Par ailleurs je suis tombé là dessus sur le cite de microsoft http://support.microsoft.com/kb/145727/en-us :
    Visual Basic, like Windows NT and Windows 2000, is based internally on the double-byte Unicode standard. However, Visual Basic assumes that the world outside of itself still uses the single-byte ANSI model. Any strings passed as parameters to an external function will be converted by Visual Basic from their internal Unicode representation to an ANSI representation before the call to the function is made. In the same way, all strings that return to Visual Basic from an external function are assumed to be in an ANSI representation, and Visual Basic will attempt to make the conversion to a Unicode representation for internal use. This behavior makes it impossible to call an external function that expects or returns a Unicode string in the same way as a function that deals only with ANSI strings.
    Du coup y-at-il vraiment une solution pour passer un tableau de string vers une dll sans utiliser la techno COM. juste avec une dll compilée sous visual c++ ?
    Merci pour votre aide

  2. #2
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    Décembre 2012
    Messages
    1 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Administrateur Système/Réseaux - Developpeur - Consultant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2012
    Messages : 1 037
    Points : 1 925
    Points
    1 925
    Billets dans le blog
    5
    Par défaut
    Bonsoir,
    il me semble la taille des éléments de ton tableau, sont de longueur nulle.

  3. #3
    Rédacteur
    Avatar de DarkVader
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    2 130
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 130
    Points : 3 118
    Points
    3 118
    Par défaut
    Bonjour,
    1/ Pourquoi ne pas passer un tableau non prédimentionné que la fonction myFunction_dll formatera elle-même
    tout en retournant un long indiquant le nb d'éléments dans le tableau ?
    2/ plutôt que SysAllocString, je préfère SysAllocStringByteLen ...
    3/ en supposant que tu ne parviennes pas à passer un tableau de String en retour,
    à défaut, pourquoi ne pas retourner un tableau des adresses et le reconstruire coté vb ?

    Question annexe : si j'ai bien compris le tableau de string n'est pas transmis à la Dll c++ mais c'est la dll c++ qui le retourne vers vb ?

  4. #4
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    Décembre 2012
    Messages
    1 037
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : Administrateur Système/Réseaux - Developpeur - Consultant
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Décembre 2012
    Messages : 1 037
    Points : 1 925
    Points
    1 925
    Billets dans le blog
    5
    Par défaut
    bonjour,
    Du coup y-at-il vraiment une solution pour passer un tableau de string vers une dll sans utiliser la techno COM. juste avec une dll compilée sous visual c++ ?
    Un petit rappel des bases sur les chaînes de caractères.
    Les chaînes schématiquement sont une suite de caractères. Donc un tableau d'octects pointant sur un tableau de valeurs constantes.
    Mystring1 = | 'B' | 'o' | 'n' |' j' | 'o' | 'u' |'r' |'\0' |
    Mystring2 = |'\0' |
    La longueur de ces 2 variables est déterminée par la convention de fin de chaîne.
    MyString1 est d'une longueur de 7 octects pour 8 éléments alors que MyString2 est de longueur 0 pour 1 élément.

    La notion de pointeur étant bien masquée en VB, on a tendance à oublier que les deux variables sont en fait des pointeurs auxquels vb alloue de la place dynamiquement.
    Si tu vois déjà ce que aaveux mettre en évidence, tu devrais programmer en tenant compte de ces caractéristiques.

    En passant ByVal MyString2 à une fonction dll qui n'interprète pas la convention de fin chaîne, pour qu'elle y écrive "Hello", le résultat sera tout simplement un débordement de tampon, car MyString2 ne contient pas assez de place pour ces 5 caractères.
    La valeur de MyString2 est en fait un tableau soit un "pointeur déguisé", sur les constantes Unicode que VB convertira par défaut en pointeur sur la table ASCI, avant la transmission.

    Si tu as bien suivi cela, tu déduiras donc que ByVal transmet tout court une référence pointant sur le premier élément de la suite de caractères où ta fonction c va écrire ou lire les valeurs de ce pointeur.
    Sous Vb il te faut impérativement dimensionner les éléments de ton tableau à la longueur utile avant la transmission.
    Il te faudra donc juste pouvoir faire les déréférencement corrects **

    C'est assez brut comme explications. Je crois que c'est assez suffisant pour imaginer la technique qu'il faut, pour faire ce que tu veux avec les chaînes, sans passer par la techno com.

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 14
    Points : 7
    Points
    7
    Par défaut
    Désolé pour l'absence du week-end. Merci beaucoup pour les réponses.
    Oui il s'agit bien de récupérer un tableau de string vers mon VB, mais si je peux le faire dans un sens, je pense que c'est facile dans l'autre.
    Si je veux passer un vecteur de string du vb vers la Dll, je n'arrive jamais à récupérer une séquence ordonnée par des [] de pointeur char* dans la dll. Inversement, si j'ai une séquence de char*, je ne récupère jamais de vecteur string() en VB...

    Une solution si je comprends bien serait de passer un seule chaine du genre :
    |'Element1'|'\0'|'Element2'|'\0'|'Element3'|'\0'|'Element4'|'\0'|...Et de reconstruire le vecteur.

    Mais avec cette méthode, comme je dois passer des vecteurs assez gros (>1 000 000) j'ai peur du crash mémoire.

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Août 2006
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 14
    Points : 7
    Points
    7
    Par défaut
    Bon, sur vos conseils, j'écris une solution qui marche pour ceux que ça pourrait intéresser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Private Declare Function MyFuntion_dll Lib "MyDll"(ByVal aFile as String, ByVal rConcatTabId as String) as Long
    Sub MyMacro
       Dim lTabSize as long
       Dim lFileName as String 
       Dim lRetourConcatString as String
       Dim lRetourTabString() as String
       Dim MaxTabSize as Long =1000000
       lFileName="C:\Users\.. \MyFile.csv"
       'Je sais que mon tableau de string comporte au max 1 million d'éléments de chaine de longueur max 32
       lRetourConcatString = Space$(32 * MaxTabSize)
       lTabSize=MyFunction_dll(lFileName,lRetourConcatString)
       Redim lRetourTabString(lTabSize+1)
       lRetourTabString = Split(lRetourConcatString, ";")
    end
    Et coté dll C++
    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
     
    int __stdcall MyFunction_dll(LPTR aStringFile, LPSTR rStringConcat)
    {  //LPSTR est typedef char*
        std::string lConcat;
        std::string lSemiColn=";";
        i=1;
        while(..)
        {
            if(..)
            {
    	    lConcat+=MyStdStringList[i];
    	    lConcat+=lSemiColn;
    	    i++;
            }
        }
        strcpy_s(rStringConcat, lConcat.size()+1, lConcat._Myptr());
        return i;
    }

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Avec l'inconvénient, bien sûr, de ne supporter que l'ASCII étendu (le plus souvent Windows-1252), pas d'unicode.

  8. #8
    Rédacteur
    Avatar de DarkVader
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    2 130
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 130
    Points : 3 118
    Points
    3 118
    Par défaut
    En quoi la solution proposée ne te convient pas ?

    Coté dll C:
    remplissage du tableau de pointeur à l'aide de sysallocstringlen
    ptrMyArray contient l'adresse du 1er élément du tableau
    et la fonction retourne le nombre d'éléments du tableau

    Coté VB
    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
    Private Declare Function returnArrayString Lib "myDll" (ByRef ptrMyArray As Long) As Long
     
        Private Declare Function CopyString Lib "kernel32" Alias "lstrcpyA" (ByVal NewString As String, oldString As Long) As Long
        Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Long) As Long
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
     
        Private Sub Command1_Click()
            Dim myArray() As String, nItem As Long, ptr As Long, x As Long, length As Long, ptrS As Long
     
            Me.Cls
     
            nItem = returnArrayString(ptr)
            ReDim myArray(0 To nItem - 1)
     
            For x = 1 To nItem
                'Recup strptr
                CopyMemory ptrS, ByVal ptr + (4 * (x - 1)), 4
     
                ' restaure
                length = lstrlen(ptrS)
                myArray(x - 1) = Space(length)
                CopyString myArray(x - 1), ByVal ptrS
     
                    Me.Print x, myArray(x - 1)
            Next
        End Sub

  9. #9
    Membre éprouvé
    Inscrit en
    Juin 2006
    Messages
    795
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 795
    Points : 1 270
    Points
    1 270
    Par défaut
    Salut marcus7,

    pour passer un tableau de String de Vb6 à une dll c++, du côté Vb6 il ne faut pas déclarer le paramètre en tant que tableau de String mais long.
    En fait, on ne donne qu'un long car on va passer le pointeur du tableau à la dll grace à la fonction VarPtrStringArray.
    Comme un exemple vaut mieux qu'une explication pas claire du tout :
    Côté dll C++ (ça c'était déjà bon...)
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int __stdcall MyFunction_dll(BSTR aStringFile, SAFEARRAY** rStringTabId)
    {...}

    côté VB6
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Private Declare Function MyFuntion_dll Lib "MyDll" (ByVal aFile As String, ByVal AddrTabId As Long) As Long
     
     
    Sub MyMacro()
    Dim i As Long
    Dim lFileName As String
    Dim lTabRetourString(10) As String
    lFileName = "C:\Users\.. \MyFile.csv"
    i = MyFunction_dll(lFileName, VarPtrStringArray(lTabRetourString))
    '...
    PS: comment fait-on pour avoir la coloration syntaxique dans la balise code ?

  10. #10
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Normalement pour la langue tu la rajoutes dans la balise CODE, genre [ CODE=VB ] ou [ CODE=C++ ] (sans les espace, bien sûr).

    Donc si j'ai bien compris ton message, VarPtrStringArray() permet de passer le SAFEARRAY de BSTR sans que Visual Basic le convertisse en Windows-1252?
    Est-il possible d'avoir la même chose pour les strings?

  11. #11
    Membre éprouvé
    Inscrit en
    Juin 2006
    Messages
    795
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 795
    Points : 1 270
    Points
    1 270
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Normalement pour la langue tu la rajoutes dans la balise CODE, genre [ CODE=VB ] ou [ CODE=C++ ] (sans les espace, bien sûr).

    Donc si j'ai bien compris ton message, VarPtrStringArray() permet de passer le SAFEARRAY de BSTR sans que Visual Basic le convertisse en Windows-1252?
    Est-il possible d'avoir la même chose pour les strings?
    Exactement !
    Pour passer une seule string et non pas un string array, il faut faire tout pareil* sauf qu'au lieu d'utiliser VarPtrStringArray(monTableauDeChaines), il faut faire VarPtr(maChaine).

    *enfin pas tout à fait, la dll c++ reçoit alors un BSTR *.



    Edit: C'est un honneur pour moi de pouvoir te venir en aide !! (pour le nombre de fois où tes posts mon aidés !!!!)
    Je n'aurais jamais cru cela possible. Enfin ça ne reste qu'une astuce pour du Vb6.
    Pour du C++, c'est une autre paire de manches.

  12. #12
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Ah, j'ai fini par trouver une page qui résume tout:
    How To Get the Address of Variables in Visual Basic

Discussions similaires

  1. Réponses: 6
    Dernier message: 18/11/2012, 15h01
  2. SAFEARRAY tableau de strings, DLL et VBA
    Par beafrancky dans le forum Débuter
    Réponses: 4
    Dernier message: 20/07/2009, 07h42
  3. Réponses: 5
    Dernier message: 27/03/2008, 14h32
  4. Passer Tableau de String à une procedure.
    Par JFKen dans le forum Access
    Réponses: 3
    Dernier message: 02/08/2006, 16h26

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