0

I'm new to C++ and I'm having a hard time getting my dll references to work. I've been trying to get it to work for a couple of days, but the few explainations I've found often refer to doing x or y, but don't tell me how to do x or y. Since I'm not a C++ veteran, I need someone to walk me through it. What I want to do is the following:

MySolution
    MyExe (Win32 .exe)
        Main.h
        Main.cpp
            (constructs ImplementationB calls the methods as defined by InterfaceA, then deletes the instances)
            (calls/fills HelperC.Foobar)
    MyInterfaces (dll)
        InterfaceA.h
            ~InterfaceA();
            virtual void DoSomething();
    MyUtils (dll)
        HelperC.h
            static float Foobar;
        HelperD.cpp
            float HelperC::Foobar = 1.0f;
    MyImplementations (dll)
        ImplementationB : InterfaceA
            (uses the value from HelperC.Foobar)

The MyExe and MyImplementations projects contain most of the executing code. But, I need an interface, so I need an interface project (MyInterfaces). I need some helper classes that need to be accessible from both MyExe and MyImplementations, hence MyUtils. I would like this helper class to be statically available, though it is not mandatory.

I had a compiling version before I started adding MyUtils with the HelperC class. I had to mark the interface destructor with __declspec(dllexport), along with the DoSomething method. I also had to mark the constructor of ImplementationB in order to instantiate it from MyExe, which makes sense. However, when I tried to mark the entire class (both the implementation and the interface) with __declspec(dllexport), the example wouldn't compile (which does not make sense).

From what I've read, having static fields in a dll and using them from external code doesn't really work all too well. So, as an alternative, I made Foobar non-static and passed a HelperC instance to the method as described by InterfaceA. Since I had already gotten simple classes to work, I figured that should work as well. However, now the compiler is throwing errors on the constructor of ImplementationB (LNK2019).

In short: I'm getting link errors all over the place in sections that have nothing to do with my changes, and there's little documentation describing the specific steps I need to perform in order to get a simple dll reference to work.
Can someone point out what I need to add and where I need to add it in order to make it compile? Also, some do's and don't's about C++ dll references would help a lot (e.g. don't use statics across projects).

Beijerinc
  • 39
  • 7
  • 1
    This sounds more like a *Microsoft Visual Studio* question than a *C++* question. – user3553031 Jan 10 '15 at 15:23
  • Sorry, you are partially correct. There is a Visual Studio aspect, but a large part of it pertains to C++ syntax. Adding a reference in VS is not that hard, but getting the reference to work (i.e. expose code) is the problem. – Beijerinc Jan 10 '15 at 15:33
  • You normally use a macro that evaluates to `__declspec(dllexport)` when building the DLL and `__declspec(dllimport)` when using the dll. – drescherjm Jan 10 '15 at 15:33
  • I've read about that, though they skipped over the part where changing from dllexport to dllimport depending on ??? works if you build the dll once. What makes it swap between import and export, and when do I swap during 1 build? – Beijerinc Jan 10 '15 at 15:36
  • http://stackoverflow.com/questions/14980649/macro-for-dllexport-dllimport-switch – drescherjm Jan 10 '15 at 15:47
  • [This](http://stackoverflow.com/questions/4489441/why-when-is-declspec-dllimport-not-needed) helped. The compiling example I reffered to didn't use dllimport but still worked. Ok, so now I have dllimport/dllexport specified using the macro explained in @drescherjm's link, but do I need to e.g. manually link the header to the executable project? It's still giving me a LNK2019, now on the dllimport part... – Beijerinc Jan 10 '15 at 16:14

1 Answers1

0

After much digging, I found out that the culprit was a magical project setting. It is called Ignore Import Library and is located at Project Properties->Linker->General, and is set to Yes by default, while it should be set to No in most cases. The setting tells the executable project to use the dll's lib file during compilation. This still sounds strange to me (sounds like duplicate build output), but as far as I understand it, the lib file describes how to link to the dll. If your dll produces a lib during build, you probably want to set the setting to No.

I also learned that to be able to use the HelperC class as a statically accessible helper, I needed to use dllimport in combination with the macro trick, as described by @drescherjm. The dllimport declaration is only ever needed to be able to use data members across libraries (static class fields or globally defined variables). It may be applied to functions as well, though it is not required, in which case it provides a slight performance boost during library linking.

For completeness, my project structure after getting it to work:

MySolution
    MyExe (Win32 .exe, Debugger Type=Mixed)
        Main.h
        Main.cpp
            (constructs ImplementationB calls the methods as defined by InterfaceA, then deletes the instances)
            (calls/fills HelperC::Foobar)
    MyInterfaces (dll, Ignore Import Library=Yes, because there is no .lib after building)
        InterfaceA.h
            class __declspec(dllexport) InterfaceA
                ~InterfaceA() {};
                virtual void DoSomething() = 0;
    MyUtils (dll, Ignore Import Library=No)
        HelperC.h
            class __declspec(dllimport/dllexport) HelperC // (see macro trick)
                static float Foobar;
        HelperD.cpp
            float HelperC::Foobar = 1.0f;
    MyImplementations (dll, Ignore Import Library=No)
        ImplementationB.h
            class __declspec(dllexport) ImplementationB : public InterfaceA
                ImplementationB();
                ~ImplementationB();
                void DoSomething();
        ImplementationB.cpp
            ImplementationB::ImplementationB() {};
            ImplementationB::~ImplementationB() {};
            ImplementationB::DoSomething() { /* Omitted */ };
                (uses HelperC::Foobar in implementation)

On a side note: if you added a default C++ class library project in Visual Studio, you may need to flip the Project Properties->Debugging->Debugger Type setting to Mixed before you will be able to set/use breakpoints in the dll code. See this.

I hope this helps others who are wrestling with dll's in C++ (and Visual Studio).

Community
  • 1
  • 1
Beijerinc
  • 39
  • 7