Tutorial: Using Reserved Words as VB6 Class Member Names-VBForums
Results 1 to 1 of 1

Thread: Tutorial: Using Reserved Words as VB6 Class Member Names

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Feb 2006
    Posts
    11,719

    Post Tutorial: Using Reserved Words as VB6 Class Member Names

    Title

    VB6 Polymorphism as a Means of Using Reserved Words as Class Member Names in VB6

    Description

    On rare occasions you'll want to create a VB6 Class, UserControl, Form, etc. that has methods or properties that duplicate VB6 keywords that the IDE and compiler just won't allow. Some examples might be Open, Close, Stop, and many others.

    The VB6 manuals (and the versions contained in the MSDN Library articles) cover the mechanism required in the sections on creating and using objects under inheritance and polymorphism. However they do not directly address what you need to do regarding these reserved words.

    I haven't seen a decent writeup anywhere on this topic so I thought I might give it a go myself.

    This tutorial is an attempt to provide an example of how you might do this, embedded in a working demo Project.

    This is a 300 level tutorial, not for beginners. It assumes a good deal of knowledge, requires a Windows SDK of recent vintage, and touches your dev system's registry (though we'll try to clean that up too). I will try to keep things as simple as I can nonetheless.

    Everything described may work just as well for VB5.

    Author name

    Bob Riemersma

    System Requirements

    Windows 2000 or newer (though even Win95 may be fine).
    VB6 Professional or better installed.
    A recent vintage Windows SDK installed (6.0 was used here).
    Administrative rights on the system (which you really need for VB6 development anyway).

    License info

    Free for anyone to use or copy with attribution. No warranties or guarantees, etc. As-is information, use at your own risk.


    Introduction

    So why might you want to do this?

    Well, sometimes it can just be annoying to have to name your "open" method OpenFile rather than Open but that generally isn't important enough for you to go to all this trouble.

    But you might be creating a DLL for use in lots of projects, by others, etc. and it has a kind of raggedy look to have to decorate your class member names just so they'll compile.

    Or in the case at hand (our guinea pig Project) I'm writing a small script host (using the MS Script Control) where I want to offer a few standard WSH objects and methods on them. In particular I want to implement a stripped down version of WScript.StdOut that has a Write method on it. "Write" is a VB reserved word so you can't normally use it as a method name.


    Step 1: First Attempt

    The Project is named RunScript. First Attempt is the name of a folder in the attached archive that attempts to limp along using xWrite instead of Write as we'd prefer to.

    This means my StdOutSim.cls looks like this:
    Code:
    Option Explicit
    '
    'A partial WScript.StdOut object simulation.
    '
    
    Public Sub WriteLine(Optional ByVal Text As String = "")
        xWrite Text
        xWrite vbNewLine
    End Sub
    
    Public Sub xWrite(ByVal Text As String)
        UIForm.txtOut.SelText = Text
    End Sub
    But it also means my test script GraphSin.vbs must look like:
    Code:
    Sub Plot(ByVal X, ByVal Y)
        Dim Line
        Dim Pos
    
        Line = Spaces & "|" & Spaces
        Pos = 1 + (Y + 1) * Scale
        Line = Left(Line, Pos - 1) & "*" & Mid(Line, Pos + 1)
        With WScript.StdOut
            .xWrite FormatSingle(X)
            .xWrite " -"
            .xWrite Line
            .xWrite "+"
            .WriteLine FormatSingle(Y)
        End With
    End Sub
    Bleh. Can we do better?


    Step 2: Make a DLL

    Make a DLL is the name of the next folder we have. It is used to create a DLL containing the classes we want to use reserved words in, prefixed "I-" (for interface). In my case I only need to tweak StdOutSim.cls so that's all I'll include.

    The steps involved here are:
    • Make a new VB6 ActiveX DLL Project.
    • Change the Project name to RunScriptInterfaces.
    • Remove the unneeded auto-created Class1.cls that we don't want.
    • Copy StdOutSim.cls into this folder as IStdOutSim.cls.
    • Use "Add file..." to add this class to our DLL Project.
    • Rename the class from StdOutSim to IStdOutSim.
    • Change the class Instancing from Private to MultiUse.
    • Edit StdOutSim as shown below:


    Code:
    Option Explicit
    '
    'A partial WScript.StdOut object simulation interface template.
    '
    
    Public Sub WriteLine(Optional ByVal Text As String = "")
    'Code not needed or wanted here:
    '    xWrite Text
    '    xWrite vbNewLine
    End Sub
    
    Public Sub xWrite(ByVal Text As String)
    'Code not needed or wanted here:
    '    UIForm.txtOut.SelText = Text
    End Sub
    The attached archive has this folder and these Project files already made.

    Then we can go ahead and compile our DLL. After that go ahead and delete leftovers like .LIB and .EXP files.

    Finally, drag and drop the new RunScriptInterfaces.dll's icon onto the icon of the provided DLLUnreg.vbs script. This will unregister our DLL since we don't need it - just a little cleanup.


    Step 3: Extract the IDL

    No archive folder for this step, but we'll use the one from the next step.

    Now we'll need to get the type library info from our DLL in a useful form so we can edit it and ultimately compile it into a standalone typelib (TLB) file.

    One easy way is to use the OLE View utility, either from your VS 6 Tools Start Menu shortcut or you can use the version from your Windows SDK's Bin folder. Run this and then open your DLL via View TypeLib...:

    Name:  sshot1a.gif
