Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.90/20: Рейтинг темы: голосов - 20, средняя оценка - 4.90
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79

А вы задумывались как работает коллекция в VB6?

31.08.2016, 23:36. Показов 5557. Ответов 29
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет.
Решил пореверсить коллекции. Выяснилось что это двоичное дерево, все смещения в классах соответствуют смещениям в оригинальной коллекции (можете заменять на структуры и смело обращаться по указателю, меняя данные). Реализованы не все методы, но для понимания алгоритма работы - это не требуется.
Сама коллекция CVBCollection:
Visual Basic
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
' //
' // Native VB collection
' // Decompiled by The trick
' //
 
Option Explicit
 
Private Const DISP_E_PARAMNOTFOUND        As Long = &H80020004
Private Const CTL_E_ILLEGALFUNCTIONCALL   As Long = &H800A0005
Private Const DISP_E_OVERFLOW             As Long = &H8002000A
Private Const E_OUTOFMEMORY               As Long = &H8007000E
 
Public pInterface1         As IUnknown            ' // 0x00
Public pInterface2         As IUnknown            ' // 0x04
Public pInterface3         As IUnknown            ' // 0x08
Public lRefCounter         As Long                ' // 0x0C
Public lNumOfItems         As Long                ' // 0x10
Public pvUnk1              As Long                ' // 0x14
Public pFirstIndexedItem   As CVBCollectionItem   ' // 0x18
Public pLastIndexedItem    As CVBCollectionItem   ' // 0x1C
Public pvUnk4              As Long                ' // 0x20
Public pFirstItem          As CVBCollectionItem   ' // 0x24
Public pRootItem           As CVBCollectionItem   ' // 0x28
Public pvUnk5              As Long                ' // 0x2C
 
' // Get item
Public Property Get Item( _
                    ByRef vKeyIndex As Variant) As Variant
    Dim hr      As Long
    Dim pItem   As CVBCollectionItem
    
    hr = GetItemByKey(vKeyIndex, pItem)
    
    If hr < 0 Then
        Err.Raise hr
        Exit Property
    End If
    
    If IsObject(pItem.vtItem) Then
        Set Item = pItem.vtItem
    Else
        Item = pItem.vtItem
    End If
    
End Property
 
' // Add item to collection
Public Sub Add( _
           ByRef vItem As Variant, _
           Optional ByRef vKey As Variant, _
           Optional ByRef vBefore As Variant, _
           Optional ByRef vAfter As Variant)
    Dim bIsEmptyKey     As Boolean
    Dim bIsEmptyBefore  As Boolean
    Dim bIsEmptyAfter   As Boolean
    Dim vIndex          As Variant
    Dim pNewItem        As CVBCollectionItem
    Dim pItem           As CVBCollectionItem
    Dim pTempItem       As CVBCollectionItem
    Dim bstrKey         As String
    Dim hr              As Long
    
    bIsEmptyKey = IsMissingParam(vKey)
    bIsEmptyBefore = IsMissingParam(vBefore)
    bIsEmptyAfter = IsMissingParam(vAfter)
    
    If bIsEmptyBefore Then
        If Not bIsEmptyAfter Then
            vIndex = vAfter
        End If
    Else
        If Not bIsEmptyAfter Then
            Err.Raise CTL_E_ILLEGALFUNCTIONCALL
            Exit Sub
        End If
        vIndex = vBefore
    End If
    
    If lNumOfItems < 0 Then
        Err.Raise DISP_E_OVERFLOW
        Exit Sub
    End If
    
    If bIsEmptyKey Then
        Set pNewItem = New CVBCollectionItem
    Else
        
        hr = GetItemByKey(vKey, pNewItem)
        If hr >= 0 Then
            Err.Raise &H800A01C9
            Exit Sub
        End If
        
        ' // 48
        Set pNewItem = New CVBCollectionItem
        
        bstrKey = BSTRKeyFromVariant(vKey)
        
        If Len(bstrKey) = 0 Then
            Err.Raise &H800A000D
            Exit Sub
        End If
        
        pNewItem.bstrKey = bstrKey
        pNewItem.bFlag = False
        
        Set pNewItem.pRight = pRootItem
        Set pNewItem.pLeft = pRootItem
        
    End If
    
    ' // VariantCopyInd
    pNewItem.vtItem = vItem
   
    If IsEmpty(vIndex) Then
        Set pItem = pLastIndexedItem
    Else
    
        hr = GetItemByKey(vIndex, pItem)
        If hr < 0 Then
            Err.Raise hr
            Exit Sub
        End If
        
        If Not bIsEmptyBefore Then
            Set pItem = pItem.pPrevIndexedItem
        End If
        
    End If
    
    If Not bIsEmptyBefore And pItem Is Nothing Then
    
        Dim pTmpItem As CVBCollectionItem
        
        Set pTmpItem = pFirstIndexedItem
        Set pFirstIndexedItem = pNewItem
        Set pTmpItem.pPrevIndexedItem = pNewItem
        Set pNewItem.pPrevIndexedItem = Nothing
        Set pNewItem.pNextIndexedItem = pTmpItem
        
    Else
    
        If Not pItem Is Nothing Then
        
            Set pNewItem.pNextIndexedItem = pItem.pNextIndexedItem
            
            If Not pItem.pNextIndexedItem Is Nothing Then
                Set pNewItem.pNextIndexedItem.pPrevIndexedItem = pNewItem
            Else
                Set pLastIndexedItem = pNewItem
            End If
            
            Set pItem.pNextIndexedItem = pNewItem
            
        Else
        
            Set pNewItem.pNextIndexedItem = Nothing
            Set pFirstIndexedItem = pNewItem
            Set pLastIndexedItem = pNewItem
          
        End If
        
    End If
    
    Set pNewItem.pPrevIndexedItem = pItem
 
    If Not bIsEmptyKey Then
        AddItemWithKeyToTree pNewItem
    End If
    
    lNumOfItems = lNumOfItems + 1
    
