Importing a C DLL's functions into a C++ program - c++

I have a 3rd party library that's written in C. It exports all of its functions to a DLL.
I have the .h file, and I'm trying to load the DLL from my C++ program.
The first thing I tried was surrounding the parts where I #include the 3rd party lib in
#ifdef __cplusplus
extern "C" {
#endif
and, at the end
#ifdef __cplusplus
} // extern "C"
#endif
But the problem there was, all of the DLL file function linkage looked like this in their header files:
a_function = (void *)GetProcAddress(dll, "a_function");
While really a_function had type int (*a_function) (int *). Apparently MSVC++ compiler doesn't like this, while MSVC compiler does not seem to mind.
So I went through (brutal torture) and fixed them all to the pattern
typedef int (*_x_a_function) (int *); // using _a_function will not work, C uses it!
_x_a_function a_function ;
Then, to link it to the DLL code, in main():
a_function = (_x_a_function)GetProcAddress(dll, "a_function");
This SEEMS to make the compiler MUCH, MUCH happier, but it STILL complains with this final set of 143 errors, each saying for each of the DLL link attempts:
error LNK2005: _x_a_function already defined in main.obj main.obj
Multiple symbol definition errors.. sounds like a job for extern! SO I went and made ALL the function pointer declarations as follows:
function_pointers.h
typedef int (*_x_a_function) (int *);
extern _x_a_function a_function ;
And in a cpp file:
function_pointers.cpp
#include "function_pointers.h"
_x_a_function a_function ;
ALL fine and dandy.. except for linker errors now of the form:
error LNK2001: unresolved external symbol _a_function main.obj
Main.cpp includes "function_pointers.h", so it should know where to find each of the functions..
I am bamboozled. Does any one have any pointers to get me functional? (Pardon the pun..)

Linker errors like that suggest you've defined all the functions in function_pointers.cpp, but forgotten to add it to the project/makefile.
Either that, or you've forgotten to "extern C" the functions in function_pointers.cpp too.

I believe that if you declared the typedefs and/or the prototype as extern "C", you must remember to extern "C" the definition too.

When you link C functions the prototypes will get a leading _ in front of them by default so
when you do a typedef using the same name
typedef int (*_a_function) (int *);
_a_function a_function
you'll get issues because there is already a function in the dll named _a_function.

Usually you declare a function in yourlibrary.h like extern "C" __declspec(dllexport) int __cdecl factorial(int); then create that function in yourlibrary.c:
extern "C" __declspec(dllexport) int __cdecl factorial(int x) {
if(x == 0)
return 1;
else
return x * factorial(x - 1);
}
After compiling your DLL you get your .dll and .lib files. The latter is used when you want to import your functions to the project. You put #include "yourlibrary.h" and #pragma comment(lib, "yourlibrary.lib") in your project, after this you can use int factorial(int) in you application.

Related

LNK2019: Calling C function from CPP code

