I am trying to use a C++Builder 11.1.5 created DLL in MSVC 2022 C++ project. Both are 32bit. I can't build the DLL in MSVC as it uses some VCL objects.
My C++ Builder defines the external function thus:
extern "C" __declspec(dllexport) void __stdcall SetEnabled(bool val) {
...
}
MSVC uses a header to reference the function:
extern "C" __declspec(dllimport) void __stdcall SetEnabled(bool val) ;
I have created a .DEF file with the same name as the DLL, containing this:
LIBRARY MYTESTDLL
EXPORTS
SetEnabled
And I have generated a .LIB file from this .DEF file using MS lib.exe:
lib.exe /DEF:MYTESTDLL.def /out:MYTESTDLL.lib /MACHINE:x86
Finally, I have added MYTESTDLL.lib to my MSVC project in the Linker->Additional Dependencies section.
But, when I build the program, I get this error:
Error LNK2019 unresolved external symbol __imp__SetEnabled#4 referenced in function _WinMain#16
I've tried adding the ordinal (#4) to my .DEF file and rebuilding the .LIB file, but I still get the same error.
In a hex editor, I can that __imp__SetEnabled is in the .LIB file, but clearly not in a way that MSVC likes.
Have I missed a step somewhere? Is there anything obviously wrong with what I've done?
Changing the MSVC header used to reference the function to:
extern "C" __declspec(dllimport) void SetEnabled(bool val) ;
and adjusting the C++Builder DLL to export the functions using __cdecl resolved the issue. I didn't realize that the __stdcall exported functions need decorating in .DEF file.
That said, I find that the DLL is fine unless I try to execute code in it that uses the VCL. Then things don't work properly. I wonder if it's not possible to write a DLL in C++Builder containing VCL code for use in MSVC?
Related
I'm working on an older c++ Visual Studio 2003 project which uses a static .lib (of which the source code is lost to time) that I would like to move to Visual studio 2010 or newer. There are a bunch of LNK2001 linker errors, all to the same symbol, when trying to build in 2010:
LNK2001: unresolved external symbol "__declspec(dllimport) >public: char const * >__thiscall type_info::name(void)const " (__imp_?>name#type_info##QBEPBDXZ)
After doing some digging, it appears that trying to build with an older static library in a newer version of MS c++ is troublesome or possibly impossible and this particular error occurs because the newer MSVCRT.dll used by VS2005+ has a different definition for type_info::name(void):
type_info::name(__type_info_node*)
There is an MSDN forum issue here with the same problem, which it appears the original poster may have gotten a solution to - he at least got it to build, which I was not able to do using the workaround given of putting the following code into the project:
#include "stdafx.h"
#pragma warning(disable:4273)
struct __type_info_node {
void *memPtr;
__type_info_node* next;
};
extern __type_info_node __type_info_root_node;
class type_info {
public:
__declspec(dllimport) const char* name() const;
__declspec(dllimport) const char* name(__type_info_node*) const;
};
const char* type_info::name() const {
return name(&__type_info_root_node);
}
I tried building in different ways with that code - inserted into an existing file, a new file, and compiling it into a .obj and using the lib.exe tool to update the original .lib with said .obj and then building, but all attempts ended up with the original errors or different ones - redefinition errors for type_info::name. I'm fairly new to c/c++ & VS so maybe I'm missing something.
Does anyone know of a way to workaround this and build in a newer version of VS? Or am I stuck using the 2003 version?
I've a header file having a "extern class definition" in it. Both these header file and class are in different C++ assembly. Now there is a class in different C++ assembly which is trying to access this "extern" class functions but there are all sorts of linker errors such as LNK2001: unresolved external symbol " class LMSystem LM"(?LM##3VLMSystem##A),LNK2019 etc.
Following is the code snippet:for CPP file
/This header file contains the extern reference/
#include "../lm/lm.h"
BOOL FDInitHW (void)
{
char pFileName[TALLY_MAX_PATH];
ASSERT(0 != g_pFdbPath);
strcpy(pFileName, g_pFdbPath);
strcat(pFileName, FILENAME_HW_KB);
return SUCCESS == LM.LMIOListReadSelective(pFileName,
LMIO_READREPLACE, FDGetSelectListPtrArray());
}
Contents of Lm.h
class LMSystem
{
public:
LMSystem();
~LMSystem();
// getting a specific list
short LMIOListReadSelective(char *fname, unsigned short readflags, LIST_SELECTOR* select_array[]);
};
extern LMSystem LM; // the library global LMSytem
So can you help me in resolving this linker error?
I think it has to do something with project properties as the old assembly developed in VC++ 6.0 is working fine and even in this Win32 C++ assembly,which I'm creating in VS2012,I'm able to go to definition of the LMSystem class using F12 or Intellisense but ideally it should point me to the variable in LM.H header file.
I've seen many post telling how to use functions of one type defined in different C++.dll in another C++ .dll. There are many project level settings changes but it doesn't always give me the correct results. So if anybody can give me a solution to this issue then it will be great help.
Instance of LM needs to be created somewhere and your linker must be able to find it. For example add LMSystem LM; to one of your source (.cpp) files
I am playing with DLLs to get a better understanding of them. So I created a simple dll (with load-time dynamic linking) which has functions to Add, Sub and Mul. In the header file for the dll I used __declspec(dllexport) for the function declaration.
For the executable, I added the .lib created after compiling the dll to the properties (for linking). After that I directly called the function Add without using __declspec(dllimport). The program worked. I then changed the function calling to __declspec(dllimport) (Add) and the program worked again.
I am not able to understand what the need of __declspec(dllimport) is? I have not yet coded a run-time linking DLL but from the examples I have seen, dllimport is not needed in that case as well.
Thanks for your assistance.
I have a small issue when it comes to writing a DLL in MSVC (the 2010 version in particular).
My program consists of the main part and a DLL. The DLL contains a function that is
__declspec(dllexport) int test_function(void) {
return 42;
}
The file is compiled using a DLL project (not using pre-compiled headers, I have chosen a empty DLL project). Now, when I want to list the exported symbols using the dumpbin tool, the test_function is not listed under exports. Is there a specific setting that forces __declspec(dllexport) to actually export symbols?
Any help is welcome. Thank you!
That should do it. If this is the whole code, check the following:
1) You are actually checking the correct dll. Look at the timestamp. Double-check the location and the name.
2) You are compiling the specified cpp (I take it your definition is in the cpp file). Just because the file is in the directory doesn't mean it gets compiled, make sure it is added to the project.
3) Make sure your function is not excluded from the compilation unit by preprocessor directives.
Also look for other symbols and try to see what differences are there between the symbols that get exported and your function.
If this fails, you should move __declspec(dllexport) to your .h file and the definition (without __declspec(dllexport) ) to your .cpp. It might not be exported because the compiler might try to optimize it out by inlining it.
I'm new to vc++. I've just built a software and it generated a .dll and a .lib. I need to use functions from this in my code. Do I need to link to both .lib and .dll to build my code? What project properties do I have to alter to do this linking?
Actually, you need only the .dll file. It contains all the necessary code and data to run it's functions. It also contains a table that links the symbolic names of the functions (e.g. the function PrintMe), their ordinals (the number of that function in the DLL) and their addresses in the DLL.
If you want to use only the DLL, you have to "manually" get the symbols resolved:
Let's say you want to use the function PrintMe of the DLL. What you had to do is to resolve it's name (PrintMe) or it's ordinal (PrintMe is the 1st function of the DLL) to it's address. For this, you could use LoadLibrary, GetModuleHandle and GetProcAdress from the Win32 API (aka Windows SDK). Additionally, this method allows you to load the DLL at runtime (see below).
The easier way is to use the MSVC(++) features __declspec(dllexport) and __declspec(dllimport), e.g.
// your DLL
__declspec(dllexport) void PrintMe()
{
printf("Hello World!");
}
// you project to use the DLL
__declspec(dllimport) void PrintMe();
The first one (dllexport) tells the compiler to export the function. The second one (dllimport) is the interesting one: It creates all the necessary code to be able to use the function from the DLL.
For this, you need the .lib file in your project (which wants to use the DLL). The .lib file contains information for the linker to resolve the symbol name (PrintMe) to its address in the DLL. Since the .lib is statically bound, the linker can make use of it - the DLL on the contrary is bound at runtime / loading time, so the linker cannot use it. (Yes, the information in the .lib file is redundant.). Note: You cannot change the whole DLL when using this method w/o rebuilding your project with the new .lib file. Some structure changes affect the addresses of the functions in the DLL, see this SO answer.
One last difference between using the Win32 API (LoadLibrary...) and the MSVC method via __declspec is the loading of the DLL. When you use LoadLibrary, the DLL is loaded at runtime, of course (so you can catch exceptions when it cannot be found and so on). The other method loads the DLL at loading time, so you program will terminate (will not run) when Windows cannot find the DLL.
When you create a project in VS, you can activate the "export symbols" checkbox at the end of a wizard (Win32 project). That gives you some examples of exported symbols. Additionally, it introduces a macro plus a preprocessor defition plus some directives that are very useful:
// DLL header
#ifdef _YOUR_DLL_EXPORTS
#define YOUR_DLL_API __declspec(dllexport)
#else
#define YOUR_DLL_API __declspec(dllimport)
#endif
YOUR_DLL_API PrintMe();
You now can use this header file to build you DLL as your DLL project has that _YOUR_DLL_EXPORTS definition (see project properties page, C++, preprocessor). The project that uses the DLL can use this header, too, but then must not have such a name defined. When you include the header file in the project in which you want to use the DLL, the macro is resolved to __declspec(dllimport). This instructs the linker to look for this function (which is found in the .lib file) and create all the necessary code to load the DLL at runtime and resolve the symbol name.