End Sub
 
' // Get item by variant key/index
Private Function GetItemByKey( _
                 ByRef vKey As Variant, _
                 ByRef pOutItem As CVBCollectionItem) As Long
    Dim bIsEmptyKey As Boolean
    Dim bstrKey     As String
    Dim lIndex      As Long
    Dim pItem       As CVBCollectionItem
    
    bIsEmptyKey = IsMissingParam(vKey)
 
    If bIsEmptyKey Or pFirstIndexedItem Is Nothing Then
        GetItemByKey = CTL_E_ILLEGALFUNCTIONCALL
        Exit Function
    End If
    
    bstrKey = BSTRKeyFromVariant(vKey)
    
    ' // This is string key
    If Len(bstrKey) Then
        
        Set pOutItem = FindItemFrom(pFirstItem, bstrKey)
        
        If pOutItem Is pRootItem Then
            GetItemByKey = CTL_E_ILLEGALFUNCTIONCALL
            Exit Function
        End If
        
    Else
    
        lIndex = Int(vKey)
        
        If lIndex <= 0 Or lIndex > lNumOfItems Then
            GetItemByKey = &H800A000D
            Exit Function
        End If
 
        Set pOutItem = pFirstIndexedItem
 
        Do Until lIndex = 1
            Set pOutItem = pOutItem.pNextIndexedItem
            lIndex = lIndex - 1
        Loop
        
    End If
    
End Function
 
' // Add item that has a key to tree
Private Function AddItemWithKeyToTree( _
                 ByVal pItem As CVBCollectionItem) As Long
    Dim pCurItem            As CVBCollectionItem
    Dim pParentItem         As CVBCollectionItem
    Dim pParentParentItem   As CVBCollectionItem
    Dim pParentLeft         As CVBCollectionItem
 
    ' // Insert item to tree
    InsertItemToTree pItem
    
    pItem.bFlag = False
    
    Set pCurItem = pItem
    
    Do Until pCurItem Is pFirstItem
    
        Set pParentItem = pCurItem.pParentItem
        
        If pParentItem.bFlag Then Exit Do
        
        Set pParentParentItem = pParentItem.pParentItem
        Set pParentLeft = pParentParentItem.pLeft
        
        If pParentItem Is pParentLeft Then
            
            Set pParentLeft = pParentParentItem.pRight
            
            If Not pParentLeft.bFlag Then
            
                pParentItem.bFlag = True
                pParentLeft.bFlag = True
                pParentItem.pParentItem.bFlag = False
                Set pCurItem = pCurItem.pParentItem.pParentItem
                
            Else
            
                If pCurItem Is pParentItem.pParentItem Then
                
                    Set pCurItem = pCurItem.pParentItem
                    MoveDownRight pParentItem
                    
                Else
                
                    pParentItem.bFlag = True
                    pParentItem.pParentItem.bFlag = False
                    MoveDownLeft pCurItem.pParentItem.pParentItem
                
                End If
                
            End If
            
        Else
            
            If pParentLeft.bFlag Then
            
                If pCurItem Is pParentItem.pLeft Then
                
                    Set pCurItem = pCurItem.pParentItem
                    MoveDownLeft pParentItem
                
                Else
                    
                    pParentItem.bFlag = True
                    pParentItem.pParentItem.bFlag = False
                    MoveDownRight pCurItem.pParentItem.pParentItem
                    
                End If
                
            Else
            
                pParentItem.bFlag = True
                pParentLeft.bFlag = True
                pParentItem.pParentItem.bFlag = False
                Set pCurItem = pCurItem.pParentItem.pParentItem
                
            End If
 
        End If
    
    Loop
    
    pFirstItem.bFlag = True
    
End Function
 
