;
; Generic Implementation of an IEnumString Interface.
; New_EnumString(StringArray(), ItemCount) will create a new IEnumString instance
; with a referencecount of 1. (this means you must call IEnumString\Release()
; to release this reference once you do not need it anymore.)
;
;
;
; To allow for the ::Clone() method without dublicating the buffer,
; the string buffer is kept separate, with its own reference count.
Structure EnumStringBuffer
RefCount.l
Strings.l[0]
; following is the literal string data
EndStructure
; IEnumString data
Structure EnumString
*Vtbl
RefCount.l
StringCount.l
Enumerator.l
*Buffer.EnumStringBuffer
EndStructure
Procedure IEnumString_QueryInterface(*THIS.EnumString, *IID.IID, *Object.LONG)
If *Object = 0
ProcedureReturn #E_INVALIDARG
ElseIf CompareMemory(*IID, ?IID_IUnknown, SizeOf(IID)) Or CompareMemory(*IID, ?IID_IEnumString, SizeOf(IID))
*Object\l = *THIS
*THIS\RefCount + 1
ProcedureReturn #S_OK
Else
*Object\l = 0
ProcedureReturn #E_NOINTERFACE
EndIf
EndProcedure
Procedure IEnumString_AddRef(*THIS.EnumString)
*THIS\RefCount + 1
ProcedureReturn *THIS\RefCount
EndProcedure
Procedure IEnumString_Release(*THIS.EnumString)
*THIS\RefCount - 1
If *THIS\RefCount = 0
*THIS\Buffer\RefCount - 1
If *THIS\Buffer\RefCount = 0
FreeMemory(*THIS\Buffer)
EndIf
FreeMemory(*THIS)
ProcedureReturn 0
Else
ProcedureReturn *THIS\RefCount
EndIf
EndProcedure
Procedure IEnumString_Next(*THIS.EnumString, celt, *rgelt.LONG, *pceltFetched.LONG)
If *THIS\Enumerator + celt <= *THIS\StringCount
count = celt
Else
count = *THIS\StringCount - *THIS\Enumerator
EndIf
For i = 0 To count-1
*rgelt\l = *THIS\Buffer\Strings[*THIS\Enumerator + i]
*rgelt + 4
Next i
*THIS\Enumerator + count
If *pceltFetcted
*pceltFetched\l = count
EndIf
If count = celt
ProcedureReturn #S_OK
Else
ProcedureReturn #S_FALSE
EndIf
EndProcedure
Procedure IEnumString_Skip(*THIS.EnumString, celt)
*THIS\Enumerator + celt
If *THIS\Enumerator <= *THIS\StringCount
ProcedureReturn #S_OK
Else
ProcedureReturn #S_FALSE
EndIf
EndProcedure
Procedure IEnumString_Reset(*THIS.EnumString)
*THIS\Enumerator = 0
ProcedureReturn #S_OK
EndProcedure
Procedure IEnumString_Clone(*THIS.EnumString, *ppenum.LONG)
If *ppenum = 0
ProcedureReturn #E_INVALIDARG
Else
*Clone.EnumString = AllocateMemory(SizeOf(EnumString))
If *Clone
CopyMemory(*THIS, *Clone, SizeOf(EnumString))
*Clone\RefCount = 1
*Clone\Buffer\RefCount + 1
*ppenum\l = *Clone
ProcedureReturn #S_OK
Else
*ppenum\l = 0
ProcedureReturn #E_OUTOFMEMORY
EndIf
EndIf
EndProcedure
Procedure New_EnumString(StringArray$(1), StringCount)
*THIS.EnumString = 0
Size = 4 + StringCount * 4
For i = 0 To StringCount-1
Size + Len(StringArray$(i)) * 2 + 2
Next i
*StringBuffer.EnumStringBuffer = AllocateMemory(Size)
If *StringBuffer
*StringBuffer\RefCount = 1
*Pointer = *StringBuffer + 4 + StringCount * 4
For i = 0 To StringCount - 1
*StringBuffer\Strings[i] = *Pointer
PokeS(*Pointer, StringArray$(i), -1, #PB_Unicode)
*Pointer + Len(StringArray$(i)) * 2 + 2
Next i
*THIS = AllocateMemory(SizeOf(EnumString))
If *THIS
*THIS\Vtbl = ?IEnumStringVtbl
*THIS\RefCount = 1
*THIS\StringCount = StringCount
*THIS\Enumerator = 0
*THIS\Buffer = *StringBuffer
Else
FreeMemory(*StringBuffer)
EndIf
EndIf
ProcedureReturn *THIS
EndProcedure
DataSection
IEnumStringVtbl:
Data.l @IEnumString_QueryInterface()
Data.l @IEnumString_AddRef()
Data.l @IEnumString_Release()
Data.l @IEnumString_Next()
Data.l @IEnumString_Skip()
Data.l @IEnumString_Reset()
Data.l @IEnumString_Clone()
IID_IUnknown: ; {00000000-0000-0000-C000-000000000046}
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
IID_IEnumString: ; {00000101-0000-0000-C000-000000000046}
Data.l $00000101
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection
#ACO_NONE = 0 ; No autocompletion.
#ACO_AUTOSUGGEST = $1 ; Enable the autosuggest drop-down list.
#ACO_AUTOAPPEND = $2 ; Enable autoappend.
#ACO_SEARCH = $4 ; Add a search item to the dropdown list of completed strings. If this is item is selected, you should launch a search engine to assist the user.
#ACO_FILTERPREFIXES = $8 ; Don't match common prefixes, such as "www.", "http://", and so on.
#ACO_USETAB = $10 ; Use the TAB key to select an item from the drop-down list. This flag is disabled by default.
#ACO_UPDOWNKEYDROPSLIST = $20 ; Use the UP ARROW and DOWN ARROW keys to display the autosuggest drop-down list.
#ACO_RTLREADING = $40 ; If ACO_RTLREADING is set, the text is read in the opposite direction from the text in the parent window.
; -----------------------------------------------
#Window_0 = 0
#String_0 = 0
Dim Strings.s(17)
Strings(0) = "Else"
Strings(1) = "ElseIf"
Strings(2) = "EnableDebugger"
Strings(3) = "EnableExplicit"
Strings(4) = "End"
Strings(5) = "EndDataSection"
Strings(6) = "EndEnumeration"
Strings(7) = "EndIf"
Strings(8) = "EndImport"
Strings(9) = "EndInterface"
Strings(10) = "EndMacro"
Strings(11) = "EndProcedure"
Strings(12) = "EndSelect"
Strings(13) = "EndStructure"
Strings(14) = "EndStructureUnion"
Strings(15) = "EndWith"
Strings(16) = "Enumeration"
; Initialize the COM environment
CoInitialize_(0)
If OpenWindow(#Window_0, 323, 219, 600, 300, "AutoComplete", #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered )
If CreateGadgetList(WindowID(#Window_0))
StringGadget(#String_0, 40, 40, 320, 20, "")
SetActiveGadget(#String_0)
; This creates the autocomplete object:
;
If CoCreateInstance_(?CLSID_AutoComplete, 0, 1, ?IID_IAutoComplete2, @AutoComplete.IAutoComplete2) = #S_OK
; Lets change the options for autocomplete a bit:
; See the constant definitions above for the available options.
; There is a dropdown or in-place suggestion mode.
;
AutoComplete\SetOptions(#ACO_AUTOSUGGEST|#ACO_USETAB)
; This creates the IEnumString interface from our string array:
;
Enum.IEnumString = New_EnumString(Strings(), 18)
; This sets the autocomplet with our Enum object.
; If you want more info on the last 2 parameters, read here:
; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/iautocomplete/Init.asp
; Note that these must be unicode strings if present!
;
; This also works for Comboboxes, you just need to get the handle to the edit
; control that is contained inside with the GetComboBoxInfo_() function.
;
AutoComplete\Init(GadgetID(#String_0), Enum, 0, 0)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
; Release our own references to the objects to avoid a memory leak
;
Enum\Release()
AutoComplete\Release()
EndIf
EndIf
EndIf
CoUninitialize_()
DataSection
CLSID_AutoComplete: ; {00BB2763-6A77-11D0-A535-00C04FD7D062}
Data.l $00BB2763
Data.w $6A77, $11D0
Data.b $A5, $35, $00, $C0, $4F, $D7, $D0, $62
IID_IAutoComplete: ; {00BB2762-6A77-11D0-A535-00C04FD7D062}
Data.l $00BB2762
Data.w $6A77, $11D0
Data.b $A5, $35, $00, $C0, $4F, $D7, $D0, $62
IID_IAutoComplete2: ; {EAC04BC0-3791-11D2-BB95-0060977B464C}
Data.l $EAC04BC0
Data.w $3791, $11D2
Data.b $BB, $95, $00, $60, $97, $7B, $46, $4C
EndDataSection