4

I'm working in a C++ workspace in VS2017, having two projects in the workspace: a utility project and a main project that uses the utility project.

After I added a new class (".h" and ".cpp" files) to the utility project, I noticed that although I make changes in the code, the ".lib" file is not rewritten when I build it, unless I change a method whose declaration includes __declspec(dllexport). It appears that I have to add this declaration, since otherwise, a derived issue is that of course the main project has linkage errors.

Is there a more elegant way to do it rather than adding __declspec(dllexport) before the declaration of every public method, like in the code below?

public:
    __declspec(dllexport) MyProperty(const std::string &csvLine);
    __declspec(dllexport) bool getIsActive();
    __declspec(dllexport) std::string getFormatting();
    __declspec(dllexport) PropertyType getType();
SomethingSomething
  • 11,491
  • 17
  • 68
  • 126
  • Declare the *class* as `__declspec(dllexport)`? – Some programmer dude Apr 11 '22 at 08:04
  • @Someprogrammerdude the result when trying it is a linkage error in the main project, due to this warning: `Warning C4091 '__declspec(dllexport)': ignored on left of 'MyProperty' when no variable is declared` – SomethingSomething Apr 11 '22 at 08:06
  • 1
    @Someprogrammerdude turned out that I should have inserted the `declspec` command between the `class` keyword and the class name, while the above warning I reported was when I added it before the class keyword – SomethingSomething Apr 11 '22 at 08:09
  • 2
    To be honest, declaring classes with `__declspec` modifiers is well-documented, and any decent Windows DLL with C++ tutorial should have had that information. – Some programmer dude Apr 11 '22 at 08:12
  • Does this answer your question? [Exporting a C++ class from a DLL](https://stackoverflow.com/questions/27998/exporting-a-c-class-from-a-dll) – phuclv Apr 11 '22 at 08:13
  • @phuclv yes , at least one of the answers does, even though the question there is asked from a different perspective (different problem, mostly same solution). I'd mention that I still believe that there is an added value in this question and the answer posted here. – SomethingSomething Apr 11 '22 at 08:19

1 Answers1

7

You can add the declaration to the class, instead of to the individual methods:

class __declspec(dllexport) MyProperty
{
public:
    MyProperty(const std::string &csvLine);
    bool getIsActive();
    std::string getFormatting();
    PropertyType getType();
};

Note that for the class, the place is slightly different thanfor methods - not in front of the complete declaration, but between the class keyword the class name.

As a followup, often a macro is used instead, which is defined to be either __declspec(dllexport) or __declspec(dllimport), depending on some preprocessor condition specifying whether we are currently compiling the dll or trying to use it:

#if defined(MY_DLL)
    #define MY_DLL_API __declspec(dllexport)
#else
    #define MY_DLL_API __declspec(dllimport)
#endif

class MY_DLL_API MyProperty
{
public:
    MyProperty(const std::string &csvLine);
    bool getIsActive();
    std::string getFormatting();
    PropertyType getType();
};

For your dll project, you then define MY_DLL, and for everyone who just uses the dll (without having MY_DLL defined), the header will automatically have the required dllimport.

Important: It is not recommended to pass most STL types across DLL boundaries, see for example Exporting STL class from DLL... or How can I call a function of a C++ DLL ..., as commented also below.

codeling
  • 11,056
  • 4
  • 42
  • 71
  • 3
    Just as a side not, exporting `std::string` is usually not a good idea – Andro Apr 11 '22 at 09:45
  • oh yes, you're right! though it would only be an actual problem if the .dll is potentially consumed by applications with different STL implementations, right? – codeling Apr 11 '22 at 10:31
  • I believe you are right. Here is an interesting question and answer https://stackoverflow.com/a/13866797/732348 – Andro Apr 11 '22 at 10:37
  • [Stern warning against exporting any inlined types](https://stackoverflow.com/a/4551798/402169) – tenfour Apr 12 '22 at 08:39
  • What about private methods and class members? Is it safe to use STL class objects when it is guaranteed that they can only be used by other methods of the same DLL (i.e., no external code can call/access them)? – SomethingSomething Apr 12 '22 at 11:33
  • Another question - what happens if the DLL defines a new class that derives `std::exception` or `std::runtime_error` (which can be thrown if the exported methods are used incorrectly)? Does it expose the app to the same problems? – SomethingSomething Apr 12 '22 at 14:58
  • @SomethingSomething I'm not an expert on this. Please read the linked to posts, they don't explicitly mention it but hint at, what I would interpret as that you're safe: The main problem for passing STL objects across DLL boundaries seems that templated code will be inlined; so an object passed across DLL boundaries can potentially be accessed using an implementation different than the one it was compiled for (leading to bad things). For an object staying within the same DLL, this is not the case. – codeling Apr 12 '22 at 15:00
  • 1
    `std::exception` is not templated as far as I can say, so it probably isn't affected by exactly the same problem, though again I'm not sure. I would recommend (1) doing some google searches and experiments and/or (2) asking a separate question – codeling Apr 12 '22 at 15:01
  • @codeling thank you for pointing it out. Meanwhile I found this thread: https://stackoverflow.com/questions/24511376/how-to-dllexport-a-class-derived-from-stdruntime-error – SomethingSomething Apr 12 '22 at 15:02