' COM enumerator pattern with IEnumX iteration via DECLARE
#COMPILE EXE
#DIM ALL

DECLARE FUNCTION CoInitialize LIB "OLE32.DLL" (BYVAL pvReserved AS LONG) AS LONG
DECLARE FUNCTION CoUninitialize LIB "OLE32.DLL" () AS LONG

TYPE EnumEntry
    id AS LONG
    name AS STRING
    value AS STRING
END TYPE

GLOBAL gEntry0  AS EnumEntry

GLOBAL gEntry1  AS EnumEntry

GLOBAL gEntry2  AS EnumEntry

GLOBAL gEntry3  AS EnumEntry

GLOBAL gEntry4  AS EnumEntry
GLOBAL gEnumCount  AS LONG
GLOBAL gEnumPos  AS LONG
SUB InitEnum()
    gEnumCount = 0
    gEnumPos = 0
END SUB

SUB AddItem(BYVAL idx AS LONG, BYVAL id AS LONG, BYVAL name AS STRING, BYVAL value AS STRING)
    IF idx = 0 THEN gEntry0.id = id: gEntry0.name = name: gEntry0.value = value
    IF idx = 1 THEN gEntry1.id = id: gEntry1.name = name: gEntry1.value = value
    IF idx = 2 THEN gEntry2.id = id: gEntry2.name = name: gEntry2.value = value
    IF idx = 3 THEN gEntry3.id = id: gEntry3.name = name: gEntry3.value = value
    IF idx = 4 THEN gEntry4.id = id: gEntry4.name = name: gEntry4.value = value
END SUB

SUB GetItem(BYVAL idx AS LONG, BYREF id AS LONG, BYREF name AS STRING, BYREF val AS STRING)
    IF idx = 0 THEN id = gEntry0.id: name = gEntry0.name: val = gEntry0.value
    IF idx = 1 THEN id = gEntry1.id: name = gEntry1.name: val = gEntry1.value
    IF idx = 2 THEN id = gEntry2.id: name = gEntry2.name: val = gEntry2.value
    IF idx = 3 THEN id = gEntry3.id: name = gEntry3.name: val = gEntry3.value
    IF idx = 4 THEN id = gEntry4.id: name = gEntry4.name: val = gEntry4.value
END SUB

SUB EnumReset()
    gEnumPos = 0
END SUB

SUB EnumSkip(BYVAL n AS LONG)
    gEnumPos = gEnumPos + n
    IF gEnumPos > gEnumCount THEN gEnumPos = gEnumCount
END SUB

FUNCTION EnumNext(BYREF id AS LONG, BYREF name AS STRING, BYREF val AS STRING) AS LONG
    IF gEnumPos >= gEnumCount THEN FUNCTION = 0
    GetItem(gEnumPos, id, name, val)
    gEnumPos = gEnumPos + 1
    FUNCTION = 1
END FUNCTION

SUB EnumDemo()
    InitEnum()
    AddItem(0, 1, "First", "Value1")
    AddItem(1, 2, "Second", "Value2")
    AddItem(2, 3, "Third", "Value3")
    AddItem(3, 4, "Fourth", "Value4")
    AddItem(4, 5, "Fifth", "Value5")
    gEnumCount = 5
    PRINT "Collection (5 items):"
    LOCAL i  AS LONG
    LOCAL id  AS LONG
    LOCAL n  AS STRING
    LOCAL v  AS STRING
    FOR i = 0 TO 4
        GetItem(i, id, n, v)
        PRINT "  ["; i; "] ID="; id; " name="; n; " value="; v
    NEXT i
    PRINT ""
    PRINT "Iterating:"
    FOR i = 1 TO 5
        EnumNext(id, n, v)
        PRINT "  Got: ID="; id; " name="; n
    NEXT i
    EnumReset()
    EnumSkip(2)
    PRINT "After Skip(2): pos="; gEnumPos
    EnumNext(id, n, v)
    PRINT "Next: "; n
END SUB

SUB EnumExplanation()
    PRINT ""
    PRINT "COM Enumerator pattern:"
    PRINT "  IEnumX::Next(celt, rgelt, pceltFetched)"
    PRINT "  IEnumX::Skip(celt)"
    PRINT "  IEnumX::Reset()"
    PRINT "  IEnumX::Clone(ppenum)"
    PRINT ""
    PRINT "Types: IEnumVARIANT, IEnumString, IEnumUnknown"
END SUB

FUNCTION PBMAIN() AS LONG
    PRINT "=== COM Enumerator Demo ==="
    EnumDemo()
    EnumExplanation()
    PRINT "=== End COM Enumerator ==="
    FUNCTION = 0
END FUNCTION
