Results 1 to 6 of 6

Thread: VB6 - Client-Server Using PropertyBag

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Lightbulb VB6 - Client-Server Using PropertyBag

    Cleaner than SOAP, jazzier than JSON, and better than the REST!

    VB6 has a powerful serialization object knwn as the PropertyBag. The huge improvement over the VB5 version of this object (which VB6 still supports for compatibility reasons) was the addition of the Contents property. This made it possible to use a PropertyBag as a custom serialization tool.

    There are any number of reasons why you might want to perform efficient custom object serialization. The one demonstrated here is for implementing a fast, custom, binary client-server message format - that can marshall persistable objects!

    Beats the pants off slow and crappy Web Services by far.


    The Demo

    This demonstration consists of a multi-client TCP server DemoServer, a TCP client DemoClient, and a custom persistable object library PBDemoTreeLib supplying a Node class that can be used to create lists and trees.

    Here I am using TCP port 8018 but you can easily change that or make it variable at runtime.

    There is also a small helper project MakeMDB which must be run once to create the Jet 4.0 database used by DemoServer.


    DemoServer

    This is a simple TCP server that can perform several operations or functions (I'm calling them "methods" here):

    Add(ByVal A As Double, ByVal B As Double) As Double - adds two values and returns their sum.

    Dir(ByVal Dir As String) As PBDemoTreeLib.Node - looks up a requested directory and returns a list of the files under that directory.

    HomeStates() As ADODB.Recordset - retrieves a list of "Home State" fields from the "HomeStates" table in the database and returns the disconnected Recordset.

    PresidentsAll() As ADODB.Recordset - retrieves the entire "Presidents" table from the database as a disconnected Recordset.

    PresidentsWhereHomeState(ByVal HomeState As String) As ADODB.Recordset - retrieves "Presidents" table rows where "Home State" = HomeState.
    DemoServer expects clients to make a request and await a response before making another request. However multiple clients are free to make overlapping requests of course. It is also quite possible to create "methods" that can update a database as well as simply make queries as I do here.

    When DemoServer starts it is seen on the server machine as a Notification Area ("tray") icon. The icon's ToolTip shows the number of connected clients. TCP errors are Debug.Print-ed when running in the IDE and any error causes the server to shut down. There is one item on the icon's context menu, used to exit from the server (close it).


    DemoClient

    This is a simple TCP client. It accepts a server host address (name or IP address) and when the Connect button is clicked it connects to the server.

    Upon connection it performs a HomeStates() call to populate a List control. From there you can supply values and perform any of the other operations. To exit simply close the application as usual.


    MakeMDB

    A simple helper project. Open it in the VB6 IDE, run it. It will load CSV data, creating a Jet 4.0 database "USPresidents.mdb" which you should move or copy into the Server folder where DemoServer expects to find it.

    This project isn't needed except for this one function.


    PBDemoTreeLib

    This project is a DLL used by the client and the server to provide a persistable class Node. Node can be used to create and manipulate simple trees and lists with simple Name and Value properties.

    It also demonstrates one common way of persisting VB6 Collection objects, which are not themselves persistable.

    This library is included and used in the demo to show how you can use PropertyBags to marshall customs objects and object models (DOMs, etc.). Here I only use it for a simple list, the value returned by the Dir() method.


    Communication Protocol Used Here

    This protocol is an application layer on top of TCP. It could easily be used with other transports: HTTP, SMTP (email!), MSMQ, Named Pipes, etc.

    Each message consists of two fields:

    Length - Long value, size of Contents in bytes.
    Contents - Byte array, value of a PropertyBag.Contents property.
    Messages making server requests have a property in the PropertyBag named "Method" identifying what is being requested. They will also contain other properties reprsenting arguments of the method.

    Messages returning server responses have a property in the PropertyBag named "Method" identifying what method generated the response. There are also additional properties containing the result of the method or any changed, or "ByRef" argument values.

    There is also a simple error response possible. It has "Method" set to the value "Error" and has additional error number and description properties.


    Building This Demo

    Note: Make sure you always run the VB6 IDE with elevated permissions. On XP and earlier this means running under an admin user. In Vista and later this means using "Run As" or an elevation manifest for VB6.exe.

    Start by building PBDemoTreeLib:
    • Open this project in the VB6 IDE.
    • Make and Save, then exit.
    • Drag PBDemoTreeLib.dll and drop it onto UnregDLL.vbs to unregister it.
    • Rename PBDemoTreeLib.dll to ref-PBDemoTreeLib.dll.
    • Open the project once more.
    • Go into Project|Properties... and on the Components tab of the dialog set Binary Compatibility and set the reference library to ref-PBDemoTreeLib.dll.
    • Make and Save again, then exit.

    Next open and run MakeMDB (inside the Server folder). Copy or move the resulting MDB file into the Server folder.

    Build DemoServer, then DemoClient. Same process for each:
    • Open the project in the IDE.
    • Set a reference to PBDemoTreeLib ("A Demo Public Class Lib for PBDemo").
    • Make and Save, exit.


    Running The Demo

    Create setup packages for DemoServer and DemoClient if you want to deploy them onto separate machines. Be sure to include the "USPresidents.mdb" file in your DemoServer package. The PDW supplied with VB6 is fine for this.

    Copy and install your deployment packages on your test machines as required.

    Then you can run DemoServer. It should appear in the Notification Area and you may get a firewall alert you will need to approve.

    Then run one or more copies of DemoClient. Put the server's Host Addres in the textbox and click Connect. You should see updates in the status bar and very soon the States listbox should be populated.

    Now you can supply various inputs and perform the various options.

    End the clients normally. End the server via the tray icon's popup menu.
    Attached Images Attached Images  
    Attached Files Attached Files

  2. #2

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: VB6 - Client-Server Using PropertyBag

    The portions of the code worth studying are:
    • Form1.frm of DemoServer.
    • Form1.frm of DemoClient.
    • Node.cls of PBDemoTreeLib.

    Everything else is more or less standard "plumbing" used to flesh out the working demo.

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: VB6 - Client-Server Using PropertyBag

    The DemoServer uses fairly IDE-safe subclassing so you can just run it from within an IDE instance.

    The DemoClient doesn't do anything that might upset the IDE, so you can run that from an IDE instance too.

    However as uploaded these both use PBDemoTreeLib so you'll need to compile this first, or prune out the client and server code that uses it.

  4. #4
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,802

    Re: VB6 - Client-Server Using PropertyBag

    I did not look at your examples, but I want to mention:
    I made a project about 5-6 years ago that used a PropertyBag to transfter data using server/client and it worked perfectly.

    If you want to send a lot of strings or very large strings, I used to use StrConv to convert from unicode string to byte array when sending, and did the reverse on the receiving side to put the data back in the string. This reduced the size of data to transfer quite a lot.

    Another thing that I loved about the PropertyBag, is that it is very easy to add another layer on top to secure the data using encryption by just encrypting the results from "Contents" property.

  5. #5

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: VB6 - Client-Server Using PropertyBag

    Very good points.

    I posted this because there have been some recent questions asking how to share a custom object hierarchy and how to do remote database access safely even if using an embedded database like Jet or SQLite. The traditional answer was always n-tier programming - but based on DCOM, or later Web Services.

    DCOM has been so locked down in recent Windows releases that its usefulness is failing, and it was never safe outside of a LAN. Microsoft still uses it extensively (WMI for example) but they preconfigure the necessary security options for their own use.

    Web Services simply don't have first (or even second) class support in VB6 - the SOAP Toolkits from Microsoft were never complete and often produced erratic results. PocketSOAP VB6 tools are victims of programmer rule-breaking that makes them fail on anything post-XP. The worst part is that XML is terribly bulky, inefficient, and memory- and cycle-stealing as a serialization format as well.

    The end result was that a lot of VB6 programmers ended up shrugging their shoulders or just plain giving up when trying to unravel the complexities involved.

    Hopefully these PropertyBag techniques offer a simpler answer for cases where interoperability is not required. And surprisingly enough, it seldom is!

  6. #6

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: VB6 - Client-Server Using PropertyBag

    Oh yeah, BTW:

    Using StrConv() as you suggest can cut the size of the Contents array almost in half, I agree. But there is a caveat: what you suggest is a low-fidelity process that converts to ANSI using the current codepage. This means if the server and clients have different locale settings you can run into trouble for any characters outside the 7-bit ASCII range.

    One alternative in cases where you need it (i.e. you are shipping large String values) would be to use API calls or the ADODB.Stream object to convert Unicode (UTF-16LE) to and from UTF-8. This is often just as compact, but where you have any chars above &H7F they'll be preserved instead of mutated or turned into "?" values.
    Last edited by dilettante; Feb 1st, 2012 at 06:29 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width