' // Move tree item down and left
Private Sub MoveDownLeft( _
            ByVal pItem As CVBCollectionItem)
    Dim pParentLeft   As CVBCollectionItem
    
    Set pParentLeft = pItem.pLeft
    Set pItem.pLeft = pParentLeft.pRight
    
    If Not pParentLeft.pRight Is pRootItem Then
        Set pParentLeft.pRight.pParentItem = pItem
    End If
    
    Set pParentLeft.pParentItem = pItem.pParentItem
    
    If pItem.pParentItem Is pRootItem Then
        Set pFirstItem = pParentLeft
    Else
        If pItem Is pItem.pParentItem.pRight Then
            Set pItem.pParentItem.pRight = pParentLeft
        Else
            Set pItem.pParentItem.pLeft = pParentLeft
        End If
    End If
    
    Set pParentLeft.pRight = pItem
    Set pItem.pParentItem = pParentLeft
    
End Sub
 
' // Move tree item down and right
Private Sub MoveDownRight( _
            ByVal pItem As CVBCollectionItem)
    Dim pRight  As CVBCollectionItem
    
    Set pRight = pItem.pRight
    Set pItem.pRight = pRight.pLeft
    
    If Not pRight.pLeft Is pRootItem Then
        Set pRight.pLeft.pParentItem = pItem
    End If
    
    Set pRight.pParentItem = pItem.pParentItem
    
    If pItem.pParentItem Is pRootItem Then
        Set pFirstItem = pRight
    Else
        If pItem Is pItem.pParentItem.pLeft Then
            Set pItem.pParentItem.pLeft = pRight
        Else
            Set pItem.pParentItem.pRight = pRight
        End If
    End If
    
    Set pRight.pLeft = pItem
    Set pItem.pParentItem = pRight
    
End Sub
 
' // Insert item to tree
Private Function InsertItemToTree( _
                 ByVal pItem As CVBCollectionItem) As Long
    Dim pCurItem    As CVBCollectionItem
    Dim pParentItem As CVBCollectionItem
    Dim hr          As Long
    
    Set pParentItem = pRootItem
    Set pCurItem = pFirstItem
    
    ' // Check if item exists
    If Not pParentItem Is pCurItem Then
        
        ' // Find tree node for passed item
        Do
        
            Set pParentItem = pCurItem
            
            hr = StrComp(pItem.bstrKey, pCurItem.bstrKey, vbTextCompare) + 1
            
            Select Case hr
            Case 0
                Set pCurItem = pCurItem.pLeft
            Case 1
                ' // Error. Specified item already exists
                InsertItemToTree = &H800A01C9
                Exit Function
            Case 2
                Set pCurItem = pCurItem.pRight
            End Select
            
        Loop Until pCurItem Is pRootItem
        
    Else:   hr = ObjPtr(pItem)
    End If
    
    ' // Set parent node for passed item
    Set pItem.pParentItem = pParentItem
    
    ' // Check if it is the root node
    If pParentItem Is pRootItem Then
        Set pFirstItem = pItem
    Else
        ' // Place item depending on value
        If hr Then
            Set pParentItem.pRight = pItem
        Else
            Set pParentItem.pLeft = pItem
        End If
    End If
    
End Function
                 
' // Find an item by key from specified item
Private Function FindItemFrom( _
                 ByVal pStartItem As CVBCollectionItem, _
                 ByRef bstrKey As String) As CVBCollectionItem
    Dim pCurItem    As CVBCollectionItem
    
    Set pCurItem = pStartItem
    
    Do Until pCurItem Is pRootItem
    
        Select Case StrComp(bstrKey, pCurItem.bstrKey, vbTextCompare)
        Case -1:    Set pCurItem = pCurItem.pLeft
        Case 0:     Exit Do
        Case 1:     Set pCurItem = pCurItem.pRight
        End Select
        
    Loop
    
    Set FindItemFrom = pCurItem
    
End Function
 
' // Convert a variant value to string
Private Function BSTRKeyFromVariant( _
                 ByRef vKey As Variant) As String
    Dim vTemp   As Variant
    Dim pTmpObj As Object
    
    If IsObject(vKey) Then
    
        Set pTmpObj = vKey
        
        If Not pTmpObj Is Nothing Then
            vTemp = CStr(vKey)
        Else
            Set vTemp = vKey
        End If
    
    Else
        vTemp = vKey
    End If
     
    If VarType(vTemp) = vbString Then
        BSTRKeyFromVariant = CStr(vTemp)
    End If
    
End Function
 
Private Function IsMissingParam( _
                 ByRef vParam As Variant) As Boolean
                 
#If COMPILED Then
    
    If IsError(vParam) Then
        If CInt(vParam) = DISP_E_PARAMNOTFOUND Then
            IsMissingParam = True
        End If
    End If
    
#Else
 
    IsMissingParam = IsMissing(vParam)
    
#End If
 
End Function
 
Private Sub Class_Initialize()
 
    Set pRootItem = New CVBCollectionItem
    Set pFirstItem = pRootItem
    
#If Not COMPILED Then
    
    pRootItem.bstrKey = "root"
    
#End If
 
End Sub
Элемент коллекции CVBCollectionItem:
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
' //
' // Native VB collection item
' // Decompiled by The trick
' //
 
Option Explicit
 