Views: 962
Size:  15.5 KB

    This should open a second window with the generated IDL code in the right pane.

    Don't bother trying to use the Save menu there, it creates a broken Unicode text file that is useless. It still does this even using the SDK 7.0 version of OLE View so you can see it doesn't get much love from Microsoft.

    Instead open Notepad, then click in the right pane where the generated IDL is, press Ctrl-A to select all text, Ctrl-C to copy it, and then paste that into Notepad.

    Finally close both OLE View windows (we're done) and save the Notepad file as a Orig RunScriptInterfaces.odl with ANSI encoding into the next folder...


    Step 4: Modify the IDL

    This folder (from the attached archive) comes with these files in it:

    • Annotated ODL.rtf - An RTF file showing my original ODL (IDL) with replaced and deleted lines struck out in red and new/changed lines in blue. A helpful "how to" guide for editing your DLL's ODL file to make a new interface ODL source.
    • Orig RunScriptInterfaces.odl - This was my original ODL before editing. Save yours over it.
    • RunMidl.cmd - A batch file we'll use to compile your edited ODL source.
    • RunScriptInterfaces.odl - My final ODL after editing.
    • SDK Files Needed.txt - A short text document listing the files you will want to copy from the Windows SDK into a handy Make TLib folder for easy running of the MIDL compiler.


    So you overwrote Orig RunScriptInterfaces.odl here in the previous step. Now you need to edit it and save the edited version as RunScriptInterfaces.odl (reaplcing the one I provided) and you can just use Notepad for this.

    The .RTF document shows what must change, but there are three GUID values you need to recreate with new values yourself. If your interfaces TLB will have more classes in it (we just have the one in this simple tutorial) you'll have more GUIDs to replace.

    In theory we can use the ones created originally by the VB6 compiler since we've unregisrtered them. But to be thorough go ahead and use a GUID generator to make fresh ones. I tend to just use GuidGen.exe from the SDK's Bin folder.

    Name:  sshot2.gif
Views: 947
Size:  9.5 KB


    Step 5: Make TLib

    Create this folder yourself. It can be handy for future projects, so maybe put it someplace among your stored VB6 project folders or somewhere.

    Follow the directions in SDK Files Needed.txt about the files to copy here from your Windows SDK.

    Copy the RunMidl.cmd file into here from the archive's Modify the IDL folder. Then move your edited and saved RunScriptInterfaces.odl file here as well.

    Drag and drop RunScriptInterfaces.odl's icon onto RunMidl.cmd's icon in an Explorer window. This is an easy way to accomplish the MIDL compiler run.

    This should produce two new files if all goes well:

    • log.txt - The MIDL compiler messages, errors if any, etc.
    • RunScriptInterfaces.tlb - Your new interfaces type library, ready for use.



    Step 6: Second Attempt

    Here we'll take our first approximation and create a new and improved (Now with Write!) version of RunScript.

    Copy the original Project files into a new folder. Second Attempt from the archive already has this done.

    Make a few changes...

    First we need to reference our new TLB. We can do this via "Project|References..." in the IDE, where we'll use the Browse button:

    Name:  sshot3.gif
Views: 945
Size:  25.7 KB

    Then we need to modify our StdOutSim class:

    Code:
    Option Explicit
    '
    'A partial WScript.StdOut object simulation.
    '
    
    'We'll implement the "abstract class" IStdOutSim here:
    Implements RunScriptInterfaces.IStdOutSim
    
    Private Sub IStdOutSim_Write(ByVal Text As String)
        UIForm.txtOut.SelText = Text
    End Sub
    
    Private Sub IStdOutSim_WriteLine(Optional ByVal Text As String = "")
        IStdOutSim_Write Text
        IStdOutSim_Write vbNewLine
    End Sub
    Getting those "event handler like" interface proxy method signatures is easy, and much like getting them for more usual event handlers once we've added the Implements... line to the class:

    Name:  sshot4.gif
Views: 928
Size:  10.5 KB

    Then we'll need to modify the WScriptSim class to use our new interface on our class:

    Code:
    Option Explicit
    '
    'Global Object class, an instance of which is added to the
    'Script Control as global object "WScript".  This is how our
    'scripts interact with the host.
    '
    'A partial WScript object simulation.
    '
    
    'Private WshStdOut As StdOutSim becomes:
    Private WshStdOut As RunScriptInterfaces.IStdOutSim
    
    'Public Property Get StdOut() As StdOutSim becomes:
    Public Property Get StdOut() As RunScriptInterfaces.IStdOutSim
        Set StdOut = WshStdOut
    End Property
    
    Public Function CreateObject(ByVal ProgId As String, Optional ByVal Prefix As String) As Object
        'We ignore Prefix in this implementation.
        Set CreateObject = VBA.CreateObject(ProgId)
    End Function
    
    Public Sub Echo(ParamArray Text())
        WshStdOut.WriteLine Join$(Text, vbNewLine)
    End Sub
    
    Public Sub Quit(Optional ByVal Status As Long)
        Err.Raise gINTERNAL_ERROR 'Internal error, catch this in Script Control Error event!
    End Sub
    
    Private Sub Class_Initialize()
        Set WshStdOut = New StdOutSim 'But we create an instance of the "concrete class."
    End Sub
    Now we can go ahead and compile our new program.

    But before running it we'll need to update our script:

    Code:
    Sub Plot(ByVal X, ByVal Y)
        Dim Line
        Dim Pos
    
        Line = Spaces & "|" & Spaces
        Pos = 1 + (Y + 1) * Scale
        Line = Left(Line, Pos - 1) & "*" & Mid(Line, Pos + 1)
        With WScript.StdOut
            .Write FormatSingle(X)
            .Write " -"
            .Write Line
            .Write "+"
            .WriteLine FormatSingle(Y)
        End With
    End Sub

    Cleanup

    By adding the reference to our TLB we caused VB6 to register it. We don't need the crud left in the registry, and it seems that the VB6 compiler is quite happy to continue using it even after unregistering it! Perhaps this only works if the TLB is "next to" the VBP file or something, but it seems to work fine.

    To unregister the typelib you can drag and drop RunScriptInterfaces.tlb's icon onto the icon of the provided TLBUnreg.vbs (provided in the archive's Second Attempt folder).



    Last Word

    This works great for many VB6 reserved words. However one that is particularly stubborn is the Print pseudo-method. The compiler handles this and a few others as special cases.

    That doesn't mean you can't do this with Print, but you won't be able to invoke it from within a VB6 program. It still works for a script via Script Control (VBScript doesn't care about "Print" as a reserved word), or it works compiled into a DLL that some other language will use. But for VB6 it just isn't going to happen as far as I can tell.

    At best you might get away with syntax such as this:

    Code:
    fudd.[Print] arg1, arg2, arg3
    ... assuming an object [t]fudd[/tt] of a class you have created a Print method on via this polymorphism trick.

    I hope this information helps someone. As I said, I haven't seen it written up before even though a lot of us know about it.
    Attached Files Attached Files

Tags for this Thread

Posting Permissions

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



Featured


Click Here to Expand Forum to Full Width

Survey posted by VBForums.