I'm learning how to build a DLL and call it from another project(I also want the DLL can be called not only by C/C++ but also by Python). Here is my code for building the DLL:
callbacktesetDLL.h:
#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif
typedef int(CALLBACK *p)(char*);
CALLBACKTESTDLL_API int __stdcall StrToInt(char*);
CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char*, int b);
callbacktestDLL.cpp:
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>
CALLBACKTESTDLL_API int __stdcall StrToInt(char* StrInput)
{
int IntResult;
IntResult = atoi(StrInput);
return IntResult;
}
CALLBACKTESTDLL_API char* __stdcall NumCompare(p FuncP, char* StrInput, int b)
{
int a = FuncP(StrInput);
if (a>b)
{
return "a is bigger than b";
}
else
{
return "b is bigger than a";
}
}
And a Source.def file:
LIBRARY
EXPORTS
StrToInt #1
NumCompare #2
With the code above, I got callbacktestDLL.dll and callbacktestDLL.lib. With depends, the functions' names in the DLL can be shown:
Now I want to call the functions in the DLL from another project:
CallDLL.h:
#pragma comment(lib,"callbacktestDLL.lib")
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
typedef int(*p)(char*);
extern "C" _declspec(dllimport) int StrToInt(char* InpuString);
extern "C" _declspec(dllimport) char* NumCompare(p FuncP, char*, int b);
CallDLL.cpp:
#include "stdafx.h"
int main()
{
p FuncP_R = StrToInt;
NumCompare(FuncP_R, "1234", 40);
return 0;
}
However, when I run the project, it told me:error LNK2019: unresolved external symbol __imp__StrToInt and error LNK2019: unresolved external symbol __imp__NumCompare. I've already copy the .lib and .dll files under the CallDLL project's root folder. Why this happens? How can I solve it? Thank you for your attention.
I finally made it. Here is the details:
The files that generate the DLL:
callbacktestDLL.h:
typedef int(CALLBACK *p)(char*);
extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);
extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b);
callbacktestDLL.cpp:
#include "stdafx.h"
#include <stdio.h>
#include "callbacktestDLL.h"
#include <stdlib.h>
extern "C" CALLBACKTESTDLL_API int __stdcall StrToInt(char* InputString)
{
int IntResult;
IntResult = atoi(InputString);
return IntResult;
}
extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b)
{
int a = FuncP(InputString);
if (a>b)
{
return "a is bigger than b\n";
}
else
{
return "b is bigger than a\n";
}
}
Comparing to the former files in the post, I removed the .def file and added extern "C" ahead of each function declaration and definition. Then I generate a new .dll and .lib files and copy them to the CallDLL projects' root folder. I used depends to see the functions' names in the DLL:
I also changed the CallDLL's file like this:
CallDLL.h:
#pragma comment(lib,"callbacktestDLL")
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
typedef int(__stdcall *p)(char*); //same as typedef int(CALLBACK *p)(char*) in callbacktestDLL.h
extern "C" _declspec(dllimport) int __stdcall StrToInt(char* InputString); //exactly same as what's in callbacktestDLL.h apart from dllimport
extern "C" _declspec(dllimport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); //exactly same as what's in callbacktestDLL.h apart from dllimport
CallDLL.cpp:
#include "stdafx.h"
int main()
{
p FuncP_R;
char* a = "1234";
FuncP_R = StrToInt;
printf(NumCompare(FuncP_R, a, 42));
return 0;
}
It worked as expected. I think one of the mistakes I made is missing __stdcall when importing. Maybe there are also mistakes about the name mangling. I'll keep testing it.
You should always include the same header file to define a consistent interface. Creating different header files is error prone. The next change to the interface might make the interface incompatible.
There is a slight difference between the module that implements the functions to the module that uses the functions. The difference is the __declspec(dllimport) or __declspec(dllexport). That's why the header files contains the
# ifdef CALLBACKTESTDLL_EXPORTS
Your module that implements the functions also export them. Therefore you must defined the symbols in the project settings. If you compile at the command line you have to add the /D CALLBACKTESTDLL_EXPORT to the compiler arguments.
BTW: If you have defined CALLBACKTESTDLL_EXPORT your macro CALLBACKTESTDLL_API contains the __declspec(dllexport). This causes the linker to create the DLL export table. The .DEF is not necessary. You should remove it because..... it defines the interface again (at a different level).
Related
I am trying out a simple test DLL project. Under my solution, I have two projects - first C++ Dll (library) and second C++ exe (driver). Below I've attached a snapshot of the basic project setup:
dllmain.h
#ifndef DLLMAIN_H_
#define DLLMAIN_H_
#ifdef FFMPEGLIB_EXPORTS
#define FFMPEGLIB_API __declspec(dllexport)
#else
#define FFMPEGLIB_API __declspec(dllimport)
#endif // FFMPEGLIB_EXPORTS
static void TestFoo();
extern "C" FFMPEGLIB_API void Test(int* num);
extern "C" FFMPEGLIB_API void ProxyFoo();
#endif
dllmain.cpp
#include "dllmain.h"
#include "A.h"
void TestFoo()
{
A a;
a.foo();
}
void Test(int* num)
{
*num = *num + 1;
}
void ProxyFoo()
{
TestFoo();
}
driver.cpp
#include <iostream>
#include "dllmain.h"
int main(int argc, char** argv)
{
int mum = 4;
Test(&num);
std::cout << num;
ProxyFoo();
return 0;
}
The library project compiles normally, but the exe fails to compile with a linker error:
Code Description Project File
LNK2001 unresolved extern symbol _imp_ProxyFoo driver driver.obj
LNK2001 unresolved extern symbol _imp_Test driver driver.obj
LNK1120 2 unresolved externals driver driver.exe
I have two questions here:
Why does the function name of dllmain.h get mangled in spite of being marked as extern "C"?
Why can I not create an instance of test class A from extern methods? What would be a good way of doing that?
Why the function name of dllmain.h getting mangled in spite being
marked as extern "C"?
Because __declspec(dllimport).
Why can I not create instance of test class A from extern methods?
What would be good way of doing it?
I think that's fine, but you didn't provide any class A code. Just do this:
class __declspec(dllexport) A
{
/* ... */
};
Why EXE compile failed?
This is because you have not imported the LIB file of the DLL into the project.
There are two ways to import it:
Add #program comment(lib, "<YOUR_LIB_FILE>.lib") to the code file.
Add <YOUR_LIB_FILE>.lib to Properties -> Linker -> Input -> Additional Dependencies.
Microsoft documentation: https://learn.microsoft.com/en-us/cpp/build/importing-and-exporting
You need to put the extern "C" thing around your function definitions that you intend to export in dllmain.cpp so it matches the linkage of your declaration.
Also, you need to do the declexport thing too.
extern "C"
{
__declspec(dllexport) void Test(int* num)
{
*num = *num + 1;
}
__declspec(dllexport) void ProxyFoo()
{
TestFoo();
}
}
I am very new to C++ and I'm trying to do my best to have a good project structure from the beginning.
I am using the C library libjpeg and was including it in my .cpp with the use of
extern "C" {
#include <jpeglib.h>
}
It worked fine until I removed it to put it in a header file which now gives me the following errors:
inc/jpeg_utils.h: 6: inc/jpeg_utils.h: extern: not found
inc/jpeg_utils.h: 8: inc/jpeg_utils.h: Syntax error: "}" unexpected
My headerjpeg_utils.h :
#ifndef JPEG_UTILS_INCLUDE
#define JPEG_UTILS_INCLUDE
#include <stdio.h>
extern "C" {
#include <jpeglib.h>
}
int read_jpeg_file(char *filename, int decompression);
void write_jpeg_file(char *filename, unsigned char *image_buffer, int image_width, int image_height, int quality);
#endif
And at the top of jpeg_utils.cpp :
#include "../inc/jpeg_utils.h"
Did I misunderstand the use of a header ?
If you include jpeg_utils.h in a C file, that extern "C" directive will not compile (obviously, C is not C++).
Add a pre-processor directive to extern "C" only when in fact you compile as C++.
#ifdef __cplusplus
extern "C" {
#endif
#include <jpeglib.h>
#ifdef __cplusplus
}
#endif
I'm trying to link C++ DLL into a new C++ DLL which i will create,
I've followed the below tutorial step by step and many others but something wrong the "GetProcAddress" function returns NULL "http://www.dreamincode.net/forums/topic/118076-dlls-explicit-linking/"
This is the Prototype of the function i try to call from the DLL :
int RemoveAllDataFile( unsigned int id );
the function returns with 1 so the DLL is loaded successfully.
typedef int (*funcRemoveAllDataFile) (int);
int load_dll_ARbnet(int x)
{
/* Retrieve DLL handle.*/
HINSTANCE hDLL = LoadLibrary("ArbNet2Remote.dll");
if (hDLL == NULL)
{
return 0;
}
else
{
}
/*Get the function address*/
funcRemoveAllDataFile RemoveAllDataFile = (funcRemoveAllDataFile)GetProcAddress(hDLL, "RemoveAllDataFile");
if (RemoveAllDataFile)
{
return 2;
}
else
{
return 1;
}
}
The function you export from the other DLL should be declared extern "C" if using C++ source. If should be exported either with a .def file or using __declspec(dllexport):
Here's a typical DLL header file that works with .c or .cpp and both calling conventions:
#ifdef MYAPI_EXPORTS
#define MYAPI __declspec(dllexport)
#else
#define MYAPI __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
MYAPI int __cdecl func1(int x);
MYAPI int __stdcall func2(int x);
#ifdef __cplusplus
}
#endif
DLL source:
#define MYAPI_EXPORTS
#include "x.h"
int func1(int x)
{
return x*2;
}
int __stdcall func2(int x)
{
return x*3;
}
And usage:
#include <windows.h>
#include <stdio.h>
typedef int (__cdecl *FUNC1)(int);
typedef int (__stdcall *FUNC2)(int);
int main()
{
HINSTANCE hDLL = LoadLibrary("x");
FUNC1 func1 = (FUNC1)GetProcAddress(hDLL, "func1");
#ifdef _WIN64
FUNC2 func2 = (FUNC2)GetProcAddress(hDLL, "func2");
#else
FUNC2 func2 = (FUNC2)GetProcAddress(hDLL, "_func2#4");
#endif
printf("%d %d\n",func1(5),func2(5));
}
Name decoration can be discovered with dumpbin /exports <dll>. Note that x64 and x86 differ. Below is for x86:
ordinal hint RVA name
2 0 00001010 _func2#4
1 1 00001000 func1
Look at the DLL's actual exports, such as with a reporting tool like TDUMP or similar. The function you are looking for is not being exported as "RemoveAllDataFile" like you are expecting. It is actually being exported like "_RemoveAllDataFile" instead, or even something like "_RemoveAllDataFile#4".
If you are compiling the original DLL, and want the function exported as "RemoveAllDataFile", you will have to wrap the declaration of the exported function with extern "C" to remove any C++ name mangling from the exported name. Depending on your C++ compiler, you may also need to use a .def file to remove the leading underscore that is imposed by the __cdecl calling convention. When using C linkage, some C++ compilers export __cdecl functions with the leading underscore (such as Borland) and some do not (such as Microsoft).
But if you are not recompiling the original DLL, then you have no choice but to look at the DLL's exports and change your GetProcAddress() call to use the proper name that is actually being exported.
I want to debug a DLL.
This DLL exports some functions and voids:
This is the header:
#ifdef CODEC_EXPORTS
#define CODEC_API __declspec(dllexport)
#else
#define CODEC_API __declspec(dllimport)
#endif
extern "C" CODEC_API int __stdcall SpxInit(void);
extern "C" CODEC_API int __stdcall SpxEncode(unsigned char* inBuf, unsigned char* outBuf, unsigned int inlen);
extern "C" CODEC_API int __stdcall SpxEncodeNormal(void);
extern "C" CODEC_API int __stdcall SpxDecode(unsigned char* DinBuf, float* DoutBuf, unsigned int Dinlen);
extern "C" CODEC_API int __stdcall SpxFree(void);
#pragma comment(linker, "/export:SpxEncode=_SpxEncode#12")
#pragma comment(linker, "/export:SpxEncodeNormal=_SpxEncodeNormal#0")
#pragma comment(linker, "/export:SpxDecode=_SpxDecode#12")
#pragma comment(linker, "/export:SpxInit=_SpxInit#0")
#pragma comment(linker, "/export:SpxFree=_SpxFree#0")
I added a new project to my solution and simply added the following cpp file:
#include "stdafx.h"
#include "codec.h"
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
Now before trying anything else, I simply wanted to compile the new project, but VC2010 is telling me
"error LNK2001" Unresolved external symbol "_SpxDecode#12"
"error LNK2001" Unresolved external symbol "_SpxEncode#12"
etc...
So I guess I missed something, but I don't see what.
You need to add reference to your dll project
Project properties->Common Properties->References
I can`t export an array from a DLL. Here is my code:
" DLL header "
#ifdef EXPORT
#define MYLIB __declspec(dllexport)
#else
#define MYLIB
#endif
extern "C" {
/* Allows to use file both with Visual studio and with Qt*/
#ifdef __cplusplus
MYLIB double MySum(double num1, double num2);
extern MYLIB char ImplicitDLLName[];
#else
extern Q_DECL_IMPORT char ImplicitDLLName[];
Q_DECL_IMPORT double MySum(double num1, double num2);
#endif
}
" DLL source"
#define EXPORT
#include "MySUMoperator.h"
double MySum(double num1, double num2)
{
return num1 + num2;
}
char ImplicitDLLName[] = "MySUMOperator";
" client main.cpp"
int main(int argc, char** argv)
{
printf("%s", ImplicitDLLName);
}
When building I am getting from the linker this error:
Error 2 error LNK2001: unresolved external symbol _ImplicitDLLName \Client\main.obj
// My purpose of exporting the array is to study export of different data structs from DLLs
How to cope with the error raised by linker and what rules are violated?
*UPDATE: *
IDE Visual Studio 2010.
Client - is written on C++, also DLL is on C++
Assuming you're linking your import library correctly (and thats a big assumption), you're not declaring MYLIB correctly for importing symbols:
This:
#ifdef EXPORT
#define MYLIB __declspec(dllexport)
#else
#define MYLIB
#endif
Should be this:
#ifdef EXPORT
#define MYLIB __declspec(dllexport)
#else
#define MYLIB __declspec(dllimport)
#endif
Keep in mind we've little context to work with. It looks like you're trying to consume this from a C-compiled application, but without more info I can't be sure. If that is the case, then Q_DECL_IMPORT had better do the above or it still will not work. I'd start with a basic "C" linkage export and work your way up from there.
Sample EXPORTS.DLL
Exports.h
#ifdef EXPORTS_EXPORTS
#define EXPORTS_API __declspec(dllexport)
#else
#define EXPORTS_API __declspec(dllimport)
#endif
extern "C" EXPORTS_API char szExported[];
Exports.cpp
#include "stdafx.h"
#include "Exports.h"
// This is an example of an exported variable
EXPORTS_API char szExported[] = "Exported from our DLL";
Sample EXPORTSCLIENT.EXE
ExportsClient.cpp
#include "stdafx.h"
#include <iostream>
#include "Exports.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
cout << szExported << endl;
return 0;
}
Output
Exported from our DLL