34

As part of learning C++, I wrote a simple class library + application that references it. Everything builds, except the class library does not generate a .lib file, which results in the application throwing a "LINK : fatal error LNK1104: cannot open file". This seems very reasonable; obviously, if a necessary file isn't there, there's an error and it's fatal. (Side note: I don't have a book yet)

So, I went looking for reasons a .lib file might not be generated. My search-fu, by the way, is rather weak. All I did find was that, if the library did not have any __declspec(dllexport) tags, it would not export a .lib.

I shall now post the header and .cpp contents of the class library (A simple "Console" class with one "Write(std::string)" method).

Header:

// Extensions.h

#pragma once

#include "stdafx.h"

namespace Extensions {

    __declspec(dllexport) class Console
    {
    public:
        __declspec(dllexport) static void Write(std::string text);
    };
}

I am unsure whether I need to tag the function when I've tagged the class, but I can check that when it works.

And the .cpp file:

// This is the main DLL file.

#include "stdafx.h"

// #include "Console.h"

namespace Extensions {

    void Console::Write(std::string text)
    {
        std::cout << text.c_str();
    }
}

I've checked and it is set to generate a dynamic link library.

Thanks.

jon-hanson
  • 7,193
  • 2
  • 32
  • 57
Narf the Mouse
  • 1,491
  • 5
  • 17
  • 26

1 Answers1

25

Here is some sample code that demonstrates how to correctly export a class. Pay attention to the CONSOLETEST_EXPORT macro. This is the missing part of your solution. You need to define this macro in your DLL project, and leave it undefined in the projects that reference this dll.

// MAIN.CPP - TestApplication

#include <iostream>
#include "ConsoleTest.h"

int main(int argc, char** argv)
{
    std::cout << "Hello World" << std::endl;

    ConsoleTest test;

    test.Write();
    ConsoleTest::StaticWrite();

    system("pause");
}


// ConsoleTest.h - TestDll 

#include <iostream>

#ifdef CONSOLETEST_EXPORT
    #define CONSOLETEST_API __declspec(dllexport)
#else
    #define CONSOLETEST_API __declspec(dllimport)
#endif

class CONSOLETEST_API ConsoleTest
{
public:
    ConsoleTest();
    ~ConsoleTest();
    void Write();
    static void StaticWrite();
};


// ConsoleTest.cpp - TestDll

#include "ConsoleTest.h"

ConsoleTest::ConsoleTest()
{
}

ConsoleTest::~ConsoleTest()
{
}

void ConsoleTest::Write()
{
    std::cout << "Instance Write" << std::endl;
}

void ConsoleTest::StaticWrite()
{
    std::cout << "Static Write" << std::endl;
}

Check out this article on codeproject for more details. HowTo: Export C++ classes from a DLL

Nathanael
  • 1,754
  • 16
  • 25
  • Sorry for the lousy formatting of the code. There are three separate code files in that block, main.cpp, ConsoleTest.h and ConsoleTest.cpp. – Nathanael Feb 16 '11 at 18:55
  • Much better. The application is now complaining that Console doesn't exist (I changed the name back to Console from ConsoleTest, because I'm a bit CDO). The application includes "Console.h" fine and, aside from the name change and including "stdafx.h" (VSE complained if I left it out) I'm using your code exactly. Do I continue this question or start a new one? – Narf the Mouse Feb 16 '11 at 20:03
  • No problem. Parsing into separate files seemed to be pretty easy. – Narf the Mouse Feb 16 '11 at 20:04
  • Are you getting a compile error or a link error? And did you define CONSOLETEST_EXPORT in the project settings of your dll project? – Nathanael Feb 16 '11 at 20:19
  • ...In that case, I'm not sure where to #define it. I was just defining it in the header file, which, now that I think about it, probably wasn't that smart. And the first error is "error C2065: 'Console' : undeclared identifier" – Narf the Mouse Feb 16 '11 at 20:26
  • Right click on your dll project in the Solution Explorer and choose 'Properties'. Under Configuration Properties->C/C++->Preprocessor you'll find the field 'Preprocessor Definitions'. Add it to the end of this list. Make sure to set it for both debug and release builds. – Nathanael Feb 16 '11 at 20:46
  • Exact same first error, even though Console.h clearly considers it defined. – Narf the Mouse Feb 16 '11 at 20:50
  • Have you added include paths for your headers and libraries to your main project? The compiler needs to know where to find your header and library files. Properties->Configuration Properties->C/C++->General 'Additional Include Directores Properties->Configuration Properties->Linker->General 'Additional Library Directories' Properties->Configuration Properties->Linker->Input 'Additional Dependencies' – Nathanael Feb 16 '11 at 22:38
  • I stuck the location of the .dll and .lib files in each; I also stuck the location of the .h files in each. Terminated each with a semicolon. And...It's the same error. "error C2065: 'Console' : undeclared identifier" – Narf the Mouse Feb 17 '11 at 00:34
  • Ok, that's new. I commented out the Console code in the application and rebuilt it to try something else without removing the reference and I got "LINK : fatal error LNK1104: cannot open file 'C:...\Projects\CPlusPlus\Extensions\Extensions2.obj'" It's looking in the wrong directory for that - I added the right directory to the linkages, but no go. – Narf the Mouse Feb 17 '11 at 00:39
  • I think you're going to need to find someone who can sit down beside you to debug these errors. I suggest you create a new solution with the two projects I used above, and get that working first. That should help you learn how to configure the Visual Studio environment to correctly build your projects. – Nathanael Feb 17 '11 at 16:59
  • Thanks for the information about needing to add the __declspec macro! This is an old comment thread, but I wanted to add: One thing I figured I should mention is that, if you're creating a DLL in Visual Studio (2013 if it matters), VS will automatically add a definition for `PROJECTNAME_EXPORTS` under `Properties > C/C++ > Preprocessor > Preprocessor Definitions`. So, in this case, you should change the beginning macro to `#ifdef CONSOLETEST_EXPORTS` (notice the 'S' on "EXPORTS"). – 404 Not Found Dec 04 '14 at 16:57