【IntelliJ IDEA 2019.2】vs2008编写C++ dll,被java调用
1.新建一个工程。
2.关键点,改成生成dll.
关键点2:
带MTd中的T表示静态链接,这是易错点之一,错误的提示信息为:应用程序无法启动,因为应用程序的并行配置不正确
最后,为了方便调试,设置自动把dll文件复制到目标目录:
copy /y x64\Debug\SerialPort_dll.dll ..\SerialPort.dll
或者
copy /y x64\Debug\xxx.dll ..\out\production\xxxxxx\xxx.dll
3.输入代码。
#include <Windows.h>
extern "C" _declspec(dllexport) char* go(char *ch)
{
//MessageBox(NULL, TEXT(ch), TEXT("你好"), MB_OK);
return "来自dll的问候";
}
易错点:string 是不能作为返回值
虽然前面加了 extern "C" 所以,但用的是C的语法,是C++的语法,那么,string 是不能作为返回值,但可以作为传入的参数的原因是什么呢?是因为dll和exe主程序,实际上是两个不同的进程了,不同进程间的内存是不共享的,所以,当使用string作为返回值时,就会出错了,因为string申请空间是在dll,释放却在exe里,exe就会出错,因为根本就没有申请这块内存,哪来的内存去释放呢?明白了这一点,就好办了。
如果想实现 string func(),
则可以写成 char* func(), 或者 void func(string &ret) , (建议第2种写法)。
常见错误:
Exception in thread "main" java.lang.Error: Invalid memory access
通常是因为dll函数接口参数类型错误:
1.不能使用string类型。
4.先用C++测试调用一下。
以下这段代码参考自:https://www.cnblogs.com/Joetao/articles/10216993.html
#include <iostream>
#include <windows.h>
HINSTANCE hDll = LoadLibrary("vs2008_dll_test.dll");
typedef char* (*pType_go)(char *ch);
pType_go go = (pType_go)GetProcAddress(hDll, "go");
void main()
{
char *ret = go("hello,dll");
printf(ret);
FreeLibrary(hDll);
while (1){}
}
如果要分成头文件和CPP两个文件,则可以这要写:
头文件:
#pragma once
#include <iostream>
#include <windows.h>
typedef char* (*pType_Get_dll_version)(void);
extern HINSTANCE hDll;
extern pType_Get_dll_version Get_dll_version;
CPP文件:
#include "SerialPort_dll.h"
HINSTANCE hDll = LoadLibrary("SerialPort.dll");
pType_Get_dll_version Get_dll_version = (pType_Get_dll_version)GetProcAddress(hDll, "Get_dll_version");
5.java调用
参考自: https://www.cnblogs.com/AngeLeyes/p/9449390.html
1.下载JNA包
JNA的Github(这就是JNA开源项目的官网了): https://github.com/java-native-access/jna
下载jar包,如下图:
2.把jar包放到工程目录下,新建一个lib文件夹,然后把jar包放里面。
3.点击"add as library",把该库加入到工程里编译。
4.复制生成的dll到java项目的根目录,即 out/production/*/ ,如下 :
然后写调用代码(JNA方式)
说明: “JNAUtilsTest.Dll INSTANCE” 里的“JNAUtilsTest”就是当前类的名称。
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JNAUtilsTest {
public interface Dll extends Library {
JNAUtilsTest.Dll INSTANCE = (JNAUtilsTest.Dll) Native.load("vs2008_dll_test", JNAUtilsTest.Dll.class);// 加载动态库文件
String go(String s);
}
public static void main(String[] args){
System.setProperty("jna.encoding", "GBK");//解决中文乱码
String go = Dll.INSTANCE.go("777");
System.out.println(go);
}
}
C++接口传递的变量怎么和JAVA对接起来呢?这是一个问题,可参考下面的链接。
C++标准库与Java基础类对照
运行出现问题1:
Exception in thread "main" java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 应用程序。
解决方法:
因为jre是64位的,而dll是32位的,所以就出现了这个问题,所以解决方法是把dll改成64位的,那么,怎么用vs2008生成64位dll呢?
运行出现问题2:
应用程序无法启动,因为应用程序的并行配置不正确
解决方法:是因为使用MFC功能,而找不到相关的MFC系统库,最简单的方法是把MFC相关的代码删除就行,所以,代码变成了,
#include <Windows.h>
_declspec(dllexport) char* go(char *ch)
{
//MessageBox(NULL, TEXT(ch), TEXT("你好"), MB_OK);
return "来自dll的问候";
}
运行出现问题3:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'go': 找不到指定的程序。
解决方法:加上“extern "C" ”,如下,
最后终于运行成功,运行结果如下:
附件1 vs2008生成64位dll
参考自: https://blog.csdn.net/clever101/article/details/8844314
1.重新打开vs2008安装文件,再安装多一个“X64编译器和工具”,如下图:
2.安装完后,就多了一个
3.打开一个工程,点击“配置管理器”
4.
5.
6.关闭后就多了一个“X64”的选项。不过,注意,生成的文件的文件夹也变了,如下:
小技巧
可以再加多一步,使生成的dll文件自动复制到目标位置,如下: