Importing a DLL and using an extern function in C++ - c++

This must be a basic question but I am struggling with this problem for too long now.
I've looked everywhere on Google and found some similar problems and solutions but none that solved my specific problem.
I've written a very basic C++ DLL. In fact it is almost in C style because the DLL only has a main.cpp code file with a function in it so it's not even using a class.
Then I have two header files :
MqlUtils.h :
#ifndef MQLUTILS_H
#define MQLUTILS_H
struct MqlStr
{
int len;
char *string;
};
enum TradeOperation
{
OP_BUY = 0,
OP_SELL = 1,
OP_BUYLIMIT = 2,
OP_SELLLIMIT = 3,
OP_BUYSTOP = 4,
OP_SELLSTOP = 5
};
#endif
main.h :
#ifndef _DLL_H_
#define _DLL_H_
#include "MqlUtils.h"
#define MT4_EXPFUNC __declspec(dllexport)
#define export extern "C" __declspec( dllexport )
MT4_EXPFUNC int __stdcall GetOrdersDetailsNoSymbol(const int orderCount, const char * MasterLicense, const char * SlaveLicense, int orderTicket[], int op[],
double orderOpenPrice[], double orderStoploss[],
double orderTakeProfit[], double orderLots[], int orderDateTime[],
MqlStr * ordersymbol, MqlStr * ordercomments, int lotsCopyingMethod[], int returnedOrders[]);
#endif /* _DLL_H_ */
In fact, for creating my DLL, I started with existing code that someone else wrote, so the .cpp file for my DLL has some obscure syntax that I am not even sure what it is doing. Here's an excerpt of what the .cpp looks like :
#include "main.h"
#define _UNICODE 1
#define UNICODE 1
#define WIN32_LEAN_AND_MEAN
// ...
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#if BUILDING_DLL
#define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
#define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */
// ...
#ifdef __cplusplus
extern "C"
{
#endif
// ... function code
#ifdef __cplusplus
}
#endif
I did not include everything that is in the .cpp file, where there are // ... there is something else but it's basic stuff that I understand well so it shouldn't be the source of my problem...I'll be glad to post more as needed.
I am not an expert with all the obscure keywords like __declspec and such, but the DLL as it is, can be succesfully imported and the function GetOrdersDetailsNoSymbol can be used by some program, namely MetaTrader 4 (which is the main goal of my lib).
But now I would like to be able to test my library with a C++ program, so I created an empty console program, added the library project to the testing project's references and linked the .obj and .h files through the testing project's properties.
I am currently getting this when I compile the testing project :
Error 2 error LNK1120: 1 unresolved externals Z:\Codes\Debug\TestsCpp.exe TestsCpp
Error 1 error LNK2019: unresolved external symbol "__declspec(dllimport) int __cdecl GetOrdersDetailsNoSymbol(int,char *,char *,int * const,int * const,double * const,double * const,double * const,double * const,int * const,struct MqlStr *,struct MqlStr *,int * const,int * const)" (__imp_?GetOrdersDetailsNoSymbol##YAHHPAD0QAH1QAN2221PAUMqlStr##311#Z) referenced in function "void __cdecl TestClient(void)" (?TestClient##YAXXZ) Z:\Codes\TestsCpp\main.obj TestsCpp
Oh and here's the main.cpp for the testing project :
#include "MqlUtils.h"
#include "main.h"
extern __declspec(dllimport) int GetOrdersDetailsNoSymbol(int orderCount, char * MasterLicense, char * SlaveLicense, int orderTicket[], int op[],
double orderOpenPrice[], double orderStoploss[],
double orderTakeProfit[], double orderLots[], int orderDateTime[],
MqlStr* ordersymbol, MqlStr* ordercomments, int lotsCopyingMethod[], int returnedOrders[]);
void TestClient()
{
char* Master = "7C83C4C2";
char* Slave = "3B7C22A";
int returnedOrderCount[1] = {0};
double aStoredOrderOpenPrice[4];
int aStoredOrderType[4];
int aStoredOrderTicket[4];
double aStoredOrderStopLoss[4];
double aStoredOrdeTakeProfit[4];
double aStoredOrderLots[4];
int aStoredOrderDateTime[4];
int aStoredLotsMethods[4];
MqlStr* aStoredOrderComment[4];
MqlStr* aStoredOrderSymbol[4];
for (int i = 0; i < 4; i++)
{
aStoredOrderOpenPrice[i]= -1;
aStoredOrderType[i]= -1;
aStoredOrderTicket[i]= -1;
aStoredOrderStopLoss[i]= -1;
aStoredOrdeTakeProfit[i]= -1;
aStoredOrderLots[i]= -1;
aStoredOrderDateTime[i]= -1;
aStoredLotsMethods[i]= -1;
aStoredOrderComment[i]->len = 56;
aStoredOrderComment[i]->string = "11111111111111111111111111111111111111111111111111111111";
aStoredOrderSymbol[i]->len = 56;
aStoredOrderSymbol[i]->string = "11111111111111111111111111111111111111111111111111111111";
}
GetOrdersDetailsNoSymbol(1, Master, Slave, aStoredOrderTicket, aStoredOrderType,
aStoredOrderOpenPrice, aStoredOrderStopLoss,
aStoredOrdeTakeProfit, aStoredOrderLots, aStoredOrderDateTime,
*aStoredOrderSymbol, *aStoredOrderComment, aStoredLotsMethods, returnedOrderCount);
}
int main(int argc, char **argv)
{
TestClient();
return 0;
}
If anyone could help me solve this, I would be infinitely grateful.
Thanks for reading!

Your two declarations of GetOrdersDetailsNoSymbol do not match. In your header file you declare it with __stdcall and in main.cpp you don't. You should have only a single declaration. It can use #define and #ifdef to apply the dllimport or dllexport keywords as appropriate.
EDIT: Also, get rid of the extern "C" statements. And then use the DLLIMPORT #define to declare your function and only #define BUILDING_DLL in the build of your DLL.

Related

C++ dll and name mangling issue

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();
}
}

