我有一项任务是使用C ++与第三方公司的dll连接。
dll包附带:
当我被要求使用C ++时,我的另一位同事正在使用Java(基于包中的示例)与dll进行交互。 Java示例直接看起来......只需导入包装器并实例化文档中描述的任何类..
有关dll的更多信息:
_Java_mas_com_oa_rollings_as_apiJNI_Server_1disconnect@20
我的困境:
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
如何在C ++中调用该函数。我的编译器(VS 2005)中的std :: map和std :: vector有不同的函数列出了dll中的那个。例如,来自depends.exe输出:
关于我应该如何解决这个问题的任何建议/策略?是否可以像Java示例那样简单地实例化类?
答案 0 :(得分:1)
如果您尝试使用VS 2005尝试与使用VS2008构建的DLL进行交互,那么除非您可以使用普通的C接口,否则您的尝试将大多注定失败。鉴于你的描述,情况并非如此; VS2005和VS2008之间的运行时库不同,因此对象布局在编译器之间保持不变的可能性很小。您所指的“来自Dinkumware的东西”很可能是Microsoft使用Dinkumware的C ++标准库。
使用上面的示例,您还缺少几个重要的信息 - 您描述的类型(Server :: StringArray和Server :: KeyValueMap)是标准库容器。好的,但是什么的标准库容器?这些容器是模板,除非你知道这些模板已经实例化的确切类型,否则你有点卡住了。
这个DLL是否打算从C ++中调用?它导出JNI接口这一事实表明它可能不是第一位的。它是否导出除了_Java _...?
格式之外的任何其他公共符号当然,如果没有其他方法,您必须使用C ++而不是Java,您可能希望将JVM嵌入到C ++应用程序中并使用它来调用C ++ DLL。这不是我所说的优雅解决方案,但可能会有效。
答案 1 :(得分:1)
我不太明白这里使用C ++标准库数据类型。 Java代码如何提供std::map
参数?你传入的参数总是只是“不透明”的值,你可以从之前的库调用中获得输出吗?这是你能够通过不同运行时的代码使其工作的唯一方法。
总之...
当您创建JNI模块时,运行javah.exe
并生成包含以下声明的头文件:
JNIEXPORT void JNICALL Java_Native_HelloWorld(JNIEnv *, jobject);
你有没有这个模块的头文件?
如果我没记错的话,这些符号会导出为extern "C"
,所以如果你能得到正确的签名,你应该没有名称错位或不兼容的内存分配器等问题。
方法签名末尾的“@ 20”表示该函数被声明为“stdcall”,并且在调用该函数时将20个字节放在堆栈上。所有这些方法应该从JNIEnv*
和jobject
开始,在32位环境中,这些将总共8个字节,因此需要知道12个字节的参数才能生成正确的函数原型。
一旦弄清楚参数是什么,就可以生成如下内容:
typedef void (__stdcall *X)(JNIEnv *, jobject, jint i, jboolean b);
然后,您可以将GetProcAddress
的结果转换为X
并从您的C ++代码中调用它。
X x = (X)GetProcAddress(module, "name");
if (x) x(params...);
不幸的是,你所拥有的并不像我过去看到的那样。我习惯于处理来自C / C ++代码的Java数据类型,但看起来这个模块正在处理Java代码中的C ++数据类型,所以我不知道我的经验是多么相关。希望这至少是一些帮助。