I have created an MSVS2015 project (MFC/C++) which
links with a static C library. When I build the
projects I get the following error:
error LNK2019:
unresolved external symbol "void __cdecl testLinkerError(void)" (?testLinkerError##YAXXZ) referenced
in function "void __cdecl test1(void)" (?test1##YAXXZ) [PATH_REMOVED]\test.obj [NAME_OF_MFC_PROJECT]
For debugging purposes, I have created 3 files:
test.cpp
linkertest.c
linkertest.h
test.cpp has been added to the MFC project and it looks like this:
#include "linkertest.h"
void test1(void)
{
testLinkerError();
}
The header file linkertest.h looks like this:
#pragma once
#ifdef _cplusplus
extern "C" {
#endif
void testLinkerError(void);
#ifdef _cplusplus
}
#endif
And linkertest.c looks like this:
#include "linkertest.h"
void testLinkerError(void) {
int x = 5;
int y = 7;
int z = x + y;
}
I am quite sure that this is some kind of name mangling issue, but I can't figure out how to solve it.
The calling convention in both projects is set to __cdecl
based on the compiler error, you compiler tried to look up ?testLinkerError##YAXXZ which is a C++ function name. so which means on your import part (not your DLL export) you did not use extern "C"....
and one more thing, The name __cplusplus (two underscores) is defined to the value 201402L when compiling a C++ translation unit. please check your code make sure _cplusplus (one underscore) is defined.

Why new VS2013 project's functions are unresolved in linking if file is .cpp, but ok if file is .c

I'm linking all the native libs to a .dll which is used in WPF application.
I'm done this with other projects that are compiled to libs but the latest one does not work somehow, although all seems to be same way. I did like this:
.h:
#ifndef MYHEADER_H_
#define MYHEADER_H_
#ifdef __cplusplus
extern "C" {
#endif
void MySetLoginResultCallback(int(*Callback)(int Ok, const char *UserName));
#ifdef __cplusplus
} // end of extern "C"
#endif
#endif // MYHEADER_H_
.cpp:
typedef int(*LoginResultCB_t)(int IsOk, const char *UserName);
LoginResultCB_t gLoginResultCB;
void MySetLoginResultCallback(LoginResultCB_t pCB)
{
gLoginResultCB = pCB;
}
extern "C" __declspec(dllexport) int MyLoginResultCB(int Ok, cons char *UserName)
{
if (gLoginResultCB)
return gLoginResultCB(Ok, UserName);
return -1;
}
MyLoginResultCB is imported to WPF exe and called from there. In initialization the MySetLoginResultCallback is called from a C-file in native .dll.
In .dll linking I get unresolved error from MySetLoginResultCallback (which is called in native .c file). If I leave the header exactly the same and rename .cpp -> .c and remove extern "C" the .dll linking succeeds. What am I missing here?
call from aini.c
MySetLoginResultCallback(XpAfterLoginCB);
error:
1>aini.obj : error LNK2019: unresolved external symbol _MySetLoginResultCallback referenced in function _InitNoAKit
In your .cpp file, you're defining a function MySetLoginResultCallback with C++ language linkage. That's a different function than the function MySetLoginResultCallback with C language linkage declared in the .h file.
The correct solution would be to add C language linkage to the .cpp file:
extern "C" {
typedef int(*LoginResultCB_t)(int IsOk, const char *UserName);
LoginResultCB_t gLoginResultCB;
void MySetLoginResultCallback(LoginResultCB_t pCB)
{
gLoginResultCB = pCB;
}
}
Notice that function types have language linkage too, which means that the typedef LoginResultCB_t has to be declared with C language linkage in the .cpp file also, because the parameter is declared as such in the .h file.
The reason the way that extern "C" definitions ONLY in .h file worked in other projects/libs is that I included my header file with function declarations in my .cpp file with the definitions. Thanks to #molbdnilo to point this out!

LNK2019: unresolved external symbol in function

I'm using VS2008 WinCE7. I'm facing linking error during build.
The file system structure is
menu.c - ./menu.c
eboot.h - ./eboot.h
file_1.cpp - ./dir1/file_1.cpp
where . represents current directory
menu.c
#include <eboot.h>
static VOID OALWriteToEMMC(OAL_BLMENU_ITEM *pMenu);
VOID OALWriteToEMMC(OAL_BLMENU_ITEM *pMenu)
{
OALTestEMMC();
}
file_1.cpp
#include <eboot.h>
VOID OALTestEMMC();
VOID OALTestEMMC()
{
//some code
}
eboot.h
VOID OALTestEMMC();
I'm getting the error
menu.obj : error LNK2019: unresolved external symbol OALTestEMMC referenced in function OALWriteToEMMC
Please guide me how to solve it.
EDIT1:
menu.c
#ifdef __cplusplus
extern "C" VOID OALTestEMMC();
#endif
and removed the declaration in eboot.h and added it in file_1.cpp
But, the error persists.
It seems that you are compiling the function definition in C++ but the use of that function in C. Without making the function extern "C" in C++, the compiler will mangle the name, and generate a symbol that won't match the declaration used in the C code.
If you want to mix C and C++, make sure that the declarations in C++ are marked extern "C" so that the compiler won't mangle the names and will use the C calling conventions. Alternatively, compile everything in C++ (or in C)
David Rodríguez's original answer is correct. You are invoking a C++ function (OALTestEMMC) from a C source file. As David mentioned, the C++ compiler will mangle the function name. In order to suppress the name mangling so that the code in menu.c can invoke it, place the 'extern "C"' qualifier on the OALTestEMMC function (in file_1.cpp):
extern "C" VOID OALTestEMMC();
extern "C" VOID OALTestEMMC() {
// stuff
}

unresolved external symbol _CLSID_VdsLoader

I'm trying to write a program that can manage the harddisks/volumes/partitions in a Windows system. It seemed like a good idea to use Windows' Virtual Disk Service to accomplish this.
I wrote a bit of code to try it out, but when linking it I get the following error: error LNK2001: unresolved external symbol _CLSID_VdsLoader
Microsofts sample code indicates that I have to link to ole32.lib, and from googling I learned that uuid.lib is also involved. The "Additional Dependencies" line in my project settings is the following:
kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
As you can see, both previously mentioned libraries are included.
I'm trying all this on Visual C++ Express for Windows Desktop 2013. Could this be the problem? Perhaps the express version does not support 100% of the available COM objects? If that's not it, what else could it be?
This is explained here: How to avoid error "LNK2001 unresolved external" by using DEFINE_GUID, you just need for example to add #include <InitGuid.h> in your stdafx.h file.
I had similar issue with unresolved external guid. I didn't define _MIDL_USE_GUIDDEF_ macro and tried to compile code as C++ code.
Since MIDL compiler generates C source file to define guids it is compiled as C code until you explicitly tell visual studio to compile code as C++ code.
MIDL-generated header file contains (when compiled as C++):
extern "C"
{
extern "C" const IID iid; // extern "C" is redundant, extern would be enough
}
MIDL-generated guids-definition file contains (when compiled as C++):
extern "C"
{
const IID iid = { ... }; // _MIDL_USE_GUIDDEF_ macro is not defined
}
We need to remember:
extern "C" block implies C name decoration; e.g.
extern "C" { int a; }
extern "C" singleton implies C name decoration AND extern semantics; e.g.
extern "C" int a;
in C++ non-extern namespace-scope const object implies internal linkage; e.g.
const int a; // internal linkage
extern const int b; // external linkage
With this in mind we can see that header file declares const IID iid with external linkage and C name decoration, whereas guids-definition file defines const IID iid with internal linkage and C name decoration. Linkages do not match, therefore they are treated as different entities by linker. In this case const IID iid with external linkage is left undefined and is later used in the same translation unit.
When you add predefined _MIDL_USE_GUIDDEF_ macro guids-definition file will contain:
extern "C"
{
extern "C" const IID iid = { ... }; // extern "C" is redundant, extern would be enough
}
So you need to add predefined _MIDL_USE_GUIDDEF_ macro in order to explicitly compile code as C++.

Having trouble importing function from C++ dll error LNK 2019

I am trying to write and test a dll file in C++ that I can call whenever I want filesystem level access to things. I am currently having a huge headache when trying to access the methods in this dll in C++. Strangely enough, I was able to call the code in a separate C# program with little trouble, but I want to get an understanding of how dll interaction works in C++.
And this is the .cpp for my dummy executable that should only call my "newMain" test method.
// dummy.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <string>
//#pragma comment(lib,"visa32.lib")
#pragma message("automatic link to adsInterface.dll")
#pragma message(lib, "adsInterface.lib"
extern "C" int __stdcall newMain();
int _tmain(int argc, _TCHAR* argv[])
{
newMain();
std::string i;
std::cin >> i
return 0;
}
The problem is, when I run it I get this error:
error LNK2019: unresolved external symbol _newMain#0 referenced in function _wmain
error LNK1120: 1 unresolved externals
Here is the .h for adsInterface:
// adsInterface.h
#ifndef ADSINTERFACE_H
#define ADSINTERFACE_H
/* //save this for later i have no clue how this really works.
#ifdef ADSAPI_EXPORTS
#define ADSAPI __declspec(dllexport)
#else
#define ADSAPI __declspec(dllexport)
#endif
*/
namespace ADSInterface
{
//test method. should print to console.
__declspec(dllexport) int __stdcall newMain();
void hello();
}
#endif
and here is my .cpp for adsInterface:
// adsInterface.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "adsInterface.h"
#include <iostream>
namespace ADSInterface
{
/* this is where the actual internal class and other methods will go */
void hello()
{
std::cout << "hello from the DLL!" << std::endl;
}
__declspec(dllexport) int __stdcall newMain()
{
hello();
return 0;
}
}
I'll also include the .def file i used when compiling the dll:
; adsInterface.def - defines exports for adsInterface.dll
LIBRARY ADSINTERFACE
;DESCRIPTION 'A C++ dll that allows viewing/editing of alternate data streams'
EXPORTS
newMain #1
Strangely enough, I was able to import the method in C# with this line (I did not have to include a .lib file either):
[DllImport("./adsInterface.dll")] private static extern void newMain();
And it ran when I called it normally:
newMain();
I've been reading many different guides on how to import dll functions, and I've reached the point where I think I'm just mangling together different ways of importation between the languages and just making a mess of things. If anyone is able to provide some insight on how I should be importing dll methods in C++ that would be much appreciated.
delete this declaration:
extern "C" int __stdcall newMain();
and call ADSInterface::newMain() from _tmain.
In the posted code you did not define anything matching that declaration, did you?
Alternatively make the implementation calling the other one, or drag the one from namespace to global.