In the early days of VB6-usage there was DCOM (later superseded by COM+).
It came with the promise of easy cross-machine-calls (RPCs) by simply using the second
(optional) Parameter [ServerName] of the CreateObject-call...
Now, is there anybody out there (aside from myself), who ever used that (or anybody who's still using it)?
I guess not - and there's a reason for it.
Don't get me wrong - DCOM/COM+ is a great technology - which still works to this day -
*but* - for proper usage you will have to study a few books about that topic, before you
make your first serious steps ... -> right into "config-hell".
So, basically "nice stuff" (and used to this day in some LAN-scenarios, after a "config-orgy"
and countless Proxy-installs on the clients) - but firing it up as easily as the CreateObject-call
suggests? ... Forget about it.
Well, the RichClient5 offers an alternative to DCOM/COM+, which in contrast supports:
- not touching the Registry (serverside Dlls don't need to be registered)
- avoidance of clientside Proxy-installs (to match the interfaces of the serverside COM-Dlls)
- easy movement of the RC5-RPC serverside part to a different Machine per X-Copy of the Server-RootFolder
- same performance as DCOM/COM+ (thousands of Remote-Requests per second in multiple WorkerThreads)
. but using only a single Port ... whereas DCOM/COM+ needs a complete Port-Range
- usable therefore also in Internet-Scenarios, also due to strong authentication/encryption and built-in compression
Ok, so where's the beef - how to use that thing?
Here's the Code for a SimpleRPC-Demo SimpleRPC.zip ...
and a short description with some background follows below...
A finished solution consists of three things (three VB6-Projects):
VB-Project #1: The Server-Application (providing the HostProcess for the AppServer-Listener)
- in the above Zip, this is the Project sitting in Path: ..\RPCServer\RPCServer.vbp
This is the most easy of the three parts, since it is not "ClientApp- or Server-Dll specific" -
just a hosting Exe-Project for the Service which will work with any ServerDll and any Client.
You will only have to compile it once - and can then forget about it...
Here's the complete SourceCode for this ServerHost-Executable (all in a little Form):
That's it with regards to the ServerHost-instance (a normal UserMode-Executable in our Demo-case).
VB-Project(s) #2: One (or more) ActiveX-Server-Dll(s)
- in the above Zip, this is the Project sitting in Path: ..\RPCServer\RPCDlls\SimpleServerLib.vbp
When you look at the above code for the Service-Host - and its RPCListener.StartServer-function, you will see that it receives a
StartParameter 'DllPath' which in this case points to a SubFolder of the Serverhost-Executable: App.Path & "\RPCDlls\"
And this place (this RPCDlls-Folder) is, where you will have to put your compiled Server-Dlls into.
The Public Subs and Functions you will put into the Class(es) of these Dlls will be, what you later on call remotely
(without the need to register these Dlls).
Here's the whole code of the single Class (cServerClass), this Dll-Project contains -
and yes, you can write this code as any other VB6-Code, as normal Public Subs and Functions
(this little Dll-Project doesn't even have a reference to vbRichClient5, the only reference it contains,
is the one to "ADO 2.5", since it will transfer an ADO-Recordset back to the clientside later on).
That's it - nothing more is needed for the "active part" of the serverside (the Server-Dlls).
The serverside code is hereby (with #1 and #2) completely finished!
VB-Project #3: The Client-App
- in the above Zip, this is the Project sitting in Path: ..\ClientApp\SimpleRPC.vbp
What remains now, is the clientside part of the RPC - the one which *initiates* an
RPC-(Remote-Procedure-call).
The behaviour (to make the program-flow easier) is in case of the RC5-RPCs *always*
synchronously. That means, that RPCs will not return, until we got a Result, or an
Error-message - or a TimeOut-Error back from such a Remote-Method-call against the Server.
Although also the Clientside-Code is not more than 50 lines or so, I will put only
this smaller excerpt of the client-sides Form-code here into a code-section to explain...:
You will notice the red-colored Object-Variable (of type cRPCConnection) -
which resembles in its usage a bit, how one would work with e.g. the WinHTTP 5.1 Object...
Simply put - it encapsulates "the needed Socket-stuff" which is necessary, to be able to
work across machine-boundaries.
After this Object was "set up" (in Form_Load or in Sub Main - or also in a dedicated little
Wrapper-Class), what remains is to look at, where "the RPC-call happens"...
(for simplicity's sake, in this Demo not in an additional WrapperClass, but directly in the Forms: cmdAddTwoLongs_Click()
Just ask yourselves - what will need to happen under the covers of: RPCConn.RPC(...)?
Right (please look at the Strings I've marked blue in the above code):
- to be able to instantiate a Dll regfree from within the serversides \RPCDlls\ folder, we will need the DllName and the ClassName
. (so that we can create an Object-instance, which we will call LateBound then)...
- and to be able to perform a LateBound-Call (per CallByName), we will need the third blue string: "AddTwoLongs" (the Method-name)
- another requirement in the Parameter-List will be a TimeOut-Value (in the above call this is the 4th argument, the '3')
- and then finally the two arguments, which the AddTwoLongs-Method expects at the serverside (a VB6-Param-Array came in handy here)
So that's it basically with regards to a little "How-To-Do RPC-calls the easy way" with the vbRichClient5.
Note, that the RichClient RPC-Classes are in use at hundreds of Client-installations worldwide - and
that these Classes were included from the very beginning of the RichClient-project (over a decade ago).
So, this stuff was quite hardened over the years - and is not a "toy-implementation".
4) One last thing, I'd like to mention still with regards to the Demo (before you run it):
The RPC-Classes support a DebugMode (as contained in the last code-snippet above over: RPCConn.DebugMode = ...)
When this Property is True, then one can do an easy "RoundTrip-Debugging", when the
serverside Dll-Project in question is included in a VB-ProjectGroup.
The Demo will start (without the need to compile any Binaries) per Default in DebugMode -
and an appropriate \SimpleRPC\RPC_Test_Group.vbg File is included in the Root-Folder of the Demo.
Check this mode out first (leaving the DebugMode-CheckBox checked) -
later, when you e.g. have stepped through an RPC-call (per <F8> Key),
you can disable the Debug-Mode - but before you do so, you will have to compile:
- the ServerHost-Project I've mentioned in #1
- the ServerDll-Project I've mentioned in #2 (please make sure, that you compile the Dll into the \RPCDlls\-Folder)
- followed by starting the compiled ServerRPC-Executable
After that you can switch DebugMode Off - and perform "real RPC-calls over sockets"
Here's a ScreenShot of the little Client-App:
![]()
Have fun.
Olaf
It came with the promise of easy cross-machine-calls (RPCs) by simply using the second
(optional) Parameter [ServerName] of the CreateObject-call...
Now, is there anybody out there (aside from myself), who ever used that (or anybody who's still using it)?
I guess not - and there's a reason for it.
Don't get me wrong - DCOM/COM+ is a great technology - which still works to this day -
*but* - for proper usage you will have to study a few books about that topic, before you
make your first serious steps ... -> right into "config-hell".
So, basically "nice stuff" (and used to this day in some LAN-scenarios, after a "config-orgy"
and countless Proxy-installs on the clients) - but firing it up as easily as the CreateObject-call
suggests? ... Forget about it.
Well, the RichClient5 offers an alternative to DCOM/COM+, which in contrast supports:
- not touching the Registry (serverside Dlls don't need to be registered)
- avoidance of clientside Proxy-installs (to match the interfaces of the serverside COM-Dlls)
- easy movement of the RC5-RPC serverside part to a different Machine per X-Copy of the Server-RootFolder
- same performance as DCOM/COM+ (thousands of Remote-Requests per second in multiple WorkerThreads)
. but using only a single Port ... whereas DCOM/COM+ needs a complete Port-Range
- usable therefore also in Internet-Scenarios, also due to strong authentication/encryption and built-in compression
Ok, so where's the beef - how to use that thing?
Here's the Code for a SimpleRPC-Demo SimpleRPC.zip ...
and a short description with some background follows below...
A finished solution consists of three things (three VB6-Projects):
VB-Project #1: The Server-Application (providing the HostProcess for the AppServer-Listener)
- in the above Zip, this is the Project sitting in Path: ..\RPCServer\RPCServer.vbp
This is the most easy of the three parts, since it is not "ClientApp- or Server-Dll specific" -
just a hosting Exe-Project for the Service which will work with any ServerDll and any Client.
You will only have to compile it once - and can then forget about it...
Here's the complete SourceCode for this ServerHost-Executable (all in a little Form):
Code:
Private RPCListener As cRPCListener 'define the RPC-Server-Listener
Private IP As String, Port As Long, DllPath As String 'Start-Parameters
Private Sub Form_Load()
'normally this part is contained in a Windows-Service-Executable (without any UI)
IP = New_c.TCPServer.GetIP("") 'get the default-IP of the current machine
Port = 22222 'set a Port (22222 is the RC5-RPC default-port)
DllPath = App.Path & "\RPCDlls\" 'Path, where the Server is looking for the RPCDlls
Set RPCListener = New_c.RPCListener 'create the RPC-Listener-instance
If RPCListener.StartServer(IP, Port, , , , , DllPath) Then '... now we try to start the RPC-Server
Caption = "Server is listening on: " & IP & ":" & Port
Else
Caption = "Server-Start was not successful"
End If
End Sub
Private Sub Form_Terminate()
If Forms.Count = 0 Then New_c.CleanupRichClientDll
End Sub
VB-Project(s) #2: One (or more) ActiveX-Server-Dll(s)
- in the above Zip, this is the Project sitting in Path: ..\RPCServer\RPCDlls\SimpleServerLib.vbp
When you look at the above code for the Service-Host - and its RPCListener.StartServer-function, you will see that it receives a
StartParameter 'DllPath' which in this case points to a SubFolder of the Serverhost-Executable: App.Path & "\RPCDlls\"
And this place (this RPCDlls-Folder) is, where you will have to put your compiled Server-Dlls into.
The Public Subs and Functions you will put into the Class(es) of these Dlls will be, what you later on call remotely
(without the need to register these Dlls).
Here's the whole code of the single Class (cServerClass), this Dll-Project contains -
and yes, you can write this code as any other VB6-Code, as normal Public Subs and Functions
(this little Dll-Project doesn't even have a reference to vbRichClient5, the only reference it contains,
is the one to "ADO 2.5", since it will transfer an ADO-Recordset back to the clientside later on).
Code:
Private Cnn As ADODB.Connection
Public Function StringReflection(S As String) As String
StringReflection = StrReverse(S)
End Function
Public Function AddTwoLongs(ByVal L1 As Long, ByVal L2 As Long) As Long
AddTwoLongs = L1 + L2
End Function
Public Function GetADORs(SQL As String) As ADODB.Recordset
If Cnn Is Nothing Then OpenCnn
Set GetADORs = New ADODB.Recordset
GetADORs.Open SQL, Cnn, adOpenStatic, adLockBatchOptimistic 'return the ADO-Rs (its content will be auto-serialized)
End Function
Private Sub OpenCnn()
Set Cnn = New Connection
Cnn.CursorLocation = adUseClient
Cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & App.Path & "\Test.mdb"
End Sub
The serverside code is hereby (with #1 and #2) completely finished!
VB-Project #3: The Client-App
- in the above Zip, this is the Project sitting in Path: ..\ClientApp\SimpleRPC.vbp
What remains now, is the clientside part of the RPC - the one which *initiates* an
RPC-(Remote-Procedure-call).
The behaviour (to make the program-flow easier) is in case of the RC5-RPCs *always*
synchronously. That means, that RPCs will not return, until we got a Result, or an
Error-message - or a TimeOut-Error back from such a Remote-Method-call against the Server.
Although also the Clientside-Code is not more than 50 lines or so, I will put only
this smaller excerpt of the client-sides Form-code here into a code-section to explain...:
Code:
Private Const ServerDll$ = "SimpleServerLib.dll" 'Name of the used Dll in the \RPCDlls\-Folder
Private Const ServerCls$ = "cServerClass" 'Name of the Class, which is contained in above Dll
Private RPCConn As cRPCConnection 'define the Var for the clientside RPC-connection
Private Sub Form_Load()
Set RPCConn = New_c.RPCConnection 'create the clientside-RPCConnection-instance
RPCConn.DebugMode = (chkDEBUGMode.Value = vbChecked) 'Debug-Mode (should be switched Off when running as an Executable)
RPCConn.Host = "" 'put an explicit Server-IP here later on, e.g. read from an Ini-File
RPCConn.Port = 22222 'Port-Nr the Server is listening on (22222 is the RC5-RPC-default)
RPCConn.KeepAlive = True 'set KeepAlive for better performance
End Sub
'... snipped the two other Methods, which we also wrap in this Form
Private Sub cmdAddTwoLongs_Click() 'an example Remote-Method-Call
On Error GoTo ErrMsg
txtAdd.Text = RPCConn.RPC(ServerDll, ServerCls, "AddTwoLongs", 3, _
CLng(txtL1.Text), CLng(txtL2.Text)) '<- Parameter-List (two Long-Values in this case)
ErrMsg: If Err Then MsgBox Err.Description
End Sub
which resembles in its usage a bit, how one would work with e.g. the WinHTTP 5.1 Object...
Simply put - it encapsulates "the needed Socket-stuff" which is necessary, to be able to
work across machine-boundaries.
After this Object was "set up" (in Form_Load or in Sub Main - or also in a dedicated little
Wrapper-Class), what remains is to look at, where "the RPC-call happens"...
(for simplicity's sake, in this Demo not in an additional WrapperClass, but directly in the Forms: cmdAddTwoLongs_Click()
Just ask yourselves - what will need to happen under the covers of: RPCConn.RPC(...)?
Right (please look at the Strings I've marked blue in the above code):
- to be able to instantiate a Dll regfree from within the serversides \RPCDlls\ folder, we will need the DllName and the ClassName
. (so that we can create an Object-instance, which we will call LateBound then)...
- and to be able to perform a LateBound-Call (per CallByName), we will need the third blue string: "AddTwoLongs" (the Method-name)
- another requirement in the Parameter-List will be a TimeOut-Value (in the above call this is the 4th argument, the '3')
- and then finally the two arguments, which the AddTwoLongs-Method expects at the serverside (a VB6-Param-Array came in handy here)
So that's it basically with regards to a little "How-To-Do RPC-calls the easy way" with the vbRichClient5.
Note, that the RichClient RPC-Classes are in use at hundreds of Client-installations worldwide - and
that these Classes were included from the very beginning of the RichClient-project (over a decade ago).
So, this stuff was quite hardened over the years - and is not a "toy-implementation".
4) One last thing, I'd like to mention still with regards to the Demo (before you run it):
The RPC-Classes support a DebugMode (as contained in the last code-snippet above over: RPCConn.DebugMode = ...)
When this Property is True, then one can do an easy "RoundTrip-Debugging", when the
serverside Dll-Project in question is included in a VB-ProjectGroup.
The Demo will start (without the need to compile any Binaries) per Default in DebugMode -
and an appropriate \SimpleRPC\RPC_Test_Group.vbg File is included in the Root-Folder of the Demo.
Check this mode out first (leaving the DebugMode-CheckBox checked) -
later, when you e.g. have stepped through an RPC-call (per <F8> Key),
you can disable the Debug-Mode - but before you do so, you will have to compile:
- the ServerHost-Project I've mentioned in #1
- the ServerDll-Project I've mentioned in #2 (please make sure, that you compile the Dll into the \RPCDlls\-Folder)
- followed by starting the compiled ServerRPC-Executable
After that you can switch DebugMode Off - and perform "real RPC-calls over sockets"
Here's a ScreenShot of the little Client-App:

Have fun.
Olaf