; ; 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