How to call unadorned C++ function from C++/CLI - linker

I've written a C++/CLI function which I can call from Fortran. It is specified as
extern "C"
{
void __declspec(dllexport) __cdecl someFunct(int val)
{
...
}
}
This works; it calls managed code, and I can call it from Intel Visual Fortran. When I dumpbin the DLL, I see that it is exported as _someFunct
I now want to call this function from another C++/CLI DLL. I've tried the following spec (with and without a leading underscore), but both fail the same way:
extern "C" extern __declspec(dllimport) void __cdecl someFunct(int val);
The error message I get is this:
Error 4 error LNK2028: unresolved token (0A00000A) "extern "C" void __cdecl someFunct(int)" (?someFunct##$$J0YAXH#Z) referenced in function "public: void __clrcall NUnitTesting::Class1::Test(void)" (?Test#Class1#NUnitTesting##$$FQ$AAMXXZ)
It seems the linker expects an adorned name, even though I specify extern "C" in the spec. How can I force the name to be unadorned?

Figured it out. My spec has to be preceeded by name of DLL:
using namespace System::Runtime::InteropServices;
[DllImport("DLL_with_someFunct",CallingConvention=CallingConvention::Cdecl)]
extern "C" extern void __cdecl someFunct(int val);

Related

Mixing C++ and C code - Linker issues in VS10

I've got a problem mixing the C++ and C code. My C++ code was created in VS10, i.e is a Windows Form project. I want include my C function in my C++ function through of linker (.obj). The steps are:
Windows Form project
VS10 default project
Call the C function
Build the project manually using msbuild
C code
Build the project manually through a make file using nmake and generates the objects files (.obj)
With the every objects files in hands (Cpp and C), the objects are linked in a third makefile. It's a simple idea but it doesn't work. The build in msbuild show the following message:
error LNK2028: unresolved token (0A00000C) "extern "C" void __clrcall MinhaFuncao(void)" (?MinhaFuncao##$$J0YMXXZ) referenced in function "int __clrcall main(cli::array^)" (?main##$$HYMHP$01AP$AAVString#System###Z)
error LNK2019: unresolved external symbol "extern "C" void __clrcall MinhaFuncao(void)" (?MinhaFuncao##$$J0YMXXZ) referenced in function "int __clrcall main(cli::array^)" (?main##$$HYMHP$01AP$AAVString#System###Z)
The Cpp code:
#include "stdafx.h"
#include "Form1.h"
//#include"complex.h"
extern "C" {
#include "complex.h"
}
/*extern "C" {
void MinhaFuncao();
}*/
extern "C" void MinhaFuncao();
using namespace WFormTesting;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
MinhaFuncao(); //<--- Calling the Function HERE -->
// Create the main window and run it
Application::Run(gcnew Form1());
return 0;
}
The C code:
#include "complex.h"
void MinhaFuncao()
{
printf("My function AOWWW.\n");
}
The header file:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>
void MinhaFuncao();
#ifdef __cplusplus
} // extern "C"
#endif
#endif
Has someone got an idea about this problem? I read others posts about linker issues, but the solutions proposed don't work for me. I believe that the difference is due to the msbuild and the VS project... :/
You are using extern "C" in an extern C block
remove the outer extern C block surrounding
#include "complex.h"

undefined reference to `func()'

I'm making some change to an existing linux c project.
In /vobs/ua/HDL/VHDL/CmdUtil/src/help.c, I define func like this:
void func(){
...
}
In file /vobs/ua/HDL/Interface/cli/src/cliSystem.C, I write this code:
extern void func();
...
void func1(){
...
func();
...
}
In file /vobs/ua/HDL/VHDL/DsnMgr/src/shell.c, I write this:
extern void func();
...
void func2(){
...
func();
...
}
In file /vobs/ua/HDL/VHDL/DsnMgr/src/shell.c, I write this:
extern void func();
...
void func2(){
...
func();
...
}
In file /vobs/ua/HDL/VHDL/lib2v/src/asicLibCells.C, I write this:
extern void func();
...
void func3(){
...
func();
...
}
I didn't declare func in any header files.
The problem is, for the call to func in vobs/ua/HDL/Interface/cli/src/cliSystem.C and /vobs/ua/HDL/VHDL/lib2v/src/asicLibCells.C, there is error
undefined reference to `func()'
But for /vobs/ua/HDL/VHDL/DsnMgr/src/shell.c, there is no error.
After I declare func in vobs/ua/HDL/Interface/cli/src/cliSystem.C and /vobs/ua/HDL/VHDL/lib2v/src/asicLibCells.C like this:
extern "C" void func();
There is no error in /vobs/ua/HDL/VHDL/lib2v/src/asicLibCells.C, but the error in vobs/ua/HDL/Interface/cli/src/cliSystem.C persists.
What's wrong? What can I do to eliminate this error?
The problem is that the function func is a C function, and you try to call it from a C++ function. This is problematic because C++ does something called name mangling to allow things like function overload.
That means when you do your declaration
extern void func();
the C++ compiler will mangle the symbol and that mangled symbol will not be found.
In C++ you have to inhibit this name mangling for functions that comes from C object files. This is done with a special extern declaration:
extern "C" void func();
On a slightly related note, in C a declaration like
void func();
doesn't mean that the function takes no arguments like it does in C++. In C that declaration means that func takes an unspecified number of unspecified arguments. In C you must use void to declare a function that takes no arguments:
void func(void);
C++ has a thing called name mangling so that you can overload functions. If you are compiling code as C++, the declaration
extern void func(void);
will add extra characters to its name to encode the fact that it has no parameters. You can disable this by telling the C++ compiler to use C conventions:
extern "C" void func(void);
or
extern "C" {
void func(void);
}
It's normal, however to put these in a header that can be included from both C and C++ files:
#if defined __cplusplus
extern "C" {
#endif
void func(void);
// other function declarations
#if defined __cplusplus
}
#endif

Managed DLL with C linkage used in CLR library

I have a project that was originally written in C. It's pretty large so I don't want to re-write it by hand if I can avoid it. The end goal is to embed it in a C# application. I've made and used CLR libraries before, but I'm having trouble with the below.
// CommandParse.h, used in a Win32 DLL
extern "C" {
typedef struct _PARAMS {
PCHAR OutputDir;
//... other members
} PARAMS, *PPARAMS;
// defines in CommandParse.c
__declspec(dllexport) VOID CmdParseParameters(PPARAMS, int, char ** const);
}
I'm using VS2013 for these projects. And the above example is the stereotypical design pattern used in every other component.
// CommandParseWrapper.h, CLR library
namespace WrappedCode {
public ref class CommandParams {
PPARAMS params;
public:
CommandParams() {
params = new PARAMS;
}
void parse(int argc, char ** const argv) {
CmdParseParameters(params, argc, argv);
}
}
}
What I've done in the CLR project is added the Win32DLL project as a reference and added the source code to the "Additional Includes" setting in VS2013. However I've presented with the following errors.
error LNK2019: unresolved external symbol "extern "C" void __cdecl CmdParseParameters(struct _PARAMS *, int, char** const)"...
error LNK2028: unresolved token (0A00002E) "extern "C" void __cdecl CmdParseParameters(struct _PARAMS *, int, char** const)"...
Causing the compilation to fail.
Any suggestions?
Note: I'm not against editing the original code.

C - properly importing stdcall functions from unmanaged DLL

I am trying to import a function from an unmanaged DLL into a C project by creating a .def file specifying the function I need to use. I am practicing on the WinAPI function MessageBoxA from user32.dll. It is an stdcall function, like the other WinAPI functions.
Here's how I create my .def file:
LIBRARY user32.dll
EXPORTS
_MessageBoxA#16
Then I create a .lib from it like this: lib /def:"C:\Path\to\def\user32.def" /
out:"C:\path\to\project\user32-mb.lib" which successfully creates user32-mb.lib and user32-mb.exp. Then, in my C project, I do the following:
#pragma comment(lib, "user32-mb.lib")
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
EXTERNC __declspec(dllexport) int __stdcall MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
void main(){
MessageBoxA(0, "MessageBox test", "MessageBox test", 0x00000030L);
}
However, upon linking, it gives the following error:
error LNK2019: unresolved external symbol _MessageBoxA#16 referenced in function _main
However, when I change the declaration in the .def to this:
LIBRARY user32.dll
EXPORTS
MessageBoxA
And change the function prototype in my C code to cdecl instead of stdcall:
EXTERNC __declspec(dllexport) int __cdecl MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
The message box actually appears, but right on closing, it throws an error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
Which indicates that calling it with cdecl is also a bad idea since it requires stdcall after all.
The question is, what should I change in the .def file or in my project to avoid both errors and to import and call an stdcall function properly?
You need to change __declspec(dllexport) to __declspec(dllimport), as you are importing functions from a DLL, not exporting them:
EXTERNC __declspec(dllimport) int __stdcall MessageBoxA(void *hWnd, char *lpText, char *lpCaption, int uType);
^^
You need to use dllimport rather than dllexport, but in this case you should remove the __declspec(...) altogether.
And you need to specify the correct name for the function which is MessageBoxA.
LIBRARY USER32.dll
EXPORTS
MessageBoxA
Also it would be remiss of me not to point out that the correct main declaration is
int main(void)
I am still not entirely sure why, but removing the _ adding the ordinal to the function name my .def file fixed everything. My solution is:
LIBRARY USER32.dll
EXPORTS
MessageBoxA#16 #2093
Function definition:
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
typedef void *PVOID;
typedef PVOID HANDLE;
typedef HANDLE HWND;
typedef const char *LPCSTR;
typedef unsigned int UINT;
EXTERNC __declspec(dllimport)
int
__stdcall
MessageBoxA(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType);
This page indicates that winuser.h is the header. From there, you can see some macros are used, including WINUSERAPI and WINAPI. WINUSERAPI is conditionally #define-d at the beginning of that header. WINAPI can be found in the winbase.h header, where it can be seen to be tied to a calling convention, depending on the platform.
But a better question is: Why are you using dllexport and not dllimport?

linkage error with non-member functions

------------------blah.h------------------------
#pragma once
namespace SomeNamespace{
static void someMethod(){}
}
-----------------blah.c--------------------------
#include “blah.h”
int main(int argc, char**argv){
SomeNamespace::someMethod();
return 0;
}
The above works fine but if I omit ‘static’ I get:
>stdafx.obj : error LNK2005: "void __cdecl SomeNamespace::someMethod(void)"
(?someMethod#SomeNamespace##YAXXZ) already defined in Dude.obj
1>...\Debug\Dude.exe : fatal error LNK1169: one or more multiply defined
symbols found
I read about what ‘static’ does to non-member functions –
http://www.velocityreviews.com/forums/t284052-static-functions.html
…
...give it internal linkage so that it won't be visible outside the compilation unit -- i.e., (over-simplified) the linker will not see it.
This use of 'static' is deprecated, and imposes the limitation that the function cannot be used as a template argument.
The modern way is to instead place the function in an anonymous namespace…
But the thing is I want the method to be exposed. What am I doing wrong?
Declare your function in .h (i.e. void foo(int x);)
Define then in .c (i.e. void foo(int x) { ... })

Resources