CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3

Thread: dll

  1. #1
    Join Date
    Jul 2001
    Posts
    430

    dll

    Please tell me how to create c++ dll and how to use it after creation. Please give me a simple example so that I can compile it and run it. In this way, I can understand it easily. thanks


  2. #2
    Join Date
    Oct 2000
    Location
    London, England
    Posts
    4,773

    Re: dll

    when I created a test DLL (Win32 DLL, no MFC) I got these compiler options. This is with no precompiled headers.

    /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TESTDLL_EXPORTS" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
    for debug and these

    /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TESTDLL_EXPORTS" /Fo"Release/" /Fd"Release/" /FD /c

    for release. If you are doing it in an C++ application that has a wizard (allows you to create a new project, determining at the same time the type of project you want).

    ---------------------------------------------
    Laying out your DLL

    The main feature I am going to discuss is the header file.
    This is a single header file that users of the DLL include,
    and it should expose the interface (and preferably nothing but
    the interface. As long as you don't allow the user to see any
    of the implementation, you can change it later without breaking
    their programs).

    You can give your DLL a C-interface, even if it is written in C++.
    If you do that, you must put this in front of the functions

    #ifdef __cplusplus
    extern "C" {
    #endif

    // all your interface

    #ifdef __cplusplus
    }
    #endif




    This is not necessary for a C++ interface.

    An important part of the DLL header file is to declare the functions
    (or classes if a C++ interface) as exports. The best way to do this
    is to insert

    __declspec(dllimport)



    As part of the declaration of the class or function. For a class this
    goes between the word class and the name of the class. For a function
    it goes after the return type and before the name of the function. There
    is no need to use the word "extern" - it is optional for prototypes as
    they are extern by default.

    However, if you want to use the same header for your own code that builds
    the DLL, you will have to use __declspec(dllexport) instead. You can do
    this in one of two ways: either have two headers, or at the top of your
    headers have the following preprocessor option;


    #ifdef TESTDLL_EXPORTS
    #define TESTDLL_API __declspec(dllexport)
    #else
    #define TESTDLL_API __declspec(dllimport)
    #endif



    If you want your DLL to also compile on UNIX as a shared object (UNIX
    equivalent of DLL), you want another preprocessor option based on the
    operating system, thus

    #ifndef WIN32
    // above
    #else
    #define TESTDLL_API // nothing, you don't need it for UNIX
    // so you must define it to nothingness so your code compiles
    #endif

    Now for a simple test example class
    [ccode]
    class CalculatorImpl;

    class TESTDLL_API Calculator
    {
    public:
    class DivideByZeroException {};

    Calculator( double lhs=0.0, double rhs=0.0 );
    virtual ~Calculator();
    double GetSum();
    double GetMultiple();
    double GetDifference();
    double GetQuotient() throw DivideByZeroException;
    double GetPower();
    double LHS();
    double RHS();
    void LHS( double lhs );
    void RHS( double rhs );

    private:
    CalculatorImpl * pImpl;
    };



    That is all the client needs to see. No implementation detail
    except for one pointer of a type unknown to it. This pointer
    will contain the actual values of lhs and rhs, and will also
    contain all the same functions. You body of class Calculator
    will invoke it like this:

    Calculator::Calculator( double lhs, double rhs )
    {
    pImpl = new CalculatorImpl( lhs, rhs );
    }

    Calculator::~Calculator()
    {
    delete pImpl;
    }

    // other function example
    double Calculator::GetSum()
    {
    return pImpl->GetSum();
    }



    You may ask, why go to all this effort and not just put lhs and
    rhs into the private section. I will tell you.

    Normally your class will be more complex than this. Say you want
    to have a method in your class to persist the data. So you may
    want to provide a function persist(). How your class stores the
    data is an implementation detail you neither want nor need to
    reveal. However you will probably find that in order to implement
    this function, you are going to need specifics in your private
    section. While you might get away with more defined-only class
    names, that may not be enough, and the level of coupling will go
    up. You'll find your users running into problems that really are
    nothing to do with them because it is your implementation and
    not theirs.

    You may also notice that I made the destructor virtual. You or a
    user may wish to add more functionality. If that happens you can
    derive a class from it.

    There are one or two other things you might want to put in a private
    section, but these are simply implementations of standard design
    patterns. For example, if you want users only to be able to create
    an instance on the heap, make your constructor protected (or private
    to allow no derived classes) and provide a static Create() function.
    Also if you want to implement as a singleton, this is done using a
    private or protected constructor and usually (for me) a nested class
    that implements auto-pointer behaviour.

    Finally, you (and others) may note that I didn't even make the
    implementation pointer an auto_ptr (or any other version of it).
    While templates are very useful they do increase the level of
    coupling and you may well find that a compiler complains that
    it doesn't know how to delete an undefined class CalculatorImpl.
    This is because auto_ptr hidden away deletes the pointer it is
    pointing to, and your compiler would see that and want to know
    how it's done.





    The best things come to those who rate

  3. #3
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652

    Re: dll

    I just want to give some more points on how to export functions since I do prefer exporting by ordinals rather than using '__declspec'...

    There are several ways of exporting functions from a dll. The simplest way to export functions from your DLL is to export them by name. This is what happens if you use the keyword __declspec(dllexport).

    // Export a function
    __declspec(dllexport) void __cdecl Function(void);

    // Export a class member function
    class __declspec(dllexport) CFoo
    {
    };



    But you can instead export functions by ordinal. With this technique, you must use a module.definition file instead of __declspec(dllexport). To specify a function’s ordinal value, append its ordinal to the function name in the module-definition file.

    A module-definition file is a text file that contains statements for exporting functions from a DLL. Since the linker provides equivalent command-line options for most of the statements in a .def file, a typical program for Win32 does not usually require a .def file.

    The following keywords are defined for usage in a .def file:

    NAME

    This statement specifies a name for the main output file.


    LIBRARY

    This statement tells the linker to create a DLL. At the same time, the linker creates an import library. The library argument specifies the internal name of the DLL.


    DESCRIPTION

    This statement allow you to enter a short description.


    STACKSIZE

    This statement sets the size of the stack in bytes.


    SECTIONS

    This statement sets attributes for one or more sections in the image file. It can be used to override the default attributes for each type of section.


    EXPORTS

    This statement makes one or more definitions available as exports to other programs.

    EXPORTS marks the beginning of a list of export definitions. Each definition must be on a separate line. The EXPORTS keyword can be on the same line as the first definition or on a preceding line. The .def file can contain one or more EXPORTS statements.

    There are three methods for exporting a definition, listed in recommended order of use:

    1. The __declspec(dllexport) keyword in the source code
    2. An EXPORTS statement in a .DEF file
    3. An /EXPORT specification in a LINK command


    VERSION

    This statement tells the linker to put a number in the header of the DLL.


    A minimal .DEF file must contain the 'LIBRARY' and 'EXPORTS'. The following is an example of a typical .def file:

    LIBRARY ImageData
    DESCRIPTION Handles the image data

    EXPORTS

    ;public: __thiscall CImageData::CImageData(void)
    ??0CImageData@@QAE@XZ @1

    ;public: virtual __thiscall CImageData::~CImageData(void)
    ??1CImageData@@UAE@XZ @2

    ;public: void __thiscall CImageData::Clear(void)
    ?Clear@CImageData@@QAEXXZ @3



    The corresponding class will look as follows

    class CImageData
    {
    public:
    unsigned long m_ulImageWidth;
    unsigned long m_ulImageHeight;
    unsigned short m_usBitsPerPixel;
    unsigned short m_usCompression;

    CImageData();

    virtual ~CImageData() { }

    void Clear();
    };



    As you can see all three functions of the class will be exported. They have the ordinals one (constructor), two (destructor) and three ('Clear()'). Any application which will use this dll can access those functions just like they would be defined in the application itself. All you need to do is to include the header of the DLL and add the .lib file to your linker options.

    By using a .def file you have the control over the export ordinals. If you add additional functions later you just give them higher ordinals than the old ones. That allows application which are using your dll by implicit linking to use the newer version without needing to be relinked. You can also export functions using the 'NONAME' attribute which only places the ordinal number in the exports table. If you have a large number of functions you want to export using this attribute can reduce the size of the dll file.

    There are of course disadvantages as well using this approach. If you are exporting functions within a C++ file, you either have to place the decorated names in the .def file or use standard C linkage by using 'extern "C"'. In the latter the compiler won't do the name decoration...


    Ciao, Andreas

    "Software is like sex, it's better when it's free." - Linus Torvalds

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured