delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/09/08/22:49:00

From: Matthew Mastracci <mmastrac AT acs DOT ucalgary DOT ca>
Newsgroups: comp.os.msdos.djgpp
Subject: Source to COM implementation in DJGPP
Date: Mon, 8 Sep 1997 20:01:45 -0600
Organization: The University of Calgary
Lines: 250
Message-ID: <5v2anv$f7g@ds2.acs.ucalgary.ca>
NNTP-Posting-Host: mmastrac AT acs2 DOT acs DOT ucalgary DOT ca
Mime-Version: 1.0
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

    I've been working on a COM port for DJGPP for the last little while
and I've managed to implement the more important stuff from MSVC's
implementation here.  For those who don't know, COM is a way to
polymorphically handle object by way of interfaces.  It takes advantage of
the vfptr table which is a C++ standard.  I don't know how fast DJGPP's
vfptr table is compared to MSVC's.  I know that MSVC will literally
compile the vfptr table into a series of jmp's.  DJGPP seems to use
lookups.  If anyone knows anything about speed effects of this, please let
me know.

     I'd like to know if anyone is interested in this.  If not, it'll
probably be a big waste of time for me ;).  It would be great for things
like graphics/sound packages, because you could just define some
interfaces such as:

interface ISoundDevice : virtual public IUnknown
{
  void Initialize();
  void PlaySound(void * Buffer, int Size, int Channel);
  void StopSound(int Channel);
  String& GetName();
} 

or

interface IGraphicsDevice : virtual public IUnknown
{
  void StartGraphics(int Width, int Height, int Color);
  void PutPixel(int x, int y, int Color);
  void EndGraphics();
  String& GetName();
}

... etc ...  

Eventually, you can just drop those into .DXE files and use them as
"plug-and-play" drivers.  With functions like "GetName()", you can even
get the driver names from files you've never seen. 

Now, the stuff I've mananaged to implement is:

 - IID structures/comparison
 - QueryInterface/helper macros
 - A working demo

I don't, however, have this stuff done (it's in the works):

 - AddRef/Release
 - Various other things required
 - Support for .DXE's like .DLL's

Stuff that's different from MSVC COM (if you've used it):

 - Interfaces must derive from IUnknown as virtual public, instead of
public.  Therefore:

interface IX : IUnknown

becomes

interface IX : virtual public IUnknown

     This is to solve the ambiguous base class problem that I have when
trying to get IUnknown from any object supporting two interfaces.  

For those who are interested, here's the source to the demo/COM "library". 
If anyone has any suggestions/comments/etc, please feel free to send them
my way.  None of the COM stuff has been moved to a .h file, but this
compiles from the command-line:

gcc -o com.exe com.cpp -Wall

     You'll see some odd warnings, but they don't affect the compiled
.EXE:

--- begin snip ---
#include <iostream.h>
 
#define interface struct
#define PURE = 0
 
#define UINT32  unsigned long
#define UINT16  unsigned short
#define UINT8   unsigned char
#define HRESULT long
 
#define SUCCEEDED(hr)   (hr >= 0)
#define FAILED(hr)      (hr < 0)
 
#define S_OK            0x0000000
#define S_ERROR         0xFFFFFFF
 
#define E_NO_INTERFACE  0x8000000
 
#define COM_QUERYINTERFACE_ENTRY(x, y) \
  if (iid == x) \
    *ppv = ((y *)(this));
 
struct IID
{
  UINT32 Data1;
  UINT16 Data2;
  UINT16 Data3;
  UINT8  Data4[8];
};
 