error LNK2019 when importing functions from a DLL

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).

error resolving external symbol

I am trying to create a simple c++ project in Visual studio 2015
Peakdetector.h
#ifndef PEAKDETECTOR_H
#define PEAKDETECTOR_H
//-------------------------------------------------------
#ifdef DLL_BUILD_SETUP
#ifdef Q_OS_LINUX
#define DLLSPEC __attribute__((visibility("default")))
#else
#define DLLSPEC __declspec(dllexport)
#endif
#else
#ifdef Q_OS_LINUX
#define DLLSPEC
#else
#define DLLSPEC __declspec(dllimport)
#endif
#endif
namespace vpg {
#ifndef VPG_BUILD_FROM_SOURCE
class DLLSPEC PeakDetector
#else
class PeakDetector
#endif
private:
int __seek(int d) const;
double __getDuration(int start, int stop);
}
inline int PeakDetector::__seek(int d) const
{
return ((m_intervalslength + (d % m_intervalslength)) % m_intervalslength);
}
#endif
PeakDetector.cpp
#include "stdafx.h"
#include "peakdetector.h"
namespace vpg {
void PeakDetector::__updateInterval(double _duration)
{
//other stuff
}
}
When I try to run this application i get error
LNK2019 unresolved external symbol "__declspec(dllimport) private: int __cdecl vpg::PeakDetector::__seek(int)const " (__imp_?__seek#PeakDetector#vpg##AEBAHH#Z) referenced in function "private: void __cdecl vpg::PeakDetector::__updateInterval(double)" (?__updateInterval#PeakDetector#vpg##AEAAXN#Z) MyCustomProject
I am new to this and cannot figure out why am I having this error.I have just copy pasted this code from an example.Please let me know if I am missing any code. Also I dont have any .lib files.
You must add the DLL_BUILD_SETUP the defines in Visual Studio.
In order to do that, yo must go to
Project Settings -> C/C++ -> Preprocessor -> Preprocessor definitions
and add the definition to the list.
You must use the spec __declspec(dllexport) when compiling the library that is exporting the symbols (in this case the class), and __declspec(dllimport) in the project that USES that library.
I see from the source code that you've provided that there is an additional definition VPG_BUILD_FROM_SOURCE which disables the export in order to using static/inline linking, you may try to add that define instead.

Creating Cuda dll and using it on VC++ project

I have a CUDA project in visual studio 2012 containing a function that I want to use it in a VC++ project thanks to Mr.Crovella I changed my CUDA project target from .exe to .dll in project properties/Configuration Properties/General/Configuration Type. here is my header file defining my function:
kernel.h
#ifndef KERNEL_H
#define KERNEL_H
#ifdef __cplusplus
extern "C" {
#endif
void __declspec(dllexport) cuspDsolver(int *rowOffset, int *colIndex, double *values , double *X, double *rhs, int size, int nnz);
#ifdef __cplusplus
}
#endif
#endif
and here is my function implementation:
kernel.cu
#include "kernel.h"
#include <cusp/krylov/cg.h>
#include <cusp/csr_matrix.h>
#include <cusp/hyb_matrix.h>
#include <cusp/gallery/poisson.h>
#include <cusp/io/matrix_market.h>
#include <cusp\print.h>
#include <fstream>
#include <conio.h>
#include <math.h>
#include <iostream>
#include <windows.h>
using namespace std;
void cuspDsolver(int *rowOffset, int *colIndex, double *values , double *X, double *rhs, int size, int nnz)
{
cusp::csr_matrix<int,double,cusp::device_memory> A(size,size,nnz);
for (int i = 0; i < (size+1); i++)
{
A.row_offsets[i] = rowOffset[i];
}
for (int i = 0; i < nnz; i++)
{
A.column_indices[i] = colIndex[i];
A.values[i] = values[i];
}
cusp::array1d<double,cusp::device_memory> XX(size,0.);
cusp::array1d<double,cusp::device_memory> B(size,0.);
for (int i = 0; i < size; i++)
{
B[i] = rhs[i];
}
cusp::krylov::cg(A,XX,B);
for (int i = 0; i < size; i++)
{
X[i] = XX[i];
}
}
and here is my VC++ project(it is a static library system.lib project which will be used in quickMain.exe) and how I tried to use my .dll file:
system.lib
#ifdef __cplusplus
extern "C" {
#endif
void __declspec ( dllimport ) cuspDsolver(int *rowOffset, int *colIndex, double *values , double *X, double *rhs, int size, int nnz);
#ifdef __cplusplus
}
#endif
.
.
.
.
.
.
.
int
ProfileSPDLinDirectSolver::solve(void){
.
.
.
.
cuspDsolver(rowOffset,colIndex,values,answer,rightHandSide,theSize,nnz);
.
.
.
.
}
when I want to build this project(I did copy my dll file to solution directory and and solution/Debug directory) I get these errors, would you please tell me if I did anything wrong on creating or using this dll?
error LNK2019: unresolved external symbol __imp__cuspDsolver referenced in function "public: virtual int __thiscall ProfileSPDLinDirectSolver::solve(void)" (? solve#ProfileSPDLinDirectSolver##UAEHXZ) 2012\Projects\Ardalan_12\Win32\proj\quickMain\system.lib(ProfileSPDLinDirectSolver.obj)
error LNK1120: 1 unresolved externals C:\Users\Administrator\Documents\Visual Studio 2012\Projects\Ardalan_12\Win32\bin\quickMain.exe 1
Once the dll is created from kernel.cu, you will have a dll library file (say, kernel.dll) and a dll library import file (say, kernel.lib) produced.
In your VC/VS project definition for any project that wishes to use that dll, you must link against the dll library import file:
nvcc ... -lkernel
The process of adding this library to your project definition is the same process you would use for adding any other library. Make sure the kernel.dll and kernel.lib are on the linker paths you specify, also.
And, at runtime, your kernel.dll library will need to be either in the same directory as your executable or else in the windows dll load path.
You need to add __declspec(dllexport) modifier on the function declarations. This modifier tells the compiler and linker to export a function or variable from the DLL for use by other applications.
Add the followings to your kernel.h,
#pragma once
#ifdef KERNEL_EXPORTS
#define KERNEL_API __declspec(dllexport)
#else
#define KERNEL_API __declspec(dllimport)
#endif
extern "C" KERNEL_API void cuspDsolver(int *rowOffset, int *colIndex, double *values ,double *X, double *rhs, int size, int nnz);
For details, please reference to:
https://learn.microsoft.com/zh-tw/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=vs-2019#to-add-a-header-file-to-the-dll

Debugging a DLL that uses __stdcall and pragma linker

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