Public vtItem              As Variant
Public bstrKey             As String
Public pPrevIndexedItem    As CVBCollectionItem
Public pNextIndexedItem    As CVBCollectionItem
Public pvUnknown           As Long
Public pParentItem         As CVBCollectionItem
Public pRight              As CVBCollectionItem
Public pLeft               As CVBCollectionItem
Public bFlag               As Boolean
5
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
31.08.2016, 23:36
Ответы с готовыми решениями:

Как это работает? Хотелось бы реализовать на VB6
http://potrebitel.biz/angel/mk.htm

Объясните как работает коллекция ObservableCollection
Здравствуйте, есть код. public class Class { public int Name { get { return 1; } } public int...

Linq to xml - не работает, коллекция все время пустая
Не могу понять, что не правильно: XElement xdoc = XElement.Load(&quot;http://www.onliner.by/feed&quot;); IEnumerable&lt;XElement&gt;...

29
oh my god
 Аватар для fever brain
1456 / 796 / 161
Регистрация: 05.01.2016
Сообщений: 2,307
Записей в блоге: 8
01.09.2016, 11:55
Я не совсем понял, тоесть структура и коллекция будет однинаково храниться в памяти
и её можно вызвать по указателю ?
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
01.09.2016, 11:57  [ТС]
Цитата Сообщение от fever brain Посмотреть сообщение
Я не совсем понял, тоесть структура и коллекция будет однинаково храниться в памяти
и её можно вызвать по указателю ?
Я тебя не понял.
0
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
02.12.2023, 04:49
The trick, я правильно понимаю, что принцип быстрого поиска коллекции в сортировке согласноо ключам или какой-то другой принцип?
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
02.12.2023, 08:26  [ТС]
Это обычное красро-черное дерево.
2
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
02.12.2023, 20:40
Хотел реализовать это дерево на массивах и получил код случайного срабатывания. Не могу понять, почему массив RBTree.LeafNodes обнуляется после однократного выполения GetItem. В данном случае функция GetItem принимат значение индекса значения (ключа) в массиве Data() и возвращает индекс соответствующего элемента в массиве RBTree.LeafNodes(). Правильный вывод должен быть
Code
1
2
3
4
1
2
3
*
Но чаще выходят 1 и дальше нули (массив RBTree.LeafNodes обнуляется why??)
Кликните здесь для просмотра всего текста
Visual Basic
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
94
95
96
97
Private Type LeafNode
    Use As Boolean
    Ind As Long
    Rgt As Long
    Lft As Long
End Type
Private Type RedBlackTree
    LstInd As Long
    LeafNodes() As LeafNode
End Type
 
Private RBTree As RedBlackTree
 
Sub testRBTree()
    Dim Arr()
    initRBTree RBTree
    Arr = Array("hggsg", "erfmerj", "yoytoip", "opipjp", "111334", "llkkk")
    AddItem Arr, 0
    AddItem Arr, 1
    AddItem Arr, 2
    AddItem Arr, 3
    AddItem Arr, 4
    AddItem Arr, 5
    
    Debug.Print GetItem(Arr, 0)
    Debug.Print GetItem(Arr, 1)
    Debug.Print GetItem(Arr, 2)
    Debug.Print GetItem(Arr, 3)
    Debug.Print GetItem(Arr, 4)
End Sub
 
Sub initRBTree(RBTree1 As RedBlackTree)
    ReDim RBTree1.LeafNodes(1 To 100)
End Sub
 
Private Sub AddItem(Data(), Ind As Long)
    Dim LFInd As Long, LstInd As Long
    LstInd = RBTree.LstInd + 1
    LFInd = 1
    Do While RBTree.LeafNodes(LFInd).Use
        Select Case Data(RBTree.LeafNodes(LFInd).Ind)
        Case Is < Data(Ind)
            If RBTree.LeafNodes(LFInd).Rgt = 0 Then
                RBTree.LeafNodes(LFInd).Rgt = LstInd
                Exit Do
            End If
            LFInd = RBTree.LeafNodes(LFInd).Rgt
        Case Is = Data(Ind)
        
        Case Is > Data(Ind)
            If RBTree.LeafNodes(LFInd).Lft = 0 Then
                RBTree.LeafNodes(LFInd).Lft = LstInd
                Exit Do
            End If
            LFInd = RBTree.LeafNodes(LFInd).Lft
            
        End Select
    Loop
    RBTree.LstInd = LstInd
    RBTree.LeafNodes(LstInd).Ind = Ind
    RBTree.LeafNodes(LstInd).Use = True
    
End Sub
Private Function GetItem(Data(), Ind As Long) As Long
    Dim LFInd As Long ', i&
    
    LFInd = 1
    Do
'        i = i + 1
        Select Case Data(RBTree.LeafNodes(LFInd).Ind)
        Case Is < Data(Ind)
            If RBTree.LeafNodes(LFInd).Rgt <> 0 Then
                LFInd = RBTree.LeafNodes(LFInd).Rgt
            Else
                GoTo NotExist
            End If
            
        Case Is = Data(Ind)
'            vItem = oCurItem.vItem
            GetItem = LFInd
            
        Case Is > Data(Ind)
            If RBTree.LeafNodes(LFInd).Lft <> 0 Then
                LFInd = RBTree.LeafNodes(LFInd).Lft
            Else
                GoTo NotExist
            End If
        End Select
    Loop Until GetItem
    
'    Debug.Print i
    Exit Function
    
NotExist:
'    Debug.Print i
    GetItem = False
End Function


Добавлено через 2 минуты
Первоначально сделал на классах свой упрощенный вариант коллекции и он работал нормально..

Добавлено через 5 минут
Кажись понял, срабатывает корректно, после сброса переменных (режима конструктора) наверное redim в процедуре initRBTree покастит..
1
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
03.12.2023, 15:55
Дефект повторился и на x64 vba, но помогла эта строчка
Visual Basic
1
RBTree = RBEmp
Кликните здесь для просмотра всего текста
Visual Basic
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
94
95
96
97
98
99
100
Option Explicit
 
Private Type LeafNode
    KeyInd As Long
    Right As Long
    Left As Long
    Used As Boolean
End Type
Private Type RedBlackTree
    LastInd As Long
    LeafNodes() As LeafNode
End Type
 
Private RBTree As RedBlackTree
Private Keys() As Variant
 
Sub testRBTree()
    Dim Arr(), RBEmp As RedBlackTree
    
    ReDim Preserve RBTree.LeafNodes(1 To 100)
    Keys = Array("hggsg", "erfmerj", "yoytoip", "opipjp", "111334", "llkkk")
    AddItem 0
    AddItem 1
    AddItem 2
    AddItem 3
    AddItem 4
    AddItem 5
    Debug.Print GetItem("dddddd") 'не существующий ключ
    Debug.Print GetItem(Keys(4))
    Debug.Print Keys(RBTree.LeafNodes(GetItem((Keys(3)))).KeyInd)
    Debug.Print GetItem(Keys(1))
    Debug.Print GetItem(Keys(0))
    Debug.Print GetItem(Keys(2))
    
    RBTree = RBEmp
End Sub
 
Private Sub AddItem(KeyInd As Long)
    Dim LNInd As Long, LastInd As Long
    
    LastInd = RBTree.LastInd + 1
    LNInd = 1
    Do While RBTree.LeafNodes(LNInd).Used
        Select Case Keys(RBTree.LeafNodes(LNInd).KeyInd)
        Case Is < Keys(KeyInd)
            If RBTree.LeafNodes(LNInd).Right = 0 Then
                RBTree.LeafNodes(LNInd).Right = LastInd
                Exit Do
            End If
            LNInd = RBTree.LeafNodes(LNInd).Right
        
'        Case Is = Keys(KeyInd) 'ни чего не делаем, пока нет идей
            
        Case Is > Keys(KeyInd)
            If RBTree.LeafNodes(LNInd).Left = 0 Then
                RBTree.LeafNodes(LNInd).Left = LastInd
                Exit Do
            End If
            LNInd = RBTree.LeafNodes(LNInd).Left
            
        End Select
    Loop
    
    RBTree.LastInd = LastInd
    RBTree.LeafNodes(LastInd).KeyInd = KeyInd
    RBTree.LeafNodes(LastInd).Used = True
End Sub
 
Private Function GetItem(Key) As Long
    Dim LNInd As Long ', i&
    
    LNInd = 1
    Do
'        i = i + 1
        Select Case Keys(RBTree.LeafNodes(LNInd).KeyInd)
        Case Is < Key
            If RBTree.LeafNodes(LNInd).Right <> 0 Then
                LNInd = RBTree.LeafNodes(LNInd).Right
            Else
                GoTo NotExist
            End If
            
        Case Is = Key
            GetItem = LNInd
            
        Case Is > Key
            If RBTree.LeafNodes(LNInd).Left <> 0 Then
                LNInd = RBTree.LeafNodes(LNInd).Left
            Else
                GoTo NotExist
            End If
        End Select
    Loop Until GetItem
    
'    Debug.Print "Кол-во итераций поиска: "; i
    Exit Function
NotExist:
'    Debug.Print "Кол-во итераций поиска: "; i
    GetItem = False
End Function


Добавлено через 4 часа 6 минут
Не получилось обогнать "на легке" коллекцию. Если честно, реверс мне не очень понравился, много там копирований, преобразований. Конечно Трик там многое упростил, но при всех прочих, даже без копирования ключей и итемов при добавлении их в дерево, код оказался чуть менее быстрым (на 30%), но это конечно без winapi и строгой типизации ключей и компиляции в натив (проверялось все на vba).
Тест скорости коллекции vs самодельного "дерева"
Visual Basic
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
Private Type LeafNode
    Used As Boolean
    KeyInd As Long
    Right As Long
    Left As Long
End Type
Private Type RedBlackTree
    LastInd As Long
    LeafNodes() As LeafNode
End Type
 
Private RBTree As RedBlackTree
Private Keys() As Variant
 
Sub SpeedTest()
    Const sSz As Long = 8         'размер строки
    Const Cnt As Long = 100000    'размер массивов Keys и ArrOut
    Const Ub As Long = Cnt - 1
    Dim t!, s$, i&, j&, l&, arrOut(), arrEmp()
    Dim Coll As New Collection, RBEmp As RedBlackTree
        
    ReDim Keys(Ub)
    ReDim RBTree.LeafNodes(1 To Cnt)
    
    Randomize                                   'подготовка массив случайных строк (латиница)
    For i = 0 To Ub
        Keys(i) = VBA.String(sSz, vbNullChar)
        For j = 1 To sSz
            l = VBA.Rnd * 57
            If l Then
                Mid(Keys(i), j) = VBA.ChrW(65 + l)
            End If
        Next
    Next
    
    ReDim arrOut(Ub)
'===Замер скорости массива красно-черного дерева===
    t = Timer
    For i = 0 To Ub
        AddItem i
    Next
    For i = 0 To Ub
        l = Rnd * Cnt - 1
        If l <> -1 Then
            arrOut(i) = Keys(GetItem(Keys(l)))
        End If
    Next
    
    t = Timer - t
    Debug.Print "Дерево ", t
    
    ReDim arrOut(Ub)
'===Замер скорости Коллекции===
    t = Timer
    For i = 0 To Ub
        Coll.Add Keys(i), Keys(i)
    Next
    For i = 0 To Ub
        l = Rnd * Cnt - 1
        If l <> -1 Then
            arrOut(i) = Coll(Keys(l))
        End If
    Next
    
    t = Timer - t
    Debug.Print "Коллекция ", t
    
    RBTree = RBEmp 'устраняем глюк массива внутри структуры
End Sub
 
Private Sub AddItem(KeyInd As Long)
    Dim LNInd As Long, LastInd As Long
    
    LastInd = RBTree.LastInd + 1
    LNInd = 1
    Do While RBTree.LeafNodes(LNInd).Used
        Select Case Keys(RBTree.LeafNodes(LNInd).KeyInd)
        Case Is < Keys(KeyInd)
            If RBTree.LeafNodes(LNInd).Right = 0 Then
                RBTree.LeafNodes(LNInd).Right = LastInd
                Exit Do
            End If
            LNInd = RBTree.LeafNodes(LNInd).Right
        
'        Case Is = Keys(KeyInd) 'ни чего не делаем, пока нет идей
            
        Case Is > Keys(KeyInd)
            If RBTree.LeafNodes(LNInd).Left = 0 Then
                RBTree.LeafNodes(LNInd).Left = LastInd
                Exit Do
            End If
            LNInd = RBTree.LeafNodes(LNInd).Left
            
        End Select
    Loop
    
    RBTree.LastInd = LastInd
    RBTree.LeafNodes(LastInd).KeyInd = KeyInd
    RBTree.LeafNodes(LastInd).Used = True
End Sub
 
Private Function GetItem(Key) As Long
    Dim LNInd As Long ', i&
    
    LNInd = 1
    With RBTree
      Do
  '        i = i + 1          
          On StrComp(Keys(RBTree.LeafNodes(LNInd).KeyInd), Key) + 1 GoTo 1, 2
          If True Then
              If .LeafNodes(LNInd).Right <> 0 Then
                  LNInd = .LeafNodes(LNInd).Right
              Else
                  GoTo NotExist
              End If
              
          ElseIf False Then
1:            GetItem = .LeafNodes(LNInd).KeyInd 'LNInd
              Exit Function
              
          ElseIf False Then
2:            If .LeafNodes(LNInd).Left <> 0 Then
                  LNInd = .LeafNodes(LNInd).Left
              Else
                  GoTo NotExist
              End If
              
          End If
          
      Loop Until GetItem
    End With
    
'    Debug.Print "Кол-во итераций поиска: "; i
    Exit Function
NotExist:
'    Debug.Print "Кол-во итераций поиска: "; i
    GetItem = -1
End Function

Code
1
2
Дерево         1,1875 
Коллекция      0,9375
Добавлено через 2 часа 48 минут
Добавил winapi и стало так.
Code
1
2
Дерево         0,75 
Коллекция      0,953125
Чуть позже добавлю диктионари в сравнение и выложу код

Добавлено через 12 минут
В общем так, словарь на удивленье подкачал, вроде все на раннем связывании..
Code
1
2
3
Дерево         0,734375 
Коллекция      0,9453125 
Словарь        1,671875
Кликните здесь для просмотра всего текста
Visual Basic
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
Private Type LeafNode
    Used As Boolean
    KeyInd As Long
    Right As Long
    Left As Long
End Type
Private Type RedBlackTree
    LastInd As Long
    LeafNodes() As LeafNode
End Type
Private Type sVariant
    cr As Currency
    st As String
    lp As LongPtr
End Type
 
#If Win64 Then
    Private Const ptrSz = 8
#Else
    Private Const ptrSz = 4
#End If
 
Private RBTree As RedBlackTree
Private Ptr0 As LongPtr, Keys() As Variant, svKeys() As sVariant
 
Sub SpeedTest()
    Const sSz As Long = 8         'размер строки
    Const Cnt As Long = 100000    'размер массивов Keys и ArrOut
    Const Ub As Long = Cnt - 1
    Dim t!, s$, i&, j&, l&, arrOut(), arrEmp()
    Dim Coll As New Collection, Dict As New Dictionary, RBEmp As RedBlackTree
        
    ReDim Keys(Ub)
    ReDim RBTree.LeafNodes(1 To Cnt)
    CopyMemory ByVal VarPtr(Ptr0) + ptrSz * 2, ByVal VarPtr(Ptr0) + ptrSz, ptrSz
    
    Randomize                                   'подготовка массив случайных строк (латиница)
    For i = 0 To Ub
        Keys(i) = vbNullString
        svKeys(i).st = VBA.String(sSz, vbNullChar)
        For j = 1 To sSz
            l = VBA.Rnd * 57
            If l Then
                Mid$(svKeys(i).st, j) = VBA.ChrW(65 + l)
            End If
        Next
    Next
        
'===Замер скорости массива Красно-черного дерева===
    ReDim arrOut(Ub)
    t = Timer
    For i = 0 To Ub
        AddItem i
    Next
    For i = 0 To Ub
        l = Rnd * Cnt - 1
        If l <> -1 Then
            arrOut(i) = Keys(GetItem(svKeys(l).st))
        End If
    Next
    
    t = Timer - t
    Debug.Print "Дерево ", t
    CopyMemory ByVal VarPtr(Ptr0) + ptrSz * 2, Ptr0, ptrSz
    
'===Замер скорости Коллекции===
    ReDim arrOut(Ub)
    t = Timer
    For i = 0 To Ub
        Coll.Add Keys(i), Keys(i)
    Next
    For i = 0 To Ub
        l = Rnd * Cnt - 1
        If l <> -1 Then
            arrOut(i) = Coll(Keys(l))
        End If
    Next
    
    t = Timer - t
    Debug.Print "Коллекция ", t
    
'===Замер скорости Словаря===
    ReDim arrOut(Ub)
    t = Timer
    For i = 0 To Ub
        Dict.Add Keys(i), Keys(i)
    Next
    For i = 0 To Ub
        l = Rnd * Cnt - 1
        If l <> -1 Then
            arrOut(i) = Dict(Keys(l))
        End If
    Next
    
    t = Timer - t
    Debug.Print "Словарь ", t
    
    RBTree = RBEmp 'устраняем глюк массива внутри структуры
End Sub
 
Private Sub AddItem(KeyInd As Long)
    Dim LNInd As Long, LastInd As Long
    
    LastInd = RBTree.LastInd + 1
    LNInd = 1
    Do While RBTree.LeafNodes(LNInd).Used
        On StrComp(svKeys(RBTree.LeafNodes(LNInd).KeyInd).st, svKeys(KeyInd).st) + 1 GoTo 1, 2
        If True Then
            If RBTree.LeafNodes(LNInd).Right = 0 Then
                RBTree.LeafNodes(LNInd).Right = LastInd
                Exit Do
            End If
            LNInd = RBTree.LeafNodes(LNInd).Right
        
        ElseIf False Then     'ни чего не делаем, пока нет идей
'1:
        ElseIf False Then
2:          If RBTree.LeafNodes(LNInd).Left = 0 Then
                RBTree.LeafNodes(LNInd).Left = LastInd
                Exit Do
            End If
            LNInd = RBTree.LeafNodes(LNInd).Left
            
        End If
    Loop
    
    RBTree.LastInd = LastInd
    RBTree.LeafNodes(LastInd).KeyInd = KeyInd
    RBTree.LeafNodes(LastInd).Used = True
1:
End Sub
 
Private Function GetItem(sKey As String) As Long
    Dim LNInd As Long ', i&
    
    LNInd = 1
    With RBTree
      Do
  '        i = i + 1  
          On StrComp(svKeys(RBTree.LeafNodes(LNInd).KeyInd).st, sKey) + 1 GoTo 1, 2
          If True Then
              If .LeafNodes(LNInd).Right <> 0 Then
                  LNInd = .LeafNodes(LNInd).Right
              Else
                  GoTo NotExist
              End If
 
          ElseIf False Then
1:            GetItem = .LeafNodes(LNInd).KeyInd 'LNInd
              Exit Function
 
          ElseIf False Then
2:            If .LeafNodes(LNInd).Left <> 0 Then
                  LNInd = .LeafNodes(LNInd).Left
              Else
                  GoTo NotExist
              End If
 
          End If          
          
      Loop Until GetItem
    End With
    
'    Debug.Print "Кол-во итераций поиска: "; i
    Exit Function
NotExist:
'    Debug.Print "Кол-во итераций поиска: "; i
    GetItem = -1
End Function
1
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
03.12.2023, 16:45  [ТС]
testuser2, вот я делал аналог словаря. В некоторых случаях он работал даже быстрее чем родной.
1
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
03.12.2023, 17:10
The trick, я видел у тебя также хэш-таблицу со строковыми ключами. Можно добавить их все к сравнению + эту )
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
03.12.2023, 17:57  [ТС]
Цитата Сообщение от testuser2 Посмотреть сообщение
Можно добавить их все к сравнению + эту )
Не увидел там реализацию перечислений.
1
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
04.12.2023, 01:59
Думал улучшить результат с помощью lstrcmp, но он оказался медленей бейсикового StrComp, даже из tlb.
1
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
25.04.2024, 15:12
The trick, ты не мог бы хотя бы в общих чертах сказать для любознательных пайонеров, как можно исследовать структуру объекта, смещения, это надо что-то дизассемблирова или можно где-то это взять/увидеть..?
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
26.04.2024, 12:42  [ТС]
testuser2, я использовал OllyDbg.
1
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
26.04.2024, 15:23
Цитата Сообщение от The trick Посмотреть сообщение
OllyDbg.
Понял, все-таки асм..
0
Испарился
 Аватар для HackerVlad