IID IID_IUnknown = { 0x00000000, 0x0000, 0x0000, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
IID IID_IX = { 0x00000001, 0x0000, 0x0000, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
IID IID_IY = { 0x00000002, 0x0000, 0x0000, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
bool operator ==(IID& iid1, IID& iid2)
{
   return (iid1.Data1 == iid2.Data1 && iid1.Data2 == iid2.Data2 
     && iid1.Data3 == iid2.Data3 && iid1.Data4 == iid2.Data4);
}
 
interface IUnknown
{
  virtual HRESULT QueryInterface(IID& iid, void ** ppv) = 0;
  virtual long AddRef() = 0;
  virtual long Release() = 0;
};
 
interface IX : virtual IUnknown
{
  virtual void fx1() = 0;
  virtual void fx2() = 0;
};
 
interface IY : virtual IUnknown
{
  virtual void fyA() = 0;
  virtual void fyB() = 0;
};
 
class CA : public IX, public IY
{
public:
  virtual HRESULT QueryInterface(IID& iid, void ** ppv);
  virtual long AddRef() { }
  virtual long Release() { }
 
  virtual void fx1()
  { cout << "CA's fx1()" << endl; }
  virtual void fx2()
  { cout << "CA's fx2()" << endl; }
  virtual void fyA()
  { cout << "CA's fyA()" << endl; }
  virtual void fyB()
  { cout << "CA's fyB()" << endl; }
};
 
class CB : public IX, public IY
{
public:
  virtual HRESULT QueryInterface(IID& iid, void ** ppv);
  virtual long AddRef() { }
  virtual long Release() { }
  
  virtual void fx1()
  { cout << "CB's fx1()" << endl; }
  virtual void fx2()
  { cout << "CB's fx2()" << endl; }
  virtual void fyA()
  { cout << "CB's fyA()" << endl; }
  virtual void fyB()
  { cout << "CB's fyB()" << endl; }
};
 
HRESULT CA::QueryInterface(IID& iid, void ** ppv)
{
  *ppv = NULL;
  COM_QUERYINTERFACE_ENTRY(IID_IUnknown, IUnknown);
  COM_QUERYINTERFACE_ENTRY(IID_IX, IX);
  COM_QUERYINTERFACE_ENTRY(IID_IY, IY);
                 
  return (*ppv != NULL ? S_OK : E_NO_INTERFACE);
}
 
HRESULT CB::QueryInterface(IID& iid, void ** ppv)
{
  *ppv = NULL;
  COM_QUERYINTERFACE_ENTRY(IID_IUnknown, IUnknown);
  COM_QUERYINTERFACE_ENTRY(IID_IX, IX);
  COM_QUERYINTERFACE_ENTRY(IID_IY, IY);
                 
  return (*ppv != NULL ? S_OK : E_NO_INTERFACE);
}
 
int main(void)
{
  CA * pA = new CA;
  CB * pB = new CB;
 
  IX * pX;
  IY * pY;
  
  IUnknown * pUnknown;
  pA->QueryInterface(IID_IUnknown, (void**)&pUnknown);
  
  if (SUCCEEDED(pUnknown->QueryInterface(IID_IX, (void**)&pX)))
  {
    pX->fx1();
    if (SUCCEEDED(pX->QueryInterface(IID_IY, (void**)&pY)))
    {
      pY->fyA();
      IUnknown * pYUnknown;
      if (SUCCEEDED(pY->QueryInterface(IID_IUnknown, (void**)&pYUnknown)))
      {
        if (pYUnknown == pUnknown)
        {
          cout << "IUnknown was properly returned from IY." << endl;
        }
        else
        {
          cout << "IUnknown from IY is different from IUnknown from
class!" << endl;
        }
      }
      else
      {
        cout << "Couldn't get IUnknown from IY!" << endl;
      }
    }
    else
    {
      cout << "Couldn't get IY from IX!" << endl;
    }
  }
  else
  {
    cout << "Couldn't get IX from IUnknown" << endl;
  }
 
  delete pB;
  delete pA;
 
  return 0;
}
--- end snip ---

/\/\att /\/\astracci                  mmastrac AT acs DOT ucalgary DOT ca

GCS/GE    d- s+:+ a--- C++++ UA P+ L E-- W+ N++ o K+ w+ O M- V 
          PS++ PE++ Y+ PGP t+++ 5+++ X++ R++ tv+ b+++ DI++++ I 
          G++ e h r* z?

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019