IAutoComplete for the COM freaks
Posted: Thu Jun 16, 2005 5:52 pm
This will show you how to use the IAutoComplete object, the one that expands an edit control with strings like in the IE URL.
The 1st code chunk are list functions of my own, it's just a small set of an include i use. the names an behaviour is inspired by the C++ CObList class, there aren't current elements, nor indexs.. But you could probably use a PB list.
The 2nd code is the example itself.
I haven't implemented the Skip() and Clone() methods because i think they are not used but this is just an assumption you should check it.
You are supposed to type something in the edit box if there are similar strings in the string list it will be expanded with string candidates.
The 1st code chunk are list functions of my own, it's just a small set of an include i use. the names an behaviour is inspired by the C++ CObList class, there aren't current elements, nor indexs.. But you could probably use a PB list.
The 2nd code is the example itself.
I haven't implemented the Skip() and Clone() methods because i think they are not used but this is just an assumption you should check it.
You are supposed to type something in the edit box if there are similar strings in the string list it will be expanded with string candidates.
Code: Select all
;- Linked list
Structure _LL_ELEMENT_
*pNext._LL_ELEMENT_
*pPrev._LL_ELEMENT_
*elData.l
EndStructure
Structure _LL_DATA_
*pFirst._LL_ELEMENT_
*pLast._LL_ELEMENT_
size.l ;number of elements in list
elSize.l ;element size (not including extra pointers pNext, pPrev)
EndStructure
Procedure liGetNext(*ppEl.LONG)
*pEl._LL_ELEMENT_ = *ppEl\l - OffsetOf(_LL_ELEMENT_\elData)
If *pEl\pNext
*ppEl\l = *pEl\pNext + OffsetOf(_LL_ELEMENT_\elData)
Else
*ppEl\l = #NULL
EndIf
EndProcedure
Procedure liGetHead(*pList._LL_DATA_)
If *pList\pFirst
ProcedureReturn @*pList\pFirst\elData
Else
ProcedureReturn #NULL
EndIf
EndProcedure
Procedure liNew(elSize)
*pList._LL_DATA_ = AllocateMemory(SizeOf(_LL_DATA_))
*pList\size = 0
*pList\elSize = elSize
ProcedureReturn *pList
EndProcedure
Procedure liAddTail(*pList._LL_DATA_)
*pNewEl._LL_ELEMENT_ = AllocateMemory(OffsetOf(_LL_ELEMENT_\elData) + *pList\elSize)
If *pList\size=0 ;no items, add as first
*pList\pFirst = *pNewEl
*pList\pLast = *pNewEl
Else ;Items, add after last
*pNewEl\pPrev = *pList\pLast
*pList\pLast\pNext = *pNewEl
*pList\pLast = *pNewEl
EndIf
*pList\size + 1
ProcedureReturn @*pNewEl\elData
EndProcedure
Code: Select all
;- IAutoComplete
#CLSCTX_INPROC_SERVER = $1
#ACO_NONE = 0
#ACO_AUTOSUGGEST = $1
#ACO_AUTOAPPEND = $2
#ACO_SEARCH = $4
#ACO_FILTERPREFIXES = $8
#ACO_USETAB = $10
#ACO_UPDOWNKEYDROPSLIST = $20
#ACO_RTLREADING = $40
Interface _IEnumString Extends IEnumString
put_List(*hList._LL_DATA_)
get_List()
_ClearList()
DestroyList()
EndInterface
;Creates an unicode string from an ansi string, returns pointer to unicode string
;String memory needs to be freed by the caller
Procedure cWstr(st$)
blen = (lstrlen_(st$) * 2) + 2
wbuf = AllocateMemory(blen)
MultiByteToWideChar_(#CP_ACP, 0, st$, -1, wbuf, blen)
ProcedureReturn wbuf
EndProcedure
Structure IEnumString_VT
;IEnumString
QueryInterface.l
AddRef.l
Release.l
_Next.l
Skip.l
Reset.l
Clone.l
;Obj own functions
put_List.l
get_List.l
_ClearList.l
DestroyList.l
EndStructure
Structure IEnumString_OBJ
*vt.IEnumString_VT
objCount.l
*hstList._LL_DATA_ ;string list handle (list of pointers to unicode strings)
*strCurr.LONG ;pointer to current list element
EndStructure
;- IUnknown
Procedure est_QueryInterface(*THIS.IEnumString_OBJ, *iid.GUID, *Object.LONG)
If CompareMemory(*iid, ?IID_IUnknown, SizeOf(GUID)) Or CompareMemory(*iid, ?IID_IEnumString, SizeOf(GUID))
*Object\l = *THIS
*THIS\objCount + 1
ProcedureReturn #S_OK
Else
*Object\l = 0
ProcedureReturn #E_NOINTERFACE
EndIf
EndProcedure
Procedure.l est_AddRef(*THIS.IEnumString_OBJ)
*THIS\objCount + 1
ProcedureReturn *THIS\objCount
EndProcedure
Procedure.l est_Release(*THIS.IEnumString_OBJ)
*THIS\objCount - 1
ProcedureReturn *THIS\objCount
EndProcedure
;- IEnumString
Procedure est_Next(*THIS.IEnumString_OBJ, celt.l, *rgelt.LONG, *pceltFetched.LONG)
If *THIS\strCurr ;not last
*rgelt\l = *THIS\strCurr\l
*pceltFetched\l = 1
liGetNext(@*THIS\strCurr)
ProcedureReturn #S_OK
Else
*pceltFetched\l = 0
ProcedureReturn #S_FALSE
EndIf
EndProcedure
Procedure est_Skip(*THIS.IEnumString_OBJ, celt.l)
ProcedureReturn #S_FALSE
EndProcedure
Procedure est_Reset(*THIS.IEnumString_OBJ)
*THIS\strCurr = liGetHead(*THIS\hstList)
ProcedureReturn #S_OK
EndProcedure
Procedure est_Clone(*THIS.IEnumString_OBJ, *ppenum.l)
ProcedureReturn #E_UNEXPECTED
EndProcedure
;Sets the object string list
Procedure est_put_List(*THIS.IEnumString_OBJ, hstList.l) : *THIS\hstList = hstList : EndProcedure
;Gets the object string list
Procedure est_get_List(*THIS.IEnumString_OBJ) : ProcedureReturn *THIS\hstList : EndProcedure
;Frees the object string list elements and sets the current string element to null,
;leaves the string list handle valid.
Procedure est_ClearList(*THIS.IEnumString_OBJ)
*pELdat.LONG ;pointer to element data
*pEl.l ;pointer to list element
If *THIS\hstList
*pELdat = liGetHead(*THIS\hstList)
While *pELdat
*pEl = *pEldat - OffsetOf(_LL_ELEMENT_\elData) ;save pointer for deletion
FreeMemory(*pELdat\l) ;free unicode string
liGetNext(@*pELdat)
FreeMemory(*pEl) ;free element
Wend
*THIS\hstList\size = 0
*THIS\hstList\pFirst = #NULL
*THIS\hstList\pLast = #NULL
*THIS\strCurr = #NULL
EndIf
EndProcedure
;Destroys the string list invalidating the handle
Procedure est_DestroyList(*THIS.IEnumString_OBJ)
oest._IEnumString = *THIS
If *THIS
oest\_ClearList()
FreeMemory(*THIS\hstList)
EndIf
EndProcedure
;EnumString Object constructor
Procedure CEnumString()
*obj.IEnumString_OBJ = allocatememory(SizeOf(IEnumString_OBJ))
*obj\vt = AllocateMemory(SizeOf(IEnumString_VT))
*obj\vt\QueryInterface = @est_QueryInterface()
*obj\vt\AddRef = @est_AddRef()
*obj\vt\Release = @est_Release()
*obj\vt\_Next = @est_Next()
*obj\vt\Skip = @est_Skip()
*obj\vt\Reset = @est_Reset()
*obj\vt\Clone = @est_Clone()
*obj\vt\put_List = @est_put_List()
*obj\vt\get_List = @est_get_List()
*obj\vt\_ClearList = @est_ClearList()
*obj\vt\DestroyList = @est_DestroyList()
ProcedureReturn *obj
EndProcedure
;EnumString Object destructor
;Frees object memory. It does not free string list memory.
Procedure DEnumString(*obj.IEnumString_OBJ)
If *obj
If *obj\vt : FreeMemory(*obj\vt) : EndIf
FreeMemory(*obj)
EndIf
EndProcedure
;- #CODE
;Init COM
CoInitialize_(0)
;Create window
OpenWindow(0,0,0,322,275,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"IAutoComplete") And CreateGadgetList(WindowID(0))
hwED = StringGadget(0, 8, 10, 306, 20, "")
;- Create object that exposes EnumString
oest._IEnumString = CEnumString()
;Make a list of pointers to unicode strings
*pl.LONG ;List element
hstl = liNew(SizeOf(LONG))
*pl = liAddTail(hstl) : *pl\l = cwstr("Red")
*pl = liAddTail(hstl) : *pl\l = cwstr("Green")
*pl = liAddTail(hstl) : *pl\l = cwstr("Blue")
*pl = liAddTail(hstl) : *pl\l = cwstr("White")
*pl = liAddTail(hstl) : *pl\l = cwstr("Yellow")
*pl = liAddTail(hstl) : *pl\l = cwstr("Black")
;Set the object list
oest\put_List(hstl)
;- Create AutoComplete object
r = CoCreateInstance_(?CLSID_AutoComplete, #NULL, #CLSCTX_INPROC_SERVER, ?IID_IAutoComplete, @oac.IAutoComplete2)
If r<>#S_OK ;error
End
EndIf
;Setup AutoComplete
oac\SetOptions(#ACO_AUTOSUGGEST)
oac\Init(hwED, oest, 0, 0)
;Msg loop
fQuit = 0
Repeat
EvID = WaitWindowEvent()
If EvID=#PB_Event_CloseWindow
fQuit=1
EndIf
Until fQuit
;Free
oac\Release()
oest\DestroyList()
DEnumString(oest)
CoUnInitialize_()
End
;- #DATA
DataSection
IID_IEnumString:
Data.l $00000101
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
IID_IAutoComplete:
Data.l $00bb2762
Data.w $6a77, $11d0
Data.b $a5, $35, $00, $c0, $4f, $d7, $d0, $62
CLSID_AutoComplete:
Data.l $00BB2763
Data.w $6a77, $11d0
Data.b $a5, $35, $00, $c0, $4f, $d7, $d0, $62
IID_IUnknown:
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection