15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Exporting classes...

Jean FEVRE -- jeanf@afp.com
Tuesday, February 06, 1996

We wrote some classes that we use very often and put them in 
some DLL.
What is the best way to export class members with allways the 
same ID. I try two DEF manager : dllxport32 and defmgr32.

What is the best solution from msvc 4.0.

What is used by Microsoft for the generation of MFC40.DLL???

regards

Jean



Brian V. Zaino 516 233-6862 -- brian.zaino@reuters.com
Thursday, February 08, 1996

[Mini-digest: 3 responses]

>>We wrote some classes that we use very often and put them in=20
>>some DLL.
>>What is the best way to export class members with allways the=20
>>same ID. I try two DEF manager : dllxport32 and defmgr32.
>>
>>What is the best solution from msvc 4.0.
>>
>>What is used by Microsoft for the generation of MFC40.DLL???
>>
>>regards
>>
>>Jean
Jean,

Below, I have included one suggestion for exposing a=20
C++ class from a dll.

Brian V. Zaino
Internet:  brian.zaino@reuters.com
A method for exposing a C++ class from a dll.

This method consists of:
1.  A class factory which can instantiate the objects.
2.  An Interface definition which is given to the user of the dll.
3.  A proxy class which implements the Interface and is instantiated
by the class factory.
4.  A real class which does the actual work.  The appropriate members
are called via the proxy class.  The user of the dll never sees this
real class.

Some Problems:
1.  Additional Indirection.
2.  Additional work for the class writer.  Instead of just having to
implement the real class, the proxy class needs to be implemented as
well.

Some Benefits:
1.  You can add functionality to the real class without affecting the
interface.  For example, you can add a new member function X to the
real class without changing the proxy or interface classes.  In this
case, you would probably keep the original interface and proxy for
backwards compatibility and then add a new interface that has full
functionality.
2.  You can support more than one interface at the same time.  There
is no reason why the real class can be acted upon by several
interfaces and proxy classes.


Sample code follows:

1. Here are some defines for the exported classes and functions.=20
BUILD_DLL is defined by the DLL=92s environment and NOT by the user o=
f
the DLL.  This #define should be different for each dll.  The purpose
of these #defines is to allow sharing of headers between the DLL and
the users of the DLL.

#ifdef BUILD_DLL
   #define MYDllExport __declspec(dllexport)
#else
   #define MYDllExport
#endif

2. Define a pure virtual interface class without constructor and
destructor.  This is the interface you want the user of the DLL to
see.  In fact, this definition should be placed into a *.h file that
will be given to the user of the DLL.  Note that this class has no
implementation.  It is just an interface.

class MYDllExport IInterface
{
public:
   virtual BOOL SomeFunctionA(int nA)=3D0;
   virtual BOOL SomeFunctionB(Cstring csB)=3D0;
   virtual BOOL SomeFunctionY(int nA, int nY)=3D0;
};

3. Define and implement the real/worker class.  This class can
anything you need it to be.  It is possible to have one class with
several interfaces.

class CRealClass
{
// Friend classes are any classes that proxy for us.
friend class CInterfaceProxy;

private:
   // private constructor/destructor so that only the friend classes
can
   // create an instance of this class.
   CRealClass();
   ~CRealClass();

public:
   virtual BOOL RealFunctionA(int nA);
   virtual BOOL RealFunctionB(Cstring csB);
   virtual BOOL RealFunctionNewY(int nA, int nY);
};


CRealClass::CRealClass()
{
}

CRealClass::~CRealClass()
{
}

BOOL CRealClass::RealFunctionA(int nA)
{
   // Perform work here.
   return(TRUE);
}

BOOL CRealClass::RealFunctionB(Cstring csB)
{
   // Perform work here.
   return(TRUE);
}

BOOL CRealClass::RealFunctionNewY(int nA, int nY)
{
   // Perform work here.
   return(TRUE);
}

4.  Define and Implement the Interface Proxy Class.  This class is th=
e
implementation of the exported interface (Iinterface) class.

