c++源码的数据结构复杂,java如何调用dll?

发布于 2022-09-12 00:17:32 字数 11755 浏览 8 评论 0

本来有个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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝海 2022-09-19 00:17:33

考虑用rpc直接传数据,这样也许会好一些,不要耦合太深

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文