How to create IUnknown Interface (Example)
Posted: Mon Sep 27, 2021 2:32 pm
The use and creation of interfaces is not described in detail in the PB help.
Here is an example for creating the interface IUnknown.
Update description
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()