Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1529

[VB6] Using IAutoComplete / IAutoComplete2 including autocomplete with custom lists

$
0
0
IAutoComplete / IAutoComplete2 / IEnumString

SHAutocomplete has many well known limitations, the biggest being if you want to supply your own list to use with it. I was very impressed with Krool's work on this interface, and not wanting to include a whole other TLB set out to do it with oleexp.

Turns out it's far easier to work with using oleexp; the only major limitation being how to go about handling multiple autocompletes with different custom lists. UPDATE: Previously this class couldn't support multiple custom lists for different controls because the v-table swapping method was only passing IEnumString, rather than a full cEnumString class. If it were possible to get the full class, one might expect to be able to just change it to As cEnumString - but that didn't work. However changing it to a Long to get the pointer itself actually produced a pointer to the full instance of the class, and voilà, the undocumented-but-ever-useful vbaObjSetAddRef to the rescue, a reference to the class instance is born!
Code:

'Before:
'Public Function EnumStringNext(ByVal this As oleexpimp.IEnumString, ByVal celt As Long, ByVal rgelt As Long, ByVal pceltFetched As Long) As Long
'now:
Public Function EnumStringNext(ByVal this As Long, ByVal celt As Long, ByVal rgelt As Long, ByVal pceltFetched As Long) As Long
Dim cObj As cEnumString
vbaObjSetAddRef cObj, this
If (cObj Is Nothing) = False Then
    EnumStringNext = cObj.IES_Next(celt, rgelt, pceltFetched)
Else
    Debug.Print "esn obj fail"
End If

End Function

Finally, IAutoCompleteDropdown is used to provide the status of the dropdown autosuggest list. The .DropdownStatus method reports whether it's down, and the text of an item if an item in the list is selected. In the sample project, this is run on an automatically updated timer enabled in the 'basic filesystem' routine. It also exposes the .ResetEnumerator call to update the dropdown list while it's open.

Here's what the code looks like:

cAutoComplete.cls
Code:

Option Explicit

Private pACO As AutoComplete
Private pACL As ACListISF
Private pACL2 As IACList2
Private pACLH As ACLHistory
Private pACLMRU As ACLMRU
Private pACM As ACLMulti
Private pObjMgr As IObjMgr
Private pDD As IAutoCompleteDropDown
Private pUnk As oleexp3.IUnknown
Private m_hWnd As Long
Private pCust As cEnumString

Private Declare Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long) As Long
Private Declare Sub CoTaskMemFree Lib "ole32.dll" (ByVal PV As Long)

Private Sub Class_Initialize()
Set pACO = New AutoComplete
End Sub

Public Sub AC_Filesys(hWnd As Long, lOpt As AUTOCOMPLETEOPTIONS)
Set pACL = New ACListISF
pACO.Init hWnd, pACL, "", ""
pACO.SetOptions lOpt
pACO.Enable 1
m_hWnd = hWnd
End Sub
Public Sub AC_Disable()
pACO.Enable 0
End Sub
Public Sub AC_Enable()
pACO.Enable 1
End Sub
Public Sub AC_Custom(hWnd As Long, sTerms() As String, lOpt As AUTOCOMPLETEOPTIONS)
Set pCust = New cEnumString
pCust.SetACStringList sTerms
pACO.Init hWnd, pCust, "", ""
pACO.SetOptions lOpt
pACO.Enable 1
m_hWnd = hWnd
End Sub
Public Sub AC_ACList2(hWnd As Long, lOpt As AUTOCOMPLETEOPTIONS, lOpt2 As AUTOCOMPLETELISTOPTIONS)
Set pACL = New ACListISF
Set pACL2 = pACL
If (pACL2 Is Nothing) = False Then
    pACL2.SetOptions lOpt2
    pACO.Init hWnd, pACL2, "", ""
    pACO.SetOptions lOpt
    pACO.Enable 1
    m_hWnd = hWnd
Else
    Debug.Print "Failed to create IACList2"
End If
End Sub
Public Sub AC_History(hWnd As Long, lOpt As AUTOCOMPLETEOPTIONS)
Set pACLH = New ACLHistory
pACO.Init hWnd, pACLH, "", ""
pACO.SetOptions lOpt
pACO.Enable 1
m_hWnd = hWnd

