Introduction
This explains the working of OLE Automation Running Instances at a particular time.
Background
After a lot of Googling, I found some code in C#. The full code can be found here.
The logic is simple, if automation classes are put to run. First, they must register themselves in the Global List, get the Active Objects and then destroy the Objects.
Using the Code
The C# code is very simple and easy to understand. My major focus is to write the code in C++.
First, have a look at the C# code. I made a C++ class that would display all the Running Instances in List Control. Hope this would help for those struggling.
First, get the number of Objects that we would like to count the instances of. We have taken the Names of the OLE classes in array, say, <string progIds[]>
.
string progIds[] = {Excel.Application, Word.Application, Outlook.Application};
Get the Running Object Table from IRunningObjectTable
as which contains all the registered global OLE Objects:
IRunningObjectTable* pRunningObjects;
GetRunningObjectTable (NULL, &pRunningObjects);
This is basically the Global Access Object. Refer to MSDN for further clarification.
Enumerate the Running Global Objects in IEnumMoniker
Object.
IEnumMoniker* pEnumObjects;
pRunningObjects->EnumRunning (&pEnumObjects);
We are almost done now.
Run a loop to get individual elements from the Enumerated Objects, till they are SUCCESS returned, i.e. 0
.
To push it a little further, we can compare the names with the string
array passed earlier with <LPOLESTR lpdisplayName[]>
.
This can be put as:
IMoniker* pIndividualObject;
ULONG lRetuned;
while (pEnumObjects->Next(1, &pIndividualObject, &lRetuned) == 0)
{
IBindCtx* pBindObj;
CreateBindCtx (0, &pBindObj);
if (pBindObj == NULL) continue;
LPOLESTR lpdisplayName;
pIndividualObject->GetDisplayName (pBindObj, NULL, &lpdisplayName);
}
Last but not the Least, do not forget to release all the automation classes initialized or used exactly in the same decreasing order, with the last one to be used, being the first one to be released.
Example, before ending of the loop:
pBindObj->Release ();
pIndividualObject->Release ();
Same goes with pEnumObjects
, and then pRunningObjects
before the program ends.
Points of Interest
My motive was to ease the work with minimum requirement. Hope I have accomplished my goal.
History
Automation classes are an important part of Programming Culture, and hence maintaining them and releasing them when not required is an important task. But many times, we, as developers, fail to do so, in one way or the other.
Hence, to verify whether we have accomplished the task, here is an example. This can be extended further to using GetActiveObject
, RegisterActiveObject
and RevokeActiveObject
. That would be extended in the next article.
Until then, happy coding.