Module BaseClass (Module as Object)

Share your advanced PureBasic knowledge/code with the community.
Post Reply
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Module BaseClass (Module as Object)

Post by mk-soft »

Wanted to rewrite my OOP precompiler.
But firmly point this is also to solve without pre-compiler.

My goal is to walk without many new keyname a module in a object. I think I have succeeded.

The module BaseClass causes you with all the necessary components:
- Creating a new class with a "BaseClass" or an inherited class.
- The basic function Object\Release () and Object\AddRef ().
- Declaration of call environment "Initalize" and "Dispose", even when inheritance.
- Declaration of methods and overwrite inheritance methods.

There are few rules:
- The structure of the variables (Properties) must be defined with extends structure of "sBaseClass" or extends structure of "inheritance class".
- The interface for the methods must be defined with extends interface "iBaseClass" or extends interface of "inheritance class".
- The inheriting class must have a BaseClass.

Examples with BaseClassSmall:
- Own Flat Gadgets

BaseClass small version

Update v1.05
- Now compatible to extended version
+ Macro AsNewMethode, Macro CloneObject

Update v1.07
- Bugfix FreeMutex

Update v1.09r4
- Map of classes encapsulated
- Check of the new class in procedure 'AddClass(...)' extended
- Change Macros because map of classes not longer global
- Change CheckInterface. Parameter is not longer required
- Name of classes not longer case sensitive (no case)

Update v1.10
- Change ClassName Management.

The module name is no longer the internal class name. This means that the interface name is now specified for inheritance, and not the module name.
Is therefore more logical.

Update v1.13
- Optimize CheckInterface

Update v1.14
- Change name of Macro 'dq' to '_dq_'

Update v1.16
- Update Method QueryInterface with default result for 'IUnknown'
- Optimize code

Update v1.17
- Added Pointer for Private Attributes (Object)
- Added Pointer for Package Attributes (Classes)
- Added new Macro InitPackage()
- Rename internal BaseSystem structure name Self.udtClass to Class.udtClass

Update v1.21
- Removed Private Macros and Pointer

Modul_BaseClassSmall.pb

Code: Select all

