dcsimg
Results 1 to 25 of 25

Thread: searching through a collection

  1. #1

    Thread Starter
    Fanatic Member venerable bede's Avatar
    Join Date
    Sep 2002
    Location
    The mystic land of Geordies
    Posts
    1,018

    searching through a collection

    I have a simple collection which typically holds the following:


    HTML Code:
    Value       Key
    125434    J
    544334    H
    All I want to do is to loop through it and look for H and if I find H I want to display 544334.
    If there is no match then I want to ignore and break out.

    I know this sounds easy but this old VB6 stuff is driving me nutty :-(

    Parksie

  2. #2
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: searching through a collection

    This might help.

    Code:
    Public Function ContainsKey(Col As Collection, Key As Variant) As Boolean
    On Error Resume Next
        Col.Item Key
        ContainsKey = (Err.Number = 0&)
        Err.Clear
    End Function
    AIR CODE:

    Code:
    Dim MyKey: MyKey = "H"
    If ContainsKey(C, MyKey) Then Debug.Print C.Item(MyKey)
    Last edited by DEXWERX; Feb 16th, 2016 at 12:36 PM.

  3. #3

    Thread Starter
    Fanatic Member venerable bede's Avatar
    Join Date
    Sep 2002
    Location
    The mystic land of Geordies
    Posts
    1,018

    Re: searching through a collection

    Is there no For Each in VB6 collections?

    Parksie

  4. #4
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: searching through a collection

    Quote Originally Posted by venerable bede View Post
    Is there no For Each in VB6 collections?
    There is, but you didn't need it to do what you were asking.

    Code:
        
        Dim MyItem
        For Each MyItem In c
            Debug.Print MyItem
        Next

  5. #5

    Thread Starter
    Fanatic Member venerable bede's Avatar
    Join Date
    Sep 2002
    Location
    The mystic land of Geordies
    Posts
    1,018

    Re: searching through a collection

    How would I loop through them ?

    Parksie

  6. #6
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: searching through a collection

    Quote Originally Posted by DEXWERX View Post
    There is, but you didn't need it to do what you were asking.

    Code:
        
        Dim MyItem
        For Each MyItem In c
            Debug.Print MyItem
        Next
    Sorry I was too slow

  7. #7
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,329

    Re: searching through a collection

    For what you want to do, you don't need to loop.

    The ContainsKey checks if an item with the key exists, and the "air code" not only calls it but also gets the value from that item.


    While you could do the same with a loop, I'm pretty sure this is a faster option.

  8. #8
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: searching through a collection

    Here's my collection routines...

    MCollection.zip

  9. #9
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,762

    Re: searching through a collection

    Kind of off-topic post:

    Note that `ContainsKey` is very inefficient when checked keys are *not* found, because the runtime has to populate `Err` object which is an expensive operation. When the keys are present `ContainsKey` is very performant O(1) hash lookup implementation.

    Also note that if you are using `Break on all errors` IDE setting (and you *have to*, particularly on large projects) the `On Error Resume Next` is "ignored" and IDE breaks on the `Item` call.

    I'm using a typelib with tweaked `Collection` interface that does not return HRESULT on `Item` and all other methods but a plain `long` so no errors are raised and retval can be checked for S_OK manually.

    Code:
        [
          odl,
          uuid(A4C46780-499F-101B-BB78-00AA00383CBB),
        ]
        interface IVbCollection  : IUnknown {
            HRESULT GetTypeInfoCount(
                [out, retval] int* pctinfo);
    
            LONG GetTypeInfo(
                [in] int itinfo,
                [in] long lcid,
                [out] void *pptinfo);
    
            LONG GetIDsOfNames(
                [in] void *riid,
                [in] LPWSTR *rgszNames,
                [in] int cNames,
                [in] long lcid,
                [out] long *rgdispid);
    
            LONG Invoke(
                [in] long dispidMember,
                [in] void *riid,
                [in] long lcid,
                [in] short wFlags,
                [in] void *pdispparams,
                [out] VARIANT *pvarResult,
                [out] void *pexcepinfo,
                [out] int *puArgErr);
                
            long Item(
                [in] VARIANT* Index, 
                [out, optional] VARIANT* pvarRet);
                
            long Add(
                [in] VARIANT* Item, 
                [in, optional] VARIANT* Key, 
                [in, optional] VARIANT* Before, 
                [in, optional] VARIANT* After);
                
            long Count([out] long* pcRet);
            long Remove([in] VARIANT* Index);
            long NewEnum([out] IUnknown** ppunk);
        };
    cheers,
    </wqw>

  10. #10
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,868

    Re: searching through a collection

    Good point and a useful interface definition. I'd probably try to add a "hidden" attribute to NewEnum though.

    This goes a long way to removing one advantage of Scripting.Dictionary. Using those adds a dependency (not something I worry about much). But that object also contains performance time bombs, the properties that return entire arrays of values (.Items, .Keys).
    Last edited by dilettante; Feb 18th, 2016 at 03:04 PM.

  11. #11
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: searching through a collection

    Quote Originally Posted by wqweto View Post
    Kind of off-topic post:

    Note that `ContainsKey` is very inefficient when checked keys are *not* found, because the runtime has to populate `Err` object which is an expensive operation. When the keys are present `ContainsKey` is very performant O(1) hash lookup implementation.

    Also note that if you are using `Break on all errors` IDE setting (and you *have to*, particularly on large projects) the `On Error Resume Next` is "ignored" and IDE breaks on the `Item` call.

    I'm using a typelib with tweaked `Collection` interface that does not return HRESULT on `Item` and all other methods but a plain `long` so no errors are raised and retval can be checked for S_OK manually.

    Code:
        [
          odl,
          uuid(A4C46780-499F-101B-BB78-00AA00383CBB),
        ]
        interface IVbCollection  : IUnknown {
            HRESULT GetTypeInfoCount(
                [out, retval] int* pctinfo);
    
            LONG GetTypeInfo(
                [in] int itinfo,
                [in] long lcid,
                [out] void *pptinfo);
    
            LONG GetIDsOfNames(
                [in] void *riid,
                [in] LPWSTR *rgszNames,
                [in] int cNames,
                [in] long lcid,
                [out] long *rgdispid);
    
            LONG Invoke(
                [in] long dispidMember,
                [in] void *riid,
                [in] long lcid,
                [in] short wFlags,
                [in] void *pdispparams,
                [out] VARIANT *pvarResult,
                [out] void *pexcepinfo,
                [out] int *puArgErr);
                
            long Item(
                [in] VARIANT* Index, 
                [out, optional] VARIANT* pvarRet);
                
            long Add(
                [in] VARIANT* Item, 
                [in, optional] VARIANT* Key, 
                [in, optional] VARIANT* Before, 
                [in, optional] VARIANT* After);
                
            long Count([out] long* pcRet);
            long Remove([in] VARIANT* Index);
            long NewEnum([out] IUnknown** ppunk);
        };
    cheers,
    </wqw>
    I love posts like these. Here's my tweaks. (mostly cosmetic for the IDE)

    Code:
    	
    /* VBA.Collection Interface that bypasses VB Runtime Error Checking 
        from wqweto http://www.vbforums.com/showthread.php?822115-searching-through-a-collection */
        [uuid(A4C46780-499F-101B-BB78-00AA00383CBB),odl,hidden,helpstring("Collection Interface that bypasses VB Runtime Error Checking")]
        interface ICollection  : IDispatch {
            [id(0)]
            LONG Item(
                [in] VARIANT* Index, 
                [out, optional] VARIANT* pvarRet);
                
            LONG Add(
                [in] VARIANT* Item, 
                [in, optional] VARIANT* Key, 
                [in, optional] VARIANT* Before, 
                [in, optional] VARIANT* After);
                
            LONG Count([out] LONG* pcRet);
            LONG Remove([in] VARIANT* Index);
            LONG _NewEnum([out] IUnknown** ppunk);
        };
    Code:
    Public Function ContainsKeyFast(Col As Collection, Key As Variant) As Boolean
        Dim ICol As ICollection
        ObjRef(ICol) = ObjRef(Col)  'skip QI/AddRef
        ContainsKeyFast = (ICol.Item(Key) = S_OK)
        ObjRef(ICol) = vbNullPtr
    End Function
    
    or maybe...
    
    Public Function ContainsKeyFast(Col As Collection, Key As Variant) As Boolean
        Dim ICol As ICollection
        GetMem4 Col, ICol 'skip QI/AddRef
        ContainsKey = (ICol.Item(Key) = S_OK)
        GetMem4 0&, ICol
    End Function
    Last edited by DEXWERX; Feb 19th, 2016 at 01:21 PM. Reason: reduced the number API calls

  12. #12
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,762

    Re: searching through a collection

    @DEXWERX: This looks fast!

    In my opinion `ContainsKey` is overrated as functionality, I much prefer to use `TryGet` semantics as implemented on `Dictionary` in .Net -- returns true/false on contains/missing *and* returns the value on success, so no need for a second call to get it. If you don't need it just ignore the optional `RetVal` as it's free performancewise.

    Here is my utility function for this
    Code:
    Public Function SearchCollection(ByVal pCol As Object, Index As Variant, Optional RetVal As Variant) As Boolean
        Const DISPID_VALUE  As Long = 0
        Dim pVbCol          As IVbCollection
        
        If pCol Is Nothing Then
            '--- do nothing
        ElseIf TypeOf pCol Is IVbCollection Then
            Set pVbCol = pCol
            SearchCollection = pVbCol.Item(Index, RetVal) = S_OK
        Else
            SearchCollection = DispInvoke(pCol, DISPID_VALUE, ucsIclMethod Or ucsIclPropGet, RetVal:=RetVal, Args:=Index)
        End If
    End Function
    It's not fastest possible implementation but it workds for `ADODB.Fields` collections (or `Printers`) too *and* does not "Break on all errors" in the IDE.

    Function `DispInvoke` is complicated one that needs `IVbDispatch` -- another VB-ized interface. It just calls `IDispatch.Invoke` for default prop/method and because it's not known beforehand if DISPID_VALUE is a method or a propget it passes both flags with `ucsIclMethod Or ucsIclPropGet` -- nice hack that Olaf has mentioned here before. Btw, this is what VB6/VBA/VBScript passes on `val = obj.MyMethod` expressions for late-bound calls on `obj` (the assignment is imported, otherwise it positively is a method)

    cheers,
    </wqw>
    Last edited by wqweto; Feb 19th, 2016 at 03:06 PM.

  13. #13
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: searching through a collection

    That's a great generic function that works with all 'Collections' Thanks for sharing! (ContainsKey/TryGetValue/DispInvoke)

    Code:
    Public Function TryGetValue(Col As Collection, Key As Variant, Optional Value As Variant) As Boolean
        If Col Is Nothing Then Exit Function
        Dim ICol As ICollection
        GetMem4 Col, ICol
        TryGetValue = (ICol.Item(Key, Value) = 0&)
        GetMem4 0&, ICol
    End Function
    Last edited by DEXWERX; Feb 19th, 2016 at 03:50 PM.

  14. #14
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,057

    Re: searching through a collection

    Some more tweaks.

    Code:
    Public Function TryGetValue(ByRef Col As ICollection, ByRef Index As Variant, Optional ByRef RetVal As Variant) As Boolean
        Const S_OK = 0&
    
        If Not Col Is Nothing Then TryGetValue = Col(Index, RetVal) = S_OK
    End Function
    Attached Files Attached Files
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  15. #15
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    3,704

    Re: searching through a collection

    This doesn't work when the collections consists of objects (classes), or am I missing something obvious here?

  16. #16
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,057

    Re: searching through a collection

    Can you show your code?
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  17. #17
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    3,704

    Re: searching through a collection

    Code:
    Private Sub Main()
        Dim Col As Collection, sKey As String, RV As Variant
    
        Set Col = New Collection
        RV = ObjPtr(Col)
        sKey = Hex$(RV)
        Col.Add CLng(RV), sKey
    
        Debug.Print , "&H"; sKey
        Debug.Print TryGetValue(Col, StrReverse(sKey), RV), "&H"; Hex$(RV)
        Debug.Print TryGetValue(Nothing, sKey, RV), "&H"; Hex$(RV)
        Debug.Print TryGetValue(Col, sKey, RV), "&H"; Hex$(RV)
        
    ' Added code to test objects in collection
        Dim cClass As Class1
        Set cClass = New Class1
        
        cClass.Key = "Key 1"
        cClass.Description = "Description 1"
        
        Col.Add cClass, cClass.Key
        
        'Set cClass = Nothing
        If TryGetValue(Col, "Key 2", cClass) Then Debug.Print cClass.Description
        If TryGetValue(Col, "Key 1", cClass) Then Debug.Print cClass.Description
        
    End Sub
    
    Public Function TryGetValue(ByRef Col As ICollection, ByRef Index As Variant, Optional ByRef RetVal As Variant) As Boolean
        Const S_OK = 0&
    
        If Not Col Is Nothing Then TryGetValue = Col(Index, RetVal) = S_OK
    End Function
    Class1:
    Code:
    Option Explicit
    
    Public Key As String
    Public Description As String

  18. #18
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,057

    Re: searching through a collection

    Quote Originally Posted by Arnoutdv View Post
    This doesn't work when the collections consists of objects (classes), or am I missing something obvious here?
    It appears that tweaked method signatures like the following:

    Code:
    long Item([in] VARIANT* Index, [out, optional] VARIANT* pvarRet);
    somehow prevents a value from being returned to the caller unless the data type passed to the Optional ByRef RetVal As Variant parameter is a Variant.

    In other words, if you want to receive a value via that "out" parameter, you must pass a Variant.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  19. #19
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    3,704

    Re: searching through a collection

    Thank for the clarification Bonnie.

    Then I would write the TryGetValue() method as follows:
    Code:
    Public Function TryGetValue(ByRef Col As ICollection, ByRef Index As Variant, Optional ByRef RetVal As Variant) As Boolean
      Const S_OK = 0&
      Dim vItem As Variant
    
      If Not Col Is Nothing Then
        If Col(Index, vItem) = S_OK Then
          TryGetValue = True
          If IsObject(vItem) Then
            Set RetVal = vItem
          Else
            RetVal = vItem
          End If
        End If
      End If
    End Function

  20. #20
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: searching through a collection

    Passing in a Class as a Variant Out Value.

    Now that's an interesting, and arguably broken part of the VB6 language. At least Arnoutdv's version works well (and is consistent with the VB6 runtime philosophy - for good or bad). This is how MS would have originally handled the same type of routine. As evidenced by the automatic Setting of the passed Class1 to Out RetVal. *shrugs*

    This is a more sane way to express the same thing, and works with Bonnie's version.

    Code:
        
        Dim vOut As Variant
        Dim cClass As Class1
        Set cClass = New Class1
        
        cClass.Key = "Key 1"
        cClass.Description = "Description 1"
        
        Col.Add cClass, cClass.Key
        
        Dim vOut As Variant
        'Set cClass = Nothing
        If TryGetValue(Col, "Key 2", vOut) Then
            Set cClass = vOut
            Debug.Print cClass.Description
        End If
        If TryGetValue(Col, "Key 1", vOut) Then
            Set cClass = vOut
            Debug.Print cClass.Description
        End If
    Personally I'll shake my head and just use (a fixed) Arnoutdv's version.

    Code:
    Private Function TryGetValue(ByRef Col As ICollection, ByRef Index As Variant, Optional ByRef Value As Variant) As Boolean
        Const S_OK = 0&
        Dim RetVal
        If Not Col Is Nothing Then
            TryGetValue = Col(Index, RetVal) = S_OK
            If TryGetValue Then
                If IsObject(RetVal) Then
                    Set Value = RetVal
                Else
                    Value = RetVal
                End If
            Else
                If IsObject(Value) Then
                    Set Value = Nothing
                Else
                    Value = Empty
                End If
            End If
        End If
    End Function
    Last edited by DEXWERX; Feb 22nd, 2016 at 10:58 AM. Reason: fixed Arnoutdv's out value on failure

  21. #21
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: searching through a collection

    More examples of bad code and why an Out Value should match types.

    Most languages would just not compile. VB6 seems to let you hang yourself.

    Code:
        Dim Value As String
        Col.Add "TestString Value 1", "TsKey1"
        Col.Add "TestString Value 2", "TsKey2"
        Col.Add "TestString Value 3", "TsKey3"
        If TryGetValue(Col, "Tskey1", Value) Then Debug.Print "V1"; Value
        If TryGetValue(Col, "Tskey2", Value) Then Debug.Print "V2"; Value
        If TryGetValue(Col, "Tskey3", Value) Then Debug.Print "V3"; Value

  22. #22
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,762

    Re: searching through a collection

    Quote Originally Posted by DEXWERX View Post
    VB6 seems to let you hang yourself.
    First, let me admit that the problem is with the interface declaration in the typelib. The retval on `Item` method should be declared *in*/out like this
    Code:
            LONG Item(
                [in] VARIANT* Index, 
                [in, out, optional] VARIANT* pvarRet);
    for the case of VT_BYREF objects to be handled correctly.

    It's really a complicated case of not very well explained COM features here. Usually for a local variant variable when you `Set vTemp = oObj` the target's variant type is set to VT_DISPATCH (0x0009) and `pdispVal` member points to ObjPtr(oObj). For in/out variant parameters things get more complicated when passing objects.

    When you call `TryGetValue` with `RetVal` set to a local variable of a reference type (e.g. local `cClass As Class1`) VB6 constructs a temp variant with its type set to VT_DISPATCH *and* VT_BYREF flag set, in which case `pdispVal` member is pointing to VarPtr(cClass) not ObjPtr(cClass) i.e. the variant is not referencing the object but has a pointer to a variable (`cClass`) which in turn is referencing to the object. In this case `Set RetVal = <expr>` actually keeps the VT_BYREF flag and modifies `cClass` through the pointer.

    As a nice consequence of this feature is that when passing `cClass` as RetVal out parameter if there was `Set RetVal = New Class1` this would return the new instance in `cClass` in the caller as expected. But if for instance the code was more like `RetVal = Empty : Set RetVal = New Class1` this would *not* be able to modify `cClass` as the `RetVal` variant would lose the pointer to it (and VT_BYREF flag) on the first assignment to `Empty`.

    Now enter [out] params on interface methods. VB6 cannot declare/implement such params but it can call methods with them just fine. With [out] attribute VB6 makes sure the actual variable that is passed as [out] parameter is *cleared* before pushing a pointer to it (to prevent leaks) i.e. there is an implicit `RetVal = Empty` just before calling `Item` on the collection as the interface was declared before.

    So to reiterate again, the simple fix for this edge case is to modify the `Item` method signature to in/out `RetVal` and cross fingers that nothing is leaking, as clearly the original `VBA.Collection` interface has this parameter as out/retval only. There is a remote possibility that [in] is not expected here, but provided the method actually works, positively there were no shortcuts taken to variant assignments in method implementation.

    cheers,
    </wqw>

  23. #23
    PowerPoster
    Join Date
    Jun 2013
    Posts
    4,595

    Re: searching through a collection

    Quote Originally Posted by wqweto View Post
    So to reiterate again, the simple fix for this edge case is to modify the `Item` method signature to in/out `RetVal`
    It was the first thing I tried - and it didn't help, because the implementors
    of the VBA.Collection took the hint from the original interface-def - and
    implemented accordingly.

    Meaning, they leave the Out-Param alone, in case of a non-existing Key -
    but perform a VariantClear on it, when a Key exists, before applying the
    new Value.

    Quote Originally Posted by wqweto View Post
    ... and cross fingers that nothing is leaking, ...
    Nope, the implementation is correct - performing an (perhaps implicite) VariantClear
    instead of just blanking the Variant out with Zeros.

    To rule out any "Arg-passing-magic, interpreting the TLB-Interface-Def" on the side
    of the VB6-compiler, I wrote a version which works entirely based on pointers -
    but the results remain the same.

    The implementors of the VBA.Collection took the hint about the "out-param" seriously...

    So there's no way around it, other than the two-stage handling as seen in the examples from Arnout/Dex.

    For those interested, here's the (RC5-based) TryGet-version which works with
    pointers only - not using any TypeLibs (and it's BTW a little bit faster than the
    TypeLib-based version when native compiled).

    Code:
    Private Function TryGetValue(Col As Collection, IndexOrKey, Value) As Boolean
    Static Args&(0 To 2), pVT&, pArgs&, pItemFunc&, V
      Args(0) = ObjPtr(Col)
      If Args(0) Then 'the Col-instance is alive (not nothing)
        If pItemFunc = 0 Then 'initialize the Pointer to the Item-Method once
           New_c.MemCopy VarPtr(pVT), Args(0), 4 'deref from ObjPtr to VTable
           New_c.MemCopy VarPtr(pItemFunc), pVT + 7 * 4, 4 'deref from VTable+Offs to the Item-method
           Args(2) = VarPtr(V) 'and at this occasion initialize also the two other "statics"...
           pArgs = VarPtr(Args(0)) '...which will not change among calls
        End If
    
        Args(1) = VarPtr(IndexOrKey)
    
        If New_c.stdCallDirect(vbLong, pItemFunc, pArgs, 12) = 0 Then
          TryGetValue = True
          If IsObject(V) Then Set Value = V Else Value = V
        
        Else 'the call wasn't successful
          If IsObject(Value) Then Set Value = Nothing Else Value = Empty
        End If
      End If
    End Function
    Olaf

  24. #24
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,762

    Re: searching through a collection

    Quote Originally Posted by Schmidt View Post
    It was the first thing I tried - and it didn't help, because the implementors
    of the VBA.Collection took the hint from the original interface-def - and
    implemented accordingly.
    Ooops, my bad! You are right it's not working. Poor testing on my side so the in/out hack is not going to fly.

    Edit: Btw, this static V might leak a reference as implemented.

    Also I would optimize for speed the case when VT_BYREF is not set so that `Item` output directly to `RetVal` like this
    Code:
            If (PeekInt(VarPtr(RetVal)) And VT_BYREF) = 0 Then
                SearchCollection = pVbCol.Item(Index, RetVal) = S_OK
            ElseIf pVbCol.Item(Index, vItem) = S_OK Then
                SearchCollection = True
                If IsObject(vItem) Then
                    Set RetVal = vItem
                Else
                    RetVal = vItem
                End If
            End
    cheers,
    </wqw>
    Last edited by wqweto; Feb 23rd, 2016 at 08:20 AM.

  25. #25
    PowerPoster
    Join Date
    Jun 2013
    Posts
    4,595

    Re: searching through a collection

    Quote Originally Posted by wqweto View Post
    Edit: Btw, this static V might leak a reference as implemented.
    Not really leaking (because in the next call, a potentially still set reference
    in V would be properly cleaned up by the Collection-implementation).

    But such a potential reference in V would be "kept alive" (meaning an
    outside Object-instance for example would not "die as expected",
    in case there's still a reference to it in the static V.

    So it would be better to properly clean up V after each successful call, to
    avoid this "keeping a ref alive"-behaviour - e.g. by changing the respecitve line to:

    Code:
       If IsObject(V) Then Set Value = V: Set V=Nothing Else Value = V: V=Empty
    But that's academic in some way, unless someone writes an ASM-based replacement
    for the little RC5-example - which in its current form is only useful for playing around
    somewhat easier with the pointer-stuff (for educational purposes, not the real world,
    since there's a faster VB-compatible Collection already available in the RC5).


    Quote Originally Posted by wqweto View Post
    Also I would optimize for speed the case when VT_BYREF is not set so that `Item` output directly to `RetVal` like this
    Code:
            If (PeekInt(VarPtr(RetVal)) And VT_BYREF) = 0 Then
                SearchCollection = pVbCol.Item(Index, RetVal) = S_OK
            ElseIf pVbCol.Item(Index, vItem) = S_OK Then
                SearchCollection = True
                If IsObject(vItem) Then
                    Set RetVal = vItem
                Else
                    RetVal = vItem
                End If
            End
    Yep, good point.

    Olaf

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width