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

Posted on 2004-08-20
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
      string      m_s;

      int            m_x;
            m_x = 1;
            const type_info& t = typeid(*this);      
            m_s =;  

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?

Question by:millsoft
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
LVL 86

Expert Comment

ID: 11857333
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;en-us;168958 ("How To Exporting STL Components Inside & Outside of a Class") and;en-us;168958 ("How To Exporting STL Components Inside & Outside of a Class")
LVL 86

Accepted Solution

jkr earned 500 total points
ID: 11857350
Argh - sorry, the 2nd link should have been;en-us;172396 ("PRB: Access Violation When Accessing STL Object in DLL")

Author Comment

ID: 11876365
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.  

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
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!


Author Comment

ID: 11876614
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. :)

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")
#    define EXE_EXPORT_SPECIFIER __declspec(dllimport)
#pragma message("Importing")

      string      m_s;
      int      m_x;
      virtual ~B();

      virtual ~D() {};

// derived class in my DLL

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

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

LVL 86

Expert Comment

ID: 11876899
Glad to have been of some help, thanx :o)

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
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 concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

726 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