EDIT
To get around the problem, I added the following to the (beginning of the) header file:
#ifdef GetMessage
#undef GetMessage
static inline BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
) {
#if UNICODE
return ::GetMessageW(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
#else
return ::GetMessageA(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
#endif
}
#endif
I'm creating a C++ DLL (using Visual Studio 2008) from code like the following:
Header File:
#include <windows.h> // Edit: This is the culprit.
class __declspec(dllexport) TestBaseClass
{
protected:
char m_Message[512];
public:
TestBaseClass();
virtual char* GetMessage(void) = 0;
};
class __declspec(dllexport) TestDerivedClass : public TestBaseClass
{
public:
TestDerivedClass();
virtual char* GetMessage(void);
};
CPP File:
TestBaseClass::TestBaseClass()
{
}
TestDerivedClass::TestDerivedClass() : TestBaseClass()
{
}
char* TestDerivedClass::GetMessage(void)
{
sprintf(m_Message, "This is a Message");
return m_Message;
}
When I go to compile the DLL, I get a linker error:
error LNK2001: unresolved external symbol "public: virtual char *
__thiscall TestDerivedClass::GetMessageA(void)" (?GetMessageA#TestDerivedClass##UAEPADXZ)
If I change every instance of "GetMessage" to something else (e.g. "TestFunc"), I do not get the linker error.
Primary Question: Why can't I use "GetMessage" as my function name?
Secondary Question: Is there a way to resolve the linker error, and keep "GetMessage" in my class, as currently defined?
It's due to a quirk in the Windows headers. When you #include <windows.h>, it #defines the symbol GetMessage to either GetMessageA or GetMessageW, depending on whether or not you have Unicode support enabled (more specifically, if the UNICODE macro is defined) -- see Unicode in the Windows API and Conventions for Function Prototypes for more info on that.
To work around this, you have a few options:
Don't include the Windows headers
Define the macro NOMSG before include <windows.h> -- this will suppress the declarations of various message-related functions and macros
#undef GetMessage before your class definition
Rename your function to something else
This is pretty standard preprocessor lossage. Your identifier is getting whacked by a macro. It lives inside the Windows headers, it renames the winapi GetMessage() function to either GetMessageA or GetMessageW, depending on whether UNICODE defined.
Pick another name or use #undef GetMessage
Related
Context
Im working on a project designed to send certain commands to a device. Each device can be interfaced with a dll (e.g. deviceADll.h, deviceBDll.h) and the Dll's were not programmed by me, nor can I modify them in any way. I am in charge of integrating DeviceB to the project, with minimal changes to the structure of the project. I know the structure may not be optimal and/or well designed, so I am willing to take suggestion concerning that matter as a last resort solution.
Since the devices are very similar, all Dll functions have the same name, and often the same prototype.
Also because of this, I made a parent class (Device_ts.h), from which DeviceA_ts.h and DeviceB_ts.h inherit (I also have a factory class for the Devices, but I don't think that it's relevant to my problem).
Problem
The problem occurs when I try to include both Dlls: the project compiles, but I get a
Warning 60 warning LNK4006: Connect#12 already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
followed by a
Warning 61 warning LNK4006: __imp__Connect#12 already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
and a
Warning 62 warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
Has anyone experienced a similar situation? Should I ignore those warning or will I not be able to call DeviceB.h functions since their definitions are ignored?
I am using Visual Studio 2010, the Device_ts.h library I am writing is a static library and all the project's parameters (e.g. /MD, include directories, dependencies, MFC, etc) are set properly from what I found in my research for this problem.
Code
The include and code looks like this (I will only show one of the functions that cause the warning since I get the same error on 50 functions):
DeviceADll.h
#ifndef DEVICEA_H__
#define DEVICEA_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
namespace DeviceA
{
// some struct definition that don't cause the linker warnings
//...
// function definitions
extern "C" HANDLE PASCAL EXPORT Connect( HANDLE h_devA, const char *ip);
// ...
} // namespace DeviceA
DeviceBDll.h
#ifndef DEVICEB_H__
#define DEVICEB_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
namespace DeviceB
{
// some struct definition that don't cause the linker warnings
//...
// function definitions
extern "C" HANDLE PASCAL EXPORT Connect( HANDLE h_devB, const char *ip);
// ...
} // namespace DeviceB
Device_ts.h
#ifndef DEVICE_FCT_H_
#define DEVICE_FCT_H_
#ifndef EXPORT
#define EXPORT
#endif
#if _MSC_VER > 1000
#pragma once
#endif
#include "DeviceADll.h"
#include "DeviceBDll.h"
class CDevice {
public:
virtual BOOL Connect(char *ip_addr) = 0;
};
#endif DEVICE_FCT_H_
This is a good use-case for manual DLL loading, using LoadLibrary() and GetProcAddress().
You'll have to manage a function pointer for each function looked up this way, which is a bit of a pain, but bypassing the OS's dll loading gives you a lot of flexibility.
Also note that you do not need to link against the DLL when using this method, the dll binding is 100% runtime, and the linker is not involved at all.
Here's an example:
typedef void (*connect_fn)(HANDLE, const char*);
connect_fn connect_a;
connect_fn connect_b;
int main()
{
HINSTANCE dll_a = LoadLibrary("path_to_dll_a.dll");
HINSTANCE dll_b = LoadLibrary("path_to_dll_b.dll");
if (!dll_a || !dll_b) {
return 1;
}
connect_a = (connect_fn)GetProcAddress(dll_a , "Connect");
connect_b = (connect_fn)GetProcAddress(dll_b , "Connect");
// connect_a and connect_b can now be used.
return 0;
}
Edit: Basically, I suggest you treat the device DLLs as plugins, rather than dynamic libraries.
I'm trying to call a statically-linked static method of a C++ class, but I'm getting the VS linker error LNK2019, "unresolved external symbol". Here's the library source:
// in header file
#define DllExport __declspec (dllexport)
class MyClass{
public:
DllExport
static HWND WINAPI myFunc();
};
// in cpp file
DllExport
HWND WINAPI MyClass::myFunc(){ /* create a GUI window that has instance of MyClass set as its property (using ::SetProp) */ }
myFunc is to serve as an entry point for creating objects of MyClass, which resides hidden in the library. Only such static functions can be used to influence the functionality of a MyClass instance (by providing the corresponding HWND).
Here's the library consumer:
#define DllImport __declspec(dllimport)
DllImport
HWND WINAPI myFunc();
...
int main(){
HWND hWnd=myFunc();
... // work with the window and attached MyClass instance
}
(I believe) all file linkages are set correctly - originally, myFunc was designed as a standalone function and all worked just fine. I suspect it must be some calling convetion mismatch that makes the linker produce the error on myFunc.
Read through multiple articles on this topic, namely
http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL
and
https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx
but they didn't solve my problem.
Thanks for a suggestion!
Since your goal is to create static library, the first thing we want to do is eliminate any mention of dllexport/dllimport. Such specifiers are only used when you actually create a DLL project.
So for lib.h, we only need this (with some include guards added for good measure):
// lib.h
#ifndef LIB_H
#define LIB_H
class MyClass{
public:
static void myFunc();
};
#endif
The WINAPI specification is also unnecessary since you're the one calling the method and can just use the default calling convention without ABI issues (though if you do want to use WINAPI anyway, then you need to include <windows.h> in your header file).
For lib.cpp, we only need this:
// lib.cpp
#include <Windows.h>
#include "lib.h"
void MyClass::myFunc(){
::MessageBox(0,"myFunc call!",NULL,0);
}
For main.cpp in your app project, we only need this:
// main.cpp
#include <iostream>
#include <D:\staticlink\lib\lib.h>
int main(){
std::cout << "ahoj";
MyClass::myFunc();
char buf[10];
std::cin >> buf;
return 0;
}
I'd recommend configuring your include paths to find lib.h through your project settings instead of using absolute paths in your source code, but perhaps you can do that later after you get everything working.
After that, if a problem remains, the only thing you should need to ensure is that your app project is linking against lib.lib properly (linker settings).
Your import header file should look more like:
#define DllApi __declspec (dllexport)
class MyClass{
public:
DllApi
static HWND WINAPI myFunc();
};
Just started doing some coding for a very simple automated test framework for internal use. (I know there are hundreds of them out there - really good ones too, but at the moment that's not interesting, so don't point me to any of those, please ;)) I then came across the following problem which I can't explain, thus asking for your help.
I have the following code as part of a DLL:
(The code is barely an embryo and took me <2 minutes to write, so it's logic, structure - nothing - is refined, in any way yet.)
h-file:
#pragma once
#ifdef __DLL__ // Defined in DLL-project
#define DLLEXPORT __declspec( dllexport )
#else
#define DLLEXPORT
#endif
class DLLEXPORT AutoTest
{
public:
enum eTestID {TESTID_SomeFunction};
AutoTest(eTestID id, LPVOID lpData)
{
if(sm_bTestsActive)
ExecTest(id, lpData);
}
void ActivateTests();
private:
static void ExecTest(eTestID id, LPVOID lpData)
{
}
static BOOL sm_bTestsActive;
};
cpp-file:
#include "StdAfx.h"
#include "AutoTest.hpp"
BOOL AutoTest::sm_bTestsActive = FALSE;
void AutoTest::ActivateTests()
{
sm_bTestsActive=TRUE;
}
This compiles just fine and the DLL gets generated.
Here's my problem though - when instantiating the class with:
AutoTest(AutoTest::TESTID_SomeFunction, &SomeData);
from the main application, the linker fails with
error LNK2001: unresolved external symbol "private: static int AutoTest::sm_bTestsActive" (?sm_bTestsActive#AutoTest##0HA)
<2 minutes to write - now going on 5 hours to understand why it fails!!! :O
Here's what interesting - if I move the constructor to the cpp-file (not inlined) it works just fine!?!?
Here's that code:
h-file:
#pragma once
#ifdef __DLL__ // Defined in DLL-project
#define DLLEXPORT __declspec( dllexport )
#else
#define DLLEXPORT
#endif
class DLLEXPORT AutoTest
{
public:
enum eTestID {FK3059};
AutoTest(eTestID id, LPVOID lpData);
void ActivateTests();
private:
static void ExecTest(eTestID id, LPVOID lpData)
{
}
static BOOL sm_bTestsActive;
};
cpp-file:
#include "StdAfx.h"
#include "AutoTest.hpp"
BOOL AutoTest::sm_bTestsActive = FALSE;
AutoTest::AutoTest(eTestID id, LPVOID lpData)
{
if(sm_bTestsActive)
ExecTest(id, lpData);
}
void AutoTest::ActivateTests()
{
sm_bTestsActive=TRUE;
}
(I've made some minor edits in the code after pasting, so there may or may not be simple syntax errors.)
Also, if I remove the reference to the static member from the inline versions constructor, it works fine.
Any ideas as to why the inline version won't work?
Pay attention to your definition of DLLEXPORT.
Make sure that it is properly expanded to __declspec(dllexport) when building the DLL, or __declspec(dllimport) when building the client.
I'd suggest using a macro with a more specific name than the generic DLLEXPORT (to avoid conflicts with other macros with the same name).
Having static data members accessed from inline member functions works fine for me (tested with VS2013).
Minimal repro:
Create a Visual Studio solution with an empty DLL project and an empty console application project.
Inside the DLL project add two files:
DllClass.h:
#pragma once
#ifndef TEST_DLL_CLASS
#define TEST_DLL_CLASS __declspec(dllimport)
#endif
class TEST_DLL_CLASS DllClass
{
public:
DllClass();
int GetMember() const
{
return m_data1;
}
static int GetStaticMember()
{
return sm_data2;
}
private:
int m_data1;
static int sm_data2;
};
DllClass.cpp:
#define TEST_DLL_CLASS __declspec(dllexport)
#include "DllClass.h"
int DllClass::sm_data2 = 2;
DllClass::DllClass()
: m_data1(1)
{
}
Inside the console app project, add one file:
Test.cpp:
#include "..\DllTestClass\DllClass.h"
#include <iostream>
using namespace std;
#pragma comment(lib, "DllTestClass")
int main()
{
DllClass dllClass;
cout << dllClass.GetMember() << endl;
cout << DllClass::GetStaticMember() << endl;
}
Make sure that when building the console test app, the linker can find the DLL .lib (DllTestClass.lib) file.
For that purpose, you can navigate the console app's project properties, going to:
Project Properties | Linker | Additional Library Directories
and add $(OutDir) to the additional library directories, making it:
$(OutDir);%(AdditionalLibraryDirectories)
Builds and works correctly for me.
Should be:
#ifdef __DLL__ // Defined in DLL-project
#define DLLEXPORT __declspec( dllexport )
#else
#define DLLEXPORT __declspec( dllimport )
#endif
You can declare C++ classes with the dllimport or dllexport attribute. These forms imply that the entire class is imported or exported. Classes exported this way are called exportable classes.
More information in the documentation.
I have a library (dll) which exposes a class along with its constructors which are supposed to be used in other modules (exe and dll). I am able to instantiate that class from other library modules but not exe modules. I get the linker error - 'error LNK2019: unresolved external symbol' during linking. I am confused why linking succeeds when used in other library projects and not exe project. Can somebody help me with this?
the following is the class declaration:
class __declspec(dllimport) MyException
{
public:
MyException(unsigned int _line, const char *_file, const char *_function, MyExceptionType _type, const wchar_t* _message = 0, ...);
};
This is the whole error:
error LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl MyException::MyException(unsigned int,char const *,char const *,enum MyException::MyExceptionType,unsigned short const *,...)" (_imp??0MyException##QAA#IPBD0W4MyExceptionType#0#PBGZZ) referenced in function "public: __thiscall MyClassUsesMyException::MyClassUsesMyException(class SomeClass *,int)" (??0MyClassUsesMyException##QAE#PAVSomeClass##H#Z)
MyClassUsesMyException is being instantiated in 'MyApp.cpp'.
Thanks, Rakesh.
Update: wchar_t Not Always Native
After a fairly long exchange of information and getting a little more info from the OP, the problem is essential this:
class __declspec(dllimport) MyException
{
public:
MyException(unsigned int _line,
const char *_file,
const char *_function,
MyExceptionType _type,
const wchar_t* _message = 0, // <<== note wchar_t type
...);
};
Visual C++ can be configured to either treat wchar_t as a native type or not. When not treated as a native type, unsigned short is the specified macro substitution for wchar_t. The linker was complaining about the above function being unresolvable, but what really caught my eye was this at the tail of the undefined symbol:
,unsigned short const *,...)
Note the unsigned short. This hinted to me that the compiler was using non-native wchar_t when compiling the EXE. I considered it possible that maybe the DLL was compiled with wchar_t configured as native, thereby introducing a different signature and thus not matching up at link time.
If you're surprised this was the problem, imagine how surprised Rakesh and I were =P
Original Answer
That class should be in a single common header with preprocessor logic to determine proper import/export state of the declaration. Like so:
MyDLL.h
#ifndef MYDLL_H
#define MYDLL_H
// setup an import/export macro based on whether the
// DLL implementing this class is being compiled or
// a client of the DLL is using it. Only the MyDLL.DLL
// project should define MYDLL_EXPORTS. What it is
// defined as is not relevant. *That* it is defined *is*.
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
class MYDLL_API MyException
{
// your class definition here...
};
#endif
Then, in your DLL project that implements the exception (and only in that project), add MYDLL_EXPORTS to the preprocessor defines list in your project configuration.
I created a DLL project and successfully built it. I then tried to use the DLL in another Project, TEST, and I am getting the following error.
Error 1 error LNK2001: unresolved external symbol "public: void __thiscall SnoMessage::setRawMessageName(class ATL::CStringT<wchar_t,class StrTraitMFC_DLL<wchar_t,class ATL::ChTraitsCRT<wchar_t> > >)" (?setRawMessageName#SnoMessage##QAEXV?$CStringT#_WV?$StrTraitMFC_DLL#_WV?$ChTraitsCRT#_W#ATL#####ATL###Z)
I added the required lib in the linker properties, and I also added the header files in the TEST include directory. So the function is being recognized, but it keeps giving those errors. The DLL is comprised of the following files
SnoMessage.h
#pragma once
#include "StdAfx.h"
class SnoMessage
{
public:
__declspec(dllexport) SnoMessage(void);
__declspec(dllexport) ~SnoMessage(void);
__declspec(dllexport) void setRawMessageName(CString messageName);
__declspec(dllexport) void setRawMessageType(CString messageType);
__declspec(dllexport) void setRawMessageAttributes(std::map<CString,CString> attributes);
__declspec(dllexport) CString getRawMessageName();
__declspec(dllexport) CString getRawMessageType();
__declspec(dllexport) std::map<CString,CString> getRawMessageAttributes();
private:
CString messageName;
CString messageType;
std::map<CString,CString> attributes;
};
SnoMessage.cpp
#include "stdafx.h"
#include "SnoMessage.h"
SnoMessage::SnoMessage(void)
{
}
SnoMessage::~SnoMessage(void)
{
}
void SnoMessage::setRawMessageName(CString messageName){
this->messageName = messageName;
}
void SnoMessage::setRawMessageType(CString messageType){
this->messageType = messageType;
}
void SnoMessage::setRawMessageAttributes(std::map<CString,CString> attributes){
this->attributes = attributes;
}
CString SnoMessage::getRawMessageName(){
return messageName;
}
CString SnoMessage::getRawMessageType(){
return messageType;
}
std::map<CString,CString> SnoMessage::getRawMessageAttributes(){
return attributes;
}
And in test I am doing the following:
test.cpp
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "SnoMessage.h"
int _tmain(int argc, _TCHAR* argv[])
{
SnoMessage *msg = new SnoMessage();
msg->setRawMessageName("TEST");
return 0;
}
Let me know if you need more info, thanks.
In your dll define this in some header you want to use for your export defs...
MyExports.h
#ifdef SNOMESSAGE_EXPORTS
#define SNOMESSAGE_API __declspec(dllexport)
#else
#define SNOMESSAGE_API __declspec(dllimport)
#endif
Now in your dll you just define SNOMESSAGE_EXPORTS, then when your dll is compiled your class and methods will be visible to the exe. But when you include those same headers in the exe the Macro will import them instead of export.
//In the DLL this is == to export, in the executable this is import. Problem solved.
class SNOMESSAGE_API SnoMessage
{
public:
//...
};
You no longer need to export each member, just the class.
I would mark the whole class as exported, not just its member functions. Also, following the advice of this conversation, you need to specify __declspec(dllecport) or __declspec(dllimport) based on whether you are including the header in the DLL or the code that uses the DLL; and define the guarding macro in the DLL project.
When you compile the DLL you should have __declspec(dllexport), but when you compile exe you should have __declspec(dllimport). The easiest way to do this is to have a #define somewhere that has different value when "in DLL" and "out of DLL". Also do export the whole class instead of individual methods.
There is a case when dll compile use C call but exe use standard call, the link in x64 has no problem, but when using win32 will show this link error 2001. For that situation just use C call for both dll and exe for win32 platform (https://learn.microsoft.com/en-us/cpp/error-messages/tool-errors/name-decoration?view=msvc-160).