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

VBA Discussion :

Tableau de "pointeur"


Sujet :

VBA

  1. #1
    Membre régulier
    Inscrit en
    avril 2013
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2013
    Messages : 93
    Points : 77
    Points
    77
    Par défaut Tableau de "pointeur"
    Bonjour,

    J'utilise une dll c++ avec ces procédures.

    Est-ce qu'il est possible de passer entre le vba et le code C++ un tableau d'adresse au sens C++?

    Je voudrais que sur mon tableau à n dimensions j'ai dans chaque case l'adresse d'un autre tableau.

    Pour info, je fais ceci pour éviter d'avoir des problèmes mémoires lors de la déclaration de zones mémoires continues trop importantes.

    Si quelqu'un a des éléments de réponse je suis preneur.
    Je continue de chercher en attendant, mersi.

  2. #2
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    décembre 2012
    Messages
    1 026
    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 026
    Points : 1 893
    Points
    1 893
    Billets dans le blog
    5
    Par défaut
    bonjour,
    lance une petite recherche google sur VarPtrArray.
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  3. #3
    Membre régulier
    Inscrit en
    avril 2013
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2013
    Messages : 93
    Points : 77
    Points
    77
    Par défaut
    Merci pour la réponse.

    Il y a des choses intéressantes dessus.
    Etant donné que je suis pas un spécialiste du VBA, je me doute qu'il me manque des infos pour tout comprendre.

    J'ai fait cette petite routine pour tester:
    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
    Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Var() As Any) As Long
     
    Sub Test()
     
    Dim Array1(1 To 2) As Long
    Array1(1) = 11
    Array1(2) = 22
     
    Dim Address1 As Long
    Address1 = VarPtrArray(Array1)
     
    Dim Array2(1 To 2) As Long
    Array2(1) = 101
    Array2(2) = 202
     
    Dim Address2 As Long
    Address2 = VarPtrArray(Array2)
     
    Dim ArrayAddress(1 To 2) As Long
    ArrayAddress(1) = Address1
    ArrayAddress(2) = Address2
     
    'Fonction d'une dll c++ qui prend void* en parametre et qui retourne la somme des elements des tableaux
    Dim ret As Long
    ret = ArrayExample(ArrayAddress(1))
     
    End Sub
    Le problème c'est que j'ai ArrayAdress(1) = ArrayAdress(2). Du coup je dois mal faire quelque chose, mais quoi?


    La 2ème question est plus au niveau de la fonction c++ elle-même. Je n'arrive pas à récupérer mes données. Comment faire?

    Merci beaucoup

  4. #4
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    décembre 2012
    Messages
    1 026
    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 026
    Points : 1 893
    Points
    1 893
    Billets dans le blog
    5
    Par défaut
    bonsoir,
    en effet c'est un clou! Et si tu jetais un coup d'oeil ici: http://support.microsoft.com/kb/205277/fr,
    ou essayer cette astuce voir ce que ça donne sans passer par les adresses:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Dim ArrayAddress(1 To 2) As Variant
    ArrayAddress(1) = Array1
    ArrayAddress(2) = Array2
    J'ai entendu parler d'une allocation globale
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Private Declare Function GlobalAlloc Lib "kernel32.dll" ( _ 
    	 ByVal wFlags As Long, _ 
    	 ByVal dwBytes As Long) As Long
    pour contourner vb qui alloue dynamiquement de la mémoire pour les tableaux.
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  5. #5
    Membre régulier
    Inscrit en
    avril 2013
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2013
    Messages : 93
    Points : 77
    Points
    77
    Par défaut
    Grâce à tes liens j'ai pu avancer et je choisi l'option de prendre un tableau (SAFEARRAY) de structure personnalisée.

    J'ai trouvé un lien sympa: http://rp.developpez.com/vb/tutoriels/dll/#LXIII

    J'ai repris leur exemple et tout se passe bien.
    Du coup j'ai essayé d'adapter mais rien ne marche...

    code VBA:
    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
    Private Type data
        x() As Long
    End Type
     
    Sub Test()
     
    Dim elements(2 To 6) As data
     
     
    For i = 2 To 6
        ReDim elements(i).x(1 To 2)
    Next
     
    InitArray elements()
     
    End Sub
    code de la 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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    struct DATA {
        SAFEARRAY **x;
    } ;
     
    void __stdcall InitArray(SAFEARRAY **tableau)
    {
    	DATA *elt;
    	HRESULT ret;
    	unsigned long i;
     
    	if ((ret = SafeArrayAccessData(*tableau,(void **) &elt))==S_OK)
    	{
    		for (i = 0; i < (*tableau)->rgsabound->cElements; i++) 
    		{
    			int *tab;
    			if ((ret = SafeArrayAccessData(*(elt[i].x), (void **) &tab))==S_OK)
    			{
    				tab[0] = i*10 + 1;
    				tab[1] = i*10 + 2;
     
    				SafeArrayUnaccessData(*(elt[i].x));
    			}
    		} 
     
    		SafeArrayUnaccessData(*tableau);
    	} 
    }
    Par contre je n'arrive pas à récupérer le sous-tableau. J'ai une erreur sur le 2eme SafeArrayAccessData qui me dit qu'il ne peut pas locker elt[i].x.

    Je continue encore et toujours de trouver une solution dès que j'en ai le temps.

    Je te remercie déjà

  6. #6
    Membre chevronné
    Avatar de NVCfrm
    Homme Profil pro
    Administrateur Système/Réseaux - Developpeur - Consultant
    Inscrit en
    décembre 2012
    Messages
    1 026
    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 026
    Points : 1 893
    Points
    1 893
    Billets dans le blog
    5
    Par défaut
    bonsoir,

    je pense qu'il te faut commencer à bien assimiler la structure SafeArray.
    pas étonnant que tu écrases les variables références de tableau dans ton code.

    J'ai deux exemple simple adaptés d'un exemple du site msdn (je n'ai plus les liens) qui pourraient t'aider à traiter ton problème.
    Le premier exemple illustre l'utilisation de type défini, le deuxième l'utilisation de tableaux.

    code compilé Sous Visual 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
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    #include <windows.h>
    #include <ole2.h>
     
    #pragma pack(1)
     
    #define DLL_EXPORT __declspec(dllexport)
    #define STDCALL __stdcall
     
    typedef struct
    	{
    	short f1;
    	short filler_1;
    	long f2;
    	BYTE f3;
    	WCHAR f4;
    	BYTE filler_2;
    	float f5;
    } MyStruct;
     
     
    DLL_EXPORT void STDCALL FillUDTVariable(MyStruct * ms)
    {
    	ms->f1 = 2001;
    	ms->f2 = 20012001;
    	ms->f3 = 255;
    	ms->f4 = L'A';
    	ms->f5 = 200.1f;
    }
     
    DLL_EXPORT void STDCALL FillUDTSafeArray(LPSAFEARRAY FAR * ppsa)
    {
    	MyStruct * pdata;
    	unsigned int i;
    	pdata = (MyStruct*)((*ppsa)->pvData);
    	for (i = 0; i < ((*ppsa)->rgsabound->cElements); i++,pdata++)
    		FillUDTVariable(pdata);
    }
    La partie sous 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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    Type My_ArrayUDT
        F1 As Integer
        F2 As Long
        F3 As Byte
        F4 As String * 1
        F5 As Single
    End Type
     
    Private Declare Sub FillUDTVariable Lib "Modulo.DLL" _
        Alias "_FillUDTVariable@4" (A As My_VarUDT)
     
    Private Declare Sub FillUDTSafeArray Lib "Modulo.DLL" _
        Alias "_FillUDTSafeArray@4" (A() As My_ArrayUDT)
     
     
    Sub Test()
     
        Dim A As Long, B As My_VarUDT, C As String, D(3) As My_ArrayUDT
     
        Debug.Print "---Variable of My_VarUDT-------"
        FillUDTVariable B
     
        With B
            C = .F4
            Debug.Print .F1, .F2, .F3, C; "("; .F4(0); .F4(1); ")", .F5
        End With
     
        Debug.Print "---Safe array of My_ArrayUDT-------"
        FillUDTSafeArray D()
     
        For A = 0 To 3
            With D(A)
                Debug.Print .F1, .F2, .F3, .F4; "("; AscB(MidB(.F4, 1, 1));
                Debug.Print AscB(MidB(.F4, 2, 1)); ")", .F5
            End With
        Next A
     
    End Sub
    *******************************************
    Cet autre exemple
    le code compilé sous visual 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
    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
     
    #include <oleauto.h>
    #define EXPORT __declspec (dllexport)
    #define STDCALL __stdcall
    #define T_COUNT(t) (sizeof(t) / sizeof(t[0]))
     
       /**********************************************************
        SommeTableau - une fonction d'addition en pointeur 
    	(long *) classique du c
     
    	long *plAjout, pointeur du tableau
    	long lDims nb éléments du tableau
    	returns lSum: la somme des elements
       ***********************************************************/ 
     
    EXPORT long  STDCALL SommeTableau(
       long *plAjout, // pointeur du tableau
       long lDims) 
       {
          long lSum = 0;
          long i = 0;
     
          lSum = 0;
     
          if(lDims > 0)
          {
             for (; i < lDims; i++) 
    			 lSum = lSum + plAjout[i];
          }
          // returning
          return(lSum);
       }
     
       /*************************************************************************************
       Fonction: 
    		Somme_SafeArray 'Addition tableau de type long'
    			***Paramètres:***
    				SAFEARRAY **pTbl: tableau
    				long *lpSomme: renvoi la somme des éléments du tableau
     
    	Varaiables utilisées:
    		long lDims: nombre d'éléments du tableau
    		long countId: compteur dans la boucle
    		HRESULT lOleResult:  pour les codes retour de functions OLE
    		long *pTblElems: pointeur d'elements du SafeArray
     
       Code Renvoyé: 0  Réussite
                    <>0  Echec
       **************************************************************************************/ 
     
    EXPORT long STDCALL Somme_SafeArray(SAFEARRAY **pTbl, long *lpSomme)
    {
          long lDims;
          long countId;
          HRESULT lpOleResult; 
          long *pTblElems;
     
          *lpSomme = 0;
     
          if ( (*pTbl)->cDims != 1 ) return(1); // test dimensions
     
          if ( (*pTbl)->cbElements != 4 ) return(2); // test taille octect
     
          lDims=(*pTbl)->rgsabound[0].cElements;	// Nombre d'éléments
     
          lpOleResult = SafeArrayLock(*pTbl);	//verouillage du tableau
          if(lpOleResult)return(3);
     
          pTblElems=(long*) (*pTbl)->pvData;	// casting pour utiliser le tableau
          for (countId=0; countId < lDims; countId++)
             *lpSomme = *lpSomme + pTblElems[countId]; //addition des valeurs d'éléments du tableau dans lpSum
     
          lpOleResult=SafeArrayUnlock(*pTbl); // dévérouillage du tableau
          if (lpOleResult) return(4);
     
          return(0);
       }
    Tester sous vb ainsi après les déclarations d'Api
    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
     
    Private Sub SumArrayTest()
     
        Dim tblSomme(2) As Long
        Dim lSum As Long
        Dim k As Long
     
        tblSomme(0) = 1
        tblSomme(1) = 2
        tblSomme(2) = 3
     
        lSum = SommeTableau(tblSomme(0), UBound(tblSomme) + 1)
        Debug.Print "Somme avec pointeur tableau c classique:"; lSum
     
     
        lSum = 0
        k = Somme_SafeArray(tblSomme(), lSum)
        Debug.Print "Somme avec pointeur Safearray:"; lSum
     
    End Sub
    Ousmane


    Quand on tombe dans l'eau, la pluie ne fait plus peur.

  7. #7
    Membre régulier
    Inscrit en
    avril 2013
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2013
    Messages : 93
    Points : 77
    Points
    77
    Par défaut
    Je te remercie pour ton aide.

    Je n'arrive pas à faire ce que je veux avec tout ça.

    J'ai essayé de passer un tableau de structure ayant juste un tableau de double et sa taille comme variables.

    Avec la 1ère méthode et le LPSAFEARRAY FAR * j'arrive à parcourir le tableau de structure mais je suis bloqué quand il s'agit de toucher au tableau de la structure.

    J'ai pas l'impression que la 2ème méthode avec le SAFEARRAY ** soit utilisables dans mon cas car ej veux vraiment passer un tableaux de structure (la struct ayant un tableau dedans).

    Si jamais je trouve une solution, je la pousserai ici

    Merci pour tout.

  8. #8
    Membre régulier
    Inscrit en
    avril 2013
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : avril 2013
    Messages : 93
    Points : 77
    Points
    77
    Par défaut
    J'ai enfin réussi!!!

    Merci de ton aide

    Voilà le code:
    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
    struct DATA {
    	long *t;
    } ;
     
    MY_API void __stdcall InitArray(SAFEARRAY **tableau)
    {
    	DATA *elt;
    	HRESULT ret;
    	unsigned long i;
     
    	if ((ret = SafeArrayAccessData(*tableau,(void **) &elt))==S_OK)
    	{
    		for (i = 0; i < (*tableau)->rgsabound->cElements; i++) 
    		{
    			long *t;
    			if ((ret = SafeArrayAccessData((SAFEARRAY*)elt[i].t,(void **) &t))==S_OK)
    			{
     
    				for (int j = 0; j < 2; j++) 
    				{
    					t[j] = i * 10 + j;
    				}
     
    				SafeArrayUnaccessData(*tableau);
    			} 
     
    		} 
    		SafeArrayUnaccessData(*tableau);
    	} 
    }
    VBA:
    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
    Private Type data
        t() As Long
    End Type
     
    Private Declare Sub InitArray Lib "MYDLL.dll" (tableau() As data)
     
    Sub Test()
     
    Dim elements(2 To 6) As data, i As Long
     
    For i = 2 To 6
        ReDim elements(i).t(1 To 2)
    Next
     
    InitArray elements()
     
    End Sub

+ Répondre à la discussion
Cette discussion est résolue.

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