Mail Archives: djgpp/1997/09/08/22:49:00
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 -