End Sub
Public Sub AC_MRU(hWnd As Long, lOpt As AUTOCOMPLETEOPTIONS)
Set pACLMRU = New ACLMRU
pACO.Init hWnd, pACLMRU, "", ""
pACO.SetOptions lOpt
pACO.Enable 1
m_hWnd = hWnd

End Sub

Public Sub AC_Multi(hWnd As Long, lOpt As AUTOCOMPLETEOPTIONS, lFSOpts As AUTOCOMPLETELISTOPTIONS, bFileSys As Boolean, bHistory As Boolean, bMRU As Boolean, bCustom As Boolean, Optional vStringArrayForCustom As Variant)

  On Error GoTo e0

Set pACM = New ACLMulti
Set pObjMgr = pACM

If bFileSys Then
    Set pACL = New ACListISF
    Set pACL2 = pACL
    pACL2.SetOptions lFSOpts
    pObjMgr.Append pACL2
End If
If bMRU Then
    Set pACLMRU = New ACLMRU
    pObjMgr.Append pACLMRU
End If
If bHistory Then
    Set pACLH = New ACLHistory
    pObjMgr.Append pACLH
End If
If bCustom Then
    Dim i As Long
    Dim sTerms() As String
    ReDim sTerms(UBound(vStringArrayForCustom))
    For i = 0 To UBound(vStringArrayForCustom)
        sTerms(i) = vStringArrayForCustom(i)
    Next i
    Set pCust = New cEnumString
    pCust.SetACStringList sTerms
    pObjMgr.Append pCust
End If

pACO.Init hWnd, pObjMgr, "", ""
pACO.SetOptions lOpt
pACO.Enable 1
m_hWnd = hWnd
  On Error GoTo 0
  Exit Sub

e0:

    Debug.Print "cAutocomplete.AC_Multi.Error->" & Err.Description & " (" & Err.Number & ")"

End Sub

Public Function DropdownStatus(lpStatus As Long, sText As String)
If pDD Is Nothing Then
    Set pDD = pACO
End If
Dim lp As Long

pDD.GetDropDownStatus lpStatus, lp
SysReAllocString VarPtr(sText), lp
CoTaskMemFree lp

End Function
Public Sub ResetEnum()
If pDD Is Nothing Then
    Set pDD = pACO
End If
pDD.ResetEnumerator
End Sub

Implementing IEnumString's functions:
Code:

Public Function IES_Next(ByVal celt As Long, ByVal rgelt As Long, ByVal pceltFetched As Long) As Long
Dim lpString As Long
Dim i As Long
Dim celtFetched As Long
If rgelt = 0 Then
    IES_Next = E_POINTER
    Exit Function
End If

For i = 0 To (celt - 1)
    If nCur = nItems Then Exit For
    lpString = CoTaskMemAlloc(LenB(sItems(nCur)) & vbNullChar)
    If lpString = 0 Then IES_Next = S_FALSE: Exit Function
   
    CopyMemory ByVal lpString, ByVal StrPtr(sItems(nCur)), LenB(sItems(nCur) & vbNullChar)
    CopyMemory ByVal UnsignedAdd(rgelt, i * 4), lpString, 4&
   
    nCur = nCur + 1
    celtFetched = celtFetched + 1
Next i
 If pceltFetched Then
    CopyMemory ByVal pceltFetched, celtFetched, 4&
 End If
 If i <> celt Then IES_Next = S_FALSE

End Function
Public Function IES_Skip(ByVal celt As Long) As Long
If nCur + celt <= nItems Then
    nCur = nCur + celt
    IES_Skip = S_OK
Else
    IES_Skip = S_FALSE
End If
End Function

For the complete code, see the attached project.

Requirements
-oleexpimp.tlb v2.0 - I've forked and continued olelib2.tlb much the same as I did with the original. This new file replaces olelib2 in the same way oleexp3 replaces olelib (you can run search and replace). This file is included in the main oleexp download.
-oleexp3.tlb v3.8 - New version released with this project (29 Sep 2016)

Thanks
Krool's project mentioned above is what inspired me to do this, and I borrowed a few techniques from his project, especially for IEnumString.
Attached Files

Viewing all articles
Browse latest Browse all 1529

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>