前言
本文 介绍 利用Swig工具将CTP C++接口API转换为Java可调用的接口
整合订阅全市场合约traderapi(交易)和订阅全市场合约mdapi(行情)demo
但是由于CTP只提供了对C++版本的API接口 那现在作为java开发就很难受了 ,那我们可不可以将C转为java呢 ,?
当然是可行的,下面就是完整的教程.综合的景大佬的技术支持,
景大佬链接如下:
首先需要的技术支持有:
- 安装JDK,注意版本要跟你的CTP下载的代码和你工程一致,将环境变量配置好。
- 安装idea。-这个不过多阐述, 度娘上面很多安装教程.主要用与Java demo的测试,点击下载
- 安装Swig软件,本文中所用的Swig是swigwin-2.0.11版本,
- SWIG是一个能将C/C++接口转换为其他语言的工具,目前可以支持Python,Java,R等语言
链接:https://pan.baidu.com/s/1XR3ym5BQgeHxFsCvkP0gJw
提取码:ov63
点击下载。
- 安装libiconv库。这个库主要适用于字节编码转换,因为CTP的结算单信息是GB2312编码,而Java采用UTF-8编码,如果不
进行字节转换,得到的结算单信息中的中文将会是乱码。
本文采用的libiconv版本是自己下载的源码编译的静态库,也可以到我的github libiconv下载编译好的。
(建议直接用.这边是借用的景大佬的.)
- 安装vs2013,主要用于生成包装dll。
链接:https://pan.baidu.com/s/1I7Wyg9VfLjFOr_pXruHL-Q
提取码:c6lb
首先上海期货信息技术有限公司 下载API
解压缩进入到
在6.3.15_20190220_tradeapi64_se_windows 包下创建几个空的文件夹
目录结构如下:
6.3.15_20190220_tradeapi64_se_windows
│
│─── ctp ─── thostapi
│
│─── demo
│
│─── src
│
│─── wrap
│
│ ThostFtdcMdApi.h
│ ThostFtdcTraderApi.h
│ ThostFtdcUserApiDataType.h
│ …
2.通过Swig得到jar包
在当前文件夹内,新建文件thostapi.i,内容如下
%module(directors="1") thosttraderapi
%include "various.i"
%apply char **STRING_ARRAY { char *ppInstrumentID[] }
%{
#include "ThostFtdcMdApi.h"
#include "ThostFtdcTraderApi.h"
#include "iconv.h"
%}
%typemap(out) char[ANY], char[] {
if ($1) {
iconv_t cd = iconv_open("utf-8", "gb2312");
if (cd != reinterpret_cast<iconv_t>(-1)) {
char buf[4096] = {};
char **in = &$1;
char *out = buf;
size_t inlen = strlen($1), outlen = 4096;
if (iconv(cd, in, &inlen, &out, &outlen) != static_cast<size_t>(-1))
$result = JCALL1(NewStringUTF, jenv, (const char *)buf);
iconv_close(cd);
}
}
}
%feature("director") CThostFtdcMdSpi;
%ignore THOST_FTDC_VTC_BankBankToFuture;
%ignore THOST_FTDC_VTC_BankFutureToBank;
%ignore THOST_FTDC_VTC_FutureBankToFuture;
%ignore THOST_FTDC_VTC_FutureFutureToBank;
%ignore THOST_FTDC_FTC_BankLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BrokerLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BankLaunchBrokerToBank;
%ignore THOST_FTDC_FTC_BrokerLaunchBrokerToBank;
%include "ThostFtdcUserApiDataType.h"
%include "ThostFtdcUserApiStruct.h"
%include "ThostFtdcMdApi.h"
%feature("director") CThostFtdcTraderSpi;
%include "ThostFtdcTraderApi.h"
various.i文件是swig自带的,将swig/Lib/java/various.i拷贝过来即可。
/* -----------------------------------------------------------------------------
* various.i
*
* SWIG Typemap library for Java.
* Various useful typemaps.
* ----------------------------------------------------------------------------- */
/*
* char **STRING_ARRAY typemaps.
* These typemaps are for C String arrays which are NULL terminated.
* char *values[] = { "one", "two", "three", NULL }; // note NULL
* char ** is mapped to a Java String[].
*
* Example usage wrapping:
* %apply char **STRING_ARRAY { char **input };
* char ** foo(char **input);
*
* Java usage:
* String numbers[] = { "one", "two", "three" };
* String[] ret = modulename.foo( numbers };
*/
%typemap(jni) char **STRING_ARRAY "jobjectArray"
%typemap(jtype) char **STRING_ARRAY "String[]"
%typemap(jstype) char **STRING_ARRAY "String[]"
%typemap(in) char **STRING_ARRAY (jint size) {
int i = 0;
if ($input) {
size = JCALL1(GetArrayLength, jenv, $input);
#ifdef __cplusplus
$1 = new char*[size+1];
#else
$1 = (char **)calloc(size+1, sizeof(char *));
#endif
for (i = 0; i<size; i++) {
jstring j_string = (jstring)JCALL2(GetObjectArrayElement, jenv, $input, i);
const char *c_string = JCALL2(GetStringUTFChars, jenv, j_string, 0);
#ifdef __cplusplus
$1[i] = new char [strlen(c_string)+1];
#else
$1[i] = (char *)calloc(strlen(c_string)+1, sizeof(const char *));
#endif
strcpy($1[i], c_string);
JCALL2(ReleaseStringUTFChars, jenv, j_string, c_string);
JCALL1(DeleteLocalRef, jenv, j_string);
}
$1[i] = 0;
} else {
$1 = 0;
size = 0;
}
}
%typemap(freearg) char **STRING_ARRAY {
int i;
for (i=0; i<size$argnum-1; i++)
#ifdef __cplusplus
delete[] $1[i];
delete[] $1;
#else
free($1[i]);
free($1);
#endif
}
%typemap(out) char **STRING_ARRAY {
if ($1) {
int i;
int len=0;
jstring temp_string;
const jclass clazz = JCALL1(FindClass, jenv, "java/lang/String");
while ($1[len]) len++;
$result = JCALL3(NewObjectArray, jenv, len, clazz, NULL);
/* exception checking omitted */
for (i=0; i<len; i++) {
temp_string = JCALL1(NewStringUTF, jenv, *$1++);
JCALL3(SetObjectArrayElement, jenv, $result, i, temp_string);
JCALL1(DeleteLocalRef, jenv, temp_string);
}
}
}
%typemap(javain) char **STRING_ARRAY "$javainput"
%typemap(javaout) char **STRING_ARRAY {
return $jnicall;
}
/*
* char **STRING_OUT typemaps.
* These are typemaps for returning strings when using a C char ** parameter type.
* The returned string appears in the 1st element of the passed in Java String array.
*
* Example usage wrapping:
* void foo(char **string_out);
*
* Java usage:
* String stringOutArray[] = { "" };
* modulename.foo(stringOutArray);
* System.out.println( stringOutArray[0] );
*/
%typemap(jni) char **STRING_OUT "jobjectArray"
%typemap(jtype) char **STRING_OUT "String[]"
%typemap(jstype) char **STRING_OUT "String[]"
%typemap(javain) char **STRING_OUT "$javainput"
%typemap(in) char **STRING_OUT($*1_ltype temp) {
if (!$input) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "array null");
return $null;
}
if (JCALL1(GetArrayLength, jenv, $input) == 0) {
SWIG_JavaThrowException(jenv, SWIG_JavaIndexOutOfBoundsException, "Array must contain at least 1 element");
return $null;
}
$1 = &temp;
*$1 = 0;
}
%typemap(argout) char **STRING_OUT {
jstring jnewstring = NULL;
if ($1) {
jnewstring = JCALL1(NewStringUTF, jenv, *$1);
}
JCALL3(SetObjectArrayElement, jenv, $input, 0, jnewstring);
}
/*
* char *BYTE typemaps.
* These are input typemaps for mapping a Java byte[] array to a C char array.
* Note that as a Java array is used and thus passeed by reference, the C routine
* can return data to Java via the parameter.
*
* Example usage wrapping:
* void foo(char *array);
*
* Java usage:
* byte b[] = new byte[20];
* modulename.foo(b);
*/
%typemap(jni) char *BYTE "jbyteArray"
%typemap(jtype) char *BYTE "byte[]"
%typemap(jstype) char *BYTE "byte[]"
%typemap(in) char *BYTE {
$1 = (char *) JCALL2(GetByteArrayElements, jenv, $input, 0);
}
%typemap(argout) char *BYTE {
JCALL3(ReleaseByteArrayElements, jenv, $input, (jbyte *) $1, 0);
}
%typemap(javain) char *BYTE "$javainput"
/* Prevent default freearg typemap from being used */
%typemap(freearg) char *BYTE ""
然后再当前目录cmd下运行命令:
swig.exe -c++ -java -package ctp.thostapi -outdir src -o thosttraderapi_wrap.cpp thostapi.i
当前目录下生成了:这两个文件是用于包装原来C++接口的文件
thosttraderapi_wrap.h
thosttraderapi_wrap.cpp
打开src文件夹,可以看到这时在里面生成了一系列方法的java文件,如下
CThostFtdcAccountregisterField.java
CThostFtdcAuthenticationInfoField.java
… … …
thosttradeapiJNI.java
在cmd中cd到src文件夹底下,运行命令
javac *.java
运行结束之后可以看到生成了等量的class文件,将所有的class文件拷贝到\ctp\thostapi\文件夹中,cmd下cd到6.3.15_20190220_tradeapi64_se_windows目录下,运行命令.即可在当前文件夹下得到了jar包thostapi.jar。
jar cf thostapi.jar ctp
. 通过C++得到java可调用的dll动态库
接下来在wrap文件夹中,建立一个C++工程,工程为Win32控制台应用程序,工程名为thostapi_wrap,点下一步,工程的应用程序类型选DLL,附加选项选空项目。另外建好项目后,在工程属性-c/c+±代码生成-运行库中选多线程(/MT)。步骤图如下:
完成之后,将如下文件拷贝到\wrap\thostapi_wrap文件夹下
ThostFtdcMdApi.h
ThostFtdcTraderApi.h
ThostFtdcUserApiDataType.h
ThostFtdcUserApiStruct.h
thostmduserapi_se.lib
thosttraderapi_se.lib
thosttraderapi_wrap.cpp
thosttraderapi_wrap.h
libiconv.lib
iconv.h
其中
libiconv.lib 和iconv.h 在github下载的包里找
在thostapi_wrap.cpp 文件任意位置添加
#pragma comment(lib,"libiconv.lib")
在c++工程中添加现有项,将这些文件全部添加到工程中去。下面还要做几步:
将你安装jdk目录\Java\jdk1.8.0_111\include下的jni.h和win32文件夹下的jni_md.h, jawt_md.h一共三个文件拷贝到安装vs的include目录底下\Microsoft Visual Studio 12.0\VC\include。这是因为thosttraderapi_wrap.cpp文件中包含了<jni.h>,这是用于生成Java可调用接口的库文件。
!
这所有完成之后,C++工程中文件应该如下:
然后选择release版编译。我们按F7编译,在\wrap\thosttraderapi_wrap\Release目录底下可见thosttraderapi_wrap.dll动态库文件,说明编译成功,这样CTP Java API就编译成功了。编译中如果出现error LNK2005: abort 已经在 LIBCMT.lib(abort.obj) 中定义…等错误,可以右击工程 - 属性 ”配置属性 - 链接器 - 命令行” 添加: /NODEFAULTLIB:"libcmt.lib"解决。
完成就可在x64文件夹下看到如下:
下面就是需要将我们所需要的整合到一个包下.好方便项目引入.