1741 / 637 / 45
Регистрация: 10.09.2021
Сообщений: 2,769
26.04.2024, 18:24
testuser2, там на самом деле очень сложно понять что-то в этой программе, я пытался разобраться и у меня ничего не получилось
1
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
27.04.2024, 18:41
Цитата Сообщение от HackerVlad Посмотреть сообщение
там на самом деле очень сложно понять что-то в этой программе
Я это предполагал, , поэтому не рисковал устанавливать такую прогу, но обезьянье любопытство все-равно возобладает наверное, что поделать, придется установить когда-нибудь.
0
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
29.04.2024, 10:01
The trick, скажи пожалуйста, существует ли для com-объектов что-то наподобие функции EnumChildWindows? Можно ли как-то получить весь список com-объектов процесса, или список дочерних/связанных объектов какого-то объекта?

Добавлено через 9 минут
Что-то вроде нашел - AccessibleChildren..
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
29.04.2024, 10:14  [ТС]
testuser2, в общем случае нет. COM объект может существовать даже на другом компьютере, а в процессе (а точнее апартаменте) будет RPC-заглушка. Объект может быть зарегистрирован в ROT, вот оттуда можно извлечь список (к примеру GetObject так делает).
1
1382 / 838 / 89
Регистрация: 08.02.2017
Сообщений: 3,507
Записей в блоге: 1
29.04.2024, 12:15
The trick, а вот этот IRunningObjectTable, как ее заюзать. Декларация есть, но нет самого типа в апи-вьювере.
Visual Basic
1
Private Declare Sub GetRunningObjectTable Lib "ole32.dll" (ByVal reserved As Long, ByVal pprot As Long)
pprot должен быть укзатель на структуру IRunningObjectTable
Это структура, или нужно какой-то референс подключать? Но я в референсах что-то ни чего не нашел от ole32.dll.

