Here is an example for creating the interface IUnknown.
Update description
Code: Select all
;-TOP
; IUnknown Example (Windows Only) by mk-soft, v1.01.2, date 27.09.2021
Interface iMyObject Extends IUnknown
Set(*bStrVal.p-bstr) ; Parameter as BSTR
Get(*vResult.variant) ; Result as Variant BYREF
EndInterface
Structure sUnknown
*vTable ; First entry is always a pointer to table with the methods
RefCount.i ; Counter of reference
EndStructure
Structure sMyObject Extends sUnknown
sValue.s
EndStructure
Declare NewObject()
;- IUnknown Methods
Procedure QueryInterface(*this.sUnknown, *riid, *ppvObject.integer)
If *ppvObject = 0 Or *riid = 0
ProcedureReturn #E_INVALIDARG
EndIf
If CompareMemory(*riid, ?IID_IUnknown, 16)
*ppvObject\i = *this
*this\RefCount + 1
ProcedureReturn #S_OK
ElseIf CompareMemory(*riid, ?IID_MyObject, 16)
*ppvObject\i = NewObject()
If *ppvObject\i
ProcedureReturn #S_OK
Else
ProcedureReturn #E_OUTOFMEMORY
EndIf
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
EndProcedure
Procedure AddRef(*this.sUnknown)
*this\RefCount + 1
Debug "MyObject [" + Hex(*this) + "] - AddRef: RefCount " + *this\RefCount
ProcedureReturn *this\RefCount
EndProcedure
Procedure Release(*this.sUnknown)
If *this\RefCount <= 1
FreeStructure(*this)
Debug "MyObject [" + Hex(*this) + "] - Release: Destroy Object"
ProcedureReturn 0
Else
*this\RefCount - 1
Debug "MyObject [" + Hex(*this) + "] - Release: RefCount " + *this\RefCount
ProcedureReturn *this\RefCount
EndIf
EndProcedure
;- MyObject Methods
Procedure Set(*this.sMyObject, *bstrVal)
If *bstrVal
*this\sValue = PeekS(*bstrVal)
ProcedureReturn #S_OK
Else
ProcedureReturn #E_INVALIDARG
EndIf
EndProcedure
Procedure Get(*this.sMyObject, *vResult.Variant)
If *vResult = 0
ProcedureReturn #E_INVALIDARG
EndIf
VariantClear_(*vResult) ; Make sure that is empty
*vResult\vt = #VT_BSTR
*vResult\bstrVal = SysAllocString_(*this\sValue)
ProcedureReturn #S_OK
EndProcedure
;- Creating of Object
Procedure NewObject()
Protected *Object.sMyObject
*Object = AllocateStructure(sMyObject) ; Allocate memory for the object
If *Object
*Object\vTable = ?vTable_MyObject ; Set pointer to the methods table
*Object\RefCount = 1 ; Set start reference
EndIf
Debug "MyObject [" + Hex(*Object) + "] - New"
ProcedureReturn *Object
EndProcedure
DataSection ; Table of Methods. Same order as the interface description
vTable_MyObject:
Data.i @QueryInterface()
Data.i @AddRef()
Data.i @Release()
Data.i @Set()
Data.i @Get()
EndDataSection
DataSection ; Microsoft defaults
IID_IUnknown: ; {00000000-0000-0000-C000-000000000046}
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection
DataSection ; Create with API UuidCreate_(Uuid.iid)
IID_MyObject:
Data.l $6E17E613
Data.w $6CE4, $4559
Data.b $FF, $7E, $12, $FF, $FF, $1A, $FF, $FF
EndDataSection
; ****
;- Use of Object
Global *obj1.iMyObject, *obj2.iMyObject
Global s1.s, var.variant
; Create Object
*obj1 = NewObject()
If *obj1
*obj1\Set("Hello World!") ; <- PB allocate and free BSTR internaly
EndIf
; Create Object over QueryInterface
*obj1\AddRef()
r1 = *obj1\QueryInterface(?IID_MyObject, @*obj2)
If r1 = #S_OK
*obj2\Set("I like Purebasic") ; <- PB allocate and free BSTR internaly
EndIf
*obj1\Release()
If *obj1\Get(@var) = #S_OK
If var\vt = #VT_BSTR
s1 = PeekS(var\bstrVal)
Debug "Obj1 = " + s1
EndIf
VariantClear_(var)
EndIf
If *obj2\Get(@var) = #S_OK
If var\vt = #VT_BSTR
s1 = PeekS(var\bstrVal)
Debug "Obj2 = " + s1
EndIf
VariantClear_(var)
EndIf
*obj1\Release()
*obj2\Release()