main.h

00001 
00002 #ifndef MAIN_H_c168fc27_d6a3_4a23_b658_dca5a401e06b
00003 #define MAIN_H_c168fc27_d6a3_4a23_b658_dca5a401e06b
00004 
00005 /*!
00006 ** \mainpage Simple COM Server for vbScript
00007 **
00008 ** The following is a tutorial/explanation on how to set up a Qt program
00009 **  to act as a COM server that can be gotten access to by vbScript.
00010 **
00011 ** Why yet another COM article?
00012 **
00013 ** Because, aparently, my brain works backwards!  All the articles I read
00014 **  about COM always seem to start with building a DLL or EXE program that
00015 **  supports the COM interface.  What that leaves \b me with is an experience
00016 **  of "why am I doing this?" ism.  In other words, I'm stuck having to 
00017 **  learn about an element of a COM interface without really knowing why
00018 **  I'm having to learn about it or how it fits in to the bigger picture.
00019 **  By the time I've gotten to the point of the article where I'm actually
00020 **  using one of those early things that I didn't understand why I was 
00021 **  creating, I've forgotten what I had created... since I never really knew
00022 **  why I was having to create it in the first place.
00023 **
00024 ** Example; \b ClassFactory... what the heck is that?  I don't know.  But,
00025 **  in all the tutorials I have come across, I'm building one, without
00026 **  really understanding why.
00027 **
00028 ** This article takes a different approach.  This article starts with why
00029 **  you might be interested in COM in the first place, and then goes from
00030 **  there to understand why you have to put things in the places that you 
00031 **  do.
00032 **
00033 ** This article is also written expressly for the Qt development library, from
00034 **  http://www.trolltech.com on
00035 **  Windows (obviously, since none of this will work on Linux or Mac).  If 
00036 **  you're not familiar with Qt you are missing out!  Qt has got to be one
00037 **  of the best GUI/Application development libraries I've had my hands on.
00038 **  And, it's nearly completely free!  I say nearly completely because they
00039 **  happen to have available a complete implementation of an ActiveX server
00040 **  COM library - at a price!  I don't want that.  For two reasons.  One,
00041 **  I don't want to spend the cash.  Secondly, I want to develop open-source
00042 **  programs that anyone else can download and develop on also without 
00043 **  requiring a license from Qt.  Plus, it's fun!
00044 **
00045 ** Let's begin,
00046 **
00047 ** Why COM?
00048 **
00049 ** If you have ever done any vbScript programming of any significance, you'll
00050 **  probably recall coming across something like the following:
00051 **
00052 ** \par vbScript Example ~ Using COM
00053 ** \code
00054 ** dim dexe: set dexe = createObject("Dumont.EXE")
00055 ** dim fscr: set fscr = createObject("Scripting.FileSystemObject")
00056 ** dim wscr: set wscr = createObject("WScript.Shell")
00057 ** dim wpad: set wpad = createObject("Wordpad.Document.1")
00058 ** dim swmp: set swmp = createObject("Murky.Swamp")
00059 ** dim glnd: set glnd = createObject("Garland.Leaves")
00060 ** \endcode
00061 **
00062 ** What the preceeding codes do is define a local script variables called \b dexe,
00063 **  \b fscr, \b wscr, \b wpad and assigns to them objects called "Dumont.EXE"
00064 **  "Scripting.FileSystemObject", "WScript.Shell", "Wordpad.Document.1" and so on.
00065 **  What actually happened is the Windows COM system was invoked in the vbScript
00066 **  program, and called upon to  fetch a COM server by those names.
00067 **
00068 ** \dot
00069 ** digraph example
00070 ** {
00071 **   rankdir=LR;
00072 **   vbScript -> COM;
00073 **   COM -> "Dumont.EXE";
00074 **   COM -> "Scripting.FileSystemObject";
00075 **   COM -> "WScript.Shell";
00076 **   COM -> "Wordpad.Document.1";
00077 **   COM -> "Murky.Swamp";
00078 **   COM -> "Garland.Leaves";
00079 ** }
00080 ** \enddot
00081 **
00082 ** Now, let's go step by step as to how that happened.
00083 **
00084 ** The first thing to note about Windows is it contains within it something call
00085 **  a COM sub-system.  This is a system, contained within Windows, that allows
00086 **  different Windows programs to communicate with eachother across protected
00087 **  memory boundaries.  The interface framework that is used to perform this
00088 **  communication is common, predictable and known - it is COM.
00089 **
00090 ** To begin, the framework starts in one of the Windows system dll files.
00091 **  This is, more than likely, \b ole2.dll or some such dll.  When this dll is
00092 **  invoked by Windows, the COM system springs to life!
00093 **
00094 ** When you take a vbScript program like the one above, and issue the 
00095 **  \b createObject() command in it, you ask the ole2.dll program to dip in to
00096 **  that mysterious place called the Windows System Registry to look for 
00097 **  infomation about your requested program, in our case the \b Dumont.EXE 
00098 **  program, and others.
00099 **
00100 ** Let's look and see how that happens:
00101 **
00102 ** \image html registry-1.png
00103 **
00104 ** If you open your regedit program, and, assuming you have a program defined
00105 **  called Dumont.EXE, you will find that you can navigate to a key location
00106 **  known as the
00107 ** \code 
00108 ** My Computer\HKEY_CLASSES_ROOT\Dumont.EXE
00109 ** \endcode
00110 **
00111 ** key.  What you are looking at here is an "indexed key value" for the
00112 **  registered program name "Dumont.EXE".  What this index value is providing
00113 **  for the COM subsystem is the ability to quickly map the name Dumont.EXE to
00114 **  something called a CLSID value.  When a program like vbScript makes a 
00115 **  call to \b createObject, all it is really looking for at this point is the
00116 **  CLSID of the Dumont.EXE program.  Once the COM subsystem has this CLSID 
00117 **  value the search continues.
00118 **
00119 ** \image html registry-2.png
00120 **
00121 ** If you continue your search through your registry you will come across a 
00122 **  setting for the CLSID associated in the previous search for Dumont.EXE.
00123 **  This registry setting can be found at
00124 **
00125 ** \code
00126 ** My Computer\HKEY_CLASSES_ROOT\CLSID\{c7860c20-9b6f-4f31-8293-31cb0c1799f0}
00127 ** \endcode
00128 **
00129 ** It is this entry, the \b CLSID entry, that contains all the meat of our 
00130 **  registered program for the COM subsystem.  It contains settings in it for 
00131 **  identifying where the "server" can be found, connection settings, and any 
00132 **  other interesting parameters associated with our program.  If you have
00133 **  a program of your own that you're presently using in vbScript you can
00134 **  look for it in a similar way.  The registry entries should be there
00135 **  in a similar manner for all COM enabled programs.  You can easily search
00136 **  for "Scripting.FileSystemObject", "Word.Document", or any other program
00137 **  that you may be familiar with, and you will find registry entries in 
00138 **  basically the same format.
00139 **
00140 ** The setting \b LocalServer can be one of the following: \b LocalServer, 
00141 **  \b InprocServer or \b RemoteServer.  The details are somewhat unimportant
00142 **  at this point other than to say that \b LocalServer refers to an \b EXE 
00143 **  type of COM server, and \b InprocServer refers to an \b DLL type of COM
00144 **  server.  The \b RemoteServer value is beyond the scope of this article
00145 **  (in other words, I have very little understanding of what a RemoteServer 
00146 **  is or how to use one).
00147 ** 
00148 **
00149 ** At this point, you actually have enough to run an executable from vbScript.
00150 **  You won't be able to talk to it yet, but you can execute it because when 
00151 **  you issue the \b createObject("Dumont.EXE") command, the COM subsystem 
00152 **  will seek out these registry settings, find the program it is suppose 
00153 **  to run, and run it.  It will do this on a DLL or EXE depending on how
00154 **  you set up these registry settings.
00155 **
00156 ** Let's try it.  Let's make a program that we can launch from vbScript.  Let's
00157 **  do this assuming we're using the Qt system since... I'm using the Qt system,
00158 **  and I really want COM in my Qt systems without having to buy a license.
00159 **
00160 ** In Qt, create a new project.  Here are the project files:
00161 **
00162 ** \par main.h ~ Qt Project Main Header
00163 ** \code
00164 ** #ifndef MAIN_H_c168fc27_d6a3_4a23_b658_dca5a401e06b
00165 ** #define MAIN_H_c168fc27_d6a3_4a23_b658_dca5a401e06b
00166 **
00167 ** // nothing here yet!
00168 **
00169 ** #endif
00170 ** \endcode
00171 **
00172 ** \par main.cpp ~ Qt Project Main Implementation
00173 ** \code
00174 ** #include <QApplication>
00175 ** #include <QTextEdit>
00176 **
00177 ** #include "main.h"
00178 **
00179 ** int main( int argc, char ** argv )
00180 ** {
00181 **   QApplication app(argc,argv);
00182 **
00183 **   QTextEdit message;
00184 **   message.append( "Hello World!" );
00185 **   message.show();
00186 **
00187 **   return( app.exec() );
00188 ** }
00189 ** \endcode
00190 **
00191 ** \par SimpleCOM.pro ~ Qt Project qmake file
00192 ** \code
00193 ** TEMPLATE = app
00194 ** TARGET   = SimpleCOM
00195 ** SOURCES  = main.cpp
00196 ** INCLUDES = main.h
00197 ** \endcode
00198 ** 
00199 ** This will get you a basic Qt GUI-based executable.  It doesn't do much other than 
00200 **  simply open a text box window, but that's all we need for the moment.  All we 
00201 **  want to do is launch an executable from a vbScript \b createObject() command.
00202 **  We'll worry about actually getting something done later.  I'm assuming you
00203 **  have a working Qt installation and you know how to write and compile programs
00204 **  for it.
00205 **
00206 ** What we are going to do now is write a simple sub-routine in our application to
00207 **  get our own executable registered properly within the windows system and exposed
00208 **  to visual basic so that when we execute a \b createObject() method, our server
00209 **  program gets loaded.  Qt makes manipulating the windows registry a breeze.  Behold:
00210 **
00211 ** \par main.cpp ~ Application Registration Subroutine
00212 ** \code
00213 ** //
00214 ** // This is a simple and generic sub-routine for getting a simple COM server
00215 ** //  registered in the registry.  This can be used on lots of different
00216 ** //  COM servers, it's reasonably generic.
00217 ** //
00218 ** void RegisterComServer
00219 ** (
00220 **   const QString & progid,        // the Name value we want to fetch by.  Like, "SimpleCOM.EXE"
00221 **   const QUuid & clsid,           // the CLSID value for our app
00222 **   const QString & description,   // a useful description
00223 **   const QString & serverType,    // the type of server
00224 **   const QString & serverPath     // where to find the server
00225 ** )
00226 ** {
00227 **   //
00228 **   // Open the registry at the root
00229 **   //
00230 **   QSettings registry( "HKEY_CLASSES_ROOT", QSettings::NativeFormat );
00231 ** 
00232 **   //
00233 **   // Set the PROGID registry value for this entry, and set the 
00234 **   //  description and CLSID also
00235 **   //
00236 **   //
00237 **   registry.setValue( progid + "/Default",       description      );
00238 **   registry.setValue( progid + "/CLSID/Default", clsid.toString() );
00239 ** 
00240 **   //
00241 **   // Establish a path to the CLSID root.
00242 **   //
00243 **   QString clsroot = "CLSID/" + clsid.toString() + "/";
00244 ** 
00245 **   //
00246 **   // Set the Description, Server type, and path to the server plus the ProgID, which is a
00247 **   //  bit redundant but we're doing it anyway.
00248 **   //
00249 **   registry.setValue( clsroot + "Default",                description );
00250 **   registry.setValue( clsroot +  serverType + "/Default", serverPath  );
00251 **   registry.setValue( clsroot + "ProgID/Default",         progid      );
00252 ** 
00253 ** }
00254 ** \endcode
00255 **
00256 ** That sub-routine is fairly useful, at least for our purposes.  We are just
00257 **  trying to get a simple COM server program registered.  This sub-routine 
00258 **  will register either and EXE, DLL, or REMOTE server, it just depends on
00259 **  how you call it.
00260 **
00261 ** And, speaking of calling it, here's how we do that:
00262 **
00263 ** \par main.cpp ~ Calling our registration subroutine (subroutine omitted for brevity).
00264 ** \code
00265 ** #include <QApplication>
00266 ** #include <QTextEdit>
00267 **
00268 ** #include "main.h"
00269 **
00270 ** int main( int argc, char ** argv )
00271 ** {
00272 **   QApplication app(argc,argv);
00273 **
00274 **   RegisterComServer
00275 **   (
00276 **     "SimpleCOM.EXE",                            //  progid
00277 **     "{420a352c-429b-4512-a926-3e2b77aa33fe}",   //  clsid
00278 **     "This is a SimpleCOM server demonstration", //  description
00279 **     "LocalServer",                              //  serverType
00280 **     app.applicationDirPath()                    //  serverPath
00281 **   );
00282 **
00283 **   QTextEdit message;
00284 **   message.append( "Hello World!" );
00285 **   message.show();
00286 **
00287 **   return( app.exec() );
00288 ** }
00289 ** \endcode
00290 **
00291 ** When we run this program, we get, as expected, our simple "Hello World!"
00292 **  dialog window, but also, when we look again at the registry, we have 
00293 **  some new registry settings.
00294 **
00295 ** \image html registry-3.png
00296 **
00297 ** A little side note on CLSID values.  I obtained those values by running
00298 **  a program available here: http://dumont.showoff-db.org/guidgen/doc/html/index.html
00299 **  This is a simple guid generating program that I wrote to emulate the
00300 **  guidgen.exe generating program from Microsoft.  The reason I wrote this
00301 **  program was because I like to use GUID values in my header locking
00302 **  mechanism as well, and the regular guidgen.exe program offered by
00303 **  Microsoft didn't offer a header compatible output.  So, I rolled my own
00304 **  one lazy saturday afternoon, added a few enhancements, and published
00305 **  it online for the world to see.
00306 **
00307 ** Since we are all reading the same document and running the same demo it 
00308 **  will not be necessary for you to generate your own GUID values for this
00309 **  SimpleCOM application.  If, however, you rewrite your own SimpleCOM
00310 **  program that is similar but different, then you will want to substitute
00311 **  with your own GUID values.  Either way, if you are so motivated, 
00312 **  you can easily replace the GUID value used here with your own.  Suite
00313 **  yourself.
00314 **
00315 ** As it stands, we presently have enough to run a program from vbScript.  
00316 **  Let's try it:
00317 **
00318 ** \par SimpleCOM.vbs ~ Calling our SimpleCOM.EXE program
00319 ** \code
00320 ** dim simplecom: set simplecom = createObject("SimpleCOM.EXE")
00321 ** \endcode
00322 **
00323 ** \dot
00324 ** digraph example
00325 ** {
00326 **   rankdir=LR;
00327 **   vbScript   [ label="vbScript"  ];
00328 **   COM        [ label="COM"       ];
00329 **   SimpleCOM  [ label="SimpleCOM" ];
00330 **
00331 **   vbScript -> COM;
00332 **   COM -> SimpleCOM;
00333 ** }
00334 ** \enddot
00335 **
00336 ** When you run this program two things should happen.  First, the program
00337 **  should run.  You should get a window that says "Hello World!" and,
00338 **  after closing the window, and after about 15 seconds or so after that,
00339 **  you should get a vbScript error window as follows (I have superimposed
00340 **  the two images, you won't see the error message until you close the
00341 **  window, and, consequently, the SimpleCOM.EXE server program):
00342 **
00343 ** \image html runscript-1.png
00344 **
00345 ** Here's the good news.  We can launch another .exe program from vbScript
00346 **  using the Windows COM subsystem - yea!  Here's the bad news.  We're not
00347 **  done yet!  In fact, we are far from done.  While we got the program
00348 **  running, we can't communicate with it yet.  Yes, the program is running
00349 **  but the Windows COM subsystem doesn't know it yet - even though it is
00350 **  the COM subsystem that is responsible for the program running in the
00351 **  first place, it is our program that has to take a few more steps to
00352 **  let the COM subsystem know that it's running and how to talk to it.  In
00353 **  other words, now that the program is running, it has to 'hook' itself
00354 **  into the Windows COM subsystem so that the Windows COM subsystem can
00355 **  'make calls into' the program.
00356 ** 
00357 ** This may seem odd, but think about it.  In the case of an .exe program,
00358 **  an .exe program can be launched from more than one... um... function.  
00359 **  For instance, the user can go to the folder where the program resides
00360 **  and click on it to launch it.  He can open a console window and launch
00361 **  it from there.  And... as we are working so hard to achieve... he can
00362 **  launch the program from a vbScript program.  So, in the case of a
00363 **  vbScript program, even though the COM subsystem is the responsible party
00364 **  for the program running, it still cannot magically 'know' how to talk
00365 **  with that program unless our program lets the Windows COM subsystem know
00366 **  how it wants to be talked to.  If we launch the program by hand, then
00367 **  of course, unless our program takes steps to inform the COM subsystem
00368 **  that it's up and running, the COM subsystem won't know that it's up
00369 **  and running.  So, it is our program's responsibility to 'register'
00370 **  itself, not only in the Windows System Registry, but in the active and
00371 **  dynamic COM subsystem as well.
00372 **
00373 ** Here is one thing we want to do before we get any further.  As it stands
00374 **  right now, every time our program runs it registers itself into the 
00375 **  Windows registry.  We don't want that.  It only needs to be registered
00376 **  once, so let's provide some command-line options to get that done
00377 **  on request.  Again, Qt to the rescue.  Another trivial implementation:
00378 **
00379 ** \par main.cpp ~ Registering upon request
00380 ** \code
00381 ** if( app.arguments().contains("/register") )
00382 ** {
00383 **   RegisterComServer
00384 **   (
00385 **     "{420a352c-429b-4512-a926-3e2b77aa33fe}",   //  clsid
00386 **     "SimpleCOM.EXE",                            //  progid
00387 **     "This is a SimpleCOM server demonstration", //  description
00388 **     "LocalServer",                              //  serverType
00389 **     app.applicationFilePath()                   //  serverPath
00390 **   );
00391 **   exit(0);
00392 ** }
00393 ** \endcode
00394 **
00395 ** Now, when we run our program, our program runs.  If we include a command line
00396 **  option, our program registers itself into the registry.  This is pretty
00397 **  typical.  It is also pretty typical to implement some code that will 
00398 **  support unregistration as well.  We'll do this too, but we'll get to it
00399 **  later, because, remember, my brain works backwards, and I can only work
00400 **  on things in a forward (aka reverse) motion - ie; when I think I need them.
00401 **  Did I mention I am dyslexic?  No wonder I'm so confused all the time!
00402 **
00403 ** We now have a program that can register itself in the Windows System Registry,
00404 **  and, based upon those settings, run from a vbScript call.  This is a good
00405 **  start, but it's far from complete.  We now have to 'inform' the Windows
00406 **  COM subsystem that our program is running and available.
00407 **
00408 ** The Windows System call that we need to make is called 
00409 **  <a href="http://msdn2.microsoft.com/en-us/library/ms693407.aspx">CoRegisterClassObject</a>.
00410 **  The prototype for this function is as follows:
00411 **
00412 ** \par reference ~ CoRegisterClassObject
00413 ** \code
00414 ** STDAPI CoRegisterClassObject
00415 ** (
00416 **   REFCLSID rclsid,
00417 **   IUnknown * pUnk,
00418 **   DWORD dwClsContext,
00419 **   DWORD flags,
00420 **   LPDWORD  lpdwRegister
00421 ** );
00422 ** \endcode
00423 **
00424 ** Let's go through these parameters one by one.  
00425 **
00426 ** \par rclsid
00427 ** Reference to the CLSID of our program.  This is, guess what, the same CLSID
00428 **  we have been using when we registered our program in the Registry, remember?
00429 **  In our case this number is {420a352c-429b-4512-a926-3e2b77aa33fe}.  An
00430 **  important thing to think about here is vbScript is calling upon our program
00431 **  with a registered application name (or PROGID) of "SimpleCOM.EXE", and through 
00432 **  the use of the registry that name was translated into our CLSID number for this
00433 **  application.  And, this is the reason; we are about to register our application
00434 **  in Windows runtime dynamic memory with its CLSID and not its PROGID (or
00435 **  program name).  So, the registry registration we did earlier is an important 
00436 **  part of what we're doing.  It allows vbScript type of programs to call upon
00437 **  us by a human-readable name, and allows the Windows System Internals to manage
00438 **  us by internal CLSID reference numbers.
00439 **
00440 ** \par
00441 ** It's actually a pretty handy thing if you think about it.  For an operating
00442 **  system to be required to manipulate everthing by String values would be 
00443 **  quite a waste of resources.  But, to be able to manipulate things by a binary
00444 **  internal reference number, a CLSID perhaps, makes a lot of sense.  The binary
00445 **  CLSID value is guaranteed to be unique, anytime one is created, ever, and
00446 **  they're of a fixed size, meaning they're all the same size (making them 
00447 **  easier to manage), and, finally, in the world of memory management, they
00448 **  don't actually occupy that much memory, but can be mapped (through the
00449 **  registry, for instance) to actual, variable length, human readable string 
00450 **  values.  A CLSID value (or GUID value, which is what they actually are)
00451 **  occupy only 16 bytes of memory.  Not bad considering they can represent
00452 **  anything and they will never repeat.
00453 **
00454 ** \par pUnk
00455 ** Pointer to Unknown (ahh, a Windows favorite... unknown).  This is a pointer
00456 **  to the interface for something called a \b ClassFactory.  Remember me mentioning
00457 **  that at the beginning of this dissertation?  Well, we are about to learn,
00458 **  in excrutiating detail why we need a class factory, and how to make one.
00459 **  It is through this pointer that the Windows COM subsystem knows how to
00460 **  'call into' our application.  This pointer is the primary conduit of 
00461 **  communication into our program.  Very important!  In another time and place
00462 **  this might be called a "Callback Function Pointer".  We'll get into this 
00463 **  ClassFactory very shortly.
00464 **
00465 ** \par dwClsContext
00466 ** Class Context, or, as Microsoft puts it, "Context in which the executable code 
00467 **  is to be run."  Microsoft also includes a fairly comprehensive link to the
00468 **  possible values here: 
00469 **  <a href="http://msdn2.microsoft.com/en-us/library/ms693716(VS.85).aspx">CLSCTX</a>
00470 **  (pardon me if these links don't work - our good friend Bill has a tendancy of moving
00471 **  things around on a fairly regular basis)
00472 **
00473 ** \par flags
00474 ** What would we do without flags?  There are lots of choices here.  You can
00475 **  read about them here: 
00476 **  <a href="http://msdn2.microsoft.com/en-us/library/ms679697(VS.85).aspx">REGCLS</a>
00477 **  We'll discuss some of them as we go along.
00478 **
00479 ** \par lpdwRegister
00480 ** This is a pointer to the registration handle so that when we are done
00481 **  using this object, or if our program is shutting down or whatever, we can
00482 **  unregister it from the COM subsystem.  This is important, we need to hang
00483 **  on to this.
00484 **
00485 ** So, this is a pretty big function.  It's a pretty important one too.  It is
00486 **  this function that allows our running program to register itself (or inform
00487 **  Windows) that we are up and running, and how to call-back into us.
00488 **
00489 ** So, now we are ready to start implementing our ClassFactory.  The first question
00490 **  we have to answer, then, is; "What's an ClassFactory?"  Well, the answer is
00491 **  fairly simple.  A ClassFactory is an object, in our program, that is responsible
00492 **  for manufacturing another object.  The way to think about a ClassFactory is
00493 **  like this: Every object in our program that we are going to "Register" into
00494 **  the Windows System Registry and into the Windows Runtime Dynamic Memory
00495 **  is going to require a ClassFactory to complete that registration.  Since
00496 **  Windows doesn't know anything about our program, or what objects are 
00497 **  contained within it, much less how to "make" an object in our program, then
00498 **  we have to provide a little helper... a "ClassFactory".  Windows knows
00499 **  what a ClassFactory is and how to talk to it, and since we're the ones
00500 **  writing the ClassFactory implementation, we can make sure our implementation
00501 **  knows how to make objects within our system.  Another way to say it is, a
00502 **  "ClassFactory is a sort-of universal language translator between Windows
00503 **  (aka; the Borg) and our program (aka; a rag-tag rebel fleet)."  Simple eh?  
00504 **  Well, read on.
00505 **
00506 ** Let's make a ClassFactory of our own.  There's kind-of a basic set of 
00507 **  requirements that we must fulfill in order to be able to build a 
00508 **  class factory properly.  Here's the basic layout:
00509 **
00510 ** \par ClassFactory ~ a possible definition
00511 ** \code
00512 ** class ClassFactory: public IClassFactory
00513 ** {
00514 **   public:
00515 **
00516 **   // IUnknown
00517 **   HRESULT __stdcall QueryInterface( const IID & iid, void ** ppv );
00518 **   ULONG __stdcall AddRef();
00519 **   ULONG __stdcall Release();
00520 **
00521 **   // IClassFactory
00522 **   HRESULT __stdcall CreateInstance( IUnknown * pUnkOuter, const IID & iid, void ** ppv );
00523 **   HRESULT __stdcall LockServer( BOOL lock );
00524 **
00525 **   // ctor/dtor
00526 **   ClassFactory();
00527 **   ~ClassFactory();
00528 **
00529 **   // internals
00530 **   static LONG s_serverLocks;
00531 **   DWORD dwRegister;
00532 **
00533 ** };
00534 ** \endcode
00535 **
00536 ** Now, this is, by no means, a quality written piece of code.  A ClassFactory 
00537 **  object is an incredibly generic piece of software, for the most part, and
00538 **  our implementation, in an ideal world, should really be generic and reusable
00539 **  so that all the world could enjoy.  But, then I'd have a chunk of code
00540 **  that was so hard to explain, that I wouldn't be able to write this article.
00541 **  Therefore, I'm keeping this simple.  For now, anyhow.  Enjoy it while it lasts.
00542 **
00543 ** Let's go through this object step by step.
00544 **
00545 ** First of all, you'll notice our ClassFactory inherits from the 
00546 **  IClassFactory interface.  This interface is defined in one of the Windows
00547 **  header files.  When we inherit from this interface, we are informing
00548 **  our compiler to construct our object in a way that will allow us to hand,
00549 **  back to Windows in our CoRegisterClassObject call, a pointer to our
00550 **  object, and Windows will know that these five function calls will be
00551 **  available at the beginning of that address pointer, in the order specified.
00552 **  THAT's how windows knows how to call-in-to us.  Did you get that?  We
00553 **  construct an object, with a function table, laid out in a particular
00554 **  order, with particular functions, and give to Windows a pointer to the
00555 **  beginning of that function table.  That's our Windows Callback!  And
00556 **  That's how windows knows how to call into us.
00557 **
00558 ** Let's talk about the functions.
00559 **
00560 ** \par ClassFactory::AddRef
00561 ** \code
00562 ** ULONG __stdcall ClassFactory::AddRef()
00563 ** {
00564 **   return(1);
00565 ** }
00566 ** \endcode
00567 **
00568 ** In COM, you'll quickly learn that your objects must reference count.  But,
00569 **  an interesting thing to note about ClassFactory objects, is, they don't have
00570 **  to reference count.  A ClassFactory object is "Registered" in Windows,
00571 **  and there is only one per registration.  Therefore, by definition, when
00572 **  you register your ClassFactory, there is one object.  There will never
00573 **  be more than one ClassFactory per registration because every ClassFactory,
00574 **  when registered, is registered with a CLSID.  When Windows is called upon
00575 **  to talk to that ClassFactory, from vbScript, it is going to be talking
00576 **  to this one and only registered ClassFactory object.  By definition there
00577 **  will be only one, and, therefore, by definition, the reference count will
00578 **  only ever be one.  That's just the way that it is.  So our function returns
00579 **  only one.  
00580 **
00581 ** Don't confuse what I am saying with that you will only ever have one 
00582 **  ClassFactory in your application - not so.  Rather, you will only have one
00583 **  ClassFactory per \b Registered \b CLSID within your application.  So,
00584 **  what that means is, if your application is exposing two interfaces, you will
00585 **  have two registry settings in the Windows System Registry.  Both of those
00586 **  same registry settings may refer to the same executable, but they will be
00587 **  both requesting a ClassFactory for a different CLSID.  In this case you will
00588 **  have two ClassFactories, registered to Windows, both in the registry, and in 
00589 **  the COM Dynamic Memory area.  \b And, the reference counts on both those
00590 **  ClassFactories will always only ever be 1.
00591 **
00592 ** Nuff said!
00593 **
00594 ** \par ClassFactory::Release
00595 ** \code
00596 ** ULONG __stdcall ClassFactory::Release()
00597 ** {
00598 **   return(1);
00599 ** }
00600 ** \endcode
00601 **
00602 ** Again, we're talking about the ClassFactory.  And, as we've just learnt,
00603 **  ClassFactory objects don't reference count.  So, when we Release our 
00604 **  ClassFactory object, we don't decrement our reference count either.  That
00605 **  really makes life simple.
00606 **
00607 ** \par ClassFactory::LockServer()
00608 ** \code
00609 ** HRESULT __stdcall ClassFactory::LockServer( BOOL lock )
00610 ** {
00611 **   if( lock ) ::InterlockedIncrement( &s_serverLocks );
00612 **   else       ::InterlockedDecrement( &s_serverLocks );
00613 **   return NOERROR;
00614 ** }
00615 ** \endcode
00616 **
00617 ** Since the Windows COM subsystem is responsible for loading our program into
00618 **  memory, the question comes about when should the program be unloaded?
00619 **  The simple answer is; "when everyone is done using it."  This answer makes
00620 **  sense, but there may be instances where some task you're performing 
00621 **  would benefit from your COM server program being loaded and then locked
00622 **  into memory.  Does "Lock and Load" sound familiar?  Well, this would be
00623 **  more along the lines of "Load and Lock" - see, there's that dyslexia again!
00624 **
00625 ** This \b LockServer() function increments or decrements a server lock value
00626 **  based upon the request.  Therefore, multiple clients can lock the server
00627 **  and unlock the server as needed, and once all the locks are released then
00628 **  our server can unload itself.  Note, also, that \b s_serverLocks is
00629 **  a static variable to the ClassFactory object.  This means that if
00630 **  our program registers more than one ClassFactory, which it is allowed to
00631 **  do, then this ServerLocks counter will count ALL our server objects.
00632 **  We'll deal with the details of all that later.
00633 **
00634 **
00635 ** \par ClassFactory::QueryInterface
00636 ** \code
00637 ** HRESULT __stdcall QueryInterface( const IID & iid, void ** ppv )
00638 ** {
00639 **   //
00640 **   // This is probably totally unnecessary since the Windows COM subsystem
00641 **   //  called us, and it's totally extremely unlikely that Windows is
00642 **   //  going to call us and not give us a pointer.  But, check it anyway.
00643 **   //
00644 **   //
00645 **   if( !ppv ) return( E_FAIL );
00646 **
00647 **   //
00648 **   // Always wipe the callers reference pointer.  This way if we decide
00649 **   //  there's an error, then we can just return with that error code
00650 **   //  and not have to also worry about wiping his pointer.  Wiping pointers
00651 **   //  is a good thing.
00652 **   //
00653 **   *ppv = NULL;
00654 **
00655 **   //
00656 **   // Check the ID requested against known ID numbers for the ClassFactory
00657 **   //
00658 **   if( (::IsEqualIID( iid, IID_IUnknown      )) ||
00659 **       (::IsEqualIID( iid, IID_IClassFactory )) )
00660 **   {
00661 **     //
00662 **     // Set the callers pointer to us.  This may look a little redundant
00663 **     //  since we are already calling us from a pointer we got for us
00664 **     //  which is already pointing to us, and we're returning that same
00665 **     //  pointer, but, hey, this is COM - it's not suppose to make sense!
00666 **     //
00667 **     *ppv = (IClassFactory*) this;
00668 **
00669 **     //
00670 **     // Life is good.  Tell the world!
00671 **     //
00672 **     return( S_OK );
00673 **   }
00674 **
00675 **   //
00676 **   // If the ID requested is not one of the IClassFactory or IUnknown then
00677 **   //  we don't know what the caller is looking for.
00678 **   //
00679 **   return( E_NOINTERFACE );
00680 **
00681 ** }
00682 ** \endcode
00683 **
00684 ** Things are getting a little more complicated now.  We have a thing called
00685 **  a QueryInterface.  This is another one of those strange things in COM,
00686 **  and, probably, one of the harder things I've had to learn about it.  A 
00687 **  QueryInterface function is a function that the Windows COM subsystem uses 
00688 **  to get its hands on various interfaces for various objects.  Since the
00689 **  COM subsystem doesn't really know anything about our software, or how
00690 **  it's built, the only way it can talk to it is through pre-defined interfaces.
00691 **  So far we are dealing with two of these interfaces.  One is the \b IUnknown
00692 **  interface, and another is the \b IClassFactory interface.
00693 **
00694 ** The nice part about our C++ compiler is that when we ask it to build for us
00695 **  an object in memory, we can direct it to build it a particular way, as in
00696 **  we can direct it to build it with an interface that matches the IUnknown
00697 **  interface or an IClassFactory interface, just like Windows is expecting 
00698 **  from us.
00699 **
00700 ** Then, when the Windows COM subsystem makes a request of our objects, to
00701 **  return a particular one of those interfaces, we can do that real easily
00702 **  through C++ casting and whatnot.
00703 **
00704 ** Remember, we registered our ClassFactory object using the CoRegisterClassObject
00705 **  function call.  The type of object that were expected to register was a
00706 **  IClassFactory implementing object.  At the very least we were expected to
00707 **  register an object that implements the IUnknown interface.  We did both,
00708 **  or, we're going to do both.
00709 **
00710 ** The four functions, so far, above, are about as boiler-plate as they can get.
00711 **  You can use this ClassFactory, so far, in about any function or program that
00712 **  you want to.  That's about to change, though.  Yes, the joy never ends!  One
00713 **  more function to go...
00714 ** 
00715 
00716 ** \par ClassFactory::CreateInstance
00717 ** \code
00718 ** HRESULT __stdcall CreateInstance
00719 ** (
00720 **         IUnknown *  pUnkOuter,
00721 **   const IID      &  iid,
00722 **   void           ** ppv
00723 ** )
00724 ** {
00725 **   //
00726 **   // This is probably totally unnecessary since the Windows COM subsystem
00727 **   //  called us, and it's totally extremely unlikely that Windows is
00728 **   //  going to call us and not give us a pointer.  But, check it anyway.
00729 **   //
00730 **   //
00731 **   if( !ppv ) return( E_FAIL );
00732 **
00733 **   //
00734 **   // Assume an error by clearing the callers handle.  If things
00735 **   //  work out then ppv will get set to something meaningful.
00736 **   //
00737 **   //
00738 **   *ppv = NULL;
00739 **
00740 **   //
00741 **   // We are not supporting aggregation (yet) so return
00742 **   //  the appropriate error code.
00743 **   //
00744 **   //
00745 **   if( pUnkOuter )
00746 **     return( CLASS_E_NOAGGREGATION );
00747 **
00748 **   //
00749 **   // Create a new COM object
00750 **   //
00751 **   SimpleComObject * object = new SimpleComObject();
00752 **
00753 **   //
00754 **   // Query the COM object to see if it supports the
00755 **   //  requested interface.
00756 **   //
00757 **   HRESULT hr = object-> QueryInterface( iid, ppv );
00758 **
00759 **   //
00760 **   // If the query failed, then we can release the object.
00761 **   //
00762 **   if( FAILED(hr) )
00763 **     object-> Release();
00764 **
00765 **   //
00766 **   // We should have returned above with no error, so if we
00767 **   //  got down here then return thusly.
00768 **   //
00769 **   //
00770 **   return( hr );
00771 **
00772 ** }
00773 ** \endcode
00774 **
00775 ** Good night!  What in the world is all that?  Hush!  It's COM.  You're
00776 **  scaring the children!
00777 **
00778 ** Here's what's happening.  Windows has hooked into us through our ClassFactory
00779 **  object.  Then, Windows, ultimately, is requesting our ClassFactory to
00780 **  manufacture an object.  It does that by calling the \b CreateInstance function
00781 **  call within our ClassFactory.  That's the point of the ClassFactory - to provide
00782 **  a link between Windows and our program, and to manufacture, on demand, 
00783 **  objects to be sent back to Windows from within our program.
00784 **
00785 ** The thing to note here is that the ClassFactory is just a pre-intermediary 
00786 **  between Windows and our program.  The other thing to note here is that
00787 **  for every "PROGID" entry that we placed in the Windows System Registry,
00788 **  and corresponding CLSID, our application must build and Register within
00789 **  the Windows dynamic runtime system a ClassFactory object with the matching
00790 **  CLSID, using the \b CoRegisterClassObject function.
00791 **
00792 ** And, when I say "pre-intermediary", what I mean is there is another object
00793 **  which is the actual intermediary between Windows and our Application.  But,
00794 **  that's only because of our preferred implementation in Qt.  The object that
00795 **  the ClassFactory is manufacturing could actually be the object that our
00796 **  application has written, but, as you'll see, that's somewhat inefficient.
00797 **  If we have our ClassFactory return our application object, then that means
00798 **  that for every object in our application that we wish to expose to COM,
00799 **  we will have to make sure we write COM compatible objects, and that would
00800 **  really be a pain!  My preference would be to write my Qt applications the
00801 **  way I write my applications, without regard for COM or anything else, and
00802 **  then, with a few slight code changes, expose my entire application to COM
00803 **  and all its wonders.
00804 **
00805 ** If you look at the function above, there is a call to \b new another 
00806 **  object called \b DispatchObject.  This object is a COM compatible 
00807 **  object that is designed to support something called an \b IDispatch interface.
00808 **  And it is this IDispatch interface that really gives us a link between our
00809 **  application and vbScript.
00810 **  
00811 ** Before we go any further, let's compile all this code into our application
00812 **  and see what turns up.  One thing we can do is add \b qDebug() statements
00813 **  to our program to watch and see what the Windows COM subsystem is doing
00814 **  with us.  We are also going to have to hack a few of our routines so that
00815 **  they will run, since, they're not finished yet, and they really won't
00816 **  run properly until they are.
00817 **
00818 ** Let's start with the main.cpp file.  This is going to totally blow our
00819 **  main.cpp file, but what you're about to see is the present state of the
00820 **  main.cpp file as I have been writing this tutorial.  It's mostly complete
00821 **  from what I've been discussing so far, with a few extras.  Look it over
00822 **  carefully - it runs, I just tested it!  And I have frozen the code here:
00823 **  SimpleCOM-Freeze-1.zip
00824 **
00825 ** \par main.cpp ~ A Totally new main.cpp file
00826 ** \code
00827 ** #include "main.h"
00828 ** #include <QApplication>
00829 ** #include <QTextEdit>
00830 ** #include <QSettings>
00831 ** #include <QUuid>
00832 ** #include <ClassFactory.h>
00833 ** 
00834 ** //
00835 ** // This is a simple and generic sub-routine for getting a simple COM server
00836 ** //  registered in the registry.  This can be used on lots of different
00837 ** //  COM servers, it's reasonably generic.
00838 ** //
00839 ** void RegisterComServer
00840 ** (
00841 **   const QString & progid,      // the Name value we want to fetch by.  Like, "SimpleCOM.EXE"
00842 **   const QUuid & clsid,         // the CLSID value for our app
00843 **   const QString & description, // a useful description
00844 **   const QString & serverType,  // the type of server
00845 **   const QString & serverPath   // where to find the server
00846 ** )
00847 ** {
00848 **   //
00849 **   // Open the registry root
00850 **   //
00851 **   QSettings registry( "HKEY_CLASSES_ROOT", QSettings::NativeFormat );
00852 ** 
00853 **   //
00854 **   // Set the PROGID registry value for this entry, and set the description also
00855 **   //
00856 **   //
00857 **   registry.setValue( progid + "/Default",       description      );
00858 **   registry.setValue( progid + "/CLSID/Default", clsid.toString() );
00859 ** 
00860 **   //
00861 **   // Establish a path to the CLSID root.
00862 **   //
00863 **   QString clsroot = "CLSID/" + clsid.toString() + "/";
00864 ** 
00865 **   //
00866 **   // Set the Description, Server type, and path to the server plus the ProgID, which is a
00867 **   //  bit redundant but we're doing it anyway.
00868 **   //
00869 **   registry.setValue( clsroot + "Default",                description );
00870 **   registry.setValue( clsroot +  serverType + "/Default", serverPath  );
00871 **   registry.setValue( clsroot + "ProgID/Default",         progid      );
00872 ** 
00873 ** }
00874 ** 
00875 ** 
00876 ** void UnregisterComServer
00877 ** (
00878 **   const QString & progid // the Name value we want to fetch by.  Like, "SimpleCOM.EXE"
00879 ** )
00880 ** {
00881 **   QSettings registry( "HKEY_CLASSES_ROOT", QSettings::NativeFormat );
00882 ** 
00883 **   //
00884 **   // Get the clsid associated with this progid so we can delete it also.
00885 **   //
00886 **   QUuid clsid = registry.value( progid + "/CLSID/Default" ).toString();
00887 ** 
00888 **   registry.remove( "CLSID/" + clsid.toString() );
00889 **   registry.remove( progid );
00890 ** 
00891 ** }
00892 ** 
00893 ** //
00894 ** // Define these as static constant globals.  We refer to them in 
00895 ** //  multiple locations and its best to have them constantified
00896 ** //
00897 ** //
00898 ** #define SIMPLECOM_CLSID  "{420a352c-429b-4512-a926-3e2b77aa33fe}"
00899 ** #define SIMPLECOM_PROGID "SimpleCOM.EXE"
00900 ** 
00901 ** int main( int argc, char ** argv )
00902 ** {
00903 **   QApplication app(argc,argv);
00904 ** 
00905 **   if( app.arguments().contains("/register") )
00906 **   {
00907 **     RegisterComServer
00908 **     (
00909 **       SIMPLECOM_PROGID,                           // progid
00910 **       SIMPLECOM_CLSID,                            // clsid
00911 **       "This is a SimpleCOM server demonstration", // description
00912 **       "LocalServer",                              // serverType
00913 **       app.applicationFilePath()                   // serverPath
00914 **     );
00915 **     exit(0);
00916 **   }
00917 ** 
00918 **   if( app.arguments().contains("/unregister") )
00919 **   {
00920 **     UnregisterComServer( SIMPLECOM_PROGID );
00921 **     exit(0);
00922 **   }
00923 ** 
00924 **   ClassFactory factory( SIMPLECOM_CLSID );
00925 ** 
00926 **   QTextEdit message;
00927 **   message.append( "Hello World!" );
00928 **   message.show();
00929 ** 
00930 **   return( app.exec() );
00931 ** }
00932 ** \endcode
00933 **
00934 ** Notice that the main.cpp file is basically intact.  We have added some
00935 **  code for both registering the COM server and unregistering it as well.
00936 **  You should be able to read through those fairly easily and understand
00937 **  what's going on.
00938 **
00939 ** Then I have added reference to my new ClassFactory.  This is a hack.
00940 **  Ultimately I don't want this, but I'm just hacking this together a bit
00941 **  to get a feel for how I'm coming along.  I have also hacked the 
00942 **  ClassFactory constructor to allow it to accept a CLSID value - since
00943 **  that's what's going to get this thing going.
00944 **
00945 ** Let's take a look at the ClassFactory files.  Here's the header first:
00946 **
00947 ** \par ClassFactory.h ~ Intermediate Hack
00948 ** \code
00949 ** 
00950 ** #ifndef CLASSFACTORY_H_119fb1ec_35c1_43ee_957a_fe7132b3c24b
00951 ** #define CLASSFACTORY_H_119fb1ec_35c1_43ee_957a_fe7132b3c24b
00952 ** 
00953 ** #include <unknwn.h>
00954 ** 
00955 ** class QUuid;
00956 ** 
00957 ** class ClassFactory
00958 ** :
00959 **   public IClassFactory
00960 ** {
00961 **   public:
00962 ** 
00963 **   // IUnknown
00964 **   HRESULT __stdcall QueryInterface( const IID & iid, void ** ppv );
00965 **   ULONG __stdcall AddRef();
00966 **   ULONG __stdcall Release();
00967 ** 
00968 **   // IClassFactory
00969 **   HRESULT __stdcall CreateInstance( IUnknown * pUnkOuter, const IID & iid, void ** ppv );
00970 **   HRESULT __stdcall LockServer( BOOL lock );
00971 ** 
00972 **   // ctor/dtor
00973 **   ClassFactory( const QUuid & clsid );
00974 **   virtual ~ClassFactory();
00975 ** 
00976 **   // internals
00977 **   static LONG s_serverLocks;
00978 **   DWORD dwRegister;
00979 ** 
00980 ** };
00981 ** 
00982 ** #endif // #ifndef CLASSFACTORY_H_119fb1ec_35c1_43ee_957a_fe7132b3c24b
00983 ** \endcode
00984 **
00985 ** This hasn't been hacked much.  I've just added a parameter for the 
00986 **  constructor to provide for the CLSID as part of the registration
00987 **  process.
00988 **
00989 ** How about the ClassFactory.cpp file, that should be interesting:
00990 **
00991 ** \par ClassFactory.cpp ~ Intermediate Hack
00992 ** \code
00993 ** #include <objbase.h>
00994 ** #include <QApplication>
00995 ** #include <QUuid>
00996 **
00997 ** #include "ClassFactory.h"
00998 ** 
00999 ** //
01000 ** // This totally extremely simple class causes COM to be initialized
01001 ** //  when our application initializes.
01002 ** //
01003 ** //
01004 ** class UseCOM
01005 ** {
01006 **   public:
01007 **    UseCOM() { ::CoInitialize(NULL); }
01008 **   ~UseCOM() { ::CoUninitialize();   }
01009 ** } useCOM;
01010 ** 
01011 ** HRESULT __stdcall ClassFactory::QueryInterface( const IID & iid, void ** ppv )
01012 ** {
01013 **   //
01014 **   // This is probably totally unnecessary since the Windows COM subsystem
01015 **   //  called us, and it's totally extremely unlikely that Windows is
01016 **   //  going to call us and not give us a pointer.  But, check it anyway.
01017 **   //
01018 **   //
01019 **   if( !ppv ) return( E_FAIL );
01020 ** 
01021 **   //
01022 **   // Always wipe the callers reference pointer.  This way if we decide
01023 **   //  there's an error, then we can just return with that error code
01024 **   //  and not have to also worry about wiping his pointer.  Wiping pointers
01025 **   //  is a good thing.
01026 **   //
01027 **   *ppv = NULL;
01028 ** 
01029 **   //
01030 **   // Check the ID requested against known ID numbers for the ClassFactory
01031 **   //
01032 **   if( (::IsEqualIID( iid, IID_IUnknown      )) ||
01033 **       (::IsEqualIID( iid, IID_IClassFactory )) )
01034 **   {
01035 **     //
01036 **     // Set the callers pointer to us.  This may look a little redundant
01037 **     //  since we are already calling us from a pointer we got for us
01038 **     //  which is already pointing to us, and we're returning that same
01039 **     //  pointer, but, hey, this is COM - it's not suppose to make sense!
01040 **     //
01041 **     *ppv = (IClassFactory*) this;
01042 ** 
01043 **     qDebug( "ClassFactory::QueryInterface( %s )", qPrintable(QUuid(iid).toString()) );
01044 ** 
01045 **     //
01046 **     // Life is good.  Tell the world!
01047 **     //
01048 **     return( S_OK );
01049 **   }
01050 ** 
01051 **   //
01052 **   // If the ID requested is not one of the IClassFactory or IUnknown then
01053 **   //  we don't know what the caller is looking for.
01054 **   //
01055 **   return( E_NOINTERFACE );
01056 ** }
01057 ** 
01058 ** ULONG __stdcall ClassFactory::AddRef()
01059 ** {
01060 **   return( 1 );
01061 ** }
01062 ** 
01063 ** ULONG __stdcall ClassFactory::Release()
01064 ** {
01065 **   return( 1 );
01066 ** }
01067 ** 
01068 ** HRESULT __stdcall ClassFactory::LockServer( BOOL lock )
01069 ** {
01070 **    if( lock ) ::InterlockedIncrement( &s_serverLocks );
01071 **    else       ::InterlockedDecrement( &s_serverLocks );
01072 **    return NOERROR;
01073 ** }
01074 ** 
01075 ** HRESULT __stdcall ClassFactory::CreateInstance
01076 ** (
01077 **   IUnknown * pUnkOuter,
01078 **   const IID & iid,
01079 **   void ** ppv
01080 ** )
01081 ** {
01082 **   //
01083 **   // This is probably totally unnecessary since the Windows COM subsystem
01084 **   //  called us, and it's totally extremely unlikely that Windows is
01085 **   //  going to call us and not give us a pointer.  But, check it anyway.
01086 **   //
01087 **   //
01088 **   if( !ppv ) return( E_FAIL );
01089 ** 
01090 **   //
01091 **   // Assume an error by clearing the callers handle.  If things
01092 **   //  work out then ppv will get set to something meaningful.
01093 **   //
01094 **   //
01095 **   *ppv = NULL;
01096 ** 
01097 **   //
01098 **   // We are not supporting aggregation (yet) so return
01099 **   //  the appropriate error code.
01100 **   //
01101 **   //
01102 **   if( pUnkOuter )
01103 **     return( CLASS_E_NOAGGREGATION );
01104 ** 
01105 **   qDebug( "ClassFactory::CreateInstance( %s )", qPrintable(QUuid(iid).toString()) );
01106 ** 
01107 **   //
01108 **   // Create a new COM object
01109 **   //
01110 ** //  SimpleComObject * object = new SimpleComObject();
01111 ** 
01112 **   //
01113 **   // Query the COM object to see if it supports the
01114 **   //  requested interface.
01115 **   //
01116 ** //  HRESULT hr = object-> QueryInterface( iid, ppv );
01117 ** 
01118 **   HRESULT hr = E_FAIL;
01119 ** 
01120 **   //
01121 **   // If the query failed, then we can release the object.
01122 **   //
01123 ** //  if( FAILED(hr) )
01124 ** //    object-> Release();
01125 ** 
01126 **   //
01127 **   // We should have returned above with no error, so if we
01128 **   //  got down here then return thusly.
01129 **   //
01130 **   //
01131 **   return( hr );
01132 ** }
01133 ** 
01134 ** ClassFactory::ClassFactory( const QUuid & clsid )
01135 ** {
01136 **   HRESULT hr = ::CoRegisterClassObject
01137 **   (
01138 **     clsid,
01139 **     static_cast<IClassFactory*>(this),
01140 **     CLSCTX_LOCAL_SERVER,
01141 **     REGCLS_MULTIPLEUSE,
01142 **     &dwRegister
01143 **   );
01144 ** }
01145 ** 
01146 ** ClassFactory::~ClassFactory()
01147 ** {
01148 **   ::CoRevokeClassObject( dwRegister );
01149 ** }
01150 ** 
01151 ** LONG ClassFactory::s_serverLocks = 0;
01152 ** \endcode
01153 **
01154 ** Isn't that amazing?  It's actually readable!  This code works, folks.
01155 **  The remarkable thing is, it's actually simpler than I thought.  Let's
01156 **  start at the top.
01157 **
01158 ** First I \b \#include the \b <objbase.h> header file.  This is for COM, and
01159 **  some of the calls I'm making into the COM subsystem.  Simple!
01160 **
01161 ** Next is an interesting technique.
01162 **
01163 ** \par Getting COM initialized ~ easy schmeazy
01164 ** \code
01165 ** class UseCOM {
01166 **   public:
01167 **    UseCOM() { ::CoInitialize(NULL); }
01168 **   ~UseCOM() { ::CoUninitialize();   }
01169 ** } useCOM;
01170 ** \endcode
01171 **
01172 ** Before you can work with COM in your application, you have to initialize
01173 **  the COM subsystem in your application.  You also really need to 
01174 **  deinitialize it as well when your application shuts down.  Where to
01175 **  do this, is often the question.  Well, this simple local class has a
01176 **  simple constructor and a simple destructor, and the class itself is
01177 **  local to this module, and automatically instantiates to a module
01178 **  variable as well.  Guess what, when our application starts up, this
01179 **  class gets initialized, and guess what... the constructor gets called!
01180 **  Automatically!  How easy can that be?
01181 **
01182 ** As long as we make sure we call CoInitialize() somewhere in our application
01183 **  before we start messing with COM and call CoUninitialize before we shut down
01184 **  we're all set.  If we wanted to we could, instead of initializing this
01185 **  class in our module file like we are, we could have declared a static
01186 **  instance of it in our factory class.  Then, as soon as any factory object
01187 **  gets initialized, this class would get initialized first, once, as well
01188 **  then we'd be all set also.  Either way - suit yourself.  This works for
01189 **  me :)
01190 ** 
01191 ** The next function \b QueryInterface() is left unchanged.  It was 
01192 **  working before.  It still has the same job to do, and it's still doing
01193 **  a remarkable job of it so we've left it alone.  Though, we did add
01194 **  a qDebug statement to it so that we could see when and if it was called.
01195 **  You'll want to make sure and remove this later.
01196 **
01197 ** The functions \b AddRef(), \b Release(), and \b LockServer() are all
01198 **  untouched.  These functions are so rediculously simple that they're
01199 **  hardly worth looking at.
01200 **
01201 ** And, here we are... \b CreateInstance().  This is our baby.  This function
01202 **  is kind-of the meat of our ClassFactory.  It is the function that gets
01203 **  called by Windows when windows wants our application to create a new
01204 **  object instance.  I guess that sort-of makes sense, as the name implies.
01205 **
01206 ** What I've done here is remove some of the codes for the object creation
01207 **  routines.  I'm not ready to manufacture an object just yet since I 
01208 **  don't really
01209 **  know what that is.  But, I do want to see if this program is running at
01210 **  all.  So I've just turned off a few of those lines, and added a few debug
01211 **  statements.  It should be pretty obvious what I've done.  When I want
01212 **  to shut off a line I just put a couple of //'s in front of it.  I had to
01213 **  add a new HRESULT hr = E_FAIL; to keep everything else working though.
01214 **  Read through it, see what you think.
01215 **
01216 ** Here's the running program, with some screen captures:
01217 **
01218 ** \image html runscript-2.png
01219 **
01220 ** Check that, Jack!  Not only does the application actually run, but it also
01221 **  calls into our class factory.  How cool is that!  You can see from the
01222 **  debug statements that a bunch of QueryInterface calls are made on our
01223 **  ClassFactory.  If we were to place debug statements in our AddRef(), 
01224 **  Release() and LockServer() calls we might even see some activity there
01225 **  as well.  But, since this is only the ClassFactory let's stay on task
01226 **  We're almost there!
01227 **
01228 ** Since we hacked out any actual object creation we still are dieing with
01229 **  an error message.  No problem.  Step by step and we'll get there.
01230 **
01231 ** It's time now to create an actual COM object - one that will be returned
01232 **  to Windows and will provide for us a hook into our application program.
01233 **  The essence of this object is actually not too difficult.  It looks a 
01234 **  lot like our ClassFactory since both the ClassFactory and ComObject 
01235 **  both have to implement the IUnknown interface.  In fact, our COM object
01236 **  \b only has to implement the IUnknown interface, but that's not going
01237 **  to do it for us.  Not for vbScript anyhow.
01238 **
01239 ** It works like this.  vbScript doesn't know anything about C or C++.  It
01240 **  can't gain access to a C++ header file and read the definition of
01241 **  our object interface.  That is simply beyond its abilities.  So,
01242 **  the boys at Bill's place came up with an object interface called 
01243 **  IDispatch.  This interface is similar but different from the IClassFactory
01244 **  interface.  It is similar because both the IDispath and IClassFactory
01245 **  interfaces implement the IUnknown interface.  Yet it is different 
01246 **  because that's the only thing the two objects both implement.
01247 **
01248 ** The IDispatch interface implements a different set of functions designed
01249 **  especially for scripting languages like vbScript.  The additional functions
01250 **  allow scripting languages to "dynamically query" an object for a set
01251 **  of functions.  For instance, take the following vbScript program:
01252 **
01253 ** \par SimpleCOM.vbs ~ doing something fun
01254 ** \code
01255 ** dim simpleCOM: set simpleCOM = createObject("SimpleCOM.EXE")
01256 **
01257 ** simpleCOM.doSomethingFun "with this information"
01258 ** \endcode
01259 **
01260 ** What this program is trying to do, is get a handle on our COM server
01261 **  program \b "SimpleCOM.EXE", and then call a function inside of it
01262 **  by the name of \b doSomethingFun, and pass to it a parameter of
01263 **  \b "with this information".  Seems pretty simple, eh?  The question
01264 **  is, where is this function "doSomethingFun" and how is it that it
01265 **  can accept a parameter that looks like a string?
01266 **
01267 ** Enter IDispatch.  It is this IDispatch interface that provides for this
01268 **  capability of responding to vbScript requests for functionality.
01269 **  Let's see how to get that done.  Let's start by building a basic COM
01270 **  IDispatch type of object:
01271 **
01272 ** We need an object that implements the IDispatch interface for Windows.
01273 **  When the ClassFactory manufactures an object for us, it is going to
01274 **  manufacture an object that implements the IDispatch and hands this
01275 **  object back to windows.  Since it will be implementing the IDispatch
01276 **  Windows will know how to talk to it.  Here's an object frame:
01277 **
01278 ** \par DispatchObject ~ for IDispatch
01279 ** \code
01280 ** class DispatchObject : public IDispatch
01281 ** {
01282 **   public:
01283 ** 
01284 **  // IUnknown
01285 **  HRESULT __stdcall QueryInterface( const IID& iid, void ** ppv );
01286 **  ULONG __stdcall AddRef(void);
01287 **  ULONG __stdcall Release(void);
01288 **
01289 **  // IDispatch
01290 **  LONG __stdcall GetTypeInfoCount( UINT * o_count );
01291 **  LONG __stdcall GetTypeInfo( UINT, LCID, ITypeInfo** );
01292 **
01293 **  HRESULT __stdcall GetIDsOfNames
01294 **  (
01295 **    const IID & iid,
01296 **    BSTR * arrayNames,
01297 **    UINT countNames,
01298 **    LCID,
01299 **    DISPID * arrayDispIDs
01300 **  );
01301 **
01302 **  HRESULT __stdcall Invoke
01303 **  (
01304 **    DISPID dispidMember,
01305 **    const IID & iid,
01306 **    LCID lcid,
01307 **    WORD wFlags,
01308 **    DISPPARAMS * pDispParams,
01309 **    VARIANT * pvr,
01310 **    EXCEPINFO * pExcepInfo,
01311 **    UINT * pArgErr
01312 **  );
01313 **
01314 **  // ctor/dtor
01315 **   DispatchObject();
01316 **  ~DispatchObject();
01317 **
01318 **  // internals
01319 **  LONG m_ref;
01320 **  static LONG m_dispatchObjects;
01321 **
01322 ** };
01323 ** \endcode
01324 **
01325 ** Hey, this looks pretty simple!  In fact, with the exception of the different
01326 **  functions from the ClassFactory, it looks real simple.  The functions
01327 **  \b GetTypeInfoCount() and \b GetTypeInfo() refer to something called a
01328 **  \b TypeLibrary for COM objects.  We're probably not going to go into the
01329 **  details about type libraries here, but suffice it to say that Type Libraries
01330 **  are real handy for things like Intellisense code editors.  We can implement
01331 **  that but for the time being we'll probably skip over it until we have our
01332 **  object up and running.  The next two functions, \b GetIDsOfNames() and 
01333 **  \b Invoke() are where we will be spending most of our time.  Let's take a look
01334 **  at each function in detail and see what they're about.
01335 **
01336 ** \par DispatchObject::QueryInterface
01337 ** \code
01338 ** HRESULT __stdcall DispatchObject::QueryInterface( const IID & iid, void ** ppv )
01339 ** {
01340 **   //
01341 **   // This is probably totally unnecessary since the Windows COM subsystem
01342 **   //  called us, and it's totally extremely unlikely that Windows is
01343 **   //  going to call us and not give us a pointer.  But, check it anyway.
01344 **   //
01345 **   if( !ppv ) 
01346 **     return( E_FAIL );
01347 **
01348 **   //
01349 **   // Check the ID requested against known ID numbers for the Class 
01350 **   //  Factory.
01351 **   //
01352 **   if( ::IsEqualIID( iid, IID_IUnknown  ) ||
01353 **       ::IsEqualIID( iid, IID_IDispatch ) )
01354 **   {
01355 **     //
01356 **     // The ID he requested from is good.  So, we can give him a pointer
01357 **     //  to us (which is what he requested).  Go ahead and cast this pointer
01358 **     //  to the IDispatch type to be sure everything is laid out
01359 **     //  properly.  In other words, the .this. pointer might be ok, but if
01360 **     //  we cast .this. to a .IDispatch. then we're sure it's ok.
01361 **     //
01362 **     *ppv = (IDispatch*) this;
01363 **
01364 **     //
01365 **     // Increment the reference counter to us.
01366 **     //
01367 **     AddRef();
01368 **
01369 **     //
01370 **     // Let him know the result was successful.
01371 **     //
01372 **     return( S_OK );
01373 ** 
01374 **   } // endif( ..valid ID requested.. )
01375 **
01376 **   //
01377 **   // Something not working out as planned.
01378 **   //
01379 **   return( E_NOINTERFACE );
01380 ** 
01381 ** }
01382 ** \endcode
01383 **
01384 ** This function is nearly identical to our QueryInterface found in the ClassFactory
01385 **  object.  The only real difference is, this object, the DispatchObject object, 
01386 **  implements a different interface.  Like the ClassFactory object this object
01387 **  also implements the IUnknown interface.  All COM objects implement the IUnknown
01388 **  interface - it's the law!  But, the DispatchObject implements, also, the
01389 **  IDispatch interface.  The IDispatch interface has the functions necessary
01390 **  for vbScript to "ask" the object about the functions it implements.  That's
01391 **  what we want.
01392 **
01393 ** This function, QueryInterface, checks the requested interface.  Only two are
01394 **  allowed, the IUnknown and IDispatch.  If the requested interface is one of
01395 **  these two interfaces, then this function will return the pointer to this
01396 **  object.
01397 **
01398 ** Incidently, this is how the Windows COM subsystem determines what kind of 
01399 **  capabilities our objects support.  In other words, it "asks" them.  If
01400 **  an interface is supported, it is returned to Windows.  If it is not supported
01401 **  an error is returned.  Simple.
01402 **
01403 ** \par DispatchObject::AddRef
01404 ** \code
01405 ** ULONG __stdcall DispatchObject::AddRef()
01406 ** {
01407 **   ::InterlockedIncrement(&m_ref);
01408 **   return( m_ref );
01409 ** }
01410 ** \endcode
01411 **
01412 ** This function increments the DispatchObject reference count.  It uses a
01413 **  Windows system internal \b InterlockedIncrement() function.  Every time an
01414 **  interface pointer is requested, this value is incremented.  This way the
01415 **  DispatchObject itself can keep track of how many references are being made
01416 **  to it.
01417 **
01418 ** \par DispatchObject::Release
01419 ** \code
01420 ** ULONG __stdcall DispatchObject::Release()
01421 ** {
01422 **   ::InterlockedDecrement( &m_ref );
01423 ** 
01424 **   if( m_ref == 0 )
01425 **   {
01426 **     delete this;
01427 **     return 0;
01428 **   }
01429 ** 
01430 **   return( m_ref );
01431 ** }
01432 ** \endcode
01433 ** 
01434 ** This function releases a reference count.  The current reference count is
01435 **  decremented using a Windows system internal \b InterlockedDecrement() function.
01436 **  It is up to the consumer of this object to release its pointer when it is
01437 **  done with it.  If all the references to this object are released, then this
01438 **  object destroys itself.
01439 **
01440 **
01441 **
01442 ** \par DispatchObject::GetTypeInfoCount
01443 ** \code
01444 ** LONG __stdcall DispatchObject::GetTypeInfoCount( UINT * o_count )
01445 ** {
01446 **   if( !o_count ) return( E_FAIL );
01447 **   o_count = 0;
01448 **   return( S_OK );
01449 ** }
01450 ** \endcode
01451 **
01452 ** This function returns the Type Library Info Count.  We are not going to 
01453 **  implement this function at this time, so it is just going to return zero
01454 **  to the system.
01455 **
01456 **
01457 ** \par DispatchObject::GetTypeInfo
01458 ** \code
01459 ** LONG __stdcall DispatchObject::GetTypeInfo( UINT, LCID, ITypeInfo** )
01460 ** {
01461 **   return( S_FAIL );
01462 ** }
01463 ** \endcode
01464 **
01465 ** This function returns a pointer to a specific type library.  Since we're
01466 **  not implementing type libraries at this time we're going to ignore it also.
01467 **
01468 **
01469 ** \par DispatchObject::GetIDsOfNames
01470 ** \code
01471 ** HRESULT __stdcall DispatchObject::GetIDsOfNames
01472 ** (
01473 **    const IID & iid,
01474 **    BSTR * arrayNames,
01475 **    UINT countNames,
01476 **    LCID,
01477 **    DISPID * arrayDispIDs
01478 ** )
01479 ** {
01480 **   QStringList names;
01481 **   for( UINT i=0; i<countNames; i++ )
01482 **     names.append( QString().fromWCharArray(arrayNames[i]) );
01483 ** 
01484 **   qDebug( "DispatchObject::GetIDsOfNames(%d,%s)", countNames, qPrintable(names.join(",")) );
01485 ** 
01486 **   arrayDispIDs[0] = 5;
01487 ** 
01488 **   return( S_OK );
01489 ** }
01490 ** \endcode
01491 ** 
01492 ** This is the first function we are really interested in.  This is the function
01493 **  that first gets called from vbScript.  When a call like the following:
01494 **
01495 ** \code
01496 ** simpleCOM.doSomethingFun "with this information"
01497 ** \endcode
01498 **
01499 ** is made from vbScript, a call is ultimately made in to this routine.  What 
01500 **  vbScript is trying to do is obtain an ID number for the requested function 
01501 **  call.  In this case it is the \b doSomethingFun function call.  As it turns
01502 **  out, if you look at the parameters for this function, you'll notice that this
01503 **  function can return multiple ID numbers for multiple function calls.  vbScript
01504 **  doesn't make use of this feature, however.  It only, usually, requests one
01505 **  function at a time.
01506 **
01507 ** To demonstrate the use of this function I have placed a StringList parser
01508 **  that first pulls the strings from the argument list.  Then, just for giggles,
01509 **  it prints those function name strings to the debug terminal.
01510 **
01511 ** Now, you'll notice that I have also set the value as follows:
01512 **
01513 ** \code
01514 ** arrayDispIDs[0] = 5;
01515 ** \endcode
01516 **
01517 ** This is for demonstration purposes only.  Remember, we're taking this step by
01518 **  step.  What I'm trying to do here is verify how and when these functions are
01519 **  being called.  You'll see the point of this value later.
01520 **
01521 ** \par DispatchObject::Invoke
01522 ** \code
01523 ** HRESULT __stdcall DispatchObject::Invoke
01524 ** (
01525 **   DISPID dispidMember, 
01526 **   const IID & iid, 
01527 **   LCID lcid, 
01528 **   WORD wFlags, 
01529 **   DISPPARAMS * pDispParams, 
01530 **   VARIANT * pvr, 
01531 **   EXCEPINFO * pExcepInfo, 
01532 **   UINT * pArgErr 
01533 ** )
01534 ** {
01535 **   qDebug( "DispatchObject::Invoke(%ld)", dispidMember );
01536 **   return( S_OK );
01537 ** }
01538 ** \endcode
01539 ** 
01540 ** Finally!  This is our Invoke function.  Up to this point we've, well, Windows, has
01541 **  been doing little more than asking a bunch of questions of our object.  If
01542 **  you've fiddled with the code at this point and sprinkled it with a few
01543 **  qDebug statements to see what's going on, especially in the QueryInterface 
01544 **  functions, you'll see that Windows calls in to these objects over and over.
01545 **  You've got to wonder what Windows has on it's mind.
01546 **
01547 ** Well, the final objective is to arrive, somehow, at this function call.
01548 **  Invoke, in our example, basically means to "Invoke the function 'doSomethingFun'"
01549 **  on our object.  We thought we'd never get here!
01550 **
01551 ** Invoke has a handful of parameters, but the one primary parameter at this point
01552 **  is the dispidMember parameter.  Remember the arraDispIDs[0]=5; value I set 
01553 **  earlier in the GetIDsOfNames function?  Well, that same value should be passed
01554 **  to this function.
01555 **
01556 ** What is the purpose of the dispidMember value?  It is an index number of the 
01557 **  function that was originally requested, in this case 'doSomethingFun'.  Back
01558 **  to the previous function \b GetIDsOfNames(), the purpose of that function is
01559 **  to locate the index number of the request function.  In other words, it is to
01560 **  map the string-value of the function name to an index number of that same 
01561 **  function.  How this actually ends up happening is entirely up to you.  I do
01562 **  have a rather interesting solution for the task that's based on the Qt 
01563 **  system, but I'm not going to implement that here just yet.  I'd like to start
01564 **  by just getting this darned thing up and running.
01565 **
01566 ** But, back to our Invoke function.  Once we have the index number of the function
01567 **  we want to call, the Invoke function receives all the parameters in the 
01568 **  function call (namely the "with this information" parameters) and others,
01569 **  breaks them all up, and passes them along to our program... somehow.  Actually,
01570 **  There's no somehow about it.  I have this working already in another system,
01571 **  and it's all based upon Qt and the metaObject system.  It's really quite
01572 **  snappy, and it results in being able to expose any Qt object to programs like
01573 **  vbScript with almost no effort.
01574 **
01575 ** I'm going to entirely save that effort for a different discussion, since my
01576 **  main objective here was to get my application to act like a COM server, and
01577 **  that task is complete.  It's not real useful yet, but that's up to you
01578 **  (wink, wink).
01579 **
01580 ** The code for the current project is here: SimpleCOM-Freeze-2.zip
01581 **
01582 ** You should be able to compile and run this program and run the vbScript sample
01583 **  program and get some nice debug output with no errors.  Here's the vbScript
01584 **  program as it stands now with a screenshot of the output.
01585 **
01586 ** \par vbScript Test Program
01587 ** \code
01588 ** dim simpleCOM: set simpleCOM = createObject("SimpleCOM.EXE")
01589 ** simpleCOM.doSomethingFun "with this information"
01590 ** dim xxx: set xxx = createObject("SimpleCOM.EXE")
01591 ** set simpleCOM = nothing
01592 ** msgbox "done"
01593 ** \endcode
01594 **
01595 ** \image html runscript-3.png
01596 **
01597 **
01598 ** \par References \n
01599 **  http://www.codeproject.com/KB/COM/com_in_c1.aspx COM in Plain C by Jeff Glatt \n
01600 **  http://www.codeproject.com/KB/COM/comintro.aspx What is COM and how to use it \n
01601 */
01602 
01603 
01604 
01605 #endif




~ ~ ~ ~ ~ ~
Don't create Texas sized problems...
Comment your Code!
~ ~ ~ ~ ~ ~
Author: Mark Petryk
Lorimark Solutions, LLC