Updated:
by Mike Potter (Zugg)
Back to Introduction
Steps for Scripting COM
NOTE: This document refers to zMUD
versions 6.26 and later. Earlier versions of zMUD did not support some of
the simpler COM syntax used in these examples.
NOTE: The examples given in this document
are for Outlook 2000. Previous versions of Outlook will work a bit
differently.
The best way to get started with understanding COM is to go through an
example. When you want to access a COM Server, there are several steps to
take:
- Get some documentation on the COM Server!
- Using the Name of the COM Server, create a link to that server.
- Using the Link to the COM Server, either: a) read data from the server, b)
send data to the server, or c) execute a method on the server.
In our example, we want to query the Microsoft Outlook 2000 application and
find out how many messages are currently in our InBox. So, for the first
step, we need some documentation on Microsoft Outlook's COM Server. You
can search the Microsoft web site and find the article "Automating
Outlook from a Visual Basic Application" which has a good beginning, or
get the book "Outlook 2000 VBA" which goes into greater detail.
Here's the catch with COM: it is as simple or as hard as the application
vendor wants to make it. And you guessed it: since Microsoft
invented COM, it's applications tend to have rather complex COM
implementations. Finding out how to do something with one of their
applications usually takes the most time. Once you find some good
documentation or examples, the rest of it is easy.
Creating a Link to a COM Server
OK, now that we have some documentation, the next step is to create a link to
the Microsoft Outlook 2000 COM Server. According to the Visual Basic
documentation (and most documentation you find, *will* be in Visual Basic), you
start by doing something like this:
Dim Outlook as Object
Set Outlook = CreateObject("Outlook.Application")
As we can see from this, the Name of the COM Server is: "Outlook.Application".
This is the most important piece of information to start with. Without the
name of the server, you can't do anything. Now, in Visual Basic, they are
using a method called "CreateObject" to return a link to the COM
server. In zMUD, you use the %comcreate function instead, and assign the
result to a zMUD variable using #VAR, like this:
#VAR Outlook %comcreate("Outlook.Application")
Easy! So, anytime you learn the name of a COM Server, now you know how
to get a link to it in zMUD. In zMUD, if you then do a #VAR command to
look at the contents of a variable, you'll see this:
#VAR
Outlook <OLE object: Outlook.Application>
zMUD is telling you that the @Outlook variable doesn't contain a normal
value, but instead contains a link to an OLE object. OLE is basically the
same thing as COM. OLE stands for "Object Linking and Embedding"
and is the most common application of COM in Windows. I won't go into the
technical differences here. But what we are doing with COM is "OLE
Automation" of another application, like Microsoft Outlook in this case.
If Outlook was already running, you might want to link to the running program
instead of creating a second copy of it in memory. To do this, use the %comactive
function instead of %comcreate:
#VAR Outlook %comactive("Outlook.Application")
Retrieving a Property value from a COM Object
Now that we have a link to a COM object, it's time to do something with
it. This is where life can get complicated. Microsoft loves to nest
layers and layers of COM objects. Sometimes it takes several steps to get
what you want. In this case, we want to get down to the Inbox folder in
the Mail part of Outlook. What we learn from the Microsoft documentation
is that everything in Outlook is stored in the "MAPI Namespace".
The example in Visual Basic does this:
Set NameSpace = Outlook.GetNameSpace("MAPI")
What this is doing is taking the previous COM object link "Outlook"
and retrieving the property called "GetNameSpace". This property
takes an argument, which is "MAPI". Properties can take as many
arguments as they need. So, the general Visual Basic COM call is:
Set VariableName = COMObjectLink.PropertyName(Arguments)
In zMUD, it looks like this:
#VAR VariableName @ComObjectLink.PropertyName(Arguments)
almost just like Visual Basic! Versions of zMUD prior to 6.26 required
the more complex syntax:
#VAR VariableName %comget( COMObjectLink, PropertyName, Arguments)
Either will work, but the first syntax is easier to use and closer to other
programming languages. So, in order to get the MAPI Namespace from Outlook, we would do:
#VAR NameSpace @Outlook.GetNameSpace("MAPI")
Now, if we do a #VAR to look at the variables, we see:
Outlook
|
<OLE object: Outlook.Application>
|
NameSpace
|
<OLE object: Outlook.Application.GetNameSpace(MAPI)>
|
Notice that zMUD tells us that NameSpace is still a COM Object link. In
addition, it tells us what it is linking to. The output of the #VAR
command can be a great help in doing COM Scripting in zMUD.
OK, so now we have the MAPI NameSpace, so now what? After digging
through the documentation, we discover that the NameSpace has a property called
Folders. The "Personal Folders" is the top folder within the Folders
property. So, in Visual Basic, you would do this:
Set Folders = NameSpace.Folders("Personal Folders")
The corresponding zMUD code is:
#VAR Folders @NameSpace.Folders("Personal Folders")
Now, in Outlook you'll notice your "Personal Folders" is really a whole
collection of folders, including your Calendar, Contacts, etc. So, to get
the actual Inbox Mail folder, we need to go one level deeper:
#VAR InBox @Folders.Folders("InBox")
Whew, are we there yet? Almost. If we do another #VAR, we now
have:
Outlook
|
<OLE object: Outlook.Application>
|
NameSpace
|
<OLE object: Outlook.Application.GetNameSpace(MAPI)>
|
Folders
|
<OLE object: Outlook.Application.GetNameSpace(MAPI).Folders(Personal Folders)>
|
InBox
|
<OLE object: Outlook.Application.GetNameSpace(MAPI).Folders(Personal Folders).Folders(InBox)>
|
From this we see that InBox is *still* a COM Object link. Digging
further into the documentation, we discover that an email folder is a collection
of messages. This collection of messages is stored in the property
"Items". In order to determine the number of messages in the
collection, we need the "Count" property of the "Items".
Nested property calls
OK, you should be getting the hang of this. To get the Count property
of the Items property, you can do this:
#VAR Items @InBox.Items
#VAR Count @Items.Count
however, instead of creating all of these intermediate variables, zMUD let's
you nest property calls. So we can simplify this code by using:
#VAR Count @InBox.Items.Count
This is the same as the Visual Basic code:
Count = InBox.Items.Count
Yes, the Visual Basic code is a bit easier to read, but hey, this is zMUD,
not Visual Basic. If you do a #VAR command now, you will see:
Outlook
|
<OLE object: Outlook.Application>
|
NameSpace
|
<OLE object: Outlook.Application.GetNameSpace(MAPI)>
|
Folders
|
<OLE object: Outlook.Application.GetNameSpace(MAPI).Folders(Personal Folders)>
|
InBox
|
<OLE object: Outlook.Application.GetNameSpace(MAPI).Folders(Personal Folders).Folders(InBox)>
|
Count
|
47
|
Notice that Count is no longer an OLE object but is a normal, everyday zMUD
variable. In this case, with a value of 47 (the number of messages
currently in my InBox).
Accessing COM Properties from within a Loop
OK, so now we have read data from the COM Server. In this case we have
read the InBox and determined how many messages are in it. Let's get even
fancier. Let's print out the Subject lines for each email message.
Think about it for a second...it's actually easy:
#LOOP 1,@Count {#ECHO @InBox.Items(%i).Subject}
What we are doing is using %i in the argument field to return the ith message
from the "Items" collection. Once we have this message, we
access it's "Subject" property. This is the same as the Visual
Basic code:
for i = 1 to Count
print InBox.Items(I).Subject
next
Setting the Value of a COM Object Property
Now let's send some data back to the COM Server. Let's change the
subjects of one of the email messages. We will change the subject of the
first email message to "Test Message". First, let's go ahead and
get a link to the first message:
#VAR Msg @InBox.Items(1)
To display the current subject, we just do:
#ECHO @Msg.Subject
In fact, let's save this result:
#VAR Subject @Msg.Subject
Now, to change the subject, we use normal #VAR syntax:
#VAR ComObjectLink.Property NewValue
Older versions of zMUD required the %comset function. The format for
%comset is:
%comset( COMObjectLink, PropertyName, NewValue, OptionalArguments)
so we can do this:
#VAR Msg.Subject "Test Message"
or
Msg.Subject = "Test Message"
to change the subject of the message to "Test Message".
Executing a COM Object Method
But if you go to your Outlook application and look in your InBox, you'll see
that the subject of your first message has not been changed! How can this
be? Well, we have changed the subject within memory, but we haven't told
Outlook to SAVE the results. To Save a message, you need to call the Save
"method" for the message. In Visual Basic, you'd just do this:
Msg.Save
But in zMUD, you need to use a command to execute something, so you use the
#COM command. The format of the #COM command is:
#COM COMObjectLink MethodName OptionalArguments
so the result is:
#COM Msg Save
You can also use the #CALL command and execute the COM method as a function:
#CALL @Msg.Save
Now you'll see that the subject line of the first message in your InBox has
really been changed. I hope you didn't need that message. Never
fear, if you have truly been following along, then you'll remember that we
saved the original subject. So let's change it back:
#VAR Msg.Subject @Subject
#CALL @Msg.Save
There, back to normal.
So now we have learned how to get data from another application, send data
back to that application, and tell the application to execute a method. As
you have seen, the hardest part is getting the documentation about the server
and how it works. You'll spend far more time trying to learn about all of
the properties and methods of COM objects then you will actually writing
code. But once you figure out the correct property and object names, then
you can do some amazing things with it.
Freeing up a COM Object
Let's finish by talking a bit about memory usage. If you do a #VAR,
you'll still see all of our COM Object links sitting there. All of these
take up memory. In fact, as long as you have any of these sitting in
memory, you've also got an entire copy of the COM Application (in this case,
Outlook 2000) in memory. To get rid of these COM links, just assign
something else (like "") to the variables:
#VAR Msg ""
#VAR InBox ""
#VAR Folders ""
#VAR NameSpace ""
#VAR Outlook ""
Now if you look at #VAR, all of your OLE Objects should be gone. And if
you check your Task Manager, you'll see that Outlook is no longer running in the
background. This is how you free up COM memory in zMUD.
Using Arrays in COM
Some object methods might require an argument that is an array. For
example, the zMUDCommand method of the zMUDSession COM object requires an array
of parameters to pass to a zMUD command. In Visual Basic, you would use an
array like this:
call session.zMUDCommand( 1, array("param1","param2"))
In Delphi, you use the VarArrayOf routine and put the arguments in brackets:
session.zMUDCommand( 1, VarArrayOf( ['param1','param2']);
In zMUD, you use the %array function:
#CALL @session.zMUDCommand( 1, %array("param1","param2"))
For more examples, see: ADO Programming in zMUD,
zMUD
COM using zMUD