;-Begin Module BaseClass Small Version
; Comment : Module as Object
; Author : mk-soft
; File : BaseClassSmall.pb
; Version : v1.21.1
; Created : 16.08.2017
; Updated : 07.06.2020
; Link DE : http://www.purebasic.fr/german/viewtopic.php?f=8&t=29343
; Link EN : http://www.purebasic.fr/english/viewtopic.php?f=12&t=64305
; OS : All
; ***************************************************************************************
DeclareModule BaseClass
 
 ; ---------------------------------------------------------------------------
 
 ; Internal class declaration
 
 Prototype ProtoInvoke(*This)
 
 Structure udtInvoke
 *Invoke.ProtoInvoke
 EndStructure
 
 Structure udtClass
 Array *vTable(3)
 Array Initialize.udtInvoke(0)
 Array Dispose.udtInvoke(0)
 *Package.sPackage
 EndStructure
 
 ; ---------------------------------------------------------------------------
 
 ; BaseClass declaration
 
 Structure sBaseSystem
 *vTable
 *Class.udtClass
 RefCount.i
 Mutex.i
 EndStructure
 
 ; Public Structure
 Structure sBaseClass
 System.sBaseSystem
 EndStructure
 
 ; Public Interface 
 Interface iBaseClass
 QueryInterface(*riid, *ppvObject)
 AddRef()
 Release()
 EndInterface
 
 ; ---------------------------------------------------------------------------
 
 Macro _dq_
 "
 EndMacro
 
 ; ---------------------------------------------------------------------------
 
 ; Added New Class
 Declare AddClass(ClassInterface.s, ClassExtends.s, Size) ; Internal
 
 Macro NewClass(ClassInterface, ClassExtends=)
 ; Interface helper
 Interface __Interface Extends ClassInterface
 EndInterface
 ; Internal class pointer
 Global *__Class.udtClass
 ; Add new class
 Procedure __NewClass()
 *__Class = AddClass(_dq_#ClassInterface#_dq_, _dq_#ClassExtends#_dq_, SizeOf(ClassInterface) / SizeOf(integer))
 EndProcedure : __NewClass()
 EndMacro
 
 ; ---------------------------------------------------------------------------
 
 ; Macros for package attributes
 Macro InitPackage(_Attributes_=sPackage)
 Procedure __InitPackage()
 *__Class\Package = AllocateStructure(_Attributes_)
 EndProcedure : __InitPackage()
 EndMacro
 
 Macro GetPackage()
 *__Class\Package
 EndMacro
 
 ; ---------------------------------------------------------------------------
 
 ; Macro for init object (short)
 Macro InitObject(sProperty)
 Protected *Object.sProperty, __cnt, __index
 *Object = AllocateStructure(sProperty)
 If *Object
 *Object\System\vTable = *__Class\vTable()
 *Object\System\Class = *__Class
 *Object\System\RefCount = 0
 *Object\System\Mutex = CreateMutex()
 __cnt = ArraySize(*Object\System\Class\Initialize())
 For __index = 1 To __cnt
 *Object\System\Class\Initialize(__index)\Invoke(*Object)
 Next
 EndIf
 ProcedureReturn *Object
 EndMacro
 
 ; ---------------------------------------------------------------------------
 
 ; Macros for init object (advanced)
 Macro AllocateObject(Object, sProperty)
 Object = AllocateStructure(sProperty)
 If Object
 Object\System\vTable = *__Class\vTable()
 Object\System\Class = *__Class
 Object\System\RefCount = 0
 Object\System\Mutex = CreateMutex()
 EndIf
 EndMacro
 
 Macro InitializeObject(Object)
 If Object
 Protected __cnt, __index
 __cnt = ArraySize(Object\System\Class\Initialize())
 For __index = 1 To __cnt
 Object\System\Class\Initialize(__index)\Invoke(Object)
 Next
 EndIf
 EndMacro
 
 ; ---------------------------------------------------------------------------
 
 ; Macros for clone object
 Macro CloneObject(This, Clone, sProperty)
 Clone = AllocateStructure(sProperty)
 If Clone
 CopyStructure(This, Clone, sProperty)
 Clone\System\RefCount = 0
 Clone\System\Mutex = CreateMutex()
 EndIf
 EndMacro
 
 ; ---------------------------------------------------------------------------
 
 Macro LockObject(This)
 LockMutex(This\System\Mutex)
 EndMacro 
 
 Macro UnlockObject(This)
 UnlockMutex(This\System\Mutex)
 EndMacro 
 
 ; ---------------------------------------------------------------------------
 
 ; Macros to defined Initialize, Dispose, Methods
 
 ; Add Procedure as Initialize Object
 Macro AsInitializeObject(Name)
 Procedure __AddInitializeObject#Name()
 Protected index
 index = ArraySize(*__Class\Initialize()) + 1
 ReDim *__Class\Initialize(index)
 *__Class\Initialize(index)\Invoke = @Name()
 EndProcedure : __AddInitializeObject#Name()
 EndMacro
 
 ; Add Procedure as Dispose Object
 Macro AsDisposeObject(Name)
 Procedure __AddDisposeObject#Name()
 Protected index
 index = ArraySize(*__Class\Dispose()) + 1
 ReDim *__Class\Dispose(index)
 *__Class\Dispose(index)\Invoke = @Name()
 EndProcedure : __AddDisposeObject#Name()
 EndMacro
 
 ; Add Procedure as Methode or Overwrite inheritance methode
 Macro AsMethode(Name)
 Procedure __AddMethode#Name()
 *__Class\vTable(OffsetOf(__Interface\Name()) / SizeOf(integer)) = @Name()
 EndProcedure : __AddMethode#Name()
 EndMacro
 
 Macro AsNewMethode(Name)
 AsMethode(Name)
 EndMacro
 
 ; ---------------------------------------------------------------------------
 
 ; Debugger functions
 
 Macro CheckInterface()
 CompilerIf #PB_Compiler_Debugger
 Procedure __CheckInterface()
 Protected *xml, *node, ErrorCount
 *xml = CreateXML(#PB_Any)
 If *xml
 *node = InsertXMLStructure(RootXMLNode(*xml), *__Class\vTable(), __Interface)
 *node = ChildXMLNode(*node)
 Repeat
 If Not *node
 Break
 EndIf
 If GetXMLNodeText(*node) = "0"
 ErrorCount + 1
 Debug "Module " + #PB_Compiler_Module + ": Error Interface - Missing Methode '" + GetXMLNodeName(*node) + "()'"
 EndIf
 *node = NextXMLNode(*node)
 ForEver
 FreeXML(*xml)
 If ErrorCount
 Debug "Module " + #PB_Compiler_Module + ": Error Count " + ErrorCount
 CallDebugger
 EndIf
 EndIf
 EndProcedure : __CheckInterFace()
 CompilerEndIf
 EndMacro
 
 ; ---------------------------------------------------------------------------
 
EndDeclareModule
Module BaseClass
 
 EnableExplicit
 
 ; ---------------------------------------------------------------------------
 
 Procedure QueryInterface(*This.sBaseClass, *riid, *ppvObject.integer)
 If *ppvObject = 0 Or *riid = 0
 ProcedureReturn 80070057ドル ; #E_INVALIDARG
 EndIf
 If CompareMemory(*riid, ?IID_IUnknown, 16)
 LockMutex(*This\System\Mutex)
 *ppvObject\i = *This
 *This\System\RefCount + 1
 UnlockMutex(*This\System\Mutex)
 ProcedureReturn 0 ; #S_OK
 Else
 *ppvObject\i = 0
 ProcedureReturn 80004002ドル ; #E_NOINTERFACE
 EndIf
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 Procedure AddRef(*This.sBaseClass)
 LockMutex(*This\System\Mutex)
 *This\System\RefCount + 1
 UnlockMutex(*This\System\Mutex)
 ProcedureReturn *This\System\RefCount
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 Procedure Release(*This.sBaseClass)
 Protected index, cnt
 With *This\System
 LockMutex(*This\System\Mutex)
 If \RefCount = 0
 cnt = ArraySize(\Class\Dispose())
 For index = cnt To 1 Step -1
 \Class\Dispose(index)\Invoke(*This)
 Next
 FreeMutex(\Mutex)
 FreeStructure(*This)
 ProcedureReturn 0
 Else
 \RefCount - 1
 EndIf
 UnlockMutex(*This\System\Mutex)
 ProcedureReturn \RefCount
 EndWith
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 Procedure AddClass(ClassInterface.s, ClassExtends.s, Size)
 Static NewMap Classes.udtClass()
 Protected *class.udtClass, *extends.udtClass, sClassInterface.s, sClassExtends.s
 sClassInterface = LCase(ClassInterface)
 sClassExtends = LCase(ClassExtends)
 CompilerIf #PB_Compiler_Debugger
 If FindMapElement(Classes(), sClassInterface)
 Debug "Error: Class '" + ClassInterface + "' already exists!"
 CallDebugger
 End -1
 EndIf
 If Bool(sClassExtends)
 *extends = FindMapElement(Classes(), sClassExtends)
 If Not *extends
 Debug "Error: Extends Class '" + ClassExtends + "' not exists!"
 CallDebugger
 End -1
 EndIf
 EndIf
 CompilerEndIf
 *class = AddMapElement(Classes(), sClassInterface)
 If *class
 If Bool(sClassExtends)
 *extends = FindMapElement(Classes(), sClassExtends)
 CopyStructure(*extends, *class, udtClass)
 ReDim *class\vTable(Size)
 ProcedureReturn *class
 Else
 ReDim *class\vTable(Size)
 *class\vTable(0) = @QueryInterface()
 *class\vTable(1) = @AddRef()
 *class\vTable(2) = @Release()
 ProcedureReturn *class
 EndIf
 Else
 Debug "Error: Class '" + ClassInterface + "' Out Of Memory!"
 CallDebugger
 End -1
 EndIf
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 DataSection
 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
 
EndModule
;- End Module BaseClass
; ***************************************************************************************
Last edited by mk-soft on Sun Jun 07, 2020 12:56 pm, edited 70 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (OOP)

Post by mk-soft »

Description of the Module BaseClassSmall

Update v1.17

Preface

Purebasic is a procedure-oriented programming language, but supports the creation of object-oriented programs.

My goal is not to create an object oriented language for Purebasic, but to simplify the creation of own objects.
For full support of object oriented programming there are other programming languages available.

For some tasks it is advantageous to create them object-oriented.
Here the same effort applies with Purebasic as for example with "C".
Everything has to be defined and created by yourself. The rules for objects and the functions and methods must be kept.

1. The first entry in the object is always the pointer to the table with the methods.
2. The first parameter of the methods is always the pointer to the own object.

Classes

To create an object you need a class.
A class defines the data type of an object.
This defines the table of methods (functions) and attributes (variables).

Constructors and Destructors

Constructors are functions that bring the object into a defined state when it is created and, if necessary, create the required resources.
Destructors are functions that release resources when the object is released.

Constructors can also have parameters, but are not supported by all programming languages.
Destructors have no parameters.

Constructors and destructors have no return value.

Method Super

To inherit a class, you need a super function that passes the methods and attributes to the subclass.
This also includes the constructors and destructors of the class.
Multiple inheritance can therefore result in multiple constructors and destructors that must be called in the correct order.

Interface

Interfaces define the interface which methods exist or must exist.


What Purebasic supports

Purebasic supports interfaces and attributes, as well as inheritance of interfaces and attributes.

- Interface SubClass Extends BaseClass
- Structure SubAttribute Extends BaseAttribute

Call the methods from the interfaces.


What does the module BaseClassSmall support

Creating and managing classes : NewClass(InterfaceName, ...)
- Create tables for methods, constructors, and destructors.
* Note: Contructors with parameters are not supported.
- The method Super, automated.

The base interface with the methods of type IUnknown
- QueryInterface(*riid, *addr)
- AddRef()
- Release()

The base attributes with the structure
- System\vTable : pointer to the method table.
- System\Class : Pointer to the class with the tables of the methods, constructors, destructors and package attributes.
- System\RefCount : Counter to protect the object.
- System\Mutex : Mutex for asynchronous processing of the object.

Assignment of the contructor : Macro AsInitializeObject(Name of the procedure)
Assignment of the destructor : Macro AsDisposeObject(Name of the procedure)

Initialize of package attributes : Macro InitPackage()

Assignment of methods : Macro AsMethod(Name of method and procedure)
Overwrite methods : Macro AsNewMethod(Name of method and procedure)

Creating the object : Macro InitObject or AllocateObject/InitializeObject for the procedure to create the object
- Creating the memory for the object.
- Assignment of the Virtual Table and Basic Attributes.
- Calling the constructors in the correct order.

Method QueryInterface : Object\QueryInterface(*riid, *addr)
- Default Method with result of query IUnknown.
* The method can be overwritten if necessary.

Method AddRef : Object\AddRef()
- Increases the counter of the object.
* This is deduced with Release object. The object is only released after it has been reset to zero.
! Do not overwrite !

Method Release : Object\Release()
- Calling the destructors in the correct order.
- Releasing the memory.
! Do not overwrite !

Checking the Class in Debugger Mode
- Call CheckInterface() at the end of the module.
Last edited by mk-soft on Wed Jun 17, 2020 4:10 pm, edited 24 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (OOP)

Post by mk-soft »

Example 3 (Update)

Code: Select all

; Example 3 v1.13
IncludeFile "Modul_BaseClassSmall.pb"
; *******************************************************************************
DeclareModule User
 
 UseModule BaseClass
 
 Structure sUser Extends sBaseClass
 firstname.s
 lastname.s
 EndStructure
 
 Interface iUser Extends iBaseClass
 SetName(FirstName.s, LastName.s)
 GetName.s()
 GetFirstName.s()
 GetLastName.s()
 Clone()
 EndInterface
 
 UnuseModule BaseClass
 
 Declare.i New()
 
EndDeclareModule
Module User
 
 UseModule BaseClass
 
 NewClass(iUser)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Init(*this.sUser)
 *this\firstname = "no name"
 *this\lastname = "no name"
 Debug "Initalize Object Class User " + *this
 EndProcedure : AsInitializeObject(Init)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Dispose(*this.sUser)
 Debug "Dispose Object Class User " + *this
 EndProcedure : AsDisposeObject(Dispose)
 
 ; ---------------------------------------------------------------------------
 
 Procedure SetName(*this.sUser, FirstName.s, LastName.s)
 With *this
 \firstname = FirstName
 \lastname = LastName
 EndWith
 EndProcedure : AsMethode(SetName)
 
 ; ---------------------------------------------------------------------------
 
 Procedure.s GetName(*this.sUser)
 With *this
 ProcedureReturn \lastname + ";" + \firstname
 EndWith
 EndProcedure : AsMethode(GetName)
 
 ; ---------------------------------------------------------------------------
 
 Procedure.s GetFirstName(*this.sUser)
 ProcedureReturn *this\firstname
 EndProcedure : AsMethode(GetFirstName)
 
 ; ---------------------------------------------------------------------------
 
 Procedure.s GetLastName(*this.sUser)
 ProcedureReturn *this\lastname
 EndProcedure : AsMethode(GetLastName)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Clone(*this.sUser)
 Protected *clone.sUser
 CloneObject(*this, *clone, sUser) 
 ProcedureReturn *clone
 EndProcedure : AsMethode(Clone)
 
 ; ---------------------------------------------------------------------------
 
 Procedure New()
 InitObject(sUser)
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 CheckInterface()
 
EndModule
; *******************************************************************************
DeclareModule Adress
 
 UseModule User
 
 Structure sAdress Extends sUser
 street.s
 postal.i
 city.s
 country.s
 EndStructure
 
 Interface iAdress Extends iUser
 SetAdress(street.s, postal.i, city.s, country.s)
 GetStreet.s()
 GetPostal.i()
 GetCity.s()
 GetCountry.s()
 GetAll.s()
 EndInterface
 
 UnuseModule User
 
 Declare New()
 
EndDeclareModule
Module Adress
 
 UseModule BaseClass
 
 NewClass(iAdress, iUser)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Init(*this.sAdress)
 Debug "Initalize Object Class Adress " + *this
 EndProcedure : AsInitializeObject(Init)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Dispose(*this.sAdress)
 Debug "Dispose Object Class Adress " + *this
 EndProcedure : AsDisposeObject(Dispose)
 
 ; ---------------------------------------------------------------------------
 
 Procedure SetAdress(*this.sAdress, street.s, postal.i, city.s, country.s)
 With *this
 \street = street
 \postal = postal
 \city = city
 \country = country
 EndWith
 EndProcedure : AsMethode(SetAdress)
 
 ; ---------------------------------------------------------------------------
 
 Procedure.s GetStreet(*this.sAdress)
 With *this
 ProcedureReturn \street
 EndWith
 EndProcedure : AsMethode(GetStreet)
 
 ; ---------------------------------------------------------------------------
 
 Procedure GetPostal(*this.sAdress)
 With *this
 ProcedureReturn \postal
 EndWith
 EndProcedure : AsMethode(GetPostal)
 
 ; ---------------------------------------------------------------------------
 
 Procedure.s GetCity(*this.sAdress)
 With *this
 ProcedureReturn \city
 EndWith
 EndProcedure : AsMethode(GetCity)
 
 ; ---------------------------------------------------------------------------
 
 Procedure.s GetCountry(*this.sAdress)
 With *this
 ProcedureReturn \country
 EndWith
 EndProcedure : AsMethode(GetCountry)
 
 ; ---------------------------------------------------------------------------
 
 Procedure.s GetAll(*this.sAdress)
 Protected r1.s
 With *this
 r1 = \LastName + ";"
 r1 + \FirstName + ";"
 r1 + \street + ";"
 r1 + \city + ";"
 r1 + \postal + ";"
 r1 + \country
 ProcedureReturn r1
 EndWith
 EndProcedure : AsMethode(GetAll)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Clone(*this.sAdress)
 Protected *clone.sAdress
 CloneObject(*this, *clone, sAdress)
 ProcedureReturn *clone
 EndProcedure : AsNewMethode(Clone)
 
 ; ---------------------------------------------------------------------------
 
 Procedure New()
 InitObject(sAdress)
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 CheckInterface()
 
EndModule
; *******************************************************************************
;- Test
Define.Adress::iAdress *user, *user2
*user=Adress::New()
Debug *user\GetName()
*user\SetName("Toto", "Buddy")
*user\AddRef()
Debug *user\GetName()
*user2 = *user\Clone()
*user2\SetAdress("My Street", 12345, "My City", "My Country")
Debug *user2\GetAll()
Debug *user\Release()
Debug *user\Release()
Debug *user2\Release()
Last edited by mk-soft on Sat May 04, 2019 1:50 pm, edited 8 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (OOP)

Post by mk-soft »

Example 6 Update

Update

Code: Select all

;-TOP
; Example 6 v1.13
IncludeFile "Modul_BaseClassSmall.pb"
; *******************************************************************************
DeclareModule DataSet
 
 UseModule BaseClass
 
 ; Properties
 Structure sDataSet Extends sBaseClass
 *pData
 Count.i
 Array *pStr(0)
 EndStructure
 
 ; Methods
 Interface iDataSet Extends iBaseClass
 Get.s(index)
 Count()
 EndInterface
 
 UnuseModule BaseClass
 
 ; New Object
 Declare New(*pData)
 
EndDeclareModule
Module DataSet
 
 UseModule BaseClass
 
 NewClass(iDataSet)
 
 ; ---------------------------------------------------------------------------
 
 Procedure.s Get(*this.sDataSet, index)
 With *this
 If index < \Count
 ProcedureReturn PeekS(\pStr(index))
 Else
 ProcedureReturn ""
 EndIf
 EndWith
 EndProcedure : AsMethode(Get)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Count(*this.sDataSet)
 ProcedureReturn *this\Count
 EndProcedure : AsMethode(Count)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Init(*this.sDataSet)
 Protected *pos, len, index
 With *this
 *pos = \pData
 Repeat
 len = MemoryStringLength(*pos)
 If len
 \Count + 1
 *pos + len * SizeOf(character) + SizeOf(character)
 Else
 Break
 EndIf
 ForEver
 Dim \pStr(\Count)
 *pos = \pData
 Repeat
 len = MemoryStringLength(*pos)
 If len
 \pStr(index) = *pos
 index + 1
 *pos + len * SizeOf(character) + SizeOf(character)
 Else
 Break
 EndIf
 ForEver
 
 EndWith
 
 EndProcedure : AsInitializeObject(Init)
 
 ; ---------------------------------------------------------------------------
 
 Procedure New(*pData)
 
 Protected *obj.sDataSet
 
 AllocateObject(*obj, sDataSet)
 If *obj
 *obj\pData = *pData
 EndIf
 InitializeObject(*obj)
 
 ProcedureReturn *obj
 
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 CheckInterface()
 
EndModule
; *******************************************************************************
;- Test
EnableExplicit
Macro Object(ObjectName, ObjectType)
 ObjectName.ObjectType#::i#ObjectType
EndMacro
;BaseClass::ShowClasses()
Define.DataSet::iDataSet *set1, *set2
Define i
Debug "Data 1"
*set1 = DataSet::New(?DataSet1)
For i = 0 To *set1\Count() - 1
 Debug *set1\Get(i)
Next
Debug "----------------"
Debug "Data 2"
*set2 = DataSet::New(?DataSet2)
For i = 0 To *set2\Count() - 1
 Debug *set2\Get(i)
Next
DataSection
 DataSet1:
 Data.s "Sontag"
 Data.s "Montag"
 Data.s "Dienstag"
 Data.s "Mittwoch"
 Data.s "Donnerstag"
 Data.s "Freitag"
 Data.s "Samstag"
 Data.i 0
 
 DataSet2:
 Data.s "Januar"
 Data.s "Februar"
 Data.s "März"
 Data.s "April"
 Data.s "Mai"
 Data.s "Juni"
 Data.s "Juli"
 Data.s "August"
 Data.s "September"
 Data.s "Oktober"
 Data.s "November"
 Data.s "Dezember"
 Data.i 0
EndDataSection
Last edited by mk-soft on Sat May 04, 2019 1:51 pm, edited 6 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Update v1.13
- Change Macro InitObject for small code
- Added Macros AllocateObject and InitalizeObject for new object with parameters

Examples updated...
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Update v1.15
* Added debugger functions
- ShowInterface(...)
- CheckInterface(...)

:wink:
Last edited by mk-soft on Mon Aug 15, 2016 10:10 pm, edited 1 time in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Update v1.16
- optimize code
- added debugging info

GT :wink:
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Update v1.20
-
Update v1.21
- Change NewClass(Extends=BaseClass) -> NewClass(CLassInterface, ClassExtends=BaseClass)
* First parameter now the name of interface
+ The sequence of procedures for the methods not longer the same order as they are defined in the interface.
+ Better CheckInterface

- Added debugger info ShowClasses
* Show all Interfaces

:wink:
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Update v1.22
- Code cleaned

That is probably the smallest code to use OOP with PureBasic, without a new syntax in PureBasic to develop. :wink:
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Update v1.23
- Safety RefCounter over Mutex
Last edited by mk-soft on Sat Feb 25, 2017 2:55 pm, edited 1 time in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Update
- Added Macro CloneObject because some things to do
- Added Check mutex
- Added Macro LockObject and UnlockObject

Code: Select all

...
Procedure Clone(*this.sUser)
 Protected *clone.sUser
 CloneObject(*this, *clone, sUser) 
 ProcedureReturn *clone
EndProcedure : AsMethode(Clone)
... 
Update

Code: Select all

;-TOP
; Example 9 v1.13
CompilerIf #PB_Compiler_Thread = 0
 CompilerError "Use compiler option theadsafe"
CompilerEndIf
IncludeFile "Modul_BaseClassSmall.pb"
DeclareModule Work
 UseModule BaseClass
 
 Structure sWork Extends sBaseClass
 Value.i
 EndStructure
 
 Interface iWork Extends iBaseClass
 Add(Value)
 Sub(Value)
 EndInterface
 
 Declare New()
 
EndDeclareModule
Module Work
 
 UseModule BaseClass
 
 NewClass(iWork)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Init(*this.sWork)
 Debug "Initialize Work"
 EndProcedure : AsInitializeObject(Init)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Destroy(*this.sWork)
 Debug "Dispose Work"
 Debug "Result: " + *this\Value
 EndProcedure : AsDisposeObject(Destroy)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Add(*this.sWork, Value)
 Protected result
 LockObject(*this)
 *this\Value + Value
 result = *this\Value
 UnlockObject(*this)
 ProcedureReturn result
 EndProcedure : AsMethode(Add)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Sub(*this.sWork, Value = 0)
 Protected result
 LockObject(*this)
 *this\Value - Value
 result = *this\Value
 UnlockObject(*this)
 ProcedureReturn result
 EndProcedure : AsMethode(Sub)
 
 ; ---------------------------------------------------------------------------
 
 Procedure New()
 InitObject(sWork) ; Mehr kommt hier nicht rein!
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 CheckInterface()
 
EndModule
; ***************************************************************************************
;-Test AddRef
Procedure thAdd(*Object.Work::iWork)
 Protected time
 *Object\AddRef()
 Delay(1000)
 ;Debug "Start"
 For i = 1 To 10
 time = Random(200)
 *Object\Add(1)
 Delay(time)
 Next
 ;Debug "Ready."
 *Object\Release()
EndProcedure
Debug "Mainscope Create Object"
Define *Object.Work::iWork
*Object = Work::New()
mutex = CreateMutex()
Debug "Start Threads"
For i = 1 To 1000
 th = CreateThread(@thAdd(), *Object)
 Delay(5)
 If th = 0
 Debug "No Thread " + i
 EndIf
Next
Debug "Mainscope Wait..."
Repeat
 Delay(200)
 ref = *Object\AddRef()
 ref = *Object\Release()
 Debug ref
 If ref = 0
 Break
 EndIf
ForEver
Debug "Mainscope Release Object"
*Object\Release()
Debug "Ready."
Last edited by mk-soft on Sat May 04, 2019 1:53 pm, edited 5 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
step11
New User
New User
Posts: 7
Joined: Tue May 31, 2016 7:19 am

Re: Module BaseClass (Module as Object)

Post by step11 »

Excellent code :D
If you add a QueryInterface Method,it should support IUknwn Interface?
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Update v1.26
- Added QueryInterface for compatible with Interface 'IUnknown'.
-- The default result of QueryInterface is constant 'E_NoInterface' for compatibles with Linux and Mac
-- Show Example 10 to managed AsNewMethode 'QuerInterface'
- Change RefCounter. Begin now with Zero

Helpcode to create own Uuid

Code: Select all

Procedure.s CreateUuid()
 Protected Uuid.iid, result.s, i
 UuidCreate_(Uuid.iid)
 result = " DataSection" + #LF$
 result + " Uuid:" + #LF$
 result + " Data.l $" + RSet(Hex(Uuid\Data1), 8, "0") + #LF$
 result + " Data.w $" + RSet(Hex(Uuid\Data2), 4, "0") + ", $" + RSet(Hex(Uuid\Data3), 4, "0") + #LF$
 result + " Data.b $" + RSet(Hex(Uuid\Data4[0]), 2, "0")
 For i = 1 To 7
 result + ", $" + RSet(Hex(Uuid\Data4[i]), 2, "0")
 Next
 result + #LF$
 result + " EndDataSection" + #LF$
 ProcedureReturn result
EndProcedure
; ***************************************************************************************
Uuid.s = CreateUuid()
SetClipboardText(Uuid)
Debug Uuid
Debug "Copied into clipboard"
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
mk-soft
Always Here
Always Here
Posts: 6346
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Module BaseClass (Module as Object)

Post by mk-soft »

Example 10 - Overwrite Method QueryInterface (For Windows)

Update v1.15

Code: Select all

;-TOP
; Example 10 IUnknown
IncludeFile "Modul_BaseClassSmall.pb"
DeclareModule MyObject
 
 EnableExplicit
 
 Interface iMyObject Extends BaseClass::iBaseClass
 Add(Value)
 Sub(Value)
 Result()
 EndInterface
 
 Structure sMyObject Extends BaseClass::sBaseClass
 Value.i
 EndStructure
 
 ; Own Uuid
 DataSection
 IID_IMyObject:
 Data.l 3ドルC4855AF
 Data.w 3ドルAC7, 4ドルA60
 Data.b $FF, $FF, $FF, 2ドルA, 06,ドル 54,ドル 54,ドル $FF
 EndDataSection
 
 Declare New()
 
EndDeclareModule
Module MyObject
 
 EnableExplicit
 
 UseModule BaseClass
 
 NewClass(iMyObject)
 
 ; ---------------------------------------------------------------------------
 
 ; Overwrite Methode QueryInterface
 
 Procedure QueryInterface(*This.sBaseClass, *riid, *ppvObject.integer)
 Protected *new
 If *ppvObject = 0
 ProcedureReturn #E_INVALIDARG
 EndIf
 If CompareMemory(*riid, ?IID_IUnknown, 16)
 LockMutex(*This\System\Mutex)
 *ppvObject\i = *This
 *This\System\RefCount + 1
 UnlockMutex(*This\System\Mutex)
 ProcedureReturn #S_OK
 ElseIf CompareMemory(*riid, ?IID_IMyObject, SizeOf(iid))
 *new = New()
 If *new
 *ppvObject\i = *new
 ProcedureReturn #S_OK
 Else 
 ProcedureReturn #E_OUTOFMEMORY
 EndIf
 Else ; No Interface
 ProcedureReturn #E_NOINTERFACE
 EndIf
 EndProcedure : AsNewMethode(QueryInterface)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Initialize(*this.sMyObject)
 Debug "Initialize Object " + Hex(*this)
 EndProcedure : AsInitializeObject(Initialize)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Dispose(*this.sMyObject)
 Debug "Dispose Object " + Hex(*this)
 EndProcedure : AsDisposeObject(Dispose)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Add(*this.sMyObject, Value)
 *this\Value + Value
 EndProcedure : AsMethode(Add)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Sub(*this.sMyObject, Value)
 *this\Value - Value
 EndProcedure : AsMethode(Sub)
 
 ; ---------------------------------------------------------------------------
 
 Procedure Result(*this.sMyObject)
 ProcedureReturn *this\Value
 EndProcedure : AsMethode(Result)
 
 ; ---------------------------------------------------------------------------
 
 Procedure New()
 InitObject(sMyObject)
 EndProcedure
 
 ; ---------------------------------------------------------------------------
 
 DataSection
 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
 
 ; ---------------------------------------------------------------------------
 
 CheckInterface()
 
EndModule
; ***************************************************************************************
;-Test
Debug "Create Object"
Define *obj.IUnknown
*obj = MyObject::New()
Debug "--------------------------------"
r1 = *obj\QueryInterface(?IID_IUnknown, @*obj_temp)
If r1 = #S_OK
 Debug "QueryInterface IUnknown Ok: Object " + Hex(*obj)
 Debug "AddRef: " + *obj\AddRef()
 Debug "Release IUnknown: " + *obj\Release()
 Debug "Release IUnknown: " + *obj\Release()
EndIf
Debug "--------------------------------"
Define *obj2.MyObject::iMyObject
If *obj\QueryInterface(MyObject::?IID_IMyObject, @*obj2) = #S_OK
 Debug "QueryInterface IID_MyObject Ok: Object " + Hex(*obj2)
 Debug "Add 1000"
 *obj2\Add(1000)
 Debug "Sub 100"
 *obj2\Sub(100)
 Debug "Result: " + *obj2\Result()
 Debug "Relaease MyObject: " + *obj2\Release()
EndIf
Debug "--------------------------------"
If *obj\QueryInterface(?IID_IDispatch, 0) = #S_OK
 Debug "IDispatch Ok"
 Debug "Release IDispatch: " + *obj\Release()
Else
 Debug "No Interface IDispatch"
EndIf
Debug "--------------------------------"
Debug "Release Object"
Debug "Release: " + *obj\Release()
DataSection
 IID_NULL: ; {00000000-0000-0000-0000-000000000000}
 Data.l 00000000ドル
 Data.w 0000,ドル 0000ドル
 Data.b 00,ドル 00,ドル 00,ドル 00,ドル 00,ドル 00,ドル 00,ドル 00ドル 
 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_IDispatch:
 Data.l 00020400ドル
 Data.w 0000,ドル 0000ドル
 Data.b $C0,00,ドル00,ドル00,ドル00,ドル00,ドル00,ドル46ドル
 IID_IClassFactory:
 Data.l 00000001ドル
 Data.w 0000,ドル 0000ドル
 Data.b $C0, 0,ドル 0,ドル 0,ドル 0,ドル 0,ドル 0,ドル 46ドル
EndDataSection
:wink:
Last edited by mk-soft on Sat Feb 08, 2020 2:02 pm, edited 12 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Module BaseClass (Module as Object)

Post by ts-soft »

Better don't Import UUID.lib : http://www.purebasic.fr/english/viewtop ... 79#p205779

Better use Datasection, make a smaller foot :wink:
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
Post Reply

Return to "Tricks 'n' Tips"