Solved

DIFFICULT: C++ class exporting & __declspec(dllexport)

Posted on 2004-08-20
5
3,528 Views
Last Modified: 2008-01-09
Problem: Dynamically link C++ classes into my application at run-time to provide specific ustomized behavior.  E.g. in my case, I have several formats of file to read, say F1 & F2.  Currently, my app has a class F1Reader that reads F1 and creates a bunch of other objects of type Factor1, Factor2, Factor3, etc.  I want to add support for a new file type F2, which will produce the same type of Factor1,2,3 objects, but with different data.  Factor objects are already well-defined C++ classes within my application.  Therefore, F1Reader & F2Reader are class factories.  Further, I would like to be able to add F3 in the future without modifying my primary application.  That is I want to be able to provide F3Reader.DLL & some registry settings, and boom, it works.

One obvious solution would be to encapsulate all the Factor type objects as well as the F1Reader & F2Reader classes as COM objects.  This is certainly straight-forward, but it is a LOT of work considering the amount of current code that uses Factor1,2,3 objects.  Therefore, I'm looking for a solution that will continue to create native C++ objects with dynamically linked code, without creating COM wrappers.

My proposed solution is to refactor F1Reader & F2Reader so they derive from a common base (FactorFactoryBase), and put F1Reader & F2Reader in separate C++ DLLs that might or might not be present on the user's machine.  The interface to FactorFactoryBase will provide all my application needs to create the Factor objects.  

Consider this little attempt to test out the concept:

struct __declspec(dllexport) B
{
private:
      string      m_s;

public:
      int            m_x;
      B()
      {
            m_x = 1;
            const type_info& t = typeid(*this);      
            m_s = t.name();  
      }
};

returns a compiler warning:

c:\dev\test\cppdll\b.h(12) : warning C4251: 'm_s' : class 'std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >' needs to have dll-interface to be used by clients of struct 'B'

While this is only a warning, it is a level 1 warning, and sounds pretty fatal since I want the DLLs to derive from B.

It seems I need to instantiate an specific instance of string and export that.  But I haven't been able to figure out how.

I tried:

class __declspec(dllexport) stringEx: public basic_string<char>
{
};

& got the same warning message.

Any suggestions on how to solve this problem?

TIA,
Brad
0
Comment
Question by:millsoft
  • 3
  • 2
5 Comments
 
LVL 86

Expert Comment

by:jkr
Comment Utility
DLLs are the Windows way to reuse code, and templates are the C++ way. They do not coexist well, though. My suggestion would be to provide pure abstract interfaces as base classes and let the implementations handle that seamlessly and, even more importand, leave STL objects in the modules they were created in. Provide access interfaces instead. Check out http://support.microsoft.com/default.aspx?scid=kb;en-us;168958 ("How To Exporting STL Components Inside & Outside of a Class") and http://support.microsoft.com/default.aspx?scid=kb;en-us;168958 ("How To Exporting STL Components Inside & Outside of a Class")
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
Comment Utility
Argh - sorry, the 2nd link should have been http://support.microsoft.com/default.aspx?scid=kb;en-us;172396 ("PRB: Access Violation When Accessing STL Object in DLL")
0
 
LVL 5

Author Comment

by:millsoft
Comment Utility
Hi jkr,

Thanks for your feedback.  Below follows some more research I've done after reading your articles.  You may (or may not) find it interesting.  

Brad
===
Ok, I've been looking into the article "How To Exporting STL Components Inside & Outside of a Class".  When you mentioned it, it rang a bell.  Seems like I've done that before.  Anyway, looking through the CRT code is loaded with related stuff like this:
// copied from Xstring in VC6.

#ifdef      _DLL
#ifdef __FORCE_INSTANCE
template class _CRTIMP2 basic_string<char, char_traits<char>, allocator<char> >;
template class _CRTIMP2 basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >;
#else            // __FORCE_INSTANCE
#pragma warning(disable:4231) /* the extern before template is a non-standard extension */

extern template class _CRTIMP2 basic_string<char, char_traits<char>, allocator<char> >;
extern template class _CRTIMP2 basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >;

#pragma warning(default:4231) /* restore previous warning */
#endif            // __FORCE_INSTANCE
#endif            // _DLL

_CRTIMP2 is defined to __declspec(dllimport) whenever the DLL version of the C-runtime is selected.  So, based upon the article, it appears that MSFT is exporting std::string from their own DLL for our use.  That makes sense, although then it seems that it's not possible to export a class (B) containing an imported data member from the CRT (string), even though both my EXE and DLL should both be able to see (and import) the same exported symbol.  Go figure.

BTW, the two articles you mentioned are not quite consistent.  E.g. one article (168958) says exporting maps is impossible, and the other article (172396) uses that as an example!

0
 
LVL 5

Author Comment

by:millsoft
Comment Utility
Hi jkr,

It turns out my problem didn't have anything to do with the templates at all.  The simple problem was that my projects didn't have the CRT set to the DLL selections.  I normally use CRT in DLLs, but somewhere I missed it here, and they were all set to static linked.  Changing that fixed all the problems because string is now easily imported into the DLLs.

However, your articles did help because I found I couldn't compile the examples from the article which is how I uncovered my settings problem. :)

Brad
====
Here's the code:

// b.h in the EXE
#pragma once

#include <string>
using namespace std;
// DOING_EXE is defined for compiling the EXE containing the actual code.  
// not defined in all other cases.

#ifdef DOING_EXE
#    define EXE_EXPORT_SPECIFIER __declspec(dllexport)
#pragma message("exporting")
#else
#    define EXE_EXPORT_SPECIFIER __declspec(dllimport)
#pragma message("Importing")
#endif

struct EXE_EXPORT_SPECIFIER B
{
      string      m_s;
      int      m_x;
      B();
      virtual ~B();
};

struct EXE_EXPORT_SPECIFIER D:public B
{
      D();
      virtual ~D() {};
};

// derived class in my DLL

#ifdef CPPDLL1_EXPORTS
#define CPPDLL1_API __declspec(dllexport)
#else
#define CPPDLL1_API __declspec(dllimport)
#endif
#include "..\B.h"
// This class is exported from the CPPDLL1.dll

struct CPPDLL1_API D1:public B
{
      D1();
      virtual ~D1();
};



0
 
LVL 86

Expert Comment

by:jkr
Comment Utility
Glad to have been of some help, thanx :o)
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now