class CInterfaceProxy : public IInterface
{
// Friend classes are my class factory.
friend IInterface* CreateInterface();

private:
   // constructor/destructor are private so only the class factory ca=
n
   // instantiate one.
   CInterfaceProxy();
   ~CInterfaceProxy();

public:
   virtual BOOL SomeFunctionA(int nA);
   virtual BOOL SomeFunctionB(Cstring csB);
   virtual BOOL SomeFunctionY(int nA, int nY);

private:
   // Class has pointer to the real class.
   CRealClass * m_pRealClass;
};

CInterfaceProxy:: CInterfaceProxy()
{
   m_pRealClass =3D new CRealClass;
}

CCommPortProxy::~CCommPortProxy()
{
   delete m_pRealClass;
}

BOOL CInterfaceProxy::SomeFunctionA(int nA)
{
   return(m_pRealClass->RealFunctionA(nA));
}

BOOL CInterfaceProxy::SomeFunctionB(Cstring csB)
{
   return(m_pRealClass->RealFunctionB(csB));
}

BOOL CInterfaceProxy::SomeFunctionY(int nA, int nY)
{
   return(m_pRealClass->RealFunctionNewY(nA, nY));
}

5. Define and implement the "ClassFactory" that is used to obtain a
copy of the Interface.  This is very similar to the OLE mechanism of
Query Interface.  This is the only interface that is really exported
=66rom the DLL.

MYDllExport IInterface* CreateInterface();

MYDllExport IInterface* CreateInterface()
{
   CInterfaceProxy* pInterface;
   pInterface =3D new CInterfaceProxy();
   // Error and Exception handling code should be entered here.

   // If everything is OK, return the Pointer to the Proxy Class.
   return(pInterfaceProxy);
}


-----From: "Paul Fonte - Ext. 4633" 

dllxpt32 should maintain the ordinal values for you if you use the /r (for 
reference file) option and specifiy the output filename (it will overwrite 
the file, maintaining ordinal placement)

-----From: "Mike Blaszczak" 

From: 	owner-mfc-l@netcom.com on behalf of Jean FEVRE

> We wrote some classes that we use very often and put them in 
> some DLL. What is the best way to export class members with allways the 
> same ID. I try two DEF manager : dllxport32 and defmgr32.

I don't know what you mean by "DEF manager".

> What is the best solution from msvc 4.0.

Generally, it is using the AFX_CLASS_EXP macro and all of its friends.

 > What is used by Microsoft for the generation of MFC40.DLL???

An amazingly impressive batch file which takes the MAP file generated by the 
linker, chews it up, formats it, sorts it, and then links again with that DEF 
file. It works using Unix tools like grep and a couple of dodads that just 
read files, add numbers, and spit 'em out again.  It's fun to watch, but it is 
certainly nothing I would like to ship.

.B ekiM
TCHAR szMSDisc[] = _T("I don't speak for Microsoft");



Mukesh Prasad Development Contractor -- mukesh@everest.XAIT.Xerox.COM
Monday, February 12, 1996

>We wrote some classes that we use very often and put them in=20
>some DLL.
>What is the best way to export class members with allways the=20
>same ID. I try two DEF manager : dllxport32 and defmgr32.
>
>What is the best solution from msvc 4.0.
>

I think you are asking how to keep "ordinal numbers"s
the same from release to release.  If so, here is one
scheme we have used:

1)  Make the DLL.
2)  Run "dumpbin /exports" on the DLL (or "exehdr"),
    redirecting the output to a text file.
3)  Write a small program to _parse_ the text file
    from (2), separate out the mangled names,
    and write them out to a third file.  The output
    is your ".def" file, so assign ordinal numbers.
4)  From now on, always use this ".def" file in making
    the DLL.

Step 3 is much easier if you have access to a
Unix system with its text processing tools.

This is the general idea, though you will still
have to handle changes.  Some ordinals will get
deleted and some added.  It is a good idea never
to re-use ordinals, but just keep adding new ones
at the end.





| Вернуться в корень Архива |