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.
Related
I wasn't able to find a post with this particular issue. This is all in C, on a Windows target.
I have a DLL that I created, and some client code I created to test the DLL. The functions and types defined in the DLL are all successfully resolved by the client code except when I try to use a function pointer in the client code to a function defined in DLL.
Example:
/*--- DLL_Header.h ---*/
#ifdef BUILD_DLL
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
DLL_API void library_function(int foo, int bar);
/* --- DLL_source.c --- */
void library_function(int foo, int bar)
{
/* Do anything */
}
/* --- Client Code --- */
#include "DLL_Header.h"
void client_function_A()
{
int foo = 1;
int bar = 2;
library_function(foo,bar); /* This compiles and links with no problem! */
}
void client_function_B()
{
void (*lib_exec)(int foo, int bar);
lib_exec = &library_function; /* Compiles but then linker says unresolved external symbol __imp__library_function */
int x = 1;
int y = 2;
lib_exec(x,y);
}
client_function_B works fine if I just statically link everything, so it seems there is something I am not fundamentally understanding about the interaction between the DLL and function pointers. Can someone please help me understand what I am doing wrong, and why?
Edit: Exact error message
client_code.obj : error LNK2019: unresolved external symbol __imp__library_function referenced in function _client_function_B
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"
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);
------------------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) { ... })
I'm busy getting to know a tiny bit of C/C++, and interop with C#. I've checked several examples of creating a simple Win32 DLL and using this from C#, but when I try and call into my DLL, I get the runtime error: "Unable to find an entry point named TestFunc". My DLL looks like this, and I created it from a Win32 DLL project, with the empty project option:
Header:
__declspec(dllexport) int TestFunc(char *, char *, char *);
Code file:
#include "stdafx.h"
#include "TestLib.h"
__declspec(dllexport) int TestFunc(char *arg1, char *arg2, char *arg3)
{
char str1[] = "Brady Kelly";
char str2[] = "Hello World";
char str3[] = "1234567890";
strcpy(arg1, str1);
return 128;
}
What am I doing wrong?
Is your function compiled using C or C++ bindings? You don't specify, but it looks to me like there is a possibility that you are using the C++ compiler - the compiler uses very different name mangling from the C compiler and you will not be able to find the name "TestFunc" as simply as if you were using the C compiler or using C name mangling rules.
To simply tell the C++ compiler to use C name mangling rules, use this in the header file:
extern "C"
{
__declspec(dllexport) int TestFunc(char *, char *, char *);
}
Also, you only need the declspec in front of the function declaration (in the header file), not the definition. A useful tool for examining what is exported from the DLL, and what the DLL depends on is Dependency Walker.
Actually since you have tagged this question as C, I'd suggest a minor change from what 1800 INFORMATION's solution:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef EXPORT_MODE
#define METHODTYPE __declspec(dllexport)
#else
#define METHODTYPE __declspec(dllimport)
#endif
#ifdef __cplusplus
}
#endif
/*! _The_ method */
METHODTYPE int TestFunc(char *, char *, char *);
This will let you use the same header both in clients' code and your code.
NB: Dependency Walker is no longer bundled with VS2008. You must download it if you are using VS2008.