Hi Chris,
I used my own version of COM rather than the Microsoft version because of
lack of understanding and because I foresaw issues with timing (never proved
or disproved).
The skeleton of my simplified version is attached together with a skeleton
app method. There are things that could be improved, but I was following a
Microsoft code example (from VS5) and bear in mind that the interface was
supposed be compatible with both C and C++. I used the same names as the
Microsoft version, except for a prefix. To use the interface it is not
necessary to add the "Example.lib" to your build system if you use the
LoadLibrary call, and all you need to publish is the .h file and the DLL.
The Microsoft version may be prettier, but I have source code to my version!
Microsoft have several macros to dress up their COM interface, but I just
elected not to implement my cutdown version entirely their way.
It took me several days to realise that COM is really simple, so I hope my
example helps you trim a few corners off your learning experience.
Regards
PS. I have not compiled the example and have no interest in maintaining it.
-----Original Message-----
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] Behalf Of Chris Hanson
Sent: 10 October 2006 18:45
To: osg users
Subject: Re: [osg-users] Semi-OT: Plugin architectures
Philip Taylor wrote:
> "COM/ActiveX is out for many reasons."
> Why? My undertanding is that the basis of COM is a C structure, I would
have
> thought it met your design requirement. I have implemented a couple of
> components where the structure was more a C++ rather C style structure.
I am somewhat familiar with COM, having tried to come to grips with it
before. COM
seems unsuitable for several reasons:
Totally Windows dependent. I've seen Mozilla's XPCOM, but it seems really
complicated
to understand and build and use outside Mozilla.
Really requires people to be into the "COM mindset". It's not just like
writing some
simple code -- only the code can be dynamically added to an application. You
really have
to grasp COM's whole philosophy to get going with it.
My understanding of COM is that it requires objects to register
themselves with the
Windows registry before being accessible, and I think this is an
abomination. I understand
their reasons for it, but there are reasons I don't want my app polluting
the user's
system in that fashion. I also need something that can basically run right
out of the box
as an EXE without needing installation/uninstallation.
I'm also not trying to implement RPC and inter-endian mixing, so COM's
marshalling and
such are overkill.
I'm thinking I may just do something myself, since I haven't found an
existing solution
the meets enough of my criteria. I'll probably adopt some of the low-level
principles COM
uses to make itself language-independent and such.
> The advantage of COM is runtime linking - no need to distribute lib
files -
> just an include file to describe the interfaces returned by the factory
> method and the actual DLL.
I'm looking at doing something similar, with late-binding using method
name strings as
opposed to IDL files and GUIDs and such.
> Alternatively look at how OSG handles its plugins.
As I mentioned above, OSG's plugin design is suitable for OSG, but pretty
much lacks
many of the important criteria I'm looking for. Think of how 3dsMax breaks
plugin
compatibility everytime they release a new version, versus Photoshop which
can run plugins
written in the 3.0 era.
--
Chris 'Xenon' Hanson aka Eric Hammil | http://www.3DNature.com/ eric at
logrus
"I set the wheels in motion, turn up all the machines, activate the
programs,
and run behind the scenes. I set the clouds in motion, turn up light and
sound,
activate the window, and watch the world go 'round." -Prime Mover, Rush.
_______________________________________________
osg-users mailing list
[email protected]
http://openscenegraph.net/mailman/listinfo/osg-users
http://www.openscenegraph.org/
//*****************************************************************************
// FILE HEADER
// ~~~~ ~~~~~~
// File Name : com_example.cpp
//
// Project ID : ---/---
//
// Originated : Oct 2006 Philip Taylor
//
// Description : Implementation of an example COM style interface.
//
//******************************************************************************
#include "stdafx.h"
#include "com_example.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// **************************************************************************
// CLASS HEADER
// ~~~~~ ~~~~~~
// Name : CExampleFactory
//
// Description : A derived DLL interface to the component factory.
//
// **************************************************************************
class CExampleFactory : public CExampleFactory_API
{
public :
unsigned int m_dwRef;
public :
void QueryInterface ( int, void** ppvObj );
unsigned int AddRef () { return ++m_dwRef; } // Register another
copy of the instance
unsigned int Release (); // Delete this copy of
the instance.
};
// **************************************************************************
// CLASS HEADER
// ~~~~~ ~~~~~~
// Name : CExampleComponent0
//
// Description : A derived DLL interface to the component.
//
// **************************************************************************
class CExampleComponent0 : public CExampleComponent_API
{
public :
unsigned int m_dwRef;
public :
CExampleComponent0();
~CExampleComponent0();
unsigned int AddRef () { return ++m_dwRef; } // Register another
copy of the instance
unsigned int Release (); // Delete this copy of
the instance.
void set_Flags ( int Flags );
int get_Flags ();
private :
int m_Flags;
};
// **************************************************************************
//
// **************************************************************************
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
// **************************************************************************
// FUNCTION HEADER
// ~~~~~~~~ ~~~~~~
// Name : CExample_GetClassObject
//
// Description : Construct an instance of the CExampleFactory object.
//
// Parameters : An interface ID and a pointer to the pointer that will
// will be populated with the interface address.
//
// Return value : Void
//
// **************************************************************************
void CExample_GetClassObject( int /* version */, void** ppvObj )
{
*ppvObj = new CExampleFactory;
( ( CExampleFactory*) *ppvObj )->AddRef();
}
// **************************************************************************
// FUNCTION HEADER
// ~~~~~~~~ ~~~~~~
// Name : QueryInterface
//
// Description : Construct an Example Component object.
//
// Parameters : An interface ID and a pointer to the pointer that will
// will be populated with the interface address.
//
// Return value : Void
//
// **************************************************************************
void CExampleFactory::QueryInterface( int Version, void** ppvObj )
{
*ppvObj = 0;
if ( 0 == Version )
*ppvObj = new CExampleComponent0;
if ( 0 != *ppvObj )
( ( CExampleComponent0*) *ppvObj )->AddRef();
}
unsigned int CExampleFactory::Release()
{
if ( --m_dwRef != 0 )
return m_dwRef;
delete this;
return 0;
}
// **************************************************************************
// FUNCTION HEADER
// ~~~~~~~~ ~~~~~~
// Name : CExampleVersion0
//
// Description : Construct version 0 example interface.
//
// Parameters : None
//
// **************************************************************************
CExampleComponent0::CExampleComponent0()
{
m_dwRef = 0;
}
CExampleComponent0::~CExampleComponent0()
{
}
unsigned int CExampleComponent0::Release()
{
if ( --m_dwRef != 0 )
return m_dwRef;
delete this;
return 0;
}
void CExampleComponent0::set_Flags( int Flags )
{
m_Flags = Flags;
}
int CExampleComponent0::get_Flags()
{
return m_Flags;
}
//*****************************************************************************
// FILE HEADER
// ~~~~ ~~~~~~
// File Name : com_example.h
//
// Project ID : ---/---
//
// Originated : Oct 2006 Philip Taylor
//
// Description : Declaration of an example COM style DLL interface.
//
// To avoid Microsoft/Borland compatibility issues, the key word bool
// is not used in this interface. (Microsoft represents bool as a 32 bit
// integer whilst Borland use an 8 bit value. This interface replaces
// bool with int.
//
// It is important to note that this interface is a structure and not
// a class. This is deliberate as this file can be compiled in both
// Microsoft and Borland C++ environments without causing size errors.
// In addition, by not using constructors and destructors, there are
// no memory management issues to be resolved. This interface can
// therefore be considered as a candidate for runtime linking, rather
// than compile time linking.
//
//******************************************************************************
#ifndef COM_EXAMPLE_H_20061010_2207
#define COM_EXAMPLE_H_20061010_2207
#include <stdexcept> // Defines wstring
#ifdef COMEXAMPLE_EXPORTS
#define COMEXAMPLE_API __declspec(dllexport)
#else
#define COMEXAMPLE_API __declspec(dllimport)
#endif
// **************************************************************************
// The one and only exported interface. A true COM interface would export
// three C style interfaces - GetClassObject, Register and Deregister. This
// however is a first step and the following is sufficient for now to
// establish the principle.
// **************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif
COMEXAMPLE_API void CExample_GetClassObject( int version, void** ppvObj );
#ifdef __cplusplus
};
#endif
// **************************************************************************
// CLASS HEADER
// ~~~~~ ~~~~~~
// Name : CExampleFactory_API
//
// Description : A DLL interface to the component.
//
// NOTE: By design, this is a structure and not a class. This is because
// it tries to emulate a COM object and only the COM object knows
// how to create and destroy itself. If the definition was a class
// the compiler would need the DLL to be present at link time so
// that it could call constructor and destructor methods (even if
// the invisible default methods were used).
//
// **************************************************************************
// WARNING: Changing this structure without recompiling all users of this
// structure will result in unstable (or unsable) systems.
// **************************************************************************
struct CExampleFactory_API
{
public :
// **********************************************************************
// The COM style interface
// **********************************************************************
virtual void QueryInterface ( int Version, void** ppvObj ) = 0;
// Create an instance of CExample
// **********************************************************************
// The COM style interface - normally the IUnknown base structure
// **********************************************************************
virtual unsigned int AddRef () = 0; // Register another copy of
the instance
virtual unsigned int Release () = 0; // Delete this copy of the
instance.
};
// **************************************************************************
// CLASS HEADER
// ~~~~~ ~~~~~~
// Name : CExampleComponent_API
//
// Description : A DLL interface to the component.
//
// NOTE: By design, this is a structure and not a class. This is because
// it tries to emulate a COM object and only the COM object knows
// how to create and destroy itself. If the definition was a class
// the compiler would need the DLL to be present at link time so
// that it could call constructor and destructor methods (even if
// the invisible default methods were used).
//
// **************************************************************************
// WARNING: Changing this structure without recompiling all users of this
// structure will result in unstable (or unsable) systems.
// **************************************************************************
struct CExampleComponent_API
{
public :
// **********************************************************************
// The COM style interface - normally the IUnknown base structure
// **********************************************************************
virtual unsigned int AddRef () = 0; // Register another copy of
the instance
virtual unsigned int Release () = 0; // Delete this copy of the
instance.
// **********************************************************************
// Public property methods provided by the component
// **********************************************************************
virtual void set_Flags ( int Flags ) = 0;
virtual int get_Flags ( void ) = 0;
};
#endif COM_EXAMPLE_H_20061010_2207
#include "com_example.h"
typedef void (CALLBACK* LPGETCLASSOBJECT)( int version, void** ppvObj );
void ExerciseTheExampleDLL()
{
HINSTANCE hDLL = LoadLibrary( "Example.DLL" );
if (hDLL != NULL)
{
// get the singleton class object interface
// ---------------------------------------------
LPGETCLASSOBJECT pClassObject = (LPGETCLASSOBJECT)GetProcAddress( hDLL,
"CExample_GetClassObject" );
if ( 0 == pClassObject )
{
// handle the error
FreeLibrary(hDLL);
return;
}
// construct an instance of the class object factory
// -------------------------------------------------
CExampleFactory* pFactory;
pClassObject( 0, &pFactory );
if ( 0 != pFactory )
{
// construct an instance of the version 0 component
// -------------------------------------------------
CExampleComponent0* pComponent;
pFactory->QueryInterface( 0, &pComponent );
if ( 0 != pComponent )
{
// use the component
// ---------------------------------------------
pComponent->set_Flags( 0 );
int Flags = pComponent->get_Flags();
// Finished with the component
// ---------------------------------------------
if ( 0 == pComponent->Release() )
pComponent = 0;
}
// Finished with the factory.
// -------------------------------------------------
if ( 0 == pFactory->Release() )
pfactory = 0;
}
}
}
_______________________________________________
osg-users mailing list
[email protected]
http://openscenegraph.net/mailman/listinfo/osg-users
http://www.openscenegraph.org/