c++源码的数据结构复杂,java如何调用dll?
本来有个C#工程是可以完美调用这个dll的。但是上面准备废弃C#工程,要求用java实现调用,所以就打算用jna来调用dll,然而C++源码的数据结构挺复杂的,自己根据C++源码排除用不上的部分写了个精简版的头文件,精简后数据结构仍然比较复杂。精简版C++头文件如下:
extern "C" {
typedef unsigned int huint32;
enum HErrorCode
{
kSuccess = 0,
kInvalidInit,
kInvalidParam,
kMallocMemoryFail,
kSetParentHandleFail,
kInvalidRVFFile,
kSaveRVFFileFail,
kInvalidRTFFile,
kInvalidTxtFile,
kInvalidImgFile,
};
/** @enum HTextKey
* @brief 作为功能key, 每个key都有与之对应的value, 每项具有描述.
*/
enum HTextKey
{
kTextFontName, ///< 设置文字字体类型, value类型为wchar_t *, 表示文字字体名.
kTextFontSize, ///< 设置文字字体大小, value类型为huint32 *, *value表示字体大小值.
/**
* @brief 设置文字字体颜色, value类型为huint32 *, *value表示字体颜色.
* 颜色空间为ABGR, 其中忽略alpha通道. 例如: 0xff红色, 0xff00绿色, 0xff0000蓝色.
*/
kTextColor,
/**
* @brief 设置文字背景颜色, value类型为huint32 *, *value表示字体颜色.
* 颜色空间为ABGR, 其中alpha通道值为0. 例如: 0xff红色, 0xff00绿色, 0xff0000蓝色.
* 取消文字背景值为: 0x1FFFFFFF.
*/
kTextBackgroundColor,
kTextHAlignment, ///< 设置文字水平对齐方式, value类型为huint32 *, *value表示水平对齐方式. 请参考HTextHAlignment定义.
kTextCharSpace, ///< 文字间距, value类型为huint32 *, *value表示字间距大小, 单位为像素. 取值范围[0, 99], 步进为1.
kTextLineSpace, ///< 文字行间距, value类型为huint32 *, *value表示行间距, 单位为百分比. 取值范围[50, 195], 步进为5.
kTextBoldFlag, ///< 粗体, value类型为huint32 *, *value表示粗体标志. 1表示设置粗体, 0表示取消粗体.
kTextItalicFlag, ///< 斜体, value类型为huint32 *, *value表示斜体标志. 1表示设置斜体, 0表示取消斜体.
kTextUnderlineFlag, ///< 下划线, value类型为huint32 *, *value表示下划线标志. 1表示设置下划线, 0表示取消下划线.
/**
* @brief 设置编辑器背景颜色, value类型为huint32 *, *value表示字体颜色.
* 颜色空间为ABGR, 其中alpha通道值为0. 例如: 0xff红色, 0xff00绿色, 0xff0000蓝色.
* 取消文字背景值为: 0x1FFFFFFF.
*/
kEditBackgroundColor,
kEditBackgroundTransparent, ///< 编辑器背景色透明标志, value类型为huint32 *, *value表示透明标志. 1表示透明, 0表示不透明.
kEditBackgroundPicture, ///< 设置编辑器背景图片, 暂时不支持.
kEditVAlignment, ///< 设置段落垂直对齐方式, value类型为huint32 *, *value表示段落垂直对齐方式. 请参考HEditVAlignment定义.
kEditUndo, ///< 回退, 设置时忽略value取值. 回调时value类型为huint32 *, *value表示是否可以撤销标志. 1表示可以撤销, 0表示不可以撤销
kEditRedo, ///< 重做, 设置时忽略value取值. 回调时value类型为huint32 *, *value表示是否可以重做标志. 1表示可以重做, 0表示不可以重做
kEditCut, ///< 剪切, 设置时忽略value取值. 回调时value类型为huint32 *, *value表示是否可以剪切标志. 1表示可以剪切, 0表示不可以剪切
kEditCopy, ///< 拷贝, 设置时忽略value取值. 回调时value类型为huint32 *, *value表示是否可以拷贝标志. 1表示可以拷贝, 0表示不可以拷贝
kEditPaste, ///< 粘贴, 设置时忽略value取值. 回调时value类型为huint32 *, *value表示是否可以粘贴标志. 1表示可以粘贴, 0表示不可以粘贴
kPageInfoBack, ///< 页面信息反馈, value类型为huint32 *, value[0]表示页面总数, value[1]表示当前页面数.
kInsertPicture, ///< 插入图片, 忽略value取值.
kPictureResize, ///< 图片大小, value类型为huint32 *, value[0]表示宽度, value[1]表示高度. (单位: 像素)
kInsertTable, ///< 插入表格, 忽略value取值.
kTableProperties, ///< 表格属性, value类型为HTableProperties,如果为NULL,表示外部调用修改属性
kTablePropOperate, ///< 表格操作,value类型为HTablePropOperate
kTextChnaged, ///< 内容改变, 忽略value取值.
kRButtonDown, ///< 右键事件, 忽略value取值.
kRightToLeft, ///< 处理阿拉伯文字的方向问题, value类型为huint32 *, 0表示不启用, 1表示启用.
};
#define TranslateItemCount 31
/** @enum HMenuItemKey
* @brief 作为菜单key
*/
enum HMenuItemKey
{
kMenuUndo = 0, ///< 撤销
kMenuRedo, ///< 恢复
kMenuCut, ///< 剪切
kMenuCopy, ///< 复制
kMenuPaste, ///< 粘贴
kMenuDelete, ///< 删除
kMenuSelAll, ///< 选择全部
kMenuInsertImage, ///< 插入图片
kMenuResizeImage, ///< 调整图片大小
kMenuInsertTable, ///< 插入表格
kMenuTableProp, ///< 表格属性
kMenuRow, ///< 行菜单
kMenuInsertRowAbove, ///< 上方插入行
kMenuInsertRowBelow, ///< 下方插入行
kMenuDeleteRow, ///< 删除行
kMenuColumn, ///< 列菜单
kMenuInsertColLeft, ///< 左边插入列
kMenuInsertColRight, ///< 右边插入列
kMenuDeleteColumn, ///< 删除列
kMenuMergeCells, ///< 合并单元格
kMenuSplitCell, ///< 拆分单元格
kMenuSplitVert, ///< 垂直拆分
kMenuSplitHort, ///< 水平拆分
kMenuVertAlign, ///< 垂直对齐菜单
kMenuVAlignTop, ///< 顶端对齐
kMenuVAlignBottom, ///< 底端对齐
kMenuVAlignCenter, ///< 居中对齐
kMenuUnmerge, ///< 合并恢复菜单
kMenuUnmergeRows, ///< 合并恢复行
kMenuUnmergeColumns, ///< 合并恢复列
kMenuUnmergeAll, ///< 合并恢复全部
};
enum HEditTableStatus
{
kNone = 0x00000000, ///< 无表格.
kTable = 0x00000001, ///< 有表格.
kTableSelected = 0x00000002, ///< 有表格,并且选中.
kTableSelRectangular = 0x00000004, ///< 有表格,编辑单元格.
kTableCanMergeSelected = 0x00000008, ///< 有表格,并且可以合并单元格操作.
};
/** @enum HTextHAlignment
* @brief 水平对齐方式.
*/
enum HTextHAlignment
{
kLeftAlignment, ///< 水平左对齐.
kHCenterAlignment, ///< 水平居中对齐.
kRightAlignment, ///< 水平右对齐.
kJustifyAlignment, ///< 水平分散对齐.
};
/** @enum HEditVAlignment
* @brief 段落垂直对齐方式.
*/
enum HEditVAlignment
{
kBottomAlignment, ///< 垂直向下对齐.
kVCenterAlignment, ///< 垂直居中对齐.
kTopAlignment, ///< 垂直置顶对齐.
};
enum HImageType
{
kMemoryFile,
kLocalFile,
};
enum HSpaceType
{
kNonSpace,
kLeftSpace,
kRightSpace,
kTopSpace,
kBottomSpace,
};
enum HFixedType
{
kFixedHeight,
kFixedWidth,
kLineHeight,
kLineWidth,
};
#pragma pack(1)
typedef struct HGenImageParam
{
HImageType type;
huint32 pageWidth;
huint32 pageHeight;
bool mulImageFlag;
HFixedType fixedType;
HSpaceType spaceFlag;
} HGenImageParam;
typedef struct HImageInfo
{
HImageType type;
huint32 dataCount;
union {
wchar_t * filename; ///< 调用者传入
char * bytes; ///< 类库提供.
};
} HImageInfo;
typedef struct HInsertImageInfo
{
const char* filename;
huint32 imageWidth;
huint32 imageHeight;
} HInsertImageInfo;
typedef struct HContextInfo
{
void* stream; ///< 文本控件生成的文件流对象
void* memory; ///< 文件流
huint32 size; ///< 文件流内容的大小
} HContextInfo;
typedef struct HDefFontInfo
{
huint32 size; ///< 默认字体大小
char* name; ///< 默认字体名字
} HDefFontInfo;
typedef struct HTableProperties
{
huint32 row; ///< 行数
huint32 col; ///< 列数
huint32 Color; ///< 表格背景颜色
huint32 BestWidth; ///< 单元格宽度
huint32 CellBorderWidth; ///< 边框宽度
huint32 CellBorderColor; ///< 单元格边框颜色
huint32 CellPadding; ///< 单元格内边距
} HTableProperties;
typedef struct HTablePropOperate
{
HMenuItemKey key;
const void* value;
} HTablePropOperate;
HErrorCode LoadContextInBack(bool editType, const void *textStream, huint32 streamSize,
const HGenImageParam *param, HEditVAlignment vAlignment,
bool backgroundTrans, huint32 backgroundColor,
huint32 *pages);
HErrorCode InitEdit(const void(*callback)(HTextKey key, const void *value));
HErrorCode DestroyEdit();
HErrorCode GetPageImageInBack(huint32 pageNo, HImageInfo *image);
HErrorCode FreeImageInBack(HImageInfo *image);
}
我本来是负责.net的,对java一般般,对c++不熟,折腾了挺久才写出能成功用java调通的代码。但是调通后返回数据不对。定义的Java调用方法如下:
@Deprecated
int LoadContextInBack(byte editType, Pointer textStream, int streamSize, HGenImageParam param, int vAlignment, byte backgroundTrans, int backgroundColor, IntByReference pages);
int LoadContextInBack(bool, const void*, huint32, const HGenImageParam*, HEditVAlignment, bool, huint32, huint32*)
int LoadContextInBack(byte editType, Pointer textStream, int streamSize, HGenImageParam param, int vAlignment, byte backgroundTrans, int backgroundColor, IntBuffer pages);
int InitEdit(InitEdit_callback_callback*)
int InitEdit(EditDLLToImageDllLibrary.InitEdit_callback_callback callback);
int DestroyEdit();
int GetPageImageInBack(huint32, HImageInfo*)
int GetPageImageInBack(int pageNo, HImageInfo image);
int FreeImageInBack(HImageInfo*)</code><br>
int FreeImageInBack(HImageInfo image);
C++的枚举里的数据我在java里都定义成了“public static final int 名称 = 数字”的形式,就像下面这样:
public static interface HErrorCode {
public static final int kSuccess = 0;
public static final int kInvalidInit = 1;
public static final int kInvalidParam = 2;
public static final int kMallocMemoryFail = 3;
public static final int kSetParentHandleFail = 4;
public static final int kInvalidRVFFile = 5;
public static final int kSaveRVFFileFail = 6;
public static final int kInvalidRTFFile = 7;
public static final int kInvalidTxtFile = 8;
public static final int kInvalidImgFile = 9;
};
C++里面的结构体我在java里是这样定义的,其他的结构体也大同小异,代码如下:
public class HImageInfo extends Structure {
public int type;
public int dataCount;
public field1_union field1;
public static class field1_union extends Union {
public CharByReference filename;
public Pointer bytes;
public field1_union() {
super();
}
public field1_union(CharByReference filename) {
super();
this.filename = filename;
setType(CharByReference.class);
}
public field1_union(Pointer bytes) {
super();
this.bytes = bytes;
setType(Pointer.class);
}
public static class ByReference extends field1_union implements Structure.ByReference {
};
public static class ByValue extends field1_union implements Structure.ByValue {
};
};
public HImageInfo() {
super();
}
protected List<? > getFieldOrder() {
return Arrays.asList("type", "dataCount", "field1");
}
public HImageInfo(int type, int dataCount, field1_union field1) {
super();
this.type = type;
this.dataCount = dataCount;
this.field1 = field1;
}
public HImageInfo(Pointer peer) {
super(peer);
}
public static class ByReference extends HImageInfo implements Structure.ByReference {
};
public static class ByValue extends HImageInfo implements Structure.ByValue {
};
}
本来是不想把C++的枚举在java中写成“public static final int 名称 = 数字”的形式。但是其他写法一直调不通。现在这样虽然可以成功调用dll,但是返回的结果不是想要的,比如参考C#完美调用的例子,在java里用GetPageImageInBack方法调用dll返回了1,也就是返回的其实是HErrorCode里面kInvalidInit的值。但是应该返回的是HErrorCode里面kSuccess的值,也就是应该返回0。这方面折腾了挺久也没折腾出想要的结果,很明显我定义的调用方法不咋的,用起来也麻烦。
现在最想请教的是如何根据这个c++头文件,来定义方便快捷的java调用方法。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
考虑用rpc直接传数据,这样也许会好一些,不要耦合太深