10
votes

Array comme membre de classe

Je concevons un tampon dynamique pour les messages sortants. La structure de données prend la forme d'une file d'attente de nœuds disposant d'un tampon de réseau d'octets en tant que membre. Malheureusement, dans la VBA, les tableaux ne peuvent être membres d'une classe.

Par exemple, il s'agit d'un non-non et de ne pas compiler: xxx

Vous obtiendrez ce qui suit Erreur: "Constantes, chaînes de longueur fixe, tableaux, types définis par l'utilisateur et déclarations déclarations non autorisées en tant que membres du public de modules d'objets"

Eh bien, ça va, je vais juste en faire un membre privé avec Accessoires de propriété publique ... xxx

... et quelques tests dans un module pour vous assurer qu'il fonctionne: xxx

test n ° 1 fonctionne bien, mais test # 2 pauses, tampon est mis en surbrillance et le message d'erreur est "Nombre erroné d'arguments ou assignation de propriété non valide"

test n ° 2 fonctionne maintenant! GSERG souligne que pour appeler la propriété Obtenir la mémoire tampon () correctement et également faire référence à un index spécifique dans la mémoire tampon, deux ensembles de parenthèses sont nécessaires: Obuffer.buffer () (2)

Test n ° 3 échoue - La valeur d'origine de 3 est imprimée sur la fenêtre immédiate. Gserg a souligné dans son commentaire selon lequel la propriété publique Obtenir la mémoire tampon () ne renvoie qu'une copie et non le tableau des membres de la classe actuelle, de sorte que les modifications sont perdues.

Comment peut-on Ce troisième problème doit être résolu, rendre le tableau des membres de la classe fonctionne comme prévu?

