I am trying a very simple implementation of a C++/CLI wrapper to allow legacy C++ code to reference .Net code, as described here. I am getting stuck just trying to get my basic C++/CLI unmanaged (native) objects linked, without even including any managed/IL/.Net code.
My question is, following along with this basic setup and what I describe below, am I right to be very confused about these errors? Are there some considerations that I'm missing? Maybe the answer is that this should work, so it's not clear what's wrong. That's still helpful. A similar working example would be great.
Unresolved Symbol Errors
Error LNK2019 unresolved external symbol "__declspec(dllimport)
public: __thiscall Wrapper::Test::Test(void)"
(__imp_??0Test#Wrapper##QAE#XZ) referenced in function _main NativeApp
Error LNK2019 unresolved external symbol "__declspec(dllimport)
public: __thiscall Wrapper::Test::~Test(void)"
(__imp_??1Test#Wrapper##QAE#XZ) referenced in function _main NativeApp
I've reviewed related questions on SO without any luck. I've got my dll header included in the client C++ project, my project reference to the C++/CLI wrapper dll, and my define statements for import/export. My very simple code is shown below. I am not using any MFC. I am using VS2017. DumpBin.exe /exports shows export symbols that seem to match what the linker error says are missing.
1 0 000010D0 ??0Test#Wrapper##QAE#XZ = ??0Test#Wrapper##QAE#XZ (public: __thiscall Wrapper::Test::Test(void))
2 1 000010E0 ??1Test#Wrapper##QAE#XZ = ??1Test#Wrapper##QAE#XZ (public: __thiscall Wrapper::Test::~Test(void))
3 2 000010C0 ??4Test#Wrapper##QAEAAV01#ABV01##Z = ??4Test#Wrapper##QAEAAV01#ABV01##Z (public: class Wrapper::Test & __thiscall Wrapper::Test::operator=(class Wrapper::Test const &))
Here's the basic code...
NativeApp.exe (project)
NativeApp.cpp (File)
#include "stdafx.h"
#include <iostream>
#include "Wrapper.h" //From additional includes directory
int main()
{
std::cout << "Program Started" << std::endl;
Wrapper::Test shell = Wrapper::Test::Test(); //Use dll
std::cin.get();
return 0;
}
Reference to Wrapper
Wrapper.dll (Project)
Wrapper.cpp (File)
#include "Wrapper.h"
#pragma unmanaged
namespace Wrapper {
Test::Test() {
}
Test::~Test() {
}
}
Wrapper.h (File)
#pragma once
#ifdef WRAPPER_EXPORTS
#define WRAPPER_API __declspec(dllexport)
#else
#define WRAPPER_API __declspec(dllimport)
#endif
#pragma unmanaged
namespace Wrapper {
class WRAPPER_API Test {
public:
Test();
~Test();
};
}
I was under the impression that the project reference took care of any additional dependency settings behind the scenes. Apparently, that is not the case. The .lib file needed to be added as an additional dependency, as is described here. However, as described by this Microsoft document, everything worked without additional dependencies when I was using non /clr dlls, so I'm not sure why the additional dependency was only required for my CLR reference. Clearly, I need to read up on this some more.
In any case, my C++ client project requirements are listed below. I was missing the second requirement. Also, here is an example project that helped me diagnose the problem.
1.) Add project reference
2.) Add the .lib file as an `Additional Dependency.
[Optional] Use Additional Library Directories
3.) #include .h file in code where appropriate
[Optional] Use additional include directories
EDIT: Why the additional dependency was required, and alternative option
As noted above, I was getting hung up on why the .lib additional dependency was required for the /clr dll but not for the non-clr dll. The answer is because a /clr project is configured by default to ignore import libraries. So when the project gets referenced by another C++ project, the project reference ignores import libraries. Changing this setting (Linker > General > Ignore Import Libraries) to "No" in the /clr dll project solves the issue so that the additional dependency is not required and the project reference works the same as the non-clr C++ dll.
Related
I am using Octave within MSVC 2010. First I downloaded Octave latest version at this link. After installing, I tried to run this simple code:
#include <iostream>
#include<octave-3.6.4\octave\oct.h>
#include<octave-3.6.4\octave\config.h>
#include<octave-3.6.4\octave\octave.h>
using namespace std;
int main (void)
{
std::cout << "Hello Octave world!\n";
system("PAUSE");
return 0;
}
Note that I added these links to my project as well:
C:\Software\Octave-3.6.4\include\octave-3.6.4\octave--->Includ. Dir.,
C:\Software\Octave-3.6.4\include--->Includ. Dir.
C:\Software\Octave-3.6.4\lib--->Lib. Dir.
C:\Software\Octave-3.6.4\lib\octave\3.6.4--->Lib Dir.
I also added 1 and 2 to Additional Inc Dir!!
C:\Software\Octave-3.6.4\lib\octave\3.6.4--->Additional Lib. Dir in Linker.
First, I got this error that it cannot find math.h in Program Files while this file was in my Program Files (x86). So, I changed it to: C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h and it solved this error. However, now I get this error:
error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall octave_value::~octave_value(void)" (__imp_??1octave_value##QAE#XZ) referenced in function "public: void * __thiscall octave_value::`vector deleting destructor'(unsigned int)" (??_Eoctave_value##QAEPAXI#Z)
It is not sufficient to add the library path to the project.
You have to add the library name(s) (including .lib) to the "Additional Dependencies" in the Linker/Input tab.
Edit
To verify what library has been searched you can enable the Linker/General/Show Progress option. Then you can see in the Build Output what library has actually be used in symbol search.
Edit
Your example code doesn't show any instance of an array of octave_value instances. So it's a bit surprising that you need to link with any library with the code you've shown. But anyway you want to have these externals resolved.
If there is no other resource (manual, ...) you should detect where the octave_value class is implemented. This can be a static library or a DLL.
You can detect the DLL implementation with a dumpbin /exports on the DLLs. In that case you need the corresponding import libraries. The LIB should have the same base name as the DLL. Verify that you have added that dependency and how the linker searches this library for symbols.
The name of the symbols __imp_??1octave_value##QAE#XZ indicates that it should be in a DLL. But since you have a problem you might want to search LIBs too.
You can detect the LIB implementation with a dumpbin /symbols. In that case you have to add the LIB directly. Again verify it with the Build Output.
The dumpbin output will probably very verbose. You should use either findstr to limit the output or redirect the output to a file and search the symbols with an editor of your choice.
Search for ocatave_value. If you find a different decoration of the constructor and destructor you might have missed to set an option. A preprocessore directory could be used to define how the library is use. E.g. if you find octave_value::octave_value without the __imp_ prefix you have accidentily compiled for a DLL version altough the class is implemented in a static library. In that case, read the manual and ask at the octave mailing list forum or whatever.
I have a class that is derived from QObject and QRunnable and also has the Q_OBJECT macro. The library that contains the class compiles fine and I get a .lib and .dll file. I'm using MSVC 2013 and QT 5.4 (precompiled binaries from qt.io).
Looking at the DLL using Dependency Walker, I can see that the function is there. The file get's moc'ed which means I can look at the resulting CPP file. As a proof here's the function that's causing the trouble.
const QMetaObject DHImageConvHandler::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_DHImageConvHandler.data,
qt_meta_data_DHImageConvHandler, qt_static_metacall, Q_NULLPTR, Q_NULLPTR}
};
Now, when I try to create an app that links to this library I get the following error.
unresolved external symbol "public: static struct QMetaObject const DHImageConvHandler::staticMetaObject" (?staticMetaObject#DHImageConvHandler##2UQMetaObject##B)
referenced in function "public: static class QString __cdecl DHImageConvHandler::tr(char const *,char const *,int)" (?tr#DHImageConvHandler##SA?AVQString##PBD0H#Z)
Changing the project type for the library from "Dynamic Library" to "Static Library" makes this go away but I'm curious why. The code is in the lib. I opened the import library with a text editor and looked for staticMetaObject and, as mentioned previously, Dependency Walker also shows that it's there.
Can anyone shed some light on this?
edit 10.01.2015
I misspoke about who is using the library in question. That lib is linked to another lib which is then part of an app.
Thanks Archie for pointing me into the right direction. The dllimport/dllexport prefixes are part of the code - wait for it - but every library is using the same macro and preprocessor directive. That means, when my problem library is used by code of another library, and both use the same macro to export their symbols, the second library includes the headers of the first library with dllexport instead of dllimport. As soon as I gave my problem lib its own dllexport/dllimport macro everything worked.
I have two VC++ projects inside a sln file in visual studio 2010. I want to use a_flag in the file of another project, is this possible what i am doing below ?
Project 1:
**sample_header.h**
#ifndef SAMPLE_HEADER_API
#define SAMPLE_HEADER_API __declspec(dllimport)
#endif
extern SAMPLE_HEADER_API int a_flg;
**file1.cpp**
#define SAMPLE_HEADER_API __declspec(dllexport)
#include "sample_header.h"
// Intialization of external
int a_flag = 15;
void m_func()
{
int i = 0;
}
Project 2:
**file2.h**
#include <stdio.h>
**file2.cpp**
#include "file1.h"
#include "sample_header.h"
// provided path of "sample_header.h" in additional include directory as well
void main()
{
if(a_flag > 0)
{
std::cout << "FLAG" ;
}
}
I set project1 as a DLL, project2 as an EXE project.
In linking, I am getting this error :
error LNK2001: `unresolved external symbol "__declspec(dllimport) int a_flg" (__imp_?a_flg##3HA)` in file2.cpp
I have read Microsoft page here about the DLL creation and linking but no idea how to resolve this external symbol error.
Thanks !
You need to set the project that creates your .dll to also generate the .lib file (an import library).
A quick description of the linkage should be something like this :
DLL Dependency Project -> dependecy.dll + dependency.lib
Main Project -> depends at runtime to depedency.dll , depends at link time to dependency.lib.
In other words, your .dll is just another binary that exposes some function signatures.
At runtime you can choose for either c linkage which involves querying the dll for the exposed functors/variables via name (the hard way, but useful when you don't have the .dll source code at hand) or use a more elegant way where you link the generated static library with your main.
When using the 1st approach, you will need to treat inside your code if you cannot find a certain .dll .
When using the 2nd approach, your binary will know that it depends on a certain .dll when you try to run it .
Here's an answer you will find very useful :
How do I build an import library (.lib) AND a DLL in Visual C++?
I have a VS2013 project with a class in a separate file where I want to
use the BeaEngine to disassemble a binary. I added all the necessary
files (BeaEngine.h and BeaEngine.lib) to the project and set the linker
to include the .lib. When I call the Disasm function from inside the
main() function my project compiles just fine, but when I try to call it
from inside one of the member functions of my class, I get the following
error:
error LNK2019: Verweis auf nicht aufgelöstes externes Symbol
"__imp__Disasm" in Funktion
""private: void __thiscall BinaryBlob::callScan(unsigned int,unsigned int)"
(?callScan#BinaryBlob##AAEXII#Z)"
So to me it looks like the linker cannot find the implementation for the Disasm function.
If I comment the following line out it will compile without an error.
len = Disasm( &(this->disasm) );
My includes are like follows:
#include "stdafx.h"
#include "BinaryBlob.h"
#define BEA_ENGINE_STATIC /* specify the usage of a static version of BeaEngine */
#define BEA_USE_STDCALL /* specify the usage of a stdcall version of BeaEngine */
#include "BeaEngine.h"
Do I need to do something else besides including the BeaEngine.h?
Any help would be really appreciated!
What this says is that the compiler can see the .h file (it recognizes the .h file name) but is not linked to the library itself. I'm using VC10 but you should need to do something like
Property Pages,
General, then add the directory of the lib under Additional Library Directories
then
Input,
Additional Dependencies, put the name of the library mylib.lib
If it's a .dll either just put it with the .exe of your program or add the path of the .dll to your system PATH
Basically it's like a lawn mower: If it's getting air, gas and a spark it will run.
Air = .h file
Gas = linked to .lib or .dll (or other things on Linux)
Spark = Your program calling the lib
I create two projects in VC++ Express 2010, one is DLLTest, the other is CODETest.
In DLLTest, declare and define a function func() as follows:
__declspec(dllexport) void func() {...};
Build DLLTest project successfully, DLLTest.dll and DLLTest.lib files created.
In CODETest, i want to use the exported function as follows:
#include "DLLTest.h"
int main()
{
...
func();
...
return 0;
}
Error occurs when build CODETest project--->"unresolved external symbol "void __cdecl letterList(void)" , but when i add DLLTest.lib into directory of CODETest project, build process successfully.
I dont know why? Thanks for help.
This seems all pretty unlikely, especially the part where "func" transformed into "letterList". Nevertheless, you have to tell the linker to also link the import library of the DLL so that it can resolve identifiers that are imported from that DLL. The easiest way to do that in MSVC is:
#include "DLLTest.h"
#pragma comment(lib, "dlltest.lib")
in CodeTest.cpp. The #pragma does the same thing as the linker's Additional Dependencies setting.