I have to access a third party dll which has multiple classes in my Java application. I checked this http://blog.mwrobel.eu/how-to-call-dll-methods-from-java/
But its describing a dll with just a class and some methods. How do I access each specific class and its methods in the dll. Is this possible?
You need to wrap the functionality you need in C-compatible functions (extern "C").
For example, if I have a C++ class as follows:
class Foo {
Foo();
~Foo();
void bar();
}
Then I would need to create some wrapper functions in the shared library that will be accessible via JNA:
extern "C" void* create_foo() { return new Foo(); }
extern "C" void delete_foo(void *foo) { delete (Foo *)foo; }
extern "C" void bar(void *foo) { ((Foo *)foo)->bar(); }
If you have to do a lot of this and compile some native code anyway, you might find using SWIG to be of use. You can customize how your native classes map into Java classes and vice versa.
Did you try adapting the interface from the examples from your link. I think that if you make similar interface with loadLibrary("otherClassName",...) you will be able to load another class from this interface.
Related
ultimately my goal is to write a Qt class(my class inherits from QObject and uses Q_OBJECT macro), then build a dll from it. then in python use ctype to access that dll.
when I write the dll normally, method names get mangled so I can't use them directly. instead I have to use getattr which I don't want to use(because others may need to use the dll and I don't want them to get confused).
anyway I read that to stop name mangle I need to use extern "C"
so far I tried these:
extern "C"
{
class MyClass::public QObject
{
Q_OBJECT
public:
void SomeFunction(int Parameter);
}
}
this one does not build because in Q_OBJECT macro templates are used and I get "templates cannot be declared to have 'C' linkage" error.
i tried:
extern "C" typedef void SomeFunction_t(int parameter);
class MyClass::public QObject
{
Q_OBJECT
public:
SomeFunction_t SomeFunction;
}
this one compiled but still SomeFunction name was mangled;
also I can't use extern "C" directly before method declaration because it is inside of class.
so how can I prevent name mangling here?
I'm going to hazard a guess this might be failing because of this construct:
extern "C"
{
class I_AM_A_CPLUSPLUS_CONCEPT {};
}
Anyhow, this is solvable, but requires a little rethink. To expose the class to C, you will have to jump through a couple of hoops here.
// the C++
class MyClass : public QObject
{
Q_OBJECT
public:
void SomeFunction(int Parameter);
};
extern "C" MyClass* MyClass_new() {
return new MyClass;
}
extern "C" void MyClass_delete(MyClass* c) {
delete c;
}
extern "C" void MyClass_SomeFunction(MyClass* c, int p) {
c->SomeFunction(p);
}
'MyClass' will be mangled into a C++ name, and there isn't really any way to expose 'SomeFunction' as a member of MyClass, without using name mangling.
C-Name mangling in the above example will simply expose:
MyClass_new, MyClass_delete, and MyClass_SomeFunction as the symbol names. (i.e. devoid of the function argument types, return type, calling convention, owning class, etc... which is what C++ name mangling will add in).
Just treat MyClass as an opaque pointer, and C code should be happy enough with that. Short of resorting to pybind/boost::python (which clearly don't really work with DLL's cleanly!!), there aren't really any other nice ways to bind in a C++ object to c code.
I tried to create a function which is returning a vector in C++. But when it built to dll, the function name seems to be mangled.
I tried to use the extern C but the problem is return type vector cannot support if I use extern C
Error : C Linkage function cannot return C++ class std:: Vector
Below is the code I am using
class __declspec(dllexport) TestClass
{
public:
string sClassName;
string sName;
string sDescription;
};
extern "C"
{
vector<TestClass> __declspec(dllexport) GetInfoList();
}
We see it is not problem with easy solution. Here's an involved solution. Use a non-mangled name (extern "C") with GetProcAddress to access a special function in the higher level DLL. . Define all the functions you want to call, as virtuals, in an abstract base class. Call that function above to retrieve the pointer P to a lazily instantiated concrete class with virtuals overriden. Invoke desired method through the pointer P.
vector is C++ type and so cannot be directly given under extern "C". Give the function inside a class and export the class as C Type.
extern "C"
{
class __declspec(dllexport) ClassToExport
{
vector<TestClass> GetInfoList();
};
}
Now use this class object to axcess the function.
I want to provide a callback function for code written in Haskell (GHC). It uses GCC C-compiler-like function types to export/import functionality and interoperate at runtime with my code.
I have to provide a callback function, which in fact accept this pointer to the class and just call its method:
struct C
{
int f(int i) { ; }
static int f_callback(void * self, int i)
{
static_cast< C * >(self)->f(i);
}
};
Logically f_callback is a part of class C, so I placed it into the corresponding namespace scope.
But I worry about should I use extern "C" language specification (calling convention is matters here, not name mangling)? It is possible to declare and define extern "C" function in plain namespace, there are a couple of special rules for extern "C" functions defined with the same name in different namespaces, but there is no distinction between namespace of class scope and simple namespace one.
Is it possible to define static extern "C" function into class scope?
The external callback is by design not linked to a specific class.
Making it a static class member is perhaps nice according to the internals of your code, but it misrepresents the reality.
I'd therefore advise to make it an independent extern "C" function. This avoids misunderstanding and highlights assumptions (for example that self is assumed to be a C but could in reality be something else). If f() is public, all this will be very clean. If it would be private, you'd need to make your callback a friend and this tight coupling would be again highlighted.
The wrapper alternative would just add a redundant middleman to come to the same result.
Let's say I have a C++ header file foo.hpp:
namespace foo {
int bar(int);
}
I cannot use extern "C" because it needs to only be accessible from the namespace foo.
Is there a portable (or relatively portable) way to declare foo::bar in a C file foo.c so that it will link with anyone using foo::bar from C++?
I know that on a particular system with a particular compiler, I can just find out how foo::bar is mangled and do something like this in foo.c:
int ZN3foo3barEi(int x) { /* ... */ }
But this is neither portable nor readable.
extern "C" can be nested (in fact, that's how headers like <cstdio> typically work!), so you can just do the following:
/* C++ code */
namespace foo {
extern "C" {
int bar(int);
}
}
After that, you just implement it in C as usual:
/* C code */
int bar(int x) {
return -x; /* or whatever */
}
Unfortunately, if there's a naming conflict (say, if you have both foo::bar and baz::bar), you won't be able to have them both, unless they're the same function.
Would a wrapper be acceptable?
namespace foo {
int bar(int);
}
extern "C" int callable_from_c(int f) {
return foo::bar(f);
}
You are forced to your backup plan (to use a wrapper function) for the following reason: C++ supports overloading of functions, and by that reason you can have different implementations of bar (with different fingerprints, even compatible) while you can have only one implementation in C. Which of the C++ possibilities would be matched for bar in case you call them from C? What if you have bar(int) and bar(long) in C++ and you want to call bar(3) from C?
The solution is to have one wrapper extern "C" function that calls the appropiate non-C function. This function can be called from C and you'll get the desired results.
If you look, for example, at the identifier names that the linker manages, you'll see how the compiler mangles identifiers to cope at linking time with overloading. That does not happen if you declare a function extern "C" in C++.
Another reason is that you don't have namespaces in C. The C function version must be visible at the global namespace level. You are not able to hide a C calling convention inside a namespace because it is callable from all the C code or you'll be violating the C calling conventions.
How to create some class from dll(constructor in dll)?(C++)
or how to dynamically load class from dll?
You need to declare your class using the __declspec(dllexport) keyword when building the DLL. When using the DLL, the class needs to be declared with __declspec(dllimport):
#ifdef COMPILING_DLL
#define DECLSPEC_CLASS __declspec(dllexport)
#else
#define DECLSPEC_CLASS __declspec(dllimport)
#endif
class DECLSPEC_CLASS MyClass
{
...
}
When the DLL is compiled, you should add -DCOMPILING_DLL to the list of defines.
When using the class, you must statically link with the DLL, i.e. pass the import library mydll.lib to the main program.
If you want to load the DLL at runtime, you need to have a C-function in the DLL which creates a object and returns it for you. There is no way to lookup a constructor dynamically in a DLL (using GetProcAddress()).
Answering your question strictly, you need to add an extern "C" function that returns the result of the constructor:
extern "C" foo* __declspec(dllexport) new_foo(int x) {
return new foo(x);
}
Then in your source you can use GetProcAddr on "new_foo" to call the function.
You will need to export a function from the DLL that calls on to the constructor and returns the new object.
Try to avoid using concrete C++ types as function parameters; the idea of DLLs is that you can independently update them, but an upgraded compiler may lay out std::string differently, causing incompatibility at runtime.
This is what is at the root of COM, for example - a limited type system and a standard exported function for getting instances of objects.
Instead of exporting every method of the class using __declspec, you can also rely on the fact that the compiler can invoke virtual functions via the vtable, so for example:
//note: no __declspec
class IPublicInterface
{
virtual ~IPublicInterface() = 0;
virtual void SomeMethod() = 0;
};
//note: no __declspec
class SomeClass : IPublicInterface
{
virtual ~SomeClass() { ... }
virtual void SomeMethod() { ... }
};
//note: this is the only method which needs to be exported from the DLL
IPublicInterface* createSomeClass()
{
return new SomeClass();
}