2009-08-12 73 views
1

我有一个任务是使用C++与第三方公司的dll进行交互。如何从C++调用JNI DLL

该DLL包带有:

  • DLL本身
  • 样品Java实现 - 由一个Java包装(库)的使用SWIG工具和Java源文件
  • 文档生成它陈述了所有的公共数据类型,枚举和成员函数。

我的其他同事正在使用Java(基于包中的示例)与dll接口,同时要求我使用C++。 Java的例子看起来简单的...只是进口包装和实例在文档中描述的任何类..上的dll

更多信息:

  • 从文档,它说该DLL使用C++编程
  • 从一个hexdump,它显示它是使用VC90(VS C++ 2008正确?)和Dinkumware中的东西编译的。
  • 从depends.exe输出中,函数似乎被包装在JNI下。例如:[email protected]

我的困境:

  • DLL的公司没有改变的dll任何东西,不提供任何其他信息。
  • 如何在dll中使用类中的成员函数?
  • 我做了一些简单的LoadLibrary()和GetProcAddress,并设法获取公共成员函数的地址。
  • 但我不知道如何使用具有dll中定义的数据类型参数的函数。例如:
    从文档,所述成员函数定义为:

空隙服务器::连接(常量字符串数组,常量KeyValueMap)掷(标准:: invalid_argument,性病:: out_of_range)
的typedef的std ::地图服务器:: KeyValueMap
的typedef的std ::向量服务器::字符串数组

我如何调用该函数在C++中。我的编译器(VS 2005)中的std :: map和std :: vector具有不同的函数,列出了dll中的函数。例如,从依赖。exe文件输出:

  • 的std ::地图// KeyValueMap - 德尔,空,获取,has_1key,设置
  • 的std ::向量//字符串数组 - 加,能力,清晰,得到,为IsEmpty,储备,设置,我应该如何解决这个尺寸

任何意见/策略?有没有可能像Java示例那样简单地实例化类?

+0

这个东西是专有的,还是你可以提供DLL供我们查看? – 2009-08-12 17:36:08

回答

1

如果您尝试使用VS 2005尝试与使用VS2008构建的DLL进行交互,那么除非您可以使用普通的C接口,否则您的尝试将大部分注定要失败。根据你的描述,情况并非如此;运行时库在VS2005和VS2008之间有所不同,因此对象布局在编译器之间保持不变的可能性很小。您所指的“Dinkumware中的某些东西”很可能是C++标准库,例如Microsoft使用Dinkumware的ISTR。

用上面的例子,你也缺少一些重要的信息 - 你描述的类型(Server :: StringArray和Server :: KeyValueMap)是标准库容器。还好,但标准库容器的什么?这些容器是模板,除非你知道这些模板已经实例化的确切类型,否则你有点卡住。

这个DLL是否打算从C++调用?它导出JNI接口的事实表明它可能不在首位。它是否会输出除_Java _...格式之外的任何其他公共符号?

当然,如果没有其他的方法,你必须使用C++而不是Java,你可能需要考虑将JVM嵌入到C++应用程序中,并使用它来调用C++ dll。这不是我称之为优雅的解决方案,但它可能会工作。

+0

oppss对不起....我没有意识到,我离开了那部分... typedef std :: map 服务器:: KeyValueMap typedef std ::向量服务器:: StringArray – justin 2009-08-12 05:48:21

+0

该DLL是为了与Java一样使用,也由dll公司指出......我的同事正在做java部分......但是我的上级坚持我使它与C++一起工作......没有支持dll公司,我没有太多的选择在这里工作...... – justin 2009-08-12 06:00:54

+0

如果这些函数实际上是导出的,你可以使用它们在上述注意事项上时自己承担风险(即,你必须使用相同的编译器版本),风险自负。如果他们不是,并且与dll通信的唯一方法是通过Java API,与他们进行交互的唯一明智的方法是在您的C++中嵌入JVM以路由这些调用。恕我直言,后者是毫无意义的练习,但嘿,那只是我。 – 2009-08-12 08:32:24

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++数据类型,所以我不知道我的经验有多相关。希望至少这是一些帮助。

+0

只有dll文件随软件包一起提供......如Timo所示,dll并不打算用C++调用...... dll的原始代码是用C++编写的,但在这种情况下它已经集成与JNI和使用SWIG生成它的包装,以便它可以被Java调用...(我没有在JNI或SWIG的经验,请纠正我,如果我错了).. – justin 2009-08-12 06:12:12

+0

我想这是一个大解决方法,因为我试图从C++中调用dll(它具有C++中的JNI)...您怎么看? – justin 2009-08-12 06:15:31

+0

入口点名称看起来自动生成,所以我认为可能会在某处为它生成匹配的头文件。除了我概述的方法之外,我不知道你能做什么。 – 2009-08-12 17:32:14