Beruflich Dokumente
Kultur Dokumente
Introduction
Welcome to our three-part introduction to the wonderful world of COM!
There comes a time in every programmer's life when a project consisting of mere forms and modules just
ain't enough. Sure, you know the API, you know databases... but in the world of the enterprise, employers
want that something extra.
And that something is called COM. It's a way of organising your code so it can be used over and over
again. It's a method of helping create a bug-free development environment. It's a system that, just after
making your life a little harder, makes it one heckuva lot easier.
Basically, it's a completely wizzy way of working.
Today, we're going to figure out exactly what classes are, and how they fit into the big picture of cosmic
COM. We'll even be creating our own classes – based loosely around a dog (yes, a dog) – to demonstrate
the theory.
Ready to dive feet first into the chaotic cavern of COM, my cute curious cherubs? Step this way...
Introducing COM
You wanna know something that's gonna make your day?
Here goes: you're already a COM programmer.
Yup, that's right. I may have never met you, but I'll bet my brother's bottom dollar that
you are.
Every time you set the Text property of a Text Box, you're using COM. Every time you
run the MoveNext method on the DAO data control, you're using COM. Every time you
control Word from within Visual Basic, you're using COM.
So what exactly is COM?
Imagine a television remote control. You press button one and the television tunes into
BBC 1. Or CNN. Or whatever. You press the power button and the television turns itself
off. You press a brightness button and suddenly your screen looks like a close-up of the
infamous 'White Cat Drinking Milk on a Snowy Day' masterpiece.
Unless you're a television repair geezer – which I'm kinda hoping you're not – you don't
know how this all works. You just press the button and it jumps into action.
That also applies to the world of programming. After all, you don't really know what
happens when you change the Text property of your Text Box. Under the covers, it's
probably making two-dozen API calls – but to the end user, it just displays a certain piece
of text in the box.
The good thing about COM is that once you create things that talk the COM-way, that
use the COM method of communication, you can use them again and again anywhere.
Let's imagine you want to add a customer to your computer system. Instead of
adding a barrage of data access code, validation algorithms, and weighty database DLLs
to your application – wouldn't it be easier to run something like Customer.Add?
It sure would. And COM gives you that power.
For the rest of this instalment, we'll be taking a lightning tour of COM and Visual
Basic. All of our work will be surrounding the creation of a class – which could later be
turned into a real life COM object – all based on a Dog. That's right, a Dog. Makes sense,
doesn't it?
Sure, at times this first instalment might seem a little surreal – but it'll teach you
the foundations for all future COM coding.
Building Classes
In this section, we'll dive straight into the practical. We'll be creating our first COM object, using it, then
considering how we can improve it.
So let's get started:
• Launch Visual Basic
• Create a new 'Standard EXE'
Now COM objects are always based on classes. And classes are just chunks of code, a lot like the code in a
module, except it's used in a different way.
• Click 'Project', 'Add Class Module'
• In the prompt that appears, select 'Class Module' and click 'Open'
The Project Explorer should now show that in addition to Form1, your Project1 also contains Class1.
Whoah, too many 1s, dude.
Next, let's be all neat and tidy and change the name of our class:
• In the Properties window, change the Name property of Class1 to: CDog
•
Top Tip: Just as you use certain prefixes for certain objects – ie, 'txt' for a Text Box and 'frm' for a Form
– classes are usually prefixed with a capital 'C' or lower case 'cls'. I prefer the former.
Erm, well maybe that didn't take a few minutes – but you've done all necessary to take your first step onto
becoming a real COM programmer.
• Open Form1
• Add a Command Button to your Form
• Insert the following code behind your button:
This line of code is telling Visual Basic to set aside a bit of space for the grand entry of CDog. We can't
use this object yet though - that comes with the next line of code.
This creates a new instance of CDog. This means the previously 'empty' MyDog template is now a CDog
object we can work from. Think of it as creating a new cookie based on the CDog cookie cutter.
The first line here sets the Name variable of MyDog, whilst the second displays it in a message box. And
finally:
This code simply sets MyDog equal to Nothing. That means the cookie you originally created is eat up by
some greedy overweight teenager and completely disappears from your computer. It's called being neat.
* Press F5 to run and test your application
Did it work? Jolly good fun. But at the moment, it's probably a little difficult to tell the difference between,
say, a standard module and a class module. Well, the next sample will show us:
• Change the code behind your Command Button to:
Dim MyDog As CDog
Set MyDog = New CDog
Here, we see exactly the same as our last chunk of code – except we're using two different things, MyDog
and MyDog2. Both of these objects are based on our CDog class yet are completely independent of one
another.
That goes hand in hand with our cookie cutter analogy. Our code is the cookie cutter and you can make as
many independent cookies as you want from it, all based on that one cutter.
Now it's worth noting that most classes are built around real life objects. So, each dog already has a Name.
What other properties could we add?
• Open up Class1
• Declare the following public variable:
• Open up Form1
• Change the code behind your Command Button to:
Properties
Properties work in much the same way as public variables, except they allow you a lot more control.
Regular properties consist of two property 'routines', a Get and a Let. Both of these work together to
provide one main property. Let's look at a chunk of sample code:
The above chunk of code works much like the Age variable. When someone does something like:
MyDog.Age = 4
... the Let property runs and the number four is passed as vNewValue. This is then stored in the private
intAge variable. When someone does something like:
MsgBox MyDog.Age
... to retrieve the property, the Get property is run and the value of intAge is returned. So let's think about
that:
• Get Property – Runs when someone wants to "get" the value
• Let Property – Runs when someone wants to "let" your property equal a value
So far, I've only demonstrated these properties working exactly like standard variables (except with
a lot more code). However they also allow you to have more control over what goes into your property –
and what does not.
Let's edit our class:
• Remove the Age variable from your CDog class
• Insert the following code:
FACE="Courier" SIZE=2>
Private intAge As Integer
Public Property Get Age() As Integer
Age = intAge
End Property
The only real change here to our original chunk of example code is the Property Let routine. Here, we've
done a little checking. So imagine our user attempts to do a:
MyDog.Age=30
... our Property Let routine runs, passing thirty as vNewValue. In code, we than evaluate vNewValue to
check whether it is less than or equal to fifty. Our thirty figure is, so in this instance intAge would be set
to thirty. And that's that.
If it was over fifty, nothing would happen. The property would just exit and no values would be set.
Naturally, you could decide to raise an error or display an exclamatory message box, but I'm feeling all
kind today.
Top Tip: The numbers next to an enumeration are useful if you want to put information into a database.
As 'BigAndShaggy' really translates into the number 1, you could insert it direct into a database number
This is the private variable that will hold the Coat information on behalf of our soon-to-be-added property.
Notice how the variable is declared not as a string or integer – but as the CoatType enumeration we
created, our own 'user-defined data type'.
• With your CDog class open, click 'Tools', 'Add Procedure'
I'm now going to show you a great way of creating your property procedures superfast.
End Property
End Property
Great! But this isn't exactly what we need. Right now, this code accepts and passes back 'variants', which
can be just about anything. If you remember, our last property – Age – accepted integers. This one wants
to accept anything in the CoatType list.
• Change everything that says 'Variant' in the generated code to 'CoatType'
Now let's add a little code to actually handle the property:
• In the Property Get procedure, add the following code:
Coat = udtCoat
• In the Property Let procedure, add the following code:
udtCoat = vNewValue
• Flick back to Form1
• Change the code behind your Command Button to:
Dim MyDog As CDog
Set MyDog = New CDog
MyDog.Name = "Billy"
• Now start to type in: MyDog.Coat =
Do you see what happens? As you press the 'equals' key, a list of possible options appears. You can select
any of these. Except the Afro one. Billy certainly doesn't have Afro hair. Nor Big and Shaggy come to
think of it. In fact, just select the short crew cut option.
• Finish typing the code: MyDog.Coat = ShortCrewCut
Next up, let's retrieve the value of the Coat property. Now, if we simply display the value in a message
box, we'll only get back the number of the option we selected. In other words, if you selected
ShortCrewCut, the property will return a 2. Try it!
But there's another way of doing it – by comparing the Coat with an If-Then:
• Append the following code to the existing behind your Command Button. Make sure you type
this out yourself to see the full effect:
If MyDog.Coat = BigAndShaggy Then
Top Tip: You could also do a 'Select Case' here – but I'm trying to keep the code simple. Oh yeah, and
I'm an idle sloth.
And finally, to be all nice and tidy let's add that one final line of code to free up computer memory:
• Append the following code to the existing behind your Command Button:
Set MyDog = Nothing
• Test your application by pressing F5, then hitting your button
See what happens? That's enumerations for ya.
Subs, Functions, Parameters, Oh My!
So, we've already added variables, properties and enumerations to our classes. What else can you do with
'em?
Well, for a start, you can add Subs. That's right, bog standard ol' Subs, as regularly used in most Visual
Basic programs. Let's add one now to demonstrate their power:
• Insert the following into your CDog class:
And that's it! Here we have a regular sub inside our class that you can run quite simply with a command
like: MyDog.Bark.
Notice how after you press the period following MyDog, the Bark Sub is yellow, whilst the properties are
blue and white? That's to help you distinguish Bark as a method of your MyDog object.
• Press F5 and test your code
In addition to subs, you can also add functions to your code. I'm not going to demonstrate it here, but why
not have a go yourself? They work just the same as regular functions, except they're inside a class. Don't
forget that all Subs and Functions can also have their own parameters.
Now let's imagine I wanted my class to have a Sleep method. I'd call this Sub each time I wanted my pup
to take a cat- or rather, a dog-nap.
How do you know when someone types into your Text box? There's the Change event. How do you know
when someone clicks on your Command Button? There's the Click event. How do you know when your
pooch wakes up? Enter centre stage: the Awake event.
Events
Events are relatively simple to use.
First off, you have to define an event. This means you tell Visual Basic what the event will be called, plus
any parameters it may have. As an example, a Command Button has the Click event, no parameters. On
the other hand, the Text Box has the KeyPress event, which also passes something called a 'KeyAscii'
value.
So to define an event, you put something like this in the General Declarations section (the top bit) of your
class:
And then to 'raise' an event in code, you use the RaiseEvent method in your code. Say you have an OnAdd
event that fires off each time you add a new customer to your database. Just before you fire update the
database, you might want to 'raise' the event. You could do that like this:
RaiseEvent MyEventName("PossArgs", "Etc")
So let's spend a final few minutes adding and raising our own events. First off, let's define our event:
• Add the following code to the General Declarations section of your class:
Public Event Awake()
Now we need to add the Sleep event. In this event, I could be doing anything – adding customer
information to a database, cycling through the long process of creating management reports, anything!
But all I am going to do is add a jabberwocking loop that wastes a bit of time, then raises the Awake
event. Let's code that, erm, code now:
• Add the following Sub to your CDog class:
Public Sub Sleep()
Dim i As Long
For i = 1 To 1000000
DoEvents: DoEvents: DoEvents
Next i
RaiseEvent Awake
End Sub
This code simply loops around a million times, doing essentially nothing. On my computer, this loop lasts
around a minute or so. Yours may be slower. Or it may be faster. It all depends on gravitational pull. Or
processor speed. I forget. But after that short time delay, our Sleep Sub raises the Awake event.
So how can our test application respond to this Awake event? With Command Buttons, it's darn simple.
You just enter the code window, select your Command Button from the drop-down list and Bob's Your
Uncle.
But in that instance, you're working with a control, something you can see on a Form. Here we're working
with pure code, nothing visible.
So if we want to receive events from our code, we need to do something a little special.
• In the General Declarations (top) of your Form code window, declare the following:
End Sub
Excellent!! Now let's test our application:
• Press F5 to run your application
• Hit your Command Button
After a quick bark, your pup will take a nap, then give you a call when it has finished! Wizard!
Conclusion
In the next instalment, we'll be using the knowledge we've gained today to create a real-
life COM object based on a database. We'll also be creating a client package to access
your object and will see just how much COM code can simplify your programming. We'll
even be having a lil' chat about something they call compatibility plus how you can break
it! Hehe... <mischievous grin>
So until the next time, this is Karl Moore signing off for tonight wishing you an incredibly
pleasant evening. Goodnight!
Introduction
Welcome to the second part of our introductory COM course, hosted exclusively here on VB-World.
As ever, I'm your host Karl Moore and if you missed part one, be sure to check it out here
</activex/comcourse/>.
End Sub
Any code you enter here fires up when the class first starts. It's a lot like the Form_Load event.
• Enter the following code in the 'Initialize' event:
Set rs = New Recordset
Set rs = Nothing
Once again, this is just regular stuff. Here we're simply closing the database, then being all good and
setting rs to nothing, which calls in the heavies to effectively erase the fact that rs ever existed.
Great! Let's continue on the next page, where we'll be entering code to access records in our database!
Adding Properties and Methods
Next, I'd like to add a property that allows our user to retrieve the Customer ID. Here's a piece of sample
code I created earlier:
Public Property Get CustomerID() As String
CustomerID = rs("CustomerID")
End Property
rs("CustomerID") = NewValue
End Property
Do you understand what's happening here? The Property Get simply 'returns' whatever is in the
'CustomerID' field. This allows our end user to retrieve the property. The Property Let accepts a new value
and sets the 'CustomerID' field to that value.
In other words, there are two parts to a property. The 'getting' and the 'letting'. In fact, there's also another
one - 'setting' – but that's for a different day. Missing either the Get or the Let out will make the property
either write- or read-only.
The power here is that we can check for certain things in these property procedures. For example, to call
the Property Let here, the user could do something like:
ObjectName.CustomerID = "HALFI"
When this runs, it calls the Property Let, passing 'HALFI' as the NewValue string. I then set the
'CustomerID' field equal to NewValue. But looking at the Northwind database, I can see that the
'CustomerID' field is limited to just five characters. So if someone did something like this:
ObjectName.CustomerID = "HALFISTORE"
... then we'd get database errors. We could deal with this via database error handling, yes. But we could
also check the length of NewValue in code. If it's longer than five characters, you could either just snip the
first five letters, ignore the new value altogether - or 'raise' an error. We're going to check for the length
and if it's too long, I'll be all-cruel and raise an error. Hehe! <Evil grin goes here>
• Add this code to your class:
Public Property Get CustomerID() As String
End Property
Public Property Let CustomerID(NewValue As String) ' If the length of NewValue is greater than five If
Len(NewValue) > 5 Then ' ... then raise an error to the program ' using this class! Err.Raise
vbObjectError + 1, "CustomerID", _ "Customer ID can only be up to five " & _ "characters long!" Else ' ...
otherwise, change the field value rs("CustomerID") = NewValue End If End Property
Brilliant! We've just got time for one more method before finishing this section:
• Add the following code to your class:
Public Sub Update()
rs.Update
End Sub
When somebody runs the Update method, it simply fires the Update method of our recordset object.
Simple.
Next up, we're going to test both this property and method with a mini sample application, plus use a
special trick to follow what happens between both your class and test program.
Testing your Class
Let's get your class up-and-running:
• Press F5 to run your program
• If prompted for further information, select 'Wait for Components to Start', then click OK
Your class is now 'alive' but waiting for other programs to use its functionality.
• Launch another instance of Visual Basic
• Create a new 'Standard EXE' project
• Click 'Project', 'References'
Have a scroll around the list. These are all extra widgets you can add to your project.
• Check 'Northwind' in the list
Northwind is your ActiveX project!
• Click OK
Now let's add a little code to activate your project:
• Add a Command Button to Form1
• Type in the following:
Dim Test As Customers
Set Test = New Customers
MsgBox Test.CustomerID
Set Test = Nothing
This code creates a new Customers object. Then the CustomerID is displayed in a message box. Finally,
the Test object is set to Nothing, closing it down.
• Hit F5 to run your test application
Top Tip: If you're getting 'invalid reference' error messages when running your application, something
definitely boobed. Follow these steps to 'reset' – (1) remove the Northwind reference in your test project,
(2) restart your Northwind project, (3) add the reference to Northwind back to your test project, then try
again.
• Click your Command Button
It may take a few seconds to start-up – after all, it's opening a database connection and so on – but after
that initial delay, all calls will perform at lightening speed. You should get a message box displayed
containing the name 'ALFKI'.
End Sub
rs.Close
Set rs = Nothing
End Sub
CustomerID = rs("CustomerID")
End Property
Else
rs("CustomerID") = NewValue
End If
End Property
rs.AddNew
End Sub
rs.Update
End Sub
If rs.EditMode = adEditInProgress Or _
rs.EditMode = adEditAdd Then
rs.CancelUpdate
End If
End Sub
rs.MoveNext
End Sub
rs.MovePrevious
End Sub
End Sub
rs.MoveLast
End Sub
rs.MoveFirst
rs.Find ("CustomerID='" & CustomerID & "'")
End Function
EOF = rs.EOF
End Property
BOF = rs.BOF
End Property
End Sub
Top Tip: So far in this tutorial, we've only added code to one class. However you can easily add more
classes to your projects, by clicking 'Project', 'Add Class'. You can even make these classes work together
by utilising 'collections'. In a situation like ours however, you may want to consider using one class per
table.
Compiling your Program
And now, it's time to compile your class program.
When you do this, all the classes in your ActiveX project will magically turn into one
.DLL file. After this, most tools on your computer will be able to see and use them. So
after compiling, you'll be able to use your DLL from within VB, Excel or even C++!
So let's compile it:
• Click 'File', 'Make Northwind.dll'
• Choose a location then click 'OK'
And would you believe... that's it! You've just created and 'registered' your first real COM
component!
Building your Test Program
So, we've created our COM component and now we need to test it. Let's shoot:
• Close your Northwind project
• Create a new 'Standard EXE'
This program will access our class.
• Add a Label and List Box to Form1, like this:
That List Box will hold a list of our customers and their IDs. Here, I want the user to be able to click the
Find Customer button and have another screen popup with the editable customer details. Let's design that
screen now:
• Click 'Project', 'Add Form'
• Add seven Labels, seven Text Boxes and a Command Button to your Form
• Organise your controls like this:
End Sub
End Sub
Cust.FindByCustomerID (CustomerID)
With Cust
Text1.Text = .CustomerID
Text2.Text = .CompanyName
Text3.Text = .ContactName
Text4.Text = .Address
Text5.Text = .City
Text6.Text = .Country
Text7.Text = .Phone
End With
End Sub
With Cust
.CustomerID = Text1.Text
.CompanyName = Text2.Text
.ContactName = Text3.Text
.Address = Text4.Text
.City = Text5.Text
.Country = Text6.Text
.Phone = Text7.Text
.Update
End With
Unload Me
End Sub
Here, we have a Customer object declared as Cust right at the top of the code.
RaiseEvent FileFound
Timer1.Interval = 0
End If
End Sub
Here, our code simply checks for the file. If found, it raises the FileFound event, then sets the Timer1
Interval property to zero, stopping all future timer checks.
• Open your FileCheck class
• Declare the following object in General Declarations:
Dim WithEvents objFileCheck As Form1
This is your Form1. You're telling Visual Basic this is a space to hold your Form. The WithEvents
keyword means your class can receive the events it transmits, such as our coded FileFound.
• Select 'Class' from the 'Object' drop-down list
• Choose 'Initialize' from the 'Procedure' drop-down list
• Slap the following code behind the Class_Initialize event:
Private Sub Class_Initialize()
End Sub
This code simply sets our objFileCheck to equal a new instance of Form1. Following this, we can use all
the functionality we programmed into Form1. Next up, let's write a Sub that the program using our
application will use to monitor a file.
• Throw the following code into your FileCheck class:
Public Sub MonitorFile(Filename As String)
objFileCheck.Filename = Filename
objFileCheck.Timer1.Interval = 60000
End Sub
When our user calls this, passing a filename, the Filename variable of our Form is set to the passed
filename. Then, the Timer is 'started' by setting the Interval property to 60,000 milliseconds (or a minute
to the rest of us).
So, we've created all the jazz to monitor our file. But when it is actually 'found', we need to tell the
program using our ActiveX EXE by raising the FileFound event.
• Add the following event declaration to the General Declarations section:
Public Event FileFound(Filename As String)
This code simply 'defines' our FileFound event. Next, we'll add code to fire off this event when
appropriate.
• Select 'objFileCheck' from the 'Object' drop-down list
• Choose 'FileFound' from the 'Procedure' drop-down list
Here we have the Name, DataBindingBehaviour (for 'binding' the class to a data source)
and Persistable (used in controls, allows certain class properties to be saved). You should
also have Instancing.
Now after you've set the class name, you probably won't need to worry about the first
three. But what about Instancing?
The Instancing property determines whether or not your class can be 'seen' by the
application using your ActiveX component – and if it can, whether more than one
'instance' should be started at any one time.
Let's take a look at the options, in order of popularity:
• MultiUse – This is perhaps the most used option. This uses one 'instance' of your
component (one 'process space') to serve all the programs using it. Here, all
objects are served by one instance of your component. This saves memory space
and can allow you to "share global variables" - but has few other real-life
advantages
• Private – No-one except other objects in your component can see this class. This
is generally used when you need to create a class that will solely be used by the
other objects in your class
• GlobalMultiUse – Allows you to call the various methods and properties of your
class as if they were global functions. In other words, in VB, you don't have to
explicitly create a new object, then run that method – it's all done automatically.