This feels like a noob question, so if it's a dupe, please point me to the right location :)
I tried including a DLL written in C into a C++ program. It didn't work; gcc said
test.cpp: xxx: error: too many arguments to function.
Here's a minimal working example:
Wrapper for DLL functions:
/* myWrapper.h */
#ifndef _MYWRAPPER_H
#define _MYWRAPPER_H
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
extern FARPROC EXPORTED_functionNameP;
int GetDLLpointers();
#ifdef __cplusplus
}
#endif
#endif
Implementation thereof:
/* myWrapper.c */
#include <windows.h>
#include "myHeader.h"
#ifdef __cplusplus
extern "C" {
#endif
HINSTANCE drvsHANDLE;
extern FARPROC EXPORTED_functionNameP;
int GetDLLpointers()
{
static int result;
drvsHANDLE = LoadLibrary("myLibrary.dll");
if (drvsHANDLE == NULL) return (result=0);
EXPORTED_functionNameP = GetProcAddress(
drvsHANDLE, "originalFunctionName");
if (EXPORTED_functionNameP == NULL) return (result = 0);
return (result = 1);
}
#ifdef __cplusplus
}
#endif
Naturally, I haven't written these nor the library myself, and preferably, they should all stay untouched. I did however add the extern "C" lines.
Then, my main file:
// my Main
#include <windows.h>
#include "myHeader.h"
int main(int argc, char **argv)
{
int arg = 1;
EXPORTED_functionNameP(arg);
return 0;
}
Build commands:
gcc -I. -c -o myHeader.o myHeader.c -L. -lmyLibrary
g++ -I. -o main.exe myMain.cpp myHeader.o -L. -lmyLibrary
It works fine if I rewrite my main.cpp into valid C and compile with gcc instead of g++.
I tried changing extern "C" into extern "C++" to no avail, I tried all permutations or gcc and g++ for the two build commands, nothing.
I know it's something to do with name mangling, but I thought gcc would take care of that when you include the extern "C" lines...Can someone please explain what I'm missing here?
In case it matters --
Windows XP Pro (will be Win7 later on)
(MinGW) gcc 4.6.2
I know this is a very old question, but I am having exactly the same issues but in relation to writing a generic wrapper template for wrapping calls to LoadLibrary() and GetProcAddress()
Taking https://blog.benoitblanchon.fr/getprocaddress-like-a-boss/ as inspiration, it looks like he is taking FARPROC as a kind of "void* for Windows functions" and then casting it to the correct type subsequently.
I needed to tweak that code a little to work for me, and reproduce it here:
class ProcPtr
{
public:
explicit ProcPtr(FARPROC ptr) : m_ptr(ptr) {}
template <typename T>
operator T* () const { return reinterpret_cast<T*>(m_ptr); }
private:
FARPROC m_ptr;
};
class DllHelper
{
public:
explicit DllHelper(LPCTSTR filename) : m_module(LoadLibrary(filename)) {}
~DllHelper() { FreeLibrary(m_module); }
ProcPtr operator[](LPCSTR proc_name) const
{
return ProcPtr(::GetProcAddress(m_module, proc_name));
}
private:
HMODULE m_module;
};
So, with that helper code now available we can use it to write a wrapper class that encapsulates several functions in the Advapi32 library:
class Advapi32
{
public:
Advapi32() : m_dll(TEXT("Advapi32"))
{
getUserName = m_dll["GetUserNameA"];
openSCManager = m_dll["OpenSCManagerA"];
bogusFunction = m_dll["BogusFunctionThatDoesNotExist"];
}
decltype(GetUserNameA)* getUserName;
decltype(OpenSCManagerA)* openSCManager;
decltype(GetWindowsDirectoryA)* bogusFunction;
private:
DllHelper m_dll;
};
bogusFunction is a function with the same signature as GetWindowsDirectoryA but which doesn't exist in Advapi32. This is what I was trying to achieve - graceful fallback on an older OS which might not have a certain function.
So, finally a test app...
int main()
{
Advapi32 advapi32;
auto func1 = advapi32.getUserName;
if (func1)
{
TCHAR infoBuf[256];
DWORD bufCharCount = sizeof(infoBuf);
if (func1(infoBuf, &bufCharCount))
{
std::cout << "Username: " << infoBuf << std::endl;
}
}
auto func2 = advapi32.openSCManager;
if (func2)
{
SC_HANDLE handle = func2(NULL, NULL, SC_MANAGER_CONNECT);
if (handle)
{
std::cout << "opened SC Manager" << std::endl;
}
}
auto func3 = advapi32.bogusFunction;
if (func3)
{
std::cerr << "This should not happen!" << std::endl;
}
else
{
std::cout << "Function not supported" << std::endl;
}
}
Output:
Username: TestAccount
opened SC Manager
Function not supported
Note: This was compiled as a Windows 32-bit console application with MBCS rather than Unicode, under VS2019 with the VS2015_XP toolset, since that is what I am needing to target (don't ask).
The FARPROC type is a function pointer for a function that takes no parameters. You should declare EXPORTED_functionNameP like so (replacing void with whatever the function really returns):
extern void (*EXPORTED_functionNameP)(int);
And initialize it like so (the returned value from GetProcAddress() pretty much always needs to be cast to the correct type):
EXPORTED_functionNameP = (void (*)(int)) GetProcAddress(drvsHANDLE, "originalFunctionName");
A typedef for the funciton type might make things a bit more readable.
There is a difference between C and C++.
int (FAR WINAPI * FARPROC) ()
In C, the FARPROC declaration indicates a callback function that has an unspecified parameter list. In C++, however, the empty parameter list in the declaration indicates that a function has no parameters.
The MSDN page on CallWindowProc explains a bit more.
After a quick Google search, it seems that FARPROC is defined as this:
typedef int (FAR WINAPI *FARPROC)();
That is, FARPROC is a function that returns an int and takes no arguments. So you can't use it for any other case.
Instead declare EXPORTED_functionNameP like this:
extern void (*EXPORTED_functionNameP)(int);
Now EXPORTED_functionNameP is a pointer to a function that takes an int argument and returns no value.
It is because of FARPROC is defined as:
int (FAR WINAPI * FARPROC) ()
So you can not pass any parameters to such function in C++. For fix it you should define EXPORTED_functionNameP as pointer to function with equal semantics as defined in DLL-library. For example:
typedef (void* EXPORTED_functionNameP)(int value);
EXPORTED_functionNameP ExportedFns;
...
ExportedFns = GetProcAddress(drvsHANDLE, "originalFunctionName");
FARPROC is defined as
typedef int (FAR WINAPI *FARPROC)();
When you pass an additional argument although the argument list of the prototype is empty you get the error.
You need a proper prototype definition for PORTED_functionNameP and cas the result from GetProcAddress to that type in your GetDLLPopinters functions.
Related
I want to call a C function from a C++ dll by its address.
I know how to do it where the return type is known from this separate question: Calling a function through its address in memory in c / c++.
However, if I do not know the return type, what can I do? I've tried "typedef auto", but it seems you cannot use auto like that.
If the returning type is really unknown or it doesn't matter, you can use void in your function definition, or if it is any pointer you can use void *, but if the function is in a C coded DLL, and you'll use it in a C++ code, then you can utilize and share almost every type defined in your C code, because C++ it's a superset of C.
That said, I prepared a small example with a structure called PyObject shared in C and C++ codes.
To do this, is better creating a header with the shared types/definitions:
#ifndef PYOBJECT_DLL_H
#define PYOBJECT_DLL_H
#ifdef __cplusplus
extern "C" {
#endif
// Common structure definition
typedef struct PyObject{
int field1;
char *field2;
} PyObject;
// Public function pointer type declaration
typedef PyObject *(*__stdcall getPyObject_t)(int arg1, const char *arg2);
#ifdef __cplusplus
}
#endif
#endif // PYOBJECT_DLL_H
Let's suppose that the C code with the exported function is something like:
#include "pyobject.h"
#include <stdlib.h>
#ifdef __cplusplus
extern "C"
#endif
__declspec(dllexport) PyObject * getPyObject(int arg1, char *arg2);
PyObject *getPyObject(int arg1, char *arg2){
PyObject *obj = (PyObject *)malloc(sizeof(PyObject));
obj->field1 = arg1;
obj->field2 = arg2;
return obj;
}
Finally the C++ code using the function and data created in the library would be:
#include "pyobject.h"
#include <iostream>
#include <windows.h>
int main() {
HINSTANCE dll = LoadLibrary("pyobject.dll");
if (dll == NULL) {
std::cerr << "Cannot open pyobject.dll. Error: " << GetLastError() << "\n";
return 1;
}
getPyObject_t getPyObject = (getPyObject_t) GetProcAddress(dll, "getPyObject");
if (getPyObject == NULL) {
std::cerr << "Cannot locate 'getPyObject' function in dll. Error: " << GetLastError() << "\n";
FreeLibrary(dll);
return 2;
}
PyObject *obj = getPyObject(3, "test");
std::cout << "PyObject == { field1: " << obj->field1 << ", field2: \"" << obj->field2 << "\"}\n";
FreeLibrary(dll);
return 0;
}
Edit
As #raymondchen pointed in his comment, ignoring the return type when the C function returns a large aggregate (e.g. struct) it's not a good idea, because the C function expects that the caller already has had reserved stack space to store the returned aggregate, but if the caller treats the function as void or anything else, then compiler will not reserve that space, causing unpredictable effects (probably ending with Segmentation fault error).
To avoid it, it's always better to define the correct type in both C and C++ codes (or in the common header), especially when the C function returns an aggregate.
I am trying to export a function pointer for a function to be called. What I am after is when a function in a dll/exe needs to call a function exported by another library it gets the function pointer and calls that. The reason for this is I want to provide a hooking mechanism and I figured function pointers would be the quickest and easiest way because I can change what they point to easily are runtime.
So I found this Exporting a function pointer from dll and I cant get it to work. Whenever I call it to get the function pointer I get an error that it cant find the entry point. So the error isnt that the function pointer is working but the function to get the function pointer isnt working. I believe it is a function signature issue. Here is an example:
Colors.h
#ifndef __COLORS
#define __COLORS
#ifdef MYDLL_EXPORTS
/*Enabled as "export" while compiling the dll project*/
#define DLLEXPORT __declspec(dllexport)
#else
/*Enabled as "import" in the Client side for using already created dll file*/
#define DLLEXPORT __declspec(dllimport)
#endif
#include <string>
#include <vector>
class Colors
{
private:
std::string myColor;
static DLLEXPORT std::vector<std::string> allColors;
public:
Colors(){};
Colors(std::string MyColor);
virtual DLLEXPORT std::string getMyColor();
virtual DLLEXPORT void addToColors(std::string color);
std::vector<std::string> getAllColors();
};
typedef Colors* (*create)(std::string);
DLLEXPORT create createColors();
Colors* createColors2(std::string color);
#endif
colors.cpp
#define MYDLL_EXPORTS
#include "Color.h"
std::vector<std::string> Colors::allColors;
Colors::Colors(std::string MyColor)
{
this->myColor = MyColor;
this->allColors.push_back(this->myColor);
}
std::vector<std::string> Colors::getAllColors()
{
return this->allColors;
}
std::string Colors::getMyColor()
{
return this->myColor;
}
Colors* createColors2(std::string color)
{
return new Colors(color);
}
DLLEXPORT void Colors::addToColors(std::string color)
{
this->allColors.push_back(color);
}
DLLEXPORT create createColors()
{
return &createColors2;
}
main.cpp
#define MYDLL_EXPORTS
#include <iostream>
#include <Windows.h>
#include "Color.h"
int main()
{
Colors red("red");
Colors blue("blue");
Colors* dlltest;
//Define the function prototype
typedef Colors* (*createNewColor)();
BOOL freeResult, runTimeLinkSuccess = FALSE;
HINSTANCE dllHandle = NULL;
createNewColor dllCreateNewColor = NULL;
//Load the dll and keep the handle to it
dllHandle = LoadLibrary(L"libs/testerdll.dll");
// If the handle is valid, try to get the function address.
if (NULL != dllHandle)
{
//Get pointer to our function using GetProcAddress:
dllCreateNewColor = (createNewColor)GetProcAddress(dllHandle,"createNewColor");
// If the function address is valid, call the function.
if (runTimeLinkSuccess = (NULL != dllCreateNewColor))
{
dlltest = dllCreateNewColor();
std::cout << "Color of dll class: " << dlltest->getMyColor() << std::endl;
}
else
{
std::cout << "Failed to locate function" << std::endl;
}
//Free the library:
//freeResult = FreeLibrary(dllHandle);
}
else
{
std::cout << "Failed to load library" << std::endl;
}
std::vector<std::string> colorslist = red.getAllColors();
for (std::string color : colorslist)
{
std::cout << color << std::endl;
}
return 0;
}
Dll project
dllmain.cpp
// testerdll.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "Color.h"
__declspec(dllexport) Colors* createNewColor()
{
create temp1 = createColors(); //seems to fail here
return nullptr;
}
Yes I know I have memory leaks etc. this was just a quick example code to replicate the problem.
To return the function, you need to get it's address, and return that
e.g.
__declspec(dllexport) create createNewColor()
{
create temp1 = createColors;
return temp1;
}
However, this system (using std::string as a return type, requires that both the .exe and the .dll use the same DLL based runtime library.
stackoverflow : passing reference to STL over function boundary
C++ does not define a calling convention between files. This means that different compilers may set up C++ objects slightly differently. Microsoft limited that with the definition of COM, but that still is a possibility.
Also for visual studio, there are separate heaps (new / delete) between runtime instances. When you link against the dynamic library, all dlls and exes in the process share this DLL. But then they all need to be updated together.
So this process can work, but be wary about :-
Sharing C++ types between binaries (DLL/EXE) - no ABI
Using new in DLL, and delete in EXE. (different heaps).
STL objects are also problematic, as they are a mixture of header implementation (compiled into the binary), and DLL implementation (compiled into C++ runtime).
I have a command line (+HTTP interface) audio application in C, which currently is being compiled with gcc on Mac OSX, but which I would like to keep this application linux compatible.
However, I would like to use the freeverb3 library. This is in C++. I would prefer not to convert all my code to C++. I don't (as far as I can see) need to call any C code from C++, nor will I need to use C++ objects in my C code. Simple method calls passing arrays of doubles plus a few ints as arguments will be all that I need in terms of interaction from my main application an the C++ code.
From some quick googling, it seems that I can write a C++ interface module, which can then expose some c compatible functions that I can call to make use of freeverb3. I"ve written a micro example to see how this might work. For this example, I have a dummy c++ file called test.cpp:
#include <iostream>
using namespace std;
class test_class
{
int a;
public:
int get_a();
void set_a( int v );
};
int test_class::get_a()
{
return a;
}
void test_class::set_a( int v )
{
a = v;
}
static test_class *c;
extern "C"
{
void init();
void set( int v );
int get();
}
void init()
{
c = new test_class();
}
void set( int v )
{
c->set_a( v );
}
int get()
{
return c->get_a();
}
I have a dummy c file that calls the functions:
#include <stdio.h>
/* Forward declaratoins for extern "C" functions in C++ code */
void init();
int get();
void set( int v );
/* C language code that references functions in C++ code */
int main()
{
init();
set( 55 );
printf( "value: %d\n", get() );
set( get() + 12 );
printf( "value: %d\n", get() );
return 0;
}
And, I have a makefile that creates an executable.
test: test.o user.o
g++ -o test user.o test.o
test.o: test.cpp
g++ -c test.cpp
user.o: user.c
gcc -c user.c
Is this a good way of using C++ code from C? Is there a better/more sophisticated/more traditional way of achieving this aim?
You might want to think about it the other way.
Write your higher level application in C++, invoke the C++ library where you want without complications and call all your current C modules from the C++ level.
IMHO, this is easier to achieve than doing the same with C as high level.
If you intend to use more than one C++ object from C you need to pass an extra instance pointer (this) to the C wrapper functions:
struct A {
A();
~A();
void set(int);
};
The C wrapper:
extern "C"
{
struct A* a_create(void);
void a_destroy(struct A*);
void a_set(struct A*, int);
}
You may also like to catch all C++ exceptions in the C wrapper functions and convert them to error codes.
Pass a pointer to your object instead of using a static variable.
C++ class:
class Foo
{
public:
void doStuff();
};
Common include file:
#ifdef __cplusplus
extern "C"
{
#endif
void Foo_doStuff(void* handle);
void* Foo_create();
void Foo_destroy(void* handle);
#ifdef __cplusplus
}
#endif
Wrapper functions
void Foo_doStuff(void* handle)
{((Foo*)handle)->doStuff();}
void* Foo_create()
{return new(nothrow)Foo;}
void Foo_destroy(void* handle)
{delete (Foo*)handle;}
Not sure whether this goes from C to C++ but it is well worth looking into Swig
Make an extern "C" wrapper in C++, e.g.
// myWrapper.h
#ifdef __cplusplus
extern "C"
{
#endif
void func1(void);
int func2(void);
void func3(char const *str_ptr, size_t len);
#ifdef __cplusplus
}
#endif
// myWrapper.cpp
#include "myWrapper.h"
#include "your_cpp_library.h"
void func3(char const *str_ptr, size_t len)
{
std::string s(str_ptr, str_ptr + len);
call_cpp_function(s);
}
// etc.
In your C code you #include "myWrapper.h" and call those functions. Make sure that:
The code in myWrapper.h stays in the common subset of C and C++
You do not do any cross-boundary resource allocation
The latter might work but it's best to avoid it to be safe. The latter point means that if memory is to be allocated, it must be allocated and freed by the same side; e.g. you can't have the C++ side call malloc and give a pointer to the C side, and then have the C side call free. You have to pass the pointer back to whoever allocated it and let them free it.
Important: as Alf says in a comment, you must have main() in C++ and use the C++ linker , when doing C - C++ inter-linking. This is not a big hurdle though; you can rename your C code's main() function to main2(), and have the C++ code do extern "C" int main2(); and call it.
I'm having a little look at .dll files, I understand their usage and I'm trying to understand how to use them.
I have created a .dll file that contains a function that returns an integer named funci()
using this code, I (think) I've imported the .dll file into the project(there's no complaints):
#include <windows.h>
#include <iostream>
int main() {
HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\Documents and Settings\\User\\Desktop \\fgfdg\\dgdg\\test.dll");
if (hGetProcIDDLL == NULL) {
std::cout << "cannot locate the .dll file" << std::endl;
} else {
std::cout << "it has been called" << std::endl;
return -1;
}
int a = funci();
return a;
}
# funci function
int funci() {
return 40;
}
However when I try to compile this .cpp file that I think has imported the .dll I have the following error:
C:\Documents and Settings\User\Desktop\fgfdg\onemore.cpp||In function 'int main()':|
C:\Documents and Settings\User\Desktop\fgfdg\onemore.cpp|16|error: 'funci' was not declared in this scope|
||=== Build finished: 1 errors, 0 warnings ===|
I know a .dll is different from a header file so I know I can't import a function like this but it's the best I could come up with to show that I've tried.
My question is, how can I use the hGetProcIDDLL pointer to access the function within the .dll.
I hope this question makes sense and I'm not barking up some wrong tree yet again.
LoadLibrary does not do what you think it does. It loads the DLL into the memory of the current process, but it does not magically import functions defined in it! This wouldn't be possible, as function calls are resolved by the linker at compile time while LoadLibrary is called at runtime (remember that C++ is a statically typed language).
You need a separate WinAPI function to get the address of dynamically loaded functions: GetProcAddress.
Example
#include <windows.h>
#include <iostream>
/* Define a function pointer for our imported
* function.
* This reads as "introduce the new type f_funci as the type:
* pointer to a function returning an int and
* taking no arguments.
*
* Make sure to use matching calling convention (__cdecl, __stdcall, ...)
* with the exported function. __stdcall is the convention used by the WinAPI
*/
typedef int (__stdcall *f_funci)();
int main()
{
HINSTANCE hGetProcIDDLL = LoadLibrary("C:\\Documents and Settings\\User\\Desktop\\test.dll");
if (!hGetProcIDDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
// resolve function address here
f_funci funci = (f_funci)GetProcAddress(hGetProcIDDLL, "funci");
if (!funci) {
std::cout << "could not locate the function" << std::endl;
return EXIT_FAILURE;
}
std::cout << "funci() returned " << funci() << std::endl;
return EXIT_SUCCESS;
}
Also, you should export your function from the DLL correctly. This can be done like this:
int __declspec(dllexport) __stdcall funci() {
// ...
}
As Lundin notes, it's good practice to free the handle to the library if you don't need them it longer. This will cause it to get unloaded if no other process still holds a handle to the same DLL.
In addition to the already posted answer, I thought I should share a handy trick I use to load all the DLL functions into the program through function pointers, without writing a separate GetProcAddress call for each and every function. I also like to call the functions directly as attempted in the OP.
Start by defining a generic function pointer type:
typedef int (__stdcall* func_ptr_t)();
What types that are used aren't really important. Now create an array of that type, which corresponds to the amount of functions you have in the DLL:
func_ptr_t func_ptr [DLL_FUNCTIONS_N];
In this array we can store the actual function pointers that point into the DLL memory space.
Next problem is that GetProcAddress expects the function names as strings. So create a similar array consisting of the function names in the DLL:
const char* DLL_FUNCTION_NAMES [DLL_FUNCTIONS_N] =
{
"dll_add",
"dll_subtract",
"dll_do_stuff",
...
};
Now we can easily call GetProcAddress() in a loop and store each function inside that array:
for(int i=0; i<DLL_FUNCTIONS_N; i++)
{
func_ptr[i] = GetProcAddress(hinst_mydll, DLL_FUNCTION_NAMES[i]);
if(func_ptr[i] == NULL)
{
// error handling, most likely you have to terminate the program here
}
}
If the loop was successful, the only problem we have now is calling the functions. The function pointer typedef from earlier isn't helpful, because each function will have its own signature. This can be solved by creating a struct with all the function types:
typedef struct
{
int (__stdcall* dll_add_ptr)(int, int);
int (__stdcall* dll_subtract_ptr)(int, int);
void (__stdcall* dll_do_stuff_ptr)(something);
...
} functions_struct;
And finally, to connect these to the array from before, create a union:
typedef union
{
functions_struct by_type;
func_ptr_t func_ptr [DLL_FUNCTIONS_N];
} functions_union;
Now you can load all the functions from the DLL with the convenient loop, but call them through the by_type union member.
But of course, it is a bit burdensome to type out something like
functions.by_type.dll_add_ptr(1, 1); whenever you want to call a function.
As it turns out, this is the reason why I added the "ptr" postfix to the names: I wanted to keep them different from the actual function names. We can now smooth out the icky struct syntax and get the desired names, by using some macros:
#define dll_add (functions.by_type.dll_add_ptr)
#define dll_subtract (functions.by_type.dll_subtract_ptr)
#define dll_do_stuff (functions.by_type.dll_do_stuff_ptr)
And voilĂ , you can now use the function names, with the correct type and parameters, as if they were statically linked to your project:
int result = dll_add(1, 1);
Disclaimer: Strictly speaking, conversions between different function pointers are not defined by the C standard and not safe. So formally, what I'm doing here is undefined behavior. However, in the Windows world, function pointers are always of the same size no matter their type and the conversions between them are predictable on any version of Windows I've used.
Also, there might in theory be padding inserted in the union/struct, which would cause everything to fail. However, pointers happen to be of the same size as the alignment requirement in Windows. A static_assert to ensure that the struct/union has no padding might be in order still.
This is not exactly a hot topic, but I have a factory class that allows a dll to create an instance and return it as a DLL. It is what I came looking for but couldn't find exactly.
It is called like,
IHTTP_Server *server = SN::SN_Factory<IHTTP_Server>::CreateObject();
IHTTP_Server *server2 =
SN::SN_Factory<IHTTP_Server>::CreateObject(IHTTP_Server_special_entry);
where IHTTP_Server is the pure virtual interface for a class created either in another DLL, or the same one.
DEFINE_INTERFACE is used to give a class id an interface. Place inside interface;
An interface class looks like,
class IMyInterface
{
DEFINE_INTERFACE(IMyInterface);
public:
virtual ~IMyInterface() {};
virtual void MyMethod1() = 0;
...
};
The header file is like this
#if !defined(SN_FACTORY_H_INCLUDED)
#define SN_FACTORY_H_INCLUDED
#pragma once
The libraries are listed in this macro definition. One line per library/executable. It would be cool if we could call into another executable.
#define SN_APPLY_LIBRARIES(L, A) \
L(A, sn, "sn.dll") \
L(A, http_server_lib, "http_server_lib.dll") \
L(A, http_server, "")
Then for each dll/exe you define a macro and list its implementations. Def means that it is the default implementation for the interface. If it is not the default, you give a name for the interface used to identify it. Ie, special, and the name will be IHTTP_Server_special_entry.
#define SN_APPLY_ENTRYPOINTS_sn(M) \
M(IHTTP_Handler, SNI::SNI_HTTP_Handler, sn, def) \
M(IHTTP_Handler, SNI::SNI_HTTP_Handler, sn, special)
#define SN_APPLY_ENTRYPOINTS_http_server_lib(M) \
M(IHTTP_Server, HTTP::server::server, http_server_lib, def)
#define SN_APPLY_ENTRYPOINTS_http_server(M)
With the libraries all setup, the header file uses the macro definitions to define the needful.
#define APPLY_ENTRY(A, N, L) \
SN_APPLY_ENTRYPOINTS_##N(A)
#define DEFINE_INTERFACE(I) \
public: \
static const long Id = SN::I##_def_entry; \
private:
namespace SN
{
#define DEFINE_LIBRARY_ENUM(A, N, L) \
N##_library,
This creates an enum for the libraries.
enum LibraryValues
{
SN_APPLY_LIBRARIES(DEFINE_LIBRARY_ENUM, "")
LastLibrary
};
#define DEFINE_ENTRY_ENUM(I, C, L, D) \
I##_##D##_entry,
This creates an enum for interface implementations.
enum EntryValues
{
SN_APPLY_LIBRARIES(APPLY_ENTRY, DEFINE_ENTRY_ENUM)
LastEntry
};
long CallEntryPoint(long id, long interfaceId);
This defines the factory class. Not much to it here.
template <class I>
class SN_Factory
{
public:
SN_Factory()
{
}
static I *CreateObject(long id = I::Id )
{
return (I *)CallEntryPoint(id, I::Id);
}
};
}
#endif //SN_FACTORY_H_INCLUDED
Then the CPP is,
#include "sn_factory.h"
#include <windows.h>
Create the external entry point. You can check that it exists using depends.exe.
extern "C"
{
__declspec(dllexport) long entrypoint(long id)
{
#define CREATE_OBJECT(I, C, L, D) \
case SN::I##_##D##_entry: return (int) new C();
switch (id)
{
SN_APPLY_CURRENT_LIBRARY(APPLY_ENTRY, CREATE_OBJECT)
case -1:
default:
return 0;
}
}
}
The macros set up all the data needed.
namespace SN
{
bool loaded = false;
char * libraryPathArray[SN::LastLibrary];
#define DEFINE_LIBRARY_PATH(A, N, L) \
libraryPathArray[N##_library] = L;
static void LoadLibraryPaths()
{
SN_APPLY_LIBRARIES(DEFINE_LIBRARY_PATH, "")
}
typedef long(*f_entrypoint)(long id);
f_entrypoint libraryFunctionArray[LastLibrary - 1];
void InitlibraryFunctionArray()
{
for (long j = 0; j < LastLibrary; j++)
{
libraryFunctionArray[j] = 0;
}
#define DEFAULT_LIBRARY_ENTRY(A, N, L) \
libraryFunctionArray[N##_library] = &entrypoint;
SN_APPLY_CURRENT_LIBRARY(DEFAULT_LIBRARY_ENTRY, "")
}
enum SN::LibraryValues libraryForEntryPointArray[SN::LastEntry];
#define DEFINE_ENTRY_POINT_LIBRARY(I, C, L, D) \
libraryForEntryPointArray[I##_##D##_entry] = L##_library;
void LoadLibraryForEntryPointArray()
{
SN_APPLY_LIBRARIES(APPLY_ENTRY, DEFINE_ENTRY_POINT_LIBRARY)
}
enum SN::EntryValues defaultEntryArray[SN::LastEntry];
#define DEFINE_ENTRY_DEFAULT(I, C, L, D) \
defaultEntryArray[I##_##D##_entry] = I##_def_entry;
void LoadDefaultEntries()
{
SN_APPLY_LIBRARIES(APPLY_ENTRY, DEFINE_ENTRY_DEFAULT)
}
void Initialize()
{
if (!loaded)
{
loaded = true;
LoadLibraryPaths();
InitlibraryFunctionArray();
LoadLibraryForEntryPointArray();
LoadDefaultEntries();
}
}
long CallEntryPoint(long id, long interfaceId)
{
Initialize();
// assert(defaultEntryArray[id] == interfaceId, "Request to create an object for the wrong interface.")
enum SN::LibraryValues l = libraryForEntryPointArray[id];
f_entrypoint f = libraryFunctionArray[l];
if (!f)
{
HINSTANCE hGetProcIDDLL = LoadLibraryA(libraryPathArray[l]);
if (!hGetProcIDDLL) {
return NULL;
}
// resolve function address here
f = (f_entrypoint)GetProcAddress(hGetProcIDDLL, "entrypoint");
if (!f) {
return NULL;
}
libraryFunctionArray[l] = f;
}
return f(id);
}
}
Each library includes this "cpp" with a stub cpp for each library/executable. Any specific compiled header stuff.
#include "sn_pch.h"
Setup this library.
#define SN_APPLY_CURRENT_LIBRARY(L, A) \
L(A, sn, "sn.dll")
An include for the main cpp. I guess this cpp could be a .h. But there are different ways you could do this. This approach worked for me.
#include "../inc/sn_factory.cpp"
I'm trying to port a Windows app to Linux. This appplication marks some functions with the __stdcall attribute. However, I was told by a friend that stdcall is used only on Windows and has no meaning in Linux (but DOES exist in Windows GCC).
Searching Google - some results state that there IS stdcall in Linux.
Is there a stdcall in Linux?
Additionally, GCC indicates that:
__attribute__((__stdcall__)) and __attribute__((stdcall)) (without the underscores near stdcall).
Which one is preferred (if applied to Linux at all)?
The simplest solution is to just define __stdcall to nothing conditionally on Linux.
Here's a link to __stdcall description on MSDN:
http://msdn.microsoft.com/en-us/library/zxk0tw93(VS.80).aspx
It's only used to call WinAPI functions. To port such a Windows application to Linux, you need much more than just defining __stdcall to nothing:
#ifndef WIN32 // or something like that...
#define __stdcall
#endif
You would also need to call the Linux-specific API functions instead of Win32 API ones. Depending on the particular part of Win32 API and the size of the application (amount of code), it can be anywhere between moderately difficult and daunting.
Which specific functions are marked by the app as __stdcall?
Indeed, Windows port of GCC has to have __stdcall, because it's supposed to be able to generate conforming code for the Win32 platform. But since under Linux there is only one standard calling convention and it coincides with the default compiler output, this statement is not needed.
The reason your application is not compiling under Linux is almost certainly due to the fact, that it references Win32 API functions that are not defined under Linux -- you need to find appropriate Linux counterparts. Win32 API and Linux GLibc API-s are very much different and cannot be substituted easily.
Probably the easiest way to port your app to Linux would be to use Wine, i.e. modifying the Windows code in such a way, that it runs smoothly under Wine in Linux. This is the way even the most complex applications, like modern computer games, have been made to run under Linux.
Of course, if you really want it to be running natively under Linux, then porting is the only way to go.
stdcall is NOT just a calling convention; in addition to being a calling convention, it allows an isomorphism between C and C++ objects. Here's an example:
#define _CRT_SECURE_NO_WARNINGS // disable marking use of strcpy as error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class ICdeclGreeter {
public:
virtual ~ICdeclGreeter(){}
virtual void setGreeting(const char *greeting) = 0;
virtual void greet() = 0;
};
class IStdcallGreeter {
public:
virtual __stdcall ~IStdcallGreeter(){}
virtual void __stdcall setGreeting(const char *greeting) = 0;
virtual void __stdcall greet() = 0;
};
class CdeclGreeter : public ICdeclGreeter {
public:
char *greeting;
~CdeclGreeter() {
if (greeting != nullptr) {
free(greeting);
puts("[CdeclGreeter] destroyed");
}
}
void setGreeting(const char *greeting) {
this->greeting = (char *)malloc(strlen(greeting) + 1);
strcpy(this->greeting, greeting);
}
void greet() {
puts(greeting);
}
};
class StdcallGreeter : public IStdcallGreeter {
public:
char *greeting;
__stdcall ~StdcallGreeter() {
if (greeting != nullptr) {
free(greeting);
puts("[StdcallGreeter] destroyed");
}
}
void __stdcall setGreeting(const char *greeting) {
this->greeting = (char *)malloc(strlen(greeting) + 1);
strcpy(this->greeting, greeting);
}
void __stdcall greet() {
puts(greeting);
}
};
typedef struct pureC_StdcallGreeter pureC_StdcallGreeter;
typedef struct pureC_StdcallGreeterVtbl {
void (__stdcall *dtor)(pureC_StdcallGreeter *This);
void (__stdcall *setGreeting)(pureC_StdcallGreeter *This, const char *greeting);
void (__stdcall *greet)(pureC_StdcallGreeter *This);
} pureC_IStdcallGreeterVtbl;
struct pureC_StdcallGreeter {
pureC_IStdcallGreeterVtbl *lpVtbl;
char *greeting;
int length;
};
/* naive attempt at porting a c++ class to C;
on x86, thiscall passes This via ecx register rather than
first argument; this register cannot be accessed in C without
inline assembly or calling a reinterpretation of byte array
as a function. there is no "This" argument in any of below. */
typedef struct pureC_CdeclGreeter pureC_CdeclGreeter;
typedef struct pureC_CdeclGreeterVtbl {
void (*dtor)(pureC_CdeclGreeter *This);
void (*setGreeting)(pureC_CdeclGreeter *This, const char *greeting);
void (*greet)(pureC_CdeclGreeter *This);
} pureC_CdeclGreeterVtbl;
struct pureC_CdeclGreeter {
pureC_CdeclGreeterVtbl *lpVtbl;
char *greeting;
int length;
};
void test() {
ICdeclGreeter *g = new CdeclGreeter;
g->setGreeting("hi");
g->greet();
IStdcallGreeter *g2 = new StdcallGreeter;
g2->setGreeting("hi");
g2->greet();
// we can pass pointers to our object to pure C using this interface,
// and it can still use it without doing anything to it.
pureC_StdcallGreeter *g3 = (pureC_StdcallGreeter *)g2;
g3->lpVtbl->setGreeting(g3, "hello, world!");
g3->lpVtbl->greet(g3);
g3->lpVtbl->dtor(g3);
free(g2);
/*
// cdecl passes this via ecx in x86, and not as the first argument;
// this means that this argument cannot be accessed in C without
// inline assembly or equivelent. Trying to run code below will cause a runtime error.
pureC_CdeclGreeter *g4 = (pureC_CdeclGreeter *)g;
g4->lpVtbl->setGreeting(g4, "hello, world!");
g4->lpVtbl->greet(g4);
g4->lpVtbl->dtor(g4);
free(g);
*/
delete g;
}
int main(int argc, char **argv)
{
test();
system("pause");
return 0;
}
TLDR; it's not the same as cdecl makes C++ classes not usable from C on platforms using this convention because in order to send "This" to a method, you must set ecx register to address of "This" rather than just pushing it, and likewise if you want to implement a class in C that C++ can recognize, the method will need to get This pointer from ecx register which is not accessible to C without inline assemby or equivelent.
stdcall has this nice property that classes that use stdcall can easily be simultaneously usable from C or C++ without doing anything to them.
So you can only #define __stdcall as long as you don't deal with __thiscall; although there might be some other subtle distinctions.