(Je devrais clarifier que la question générale est "VBA ne permet pas aux tableaux d'être membres du public de classes . Comment puis-je contourner cela pour avoir un membre de la matrice d'une classe qui se comporte comme si c'était à toutes fins pratiques, notamment: # 1 attribuer à la matrice, n ° 2 Obtenir des valeurs de la matrice, n ° 3 Attribuant des valeurs dans le tableau et # 4 Utilisation du tableau directement dans un appel à CopyMemory (# 3 et # 4 sont presque équivalents)?) "


8 commentaires

J'ai rencontré ce problème lors de la création d'une structure de données pour faire tamponner les messages sortants pour certains code de réseautage. J'étais finalement capable de le résoudre, mais puisque je n'ai pas trouvé la question à ce sujet, je pensais que je l'ajouterais. Si quelqu'un connaît la réponse, n'hésitez pas à l'ajouter! Si quelqu'un d'autre l'obtient avant de pouvoir poster la réponse, je vais accepter.


Si vous vouliez réellement copier la matrice à chaque fois, vous avez oublié par parenthèses , obuffer.buffer () ( 2) . Sinon, vous voudrez peut-être avoir un look. ici .


@Gserg c'est la solution que j'ai réalisée - je pourrais faire quelque chose comme changer l'accessoir vers Propriété publique Obtenir la mémoire tampon (index aussi longtemps) que l'octet Si tout ce que je voulais faire était d'accéder à des articles individuels dans le tableau, mais Dans mon cas, je dois utiliser le tampon dans une déclaration CopyMemory , de sorte que cela ne fonctionnerait pas.


@Gserg je joue en fait avec la création de ma propre classe clsbytearray en utilisant heaphoc et heapfree pour contourner le fait que vba copie réseaux pour missions au lieu de le faire par référence. Savez-vous s'il existe une façon d'utiliser des variantes pour transmettre une référence du même tableau en mémoire? (le heaphoc et heapfree la méthode fuite si l'utilisateur clique sur le bouton d'arrêt du débogueur: '(Ce n'est donc pas mon premier choix pour une solution)


Vous pouvez Construire un descripteur de tableau sur les données existantes (d'autres arraches). Ou vous pouvez conserver le modèle accessoir, ajoutez simplement une autre propriété qui retournerait le pointeur (VARPTR) au premier membre du tableau, que vous pouvez ensuite passer à CopyMemory .


@Gserg drôle chose - je suis allé à upvote la réponse et j'ai réalisé que j'avais déjà fait déjà déjà fait à un moment donné dans le passé ... J'ai déjà un type de safearray que j'avais utilisé pour une fonction getdims . Je vais jouer avec ça. J'aime la suggestion d'utiliser une propriété pour simplement obtenir l'adresse de la matrice d'octet en mémoire, et je pense que je pourrais l'utiliser plutôt car il y aurait moins de risque de faire référence à la mémoire traitée. J'apprécie toute l'entrée! Si vous voulez copier / coller vos commentaires en une réponse, je peux accepter.


Que diriez-vous d'utiliser une méthode pour définir les valeurs SETValue (valeur BYVAL sous forme d'octet, index byval comme entier)


@ ja72 pire qu'un propriété que nous avons mentionnée ci-dessus.


3 Réponses :


0
votes

Pas la solution la plus élégante, mais la modélisation du code que vous avez fourni ...

dans Crstest: p> xxx pré>

et dans mdlmain: p>

Sub test()
Dim buf() As Byte
Dim bufnew() As Byte
Dim oBuffer As New clsTest

    ReDim buf(0 To 4)
    buf(0) = 1
    buf(1) = 2
    buf(2) = 3
    buf(3) = 4

    oBuffer.AssignArray vInput:=buf
    Debug.Print oBuffer.GetArrayValue(lItemNum:=2)

    oBuffer.AssignArray vInput:=27, lItemNum:=2
    Debug.Print oBuffer.GetArrayValue(lItemNum:=2)

    bufnew() = oBuffer.GetWholeArray
    Debug.Print bufnew(0)
    Debug.Print bufnew(1)
    Debug.Print bufnew(2)
    Debug.Print bufnew(3)

End Sub


1 commentaires

Désolé je suis allé si longtemps sans répondre! Le problème avec cette méthode est que bufnew () = obuffer.getwholarray () crée une copie de l'ensemble de la matrice. Cela pourrait ne pas sembler un gros problème, mais supposons que nous parlions d'un tableau de 2 Go ... cela serait sucer :(



2
votes

@blackhawk,

Je sais que c'est un ancien post, mais je pensais que je l'affaiterais de toute façon. p>

ci-dessous est un code que j'ai utilisé pour ajouter un tableau de points à une classe, je Utilisé une sous-classe pour définir les points individuels, il semble que votre défi est similaire: p>

MAINCLASS TCURVE strong> P>

Option Explicit

Private pSlope As Double
Private pCurvature As Double
Private pY As Variant
Private pdY As Double
Private pRadius As Double
Private pArcLen As Double
Private pChordLen As Double

Public Property Let Slope(Value As Double)
    pSlope = Value
End Property

Public Property Get Slope() As Double
    Slope = pSlope
End Property

Public Property Let Curvature(Value As Double)
    pCurvature = Value
End Property

Public Property Get Curvature() As Double
    Curvature = pCurvature
End Property

Public Property Let valY(Value As Double)
    pY = Value
End Property

Public Property Get valY() As Double
    valY = pY
End Property

Public Property Let Radius(Value As Double)
    pRadius = Value
End Property

Public Property Get Radius() As Double
    Radius = pRadius
End Property

Public Property Let ArcLen(Value As Double)
    pArcLen = Value
End Property

Public Property Get ArcLen() As Double
    ArcLen = pArcLen
End Property

Public Property Let ChordLen(Value As Double)
    pChordLen = Value
End Property

Public Property Get ChordLen() As Double
    ChordLen = pChordLen
End Property

Public Property Let dY(Value As Double)
    pdY = Value
End Property

Public Property Get dY() As Double
    dY = pdY
End Property


1 commentaires

Merci pour cela! Les fonctions accessoires que vous avez pour obtenir et définir des valeurs de remplissage définitivement les exigences n ° 2 et n ° 3, mais malheureusement, cela ne satisfait pas aux exigences n ° 1 (pouvoir définir le tampon entier directement d'un existant) et # 4 (être capable de Obtenez une référence directe au tampon afin que je puisse copymemory ()))



3
votes

Il s'avère donc que j'avais besoin d'un peu d'aide d'Oleaut32.dll, spécifiquement le 'varianteCopy' fonction. Cette fonction rend fidèlement une copie exacte d'une variante à une autre, y compris quand elle est BYREF! Em> xxx pré>

avec cette nouvelle définition, tous les tests passent! P >

'mdlMain

Public Sub Main()
    Dim buf() As Byte
    ReDim buf(0 To 4)

    buf(0) = 1
    buf(1) = 2
    buf(2) = 3
    buf(3) = 4


    Dim oBuffer As clsTest
    Set oBuffer = New clsTest

    'Test #1, the assignment
    oBuffer.Buffer = buf    'Success!

    'Test #2, get the value of an index in the array
    Debug.Print oBuffer.Buffer()(2)    'Success!  This is from GSerg's comment on the question

    'Test #3, change the value of an index in the array and verify that it is actually modified
    oBuffer.Buffer()(2) = 27
    Debug.Print oBuffer.Buffer()(2)  'Success! Diplays "27" in the immediate window
End Sub


0 commentaires