Добавлено через 2 минуты
Еще вопрос в этой таблице информация обо всех объектах в системе/сеансе или только для текущего процесса?

Добавлено через 1 час 18 минут
Опчик, что-то нашел вроде, там это ROT как клас захреначили под название stdCOM, как все сложно..
0
Модератор
10046 / 3892 / 883
Регистрация: 22.02.2013
Сообщений: 5,846
Записей в блоге: 79
29.04.2024, 14:18  [ТС]
Цитата Сообщение от testuser2 Посмотреть сообщение
Это структура, или нужно какой-то референс подключать? Но я в референсах что-то ни чего не нашел от ole32.dll.
Нужно специальную библиотеку типов подключать или через DispCallFunc вызывать.

Цитата Сообщение от testuser2 Посмотреть сообщение
Еще вопрос в этой таблице информация обо всех объектах в системе/сеансе или только для текущего процесса?
Там разные ньюансы есть, но в общем для всей оконной станции вроде.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
29.04.2024, 14:18
Помогаю со студенческими работами здесь

В VB6 не работает SELECT
Изучаю VB6 по книге. Дошел до работы с БД. При попытке присвоить RecordSource какой-либо SQL запрос (SELECT и т.д.), VB пишет типа...

Скрипт ASP в VB6 не работает
Есть работающий ASP, меняет цвет фона: &lt;%@ Language=VBScript %&gt; &lt;html&gt; &lt;body&gt; &lt;h1&gt;&lt;font face='Arial'&gt; Page...

[vb6] не работает form1.print
Здравствуйте. Помогите с совсем нубским вопросом: в VB6 среди методов формы(Form1) нет printа. Поэтому при попытке вызвать form1.print...

Почему не работает VB6 на Win2000
Здравствуйте, юзята. С Новым годом-то! Подскажите: я сделал программку и инсталляционный пакет на VB6. У меня дома и на работе...

VB6 не работает с расширением jpeg
Здравствуйте, уважаемые программисты. Помогите, пожалуйста, с программой. Вот кусочек кода: Private Sub Load() Image_skl.Picture =...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США. Нашел на реддите интересную статью под названием «Кто-нибудь знает, где получить бесплатный компьютер или. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru