1 Attachment(s)
There can be only one... [VB6 DCOM Singleton]
And maybe it's not supposed to be done, but I got Matt Curland's ActiveX EXE Singleton Server working with DCOM. :bigyello:
Huh?!?!?!
From "Design Patterns," p.127:
Quote:
Ensure a class has one instance, and provide a global point of access to it.
Matt Curland's book "Advanced Visual BAsic 6" has an obscure little chapter in it where he builds on his VBoost power VB object library, in chpater 10 entitled "VB Objects and the Running Object Table." This is also briefly described in an old article, "Give your Classes GetObject Support":
http://www.ftponline.com/archives/li...MagIssueId=98#
It is directly from these resources that I was able to get an ActiveX EXE Server to behave as a Singleton. A client will check to see if an instance of the server is out there, and if not, create one. Once that server is up and running, no more instances of the server are created. Instead, new clients hold a reference to the same Object. - {EDIT} So far I have not gotten this to work with multiple remote clients. Multplie local clients will all talk to the same server correctly.
Quote:
There can be only one...
Somewhere, through all the code and documentation I waded through lo these many moons, I did read a caveat - the Singleton built on VBoost objects is not designed to work with DCOM and sounded guaranteed not to work - although I think that might apply to VB5 projects (this is all VB6).
Well, being a stubborn fool, I went to work and tried it anyway. Looks like I got it working to a point where I can start to look at making it more robust. But before I do, I wanted to document all that I did so far.
Code first, pics second...
The project requires that you have some of Matt Curland's VBoost files in the project. If you own a copy of his book, then you have them:
[list=1][*]ROTHook.bas[*]VBoost.bas[/list=1]
The other files I will provide are not CopyRight-ed.
[list=1][*]StateServer.vbp[*]frmMain.frm[*]modMain.bas[*](ROTHook.bas)[*](VBoost.bas)[*]clsState.cls[*]UseStateServer.vbp[*]frmClient.frm[/list=1]
frmMain.frm
VB Code:
Option Explicit
'
Private WithEvents m_State As clsState
'
'
Private Sub Form_Load()
On Error Resume Next
Set m_State = GetObject(, "StateServer.clsState")
On Error GoTo 0
If m_State Is Nothing Then
Set m_State = New clsState
End If
m_State.Locked = True
Me.lblState.Caption = m_State.State
End Sub
Private Sub Form_Unload(Cancel As Integer)
m_State.Locked = False
Set m_State = Nothing
End Sub
Private Sub m_State_State(ByVal Current As Variant)
' This is an Event
Me.lblState.Caption = Current
End Sub
Private Sub txtState_Change()
m_State.State = Me.txtState.Text
End Sub
modMain.bas
VB Code:
Option Explicit
'
Private m_ServerForm As frmMain
'
Public Sub EnsureServerForm()
If m_ServerForm Is Nothing Then
Set m_ServerForm = New frmMain
m_ServerForm.Show
End If
End Sub
Sub Main()
InitVBoost
'
If App.StartMode = vbSModeStandalone Then
EnsureServerForm
End If
'
End Sub
clsState.cls
VB Code:
Option Explicit
'
'
Public Event State(ByVal Current As Variant)
Private m_ROTHook As ROTHook
Private m_varState As Variant
'
Private Sub Class_Initialize()
InitROTHook m_ROTHook
m_ROTHook.Hook.ExposeObject Me, "StateServer.clsState"
EnsureServerForm
End Sub
Private Sub Class_Terminate()
m_ROTHook.Hook.HideObject
End Sub
Friend Property Let Locked(ByVal RHS As Boolean)
m_ROTHook.Hook.Locked = RHS
End Property
Public Property Let State(ByVal vNewValue As Variant)
m_varState = vNewValue
RaiseEvent State(m_varState)
End Property
Public Property Get State() As Variant
State = m_varState
End Property
frmClient.frm
VB Code:
Option Explicit
'
Private WithEvents m_State As clsState
'
'
Private Sub Form_Load()
'
' The following 2 statements seem equivalent
'
'Set m_State = StateServer.clsState
Set m_State = GetObject("", "StateServer.clsState")
'
Me.lblState.Caption = m_State.State
End Sub
Private Sub m_State_State(ByVal Current As Variant)
' This is an Event
Me.lblState.Caption = Current
End Sub
Private Sub txtState_Change()
m_State.State = Me.txtState.Text
End Sub
Compile the Server as an ActiveX EXE, and the client as a normal EXE project. You have Binary Compatibility turned on, right?
Pick a WinXP Pro machine on the LAN to act as the server. On this machine, run DCOMCNFG.EXE to configure DCOM settings as follows (You have to execute the server EXE once):
http://www.vbforums.com/attachment.p...postid=1822172
http://www.vbforums.com/attachment.p...postid=1822174
http://www.vbforums.com/attachment.p...postid=1822175
http://www.vbforums.com/attachment.p...postid=1822176
http://www.vbforums.com/attachment.p...postid=1822177
You could just play around with the client and the server at this point from the server machine. On to the Client machine! Again, the ActiveX EXE server must be copied to the local disk of the client and executed once. Beware, never execute the server on the client directly after DCOM setup - some settings will revert! Again, run DCOMCNFG.EXE to set up the Client as follows:
http://www.vbforums.com/attachment.p...postid=1822155
http://www.vbforums.com/attachment.p...postid=1822157
http://www.vbforums.com/attachment.p...postid=1822163
http://www.vbforums.com/attachment.p...postid=1822164
My local SW firewalls have to be turned off for this to work, but that could probably be corrected. I recommend you turn yours off just to get all your ducks in a row.
Well, assuming you did all that, we are actually done! You can run the Client executable from the Client machine and type something in:
http://www.vbforums.com/attachment.p...postid=1822165
Go to the server machine, and you will see it has caught all the state changes:
http://www.vbforums.com/attachment.p...postid=1822169
Also note, you can type directly into the server window, and the State-Changing Events will show up on the client.
I will post executables that you can play with.
There are some bugs yet to be worked out. For example, if I load the Client EXE on the Client, the Server EXE opens up. However, if I leave the server EXE up, then close the ClientEXE , then re-open the Client EXE, it will not be talking to the Server EXE anymore.
I may require that the Client cannot terminate itself - I might implement a ClientTerminate Event (initiated at the server) for all the Clients to capture.