While using a 3rd party shared library i.e. DLL, I have to define the functions usable by their symbol names. So I have to declare some function types.
But the function definition involves a calling convention, in my case __cdecl.
So, naturally, this calling convention is only applicable to the MSVC compiler but I still want to compile my portable API abstraction code, which uses boost::dll with linux, even though I can not execute it on my development linux machine, so I can still check the compile time stuff.
So my idea was to define the __cdecl name to something as nothing or a white space, a NOP if you will, with the pre-processor, but I am not able to do that:
#if !BOOST_OS_WINDOWS
#define __cdecl ( ) /* error, how can I define __cdecl as 'nothing" here? */
#endif
#include <boost/dll/import.hpp>
boost::dll::shared_library lib;
unsigned long device_count(char* pid) {
typedef unsigned long(__cdecl func_sig)(char *pvid_id);
return lib.get<func_sig>("DLL_Symbol")(pid);
}
#define __cdecl
Couldn't be simpler! Or better, to limit the spreading of implementation-reserved identifiers:
#if BOOST_OS_WINDOWS
#define YOURLIB_CDECL __cdecl
#else
#define YOURLIB_CDECL /* nothing */
#endif
Related
I have to use a third-party C++ library (that I can not change) and call its API from C code.
For most of the library APIs I use a wrapper as explained in this post:
How to call C++ function from C?
But there is one API that takes a variable number of arguments.
Here is its definition (from the header file provided with the library):
void consoleDebug(char* format, ...);
I do not see how I can write the wrapper function for this API.
I tried this but it does not work:
extern "C" {
void wrapper_consoleDebug(char * format, ...)
{
va_list argptr;
va_start(argptr,format);
consoleDebug(format, argptr);
va_end(argptr);
}
}
Any idea is welcome! Thanks!
problem of call c++ functions from c that it used different decoration.
all next for cl.exe (msvc) + link.exe toolset, but think other compiler/linkers have analog features
for example when you compile in c++ function
void consoleDebug(char* format, ...)
in obj (or static lib) file will be ?consoleDebug##YAXPEADZZ symbol.
but when you use the same function from c unit - in object file will _consoleDebug (for x86) or consoleDebug (other platforms)
if we declare in c file
void consoleDebug(char* format, ...)
and do call - in obj will be stored that external symbol consoleDebug (or _consoleDebug) used. when linker will be build code - it will search - where is [_]consoleDebug actually defined (in all obj and lib passed to him) and founf nothing - no such symbol. as result we got error unresolved external symbol [_]consoleDebug
solution here in undocumented linker option /alternatename :
/alternatename:sym1=sym2
with this we say to linker (link.exe) if he need sym1 symbol and can not found it - try use sym2 instead. with this we can create next solution:
1 - we need know exactly symbol name in c++ - we can get it with __FUNCDNAME__ macro:
for example:
#define _GET_NAMES_
#ifdef _GET_NAMES_
void consoleDebug(char* format, ...)
{
#pragma message(__FUNCSIG__ ";\r\n")
#pragma message("__pragma(comment(linker, \"/alternatename:" __FUNCTION__ "=" __FUNCDNAME__ "\"))")
}
#endif // _GET_NAMES_
this is temporary, fake code, need only for print __FUNCDNAME__
then in c file we declare
void __cdecl consoleDebug(char *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebug=?consoleDebug##YAXPADZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebug=?consoleDebug##YAXPEADZZ"))
#endif
and can free use consoleDebug
in case we have multiple functions in c++ with same short name, say
void consoleDebug(char* format, ...);
void consoleDebug(wchar_t* format, ...);
this is also easy work, need only bit different name this 2 api in c code:
void __cdecl consoleDebugA(char *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebugA=?consoleDebug##YAXPADZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebugA=?consoleDebug##YAXPEADZZ"))
#endif
void __cdecl consoleDebugW(wchar_t *,...);
#ifdef _X86_
__pragma(comment(linker, "/alternatename:_consoleDebugW=?consoleDebug##YAXPA_WZZ"))
#else
__pragma(comment(linker, "/alternatename:consoleDebugW=?consoleDebug##YAXPEA_WZZ"))
#endif
after this we can simply call like
consoleDebugA("str %u\n", 1);
consoleDebugW(L"str %u\n", 2);
from c code.
no any shim/wrapper code need with this. in case you use not cl/link but other tool-chain and can not found analog of /alternatename name option - possible use asm file for create single jmp shim. say for x64
extern ?consoleDebug##YAXPEADZZ:proc
extern ?consoleDebug##YAXPEA_WZZ:proc
_TEXT segment 'CODE'
consoleDebugA proc
jmp ?consoleDebug##YAXPEADZZ
consoleDebugA endp
consoleDebugW proc
jmp ?consoleDebug##YAXPEA_WZZ
consoleDebugW endp
_TEXT ENDS
END
Thanks for your help!
I tried the suggestion from Sam Varshavchik and it works (at least in my case)! More precisely, here is what I did:
// wrapper.cpp
extern "C" { void (*wrapper_consoleDebug)(char * format, ...) = consoleDebug;}
// wrapper.h
extern void (*wrapper_consoleDebug)(char * format, ...);
// C file
#include "wrapper.h"
// in my code
wrapper_consoleDebug("my logger is %s","great");
I did not try the other suggestions yet, but I guess they would work too.
Thanks again!
Context
Im working on a project designed to send certain commands to a device. Each device can be interfaced with a dll (e.g. deviceADll.h, deviceBDll.h) and the Dll's were not programmed by me, nor can I modify them in any way. I am in charge of integrating DeviceB to the project, with minimal changes to the structure of the project. I know the structure may not be optimal and/or well designed, so I am willing to take suggestion concerning that matter as a last resort solution.
Since the devices are very similar, all Dll functions have the same name, and often the same prototype.
Also because of this, I made a parent class (Device_ts.h), from which DeviceA_ts.h and DeviceB_ts.h inherit (I also have a factory class for the Devices, but I don't think that it's relevant to my problem).
Problem
The problem occurs when I try to include both Dlls: the project compiles, but I get a
Warning 60 warning LNK4006: Connect#12 already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
followed by a
Warning 61 warning LNK4006: __imp__Connect#12 already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
and a
Warning 62 warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
Has anyone experienced a similar situation? Should I ignore those warning or will I not be able to call DeviceB.h functions since their definitions are ignored?
I am using Visual Studio 2010, the Device_ts.h library I am writing is a static library and all the project's parameters (e.g. /MD, include directories, dependencies, MFC, etc) are set properly from what I found in my research for this problem.
Code
The include and code looks like this (I will only show one of the functions that cause the warning since I get the same error on 50 functions):
DeviceADll.h
#ifndef DEVICEA_H__
#define DEVICEA_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
namespace DeviceA
{
// some struct definition that don't cause the linker warnings
//...
// function definitions
extern "C" HANDLE PASCAL EXPORT Connect( HANDLE h_devA, const char *ip);
// ...
} // namespace DeviceA
DeviceBDll.h
#ifndef DEVICEB_H__
#define DEVICEB_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
namespace DeviceB
{
// some struct definition that don't cause the linker warnings
//...
// function definitions
extern "C" HANDLE PASCAL EXPORT Connect( HANDLE h_devB, const char *ip);
// ...
} // namespace DeviceB
Device_ts.h
#ifndef DEVICE_FCT_H_
#define DEVICE_FCT_H_
#ifndef EXPORT
#define EXPORT
#endif
#if _MSC_VER > 1000
#pragma once
#endif
#include "DeviceADll.h"
#include "DeviceBDll.h"
class CDevice {
public:
virtual BOOL Connect(char *ip_addr) = 0;
};
#endif DEVICE_FCT_H_
This is a good use-case for manual DLL loading, using LoadLibrary() and GetProcAddress().
You'll have to manage a function pointer for each function looked up this way, which is a bit of a pain, but bypassing the OS's dll loading gives you a lot of flexibility.
Also note that you do not need to link against the DLL when using this method, the dll binding is 100% runtime, and the linker is not involved at all.
Here's an example:
typedef void (*connect_fn)(HANDLE, const char*);
connect_fn connect_a;
connect_fn connect_b;
int main()
{
HINSTANCE dll_a = LoadLibrary("path_to_dll_a.dll");
HINSTANCE dll_b = LoadLibrary("path_to_dll_b.dll");
if (!dll_a || !dll_b) {
return 1;
}
connect_a = (connect_fn)GetProcAddress(dll_a , "Connect");
connect_b = (connect_fn)GetProcAddress(dll_b , "Connect");
// connect_a and connect_b can now be used.
return 0;
}
Edit: Basically, I suggest you treat the device DLLs as plugins, rather than dynamic libraries.
I'm working on an existing c++ project with visual studio, and I found out that almost every function declaration gets a __cdecl in front of the function name, like:void __cdecl functionName(). Then I jump to the definition of __cdecl, which locates in the winnt.h file:
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#define NTAPI __stdcall
#else
#define _cdecl
#define __cdecl
#define NTAPI
#endif
I've searched cdecl and got that it's the default calling convention for C and C++ programs, but code above tells me that __cdecl extends to nothing. So why place a __cdecl before function name as it's just nothing ? or did I misunderstand the code above?
what's the meaning of #define __cdecl”
Lines that begin with # are preprocessor directives. #define is a directive that defines a preprocessor macro. #define __cdecl defines a macro with identifier __cdecl and empty replacement. If such macro is defined, the processor will replace all instances of the __cdecl with an empty string.
So why place a __cdecl before function name as it's just nothing ?
Take a look at the directives at the beginning of the definition in question:
#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
#else
The macro is defined conditionally. When the macro is not defined, __cdecl will not expand to nothing. When not expanded to nothing, __cdecl is a microsoft specific function specifier as you have discovered.
The conditionally defined macro allows one to write code that uses __cdecl on systems that allow it, and automatically remove it on systems that do not.
But I'm still confused with the #if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) line, what does it mean?
It is a preprocessor directive that test whether the macro _MSC_VER has greater value than 800, or if macro _STDCALL_SUPPORTED is defined. If the test is false, then the code between #if and #else is removed. If it is true, then the code between #else and #endif is removed.
It means that if an API is defined as using NTAPI it will generate code that uses the __stdcall calling convention - a variation of the Pascal calling convention in which the callee cleans the stack. With __cdecl, the caller cleans the stack (so it supports variadic type functions).
And all of this is conditional on the #if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED)
I have large C++ project, containing few modules - all of them are compiled to dynamic libraries. I target multiple platforms, including Windows, Linux and MacOSX.
Profiling tests revealed some critical points, in which I was able to get huge performance gain, for example: hash computing, some vector operations etc. I implemented this functionality in assembly using SSE/MMX.
Everything was fine, until I switched back to x64 target in Visual C++, where inline assembly is not permitted. And I'm stuck. Also, these functions are used in other modules as well.
Basically, what I am trying to achieve, is to implement some functions, that reside inside DLL in assembly. I tried this:
Api.h
extern "C" void DLL_API __stdcall sample_fun(/*args*/);
Api.asm
sample_fun PROC public ;args
.....
sample_fun ENDP
This obviously will not work, because of name mangling.
I also tried this:
Api.h
void DLL_API sample_fun(/*args*/);
Api.cpp
extern "C" __stdcall sample_fun_impl(/*args*/).
void DLL_API sample_fun(/*args*/)
{
return sample_fun_impl(/*args*/);
}
Api.asm
sample_fun_impl PROC public ;args
.....
sample_fun_impl ENDP
In this case, I am still getting linker error about unresolved external symbol (sample_fun_impl), which is weird, because it is actually a private function, called only from within the DLL.
Is it possible to do what I am trying to ?
So, the problem has been solved. Here is a minimal example of what I wanted with some explanations:
Asx.h
namespace Asx
{
#if ASX_PLATFORM_IS64BIT //This is resolved using 'ifdef _M_X64'
extern ASX_DLL_API ULONGLONG roundup_pow2_64(ULONGLONG value);
#else
extern ASX_DLL_API DWORD roundup_pow2_32(DWORD value);
#endif
}
Asx.cpp
#include "Asx.h"
#if ASX_PLATFORM_IS64BIT
extern "C" ULONGLONG __cdecl roundup_pow2_64_impl(ULONGLONG value);
#else
extern "C" DWORD __cdecl roundup_pow2_32_impl(DWORD value);
#endif
namespace Asx
{
#if ASX_PLATFORM_IS64BIT
ULONGLONG roundup_pow2_64(ULONGLONG value)
{
return roundup_pow2_64_impl(value);
}
#else
DWORD roundup_pow2_32(DWORD value)
{
return roundup_pow2_32_impl(value);
}
#endif
}
Asx_asm_impl.asm
IFNDEF ASX_PLATFORM_IS64BIT
.686P
.MODEL FLAT, C
.XMM
ENDIF
.CODE
IFDEF ASX_PLATFORM_IS64BIT
roundup_pow2_64_impl PROC public, value:QWORD
//Implementation
roundup_pow2_64_impl ENDP
ELSE
roundup_pow2_32_impl PROC public, value:DWORD
//Implementation
roundup_pow2_32_impl ENDP
ENDIF
END
What was wrong?
1) I did not take into account, that calling conventions are treated differently in x64, however accidentally this didn't cause any problems.
2) At some point, I noticed, that functions marked __cdecl are searched by linker using their name prepended with an underscore. I made dumpbin of problematic DLL and it was there - but indeed with an underscore at the beginning! So I left its declaration as it was and changed its name from roundup_pow2_32_impl to _roundup_pow2_32_impl and at the same time, I added MODEL FLAT, C.
3) I used IFDEF/IFNDEF inside .asm file. But I assumed, that all defines visible to cl will be also visible to ml/ml64. Wrong. Only after manually adding required constants everything started to work (.asm file properties -> Microsoft Macro Assembler -> General -> Preprocessor Definitions).
I guess after trying and trying many different solutions, everything turned into one, big mess. Clean setup worked perfectly:
Main.cpp
#include "../Asx/Header.h"
int main(int argc, char** argv)
{
#if ASX_PLATFORM_IS64BIT
ULONGLONG v = Asx::roundup_pow2_64(4000);
#else
DWORD v = Asx::roundup_pow2_32(4000);
#endif
return 0;
}
Result in both Win32 and x64: 4096.
And big thanks for bogdan! Without his hint about calling convention specifiers on x64, I wouldn't solve this.
EDIT
To get around the problem, I added the following to the (beginning of the) header file:
#ifdef GetMessage
#undef GetMessage
static inline BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
) {
#if UNICODE
return ::GetMessageW(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
#else
return ::GetMessageA(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
#endif
}
#endif
I'm creating a C++ DLL (using Visual Studio 2008) from code like the following:
Header File:
#include <windows.h> // Edit: This is the culprit.
class __declspec(dllexport) TestBaseClass
{
protected:
char m_Message[512];
public:
TestBaseClass();
virtual char* GetMessage(void) = 0;
};
class __declspec(dllexport) TestDerivedClass : public TestBaseClass
{
public:
TestDerivedClass();
virtual char* GetMessage(void);
};
CPP File:
TestBaseClass::TestBaseClass()
{
}
TestDerivedClass::TestDerivedClass() : TestBaseClass()
{
}
char* TestDerivedClass::GetMessage(void)
{
sprintf(m_Message, "This is a Message");
return m_Message;
}
When I go to compile the DLL, I get a linker error:
error LNK2001: unresolved external symbol "public: virtual char *
__thiscall TestDerivedClass::GetMessageA(void)" (?GetMessageA#TestDerivedClass##UAEPADXZ)
If I change every instance of "GetMessage" to something else (e.g. "TestFunc"), I do not get the linker error.
Primary Question: Why can't I use "GetMessage" as my function name?
Secondary Question: Is there a way to resolve the linker error, and keep "GetMessage" in my class, as currently defined?
It's due to a quirk in the Windows headers. When you #include <windows.h>, it #defines the symbol GetMessage to either GetMessageA or GetMessageW, depending on whether or not you have Unicode support enabled (more specifically, if the UNICODE macro is defined) -- see Unicode in the Windows API and Conventions for Function Prototypes for more info on that.
To work around this, you have a few options:
Don't include the Windows headers
Define the macro NOMSG before include <windows.h> -- this will suppress the declarations of various message-related functions and macros
#undef GetMessage before your class definition
Rename your function to something else
This is pretty standard preprocessor lossage. Your identifier is getting whacked by a macro. It lives inside the Windows headers, it renames the winapi GetMessage() function to either GetMessageA or GetMessageW, depending on whether UNICODE defined.
Pick another name or use #undef GetMessage