Difference between revisions of "Singletons"

From HashVB
Jump to: navigation, search
(Oops, didn't mean to quote the list.)
(Using the ROT for singleton objects)
 
(6 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 +
{{VB6}}
 
Singleton objects are useful for sharing data between multiple callers.
 
Singleton objects are useful for sharing data between multiple callers.
  
Line 6: Line 7:
 
  Public Singleton As New SingletonObject
 
  Public Singleton As New SingletonObject
  
As long as this is in a module, this variable (a single instance of the object) will be accessable from the entire project.
+
As long as this is in a module, this variable (a single instance of the object) will be accessible from the entire project.
 
Ideally, you should remove the "New" and use this once on startup
 
Ideally, you should remove the "New" and use this once on startup
 
  Set Singleton = New SingletonObject
 
  Set Singleton = New SingletonObject
Line 12: Line 13:
 
=Multiple processes=
 
=Multiple processes=
  
If you want to access a singleton object accross multple proccesses, you need to put in a bit more effort.
+
If you want to access a singleton object across multiple processes, you need to put in a bit more effort.
As there can only be a single "owner", this will need to be a seperate process (or ActiveX EXE) from all the callers that contains 3 important parts.
+
As there can only be a single "owner", this will need to be a separate process (or ActiveX EXE) from all the callers that contains 3 important parts.
 
* The singleton class
 
* The singleton class
 
* A public variable of the singleton class
 
* A public variable of the singleton class
 
* A global class that allows access to the public variable
 
* A global class that allows access to the public variable
  
The variable is very much like the one used for the [[#Single process]] sample above as it is only directly accessd by (multiple instances of) the global class.
+
The variable is very much like the one used for the [[#Single process|single process]] sample above as it is only directly accessed by (multiple instances of) the global class.
  
The global class only needs to contain a single function that will instantiate the singleton object if it hasn'tr been created already and then return it.
+
The global class only needs to contain a single function that will instantiate the singleton object if it hasn't been created already and then return it.
  
 
  Public Function GetSingleton As SingletonObject
 
  Public Function GetSingleton As SingletonObject
Line 31: Line 32:
 
As soon as all references have been released or destroyed then it will cleanly shutdown.
 
As soon as all references have been released or destroyed then it will cleanly shutdown.
  
Please note that this can't be done using COM DLLs as the "public" variables are private to each application.
+
Please note that this can't be done using COM DLLs as the "public" variables are private to each application and that the ActiveX EXE project needs to be set to use a thread pool of 1.
 +
 
 +
== Using the ROT ==
 +
 
 +
It is also possible to register objects with the Running Object Table (ROT) in windows so any application can access it given the Class ID.
 +
 
 +
Objects can be registered with the RegisterActiveObject API call passing a pointer to the object and its GUID:
 +
 
 +
Private Type GUID
 +
  Data1 As Long
 +
  Data2 As Integer
 +
  Data3 As Integer
 +
  Data4(0 To 7) As Byte
 +
End Type
 +
 +
Declare Function CLSIDFromProgID Lib "OLE32.DLL" (ByVal ProgID As Long, rclsid As GUID) As Long
 +
Declare Function RegisterActiveObject Lib "oleaut32.dll" (ByVal pUnk As Long, rclsid As GUID, ByVal dwFlags As Long, pdwRegister As Long) As Long
 +
 +
Const ACTIVEOBJECT_WEAK As Long = 1
 +
 
 +
CLSIDFromProgID StrPtr("ProjectName.ClassName"), GUID
 +
RegisterActiveObject ObjPtr(ClassVariable), GUID, ACTIVEOBJECT_WEAK, Handle
 +
 
 +
This object can now be access form any process with a simple call to GetObject:
 +
 
 +
Set ClassVariable = GetObject(, "ProjectName.ClassName")
 +
 
 +
Please note that when an object is registered in the ROT, it keeps a reference to it so your object will not shutdown unless you explicitly remove it with RevokeActiveObject using:
 +
 
 +
Declare Function RevokeActiveObject Lib "oleaut32.dll" (ByVal dwRegister As Long, Optional ByVal pvReserved As Long = 0) As Long
 +
 
 +
RevokeActiveObject Handle, 0
 +
 
 +
This is only a very simple sample of using the ROT. For a more advanced solution and more information, I recommend reading [http://www.powervb.com Advanced Visual Basic 6] by Matthew Curland.
  
 
Enjoy.
 
Enjoy.

Latest revision as of 16:45, 20 February 2006

float
 This article is based on Visual Basic 6. Find other Visual Basic 6 articles.

Singleton objects are useful for sharing data between multiple callers.

Single process

A singleton to be shared throughout a single project is easy.

Public Singleton As New SingletonObject

As long as this is in a module, this variable (a single instance of the object) will be accessible from the entire project. Ideally, you should remove the "New" and use this once on startup

Set Singleton = New SingletonObject

Multiple processes

If you want to access a singleton object across multiple processes, you need to put in a bit more effort. As there can only be a single "owner", this will need to be a separate process (or ActiveX EXE) from all the callers that contains 3 important parts.

  • The singleton class
  • A public variable of the singleton class
  • A global class that allows access to the public variable

The variable is very much like the one used for the single process sample above as it is only directly accessed by (multiple instances of) the global class.

The global class only needs to contain a single function that will instantiate the singleton object if it hasn't been created already and then return it.

Public Function GetSingleton As SingletonObject
  If Singleton Is Nothing Then Set Singleton = New SingletonObject
  Set GetSingleton = Singleton
End Function

If any other caller then creates another instance of the global object and calls GetSingleton, it will return the already created object.

As soon as all references have been released or destroyed then it will cleanly shutdown.

Please note that this can't be done using COM DLLs as the "public" variables are private to each application and that the ActiveX EXE project needs to be set to use a thread pool of 1.

Using the ROT

It is also possible to register objects with the Running Object Table (ROT) in windows so any application can access it given the Class ID.

Objects can be registered with the RegisterActiveObject API call passing a pointer to the object and its GUID:

Private Type GUID
  Data1 As Long
  Data2 As Integer
  Data3 As Integer
  Data4(0 To 7) As Byte
End Type

Declare Function CLSIDFromProgID Lib "OLE32.DLL" (ByVal ProgID As Long, rclsid As GUID) As Long
Declare Function RegisterActiveObject Lib "oleaut32.dll" (ByVal pUnk As Long, rclsid As GUID, ByVal dwFlags As Long, pdwRegister As Long) As Long

Const ACTIVEOBJECT_WEAK As Long = 1
CLSIDFromProgID StrPtr("ProjectName.ClassName"), GUID
RegisterActiveObject ObjPtr(ClassVariable), GUID, ACTIVEOBJECT_WEAK, Handle

This object can now be access form any process with a simple call to GetObject:

Set ClassVariable = GetObject(, "ProjectName.ClassName")

Please note that when an object is registered in the ROT, it keeps a reference to it so your object will not shutdown unless you explicitly remove it with RevokeActiveObject using:

Declare Function RevokeActiveObject Lib "oleaut32.dll" (ByVal dwRegister As Long, Optional ByVal pvReserved As Long = 0) As Long
RevokeActiveObject Handle, 0

This is only a very simple sample of using the ROT. For a more advanced solution and more information, I recommend reading Advanced Visual Basic 6 by Matthew Curland.

Enjoy.