tags:

views:

536

answers:

2

I have a task to interface with a dll from a third party company using C++.

The dll package comes with:

  • the dll itself
  • a sample Java implementation - consists of a java wrapper(library) generated using the SWIG tool and the the java source file
  • documentation that states all the public datatypes, enumeration and member functions.

My other colleague is using Java(based on the example in package) to interface with the dll while I'm asked to use C++. The Java example looks straight forward... just import the wrapper and instantiate any class described in the docs..

More info on the dll:

  • From the docs, it says the dll was programmed using C++
  • From a hexdump, it shows that it was compiled using VC90 (VS C++ 2008 right?) and something from Dinkumware.
  • From a depends.exe output, the functions seems to be wrapped under JNI. For example: _Java_mas_com_oa_rollings_as_apiJNI_Server_1disconnect@20

My dilemma:

  • The dll company is not changing anything in the dll and not providing any other info.
  • How do i use the member functions in the class from the dll?
  • I did some simple LoadLibrary() and GetProcAddress and manage to get the address of the public member functions.
  • But i dunno how to use the functions that has the datatype parameters defined in the dll. For example:
    From the docs, the member function is defined as:

void Server::connect(const StringArray, const KeyValueMap) throw(std::invalid_argument,std::out_of_range)
typedef std::map Server::KeyValueMap
typedef std::vector Server::StringArray

how do i call that function in C++. The std::map and std::vector in my compiler (VS 2005) has different functions listing that the one in the dll. For example, from the depends.exe output:

  • std::map // KeyValueMap - *del, empty, get, has_1key,set*
  • std::vector // StringArray - add, capacity, clear, get, isEMPTY, reserve, set, size

Any advice/strategy on how i should solve this? Is it possible to simply instantiate the class like the Java example?

+1  A: 

If you are trying to use VS 2005 to try and interface with a DLL that is built using VS2008, your attempts will be mostly doomed unless you can use a plain C interface. Given your description, this is not the case; The runtime libraries differ between VS2005 and VS2008 so there is little chance that the object layout has stayed the same between compilers. The 'something from Dinkumware' that you're referring to is most likely the C++ standard library as ISTR that Microsoft uses the Dinkumware one.

With your above example you're also missing several important pieces of information - the types you describe (Server::StringArray and Server::KeyValueMap) are standard library containers. OK fine, but standard library containers of what? These containers are templates and unless you know the exact types these templates have been instantiated with, you're a little stuck.

Is this DLL intended to be called from C++ at all? The fact that it export a JNI interface suggests that it might not be in the first place. Does it export any other public symbols apart from those that are of the format _Java_...?

Of course if there is no other way in and you must use C++ instead of Java, you might want to look into embedding a JVM into your C++ app and use that to call through to the C++ dll. It's not what I'd call an elegant solution but it might well work.

Timo Geusch
oppss sorry.... i didnt realize that i left that portion out...typedef std::map<std::string,std::string> Server::KeyValueMaptypedef std::vector<std::string> Server::StringArray
justin
the dll is meant to be used with Java as also indicated by the dll company... my colleague is doing the java part... but my superior insists that i make it work with C++... without the support of the dll company, i'm not given much option to work with here...
justin
If the functions are actually exported you can probably make use of them at your own risk with the caveats mentioned above (ie, you have to use the same compiler version) and at your own risk. If they aren't and the only way to communicate with the dll is via the Java API, the only sensible way to interact with them is by embedding a JVM in your C++ to route the calls. IMHO the latter is a pointless exercise but hey, that's just me.
Timo Geusch
+1  A: 

I don't quite understand the use of C++ standard library data types here. How can Java code provide a std::map argument? Are the arguments you pass in always just "opaque" values you would get as output from a previous call to the library? That's the only way you're going to be able to make it work from code under a different runtime.

Anyway...

When you make a JNI module, you run javah.exe and it generates a header file with declarations like:

JNIEXPORT void JNICALL Java_Native_HelloWorld(JNIEnv *, jobject);

Do you have any such header file for the module?

These symbols are exported as extern "C" if I recall correctly, so if you can get the correct signatures, you should have no issues with name mangling or incompatible memory allocators, etc..

The "@20" at the end of the method signature means that the function is declared "stdcall" and that 20 bytes are put on the stack when the function is called. All these methods should start with a JNIEnv* and a jobject, these will total 8 bytes I believe, on a 32-bit environment, so that leaves 12 bytes of parameters you will need to know in order to generate a correct function prototype.

Once you figure out what the parameters are, you can generate something like this:

typedef void (__stdcall *X)(JNIEnv *, jobject, jint i, jboolean b);

Then, you can cast the result of GetProcAddress to an X and call it from your C++ code.

X x = (X)GetProcAddress(module, "name");
if (x) x(params...);

Unfortunately, what you have doesn't quite look like what I have seen in the past. I am used to having to deal with Java data types from C/C++ code, but it looks like this module is dealing with C++ data types in Java code, so I don't know how relevant any of my experience is. Hopefully this is some help, at least.

Tim Sylvester
only the dll file comes with the package... as indicated by Timo, the dll is not meant to be called by C++.... the original codes of the dll is in C++, but in this case the it has been integrated with JNI and using SWIG to generate a wrapper for it so that it can be called by Java...(i've no experience in JNI or SWIG, please correct me if i'm wrong)..
justin
I guess it's a big workaround for me since I'm trying to call the dll (which has a JNI over the C++) from C++... What do you think?
justin
The entry point name looks automatically generated, so I thought there might be a matching generated header file for it somewhere. I don't know what else you can do other than the approach I outlined.
Tim Sylvester
One other idea, you might try running `winedump` on the DLL, especially the "Generate skeleton code" option, perhaps it can generate something useful: http://linux.die.net/man/1/winedump
Tim Sylvester
thanks Codebender for the winedump tip... I dont have any Linux dist available with me at the moment but i'll defnitely give winedump a go when i get a hold of one...
justin
+1 for the winedump link
fnieto