数据结构大作业-DBLP科学文献管理系统(四) Dll编写,C++与C#的数据交换

        终于讲完了后端代码,要涉及到前端的内容了。作为C++写的后台,而在Unity中是用C#中作为脚本语言。因此后台的代码想在前端进行调用,需要讲C++部分打包成Dll的动态链接库,约定好对应的格式,即可在C#中调用。

        首先需要了解C++/C#之前的主要区别,两种语言在语法上和关键字上很相似。这里体现的最主要的区别C#是托管堆代码,C++是非托管堆代码。在数据分配上C++每当用new等关键字申请空间时,编译器会在堆上为其分配内存,在使用完成后需要delete等回收空间,尤其注意在局部函数中申请的空间,一旦丢失了指向申请内存的指针,那么就会造成内存泄漏,即申请的内存空间和数据依然放在堆中,但是再也没办法使用和回收它(因为失去了地址去定位),当程序一直运行时,无效内存会越来越多,最终导致内存溢出崩溃(这就是我不怎么习惯用C++的一种原因,虽然现在已经有了auto_ptr等) 。

        而C#中的托管堆代码即将内存管理交给了OS和编译器,当一段内存没有被任何指针或变量引用后,就会由system.GC()自动回收 。基于这两种语言的特性,在C++中设计函数参数类型和数据交换时要考虑兼容性。

        这里列举一些常用的数据类型对应:

Windows Data Type

.NET Data Type

BOOL, BOOLEAN

Boolean or Int32

BSTR

String

BYTE

Byte

CHAR

Char

DOUBLE

Double

DWORD

Int32 or UInt32

FLOAT

Single

HANDLE (and all other handle types, such as HFONT and HMENU)

IntPtr, UintPtr or HandleRef

HRESULT

Int32 or UInt32

INT

Int32

LANGID

Int16 or UInt16

LCID

Int32 or UInt32

LONG

Int32

LPARAM

IntPtr, UintPtr or Object

LPCSTR

String

LPCTSTR

String

LPCWSTR

String

LPSTR

String or StringBuilder*

LPTSTR

String or StringBuilder

LPWSTR

String or StringBuilder

LPVOID

IntPtr, UintPtr or Object

LRESULT

IntPtr

SAFEARRAY

.NET array type

SHORT

Int16

TCHAR

Char

UCHAR

SByte

UINT

Int32 or UInt32

ULONG

Int32 or UInt32

VARIANT

Object

VARIANT_BOOL

Boolean

WCHAR

Char

WORD

Int16 or UInt16

WPARAM

IntPtr, UintPtr or Object

        这里只用了一些比较常用的。比如整数类型DWORD(C++)对应uint(C#),字符串传值时使用char*(C++)对应string/stringBuilder(C#)。

        其次是在C++中导出Dll,用vs可以很简单的创建一个C++Dll工程。

然后在.cpp文件写好函数,这里拿项目中需要得到一个string的哈希值做例子

DWORD Hash4(const string& tar) //计算哈希值函数
{
    DWORD64 ans = 0;
    for (int i = 0; i < tar.length(); i++) {
        ans = ((ans >> 8) & 0xf) ^ ((ans << 4) ^ tar[i]);
    }
    return ans & 0xfff;
}
DWORD GetHash(char* tar) 
{
    string temp = tar;
    return Hash4(temp);
}

在.h中补充函数原型,添加上extern "C" _declspec(dllimport)语句

#ifdef DL1_API
#else
#define DL1_API extern "C" _declspec(dllimport) //交给客户端使用时
#endif

DL1_API DWORD GetHash(char* tar);

         最后在C#中使用[DllImport]导入, static extern 并对上函数原型参数列表,中间的名称为打包出来的Dll文件名,注意如果是在unity中想使用dll,需要放在对应的assert/plugin文件夹中,即可加载dll数据库。只是普通的C#控制台程序和执行文件同目录即可

        注意制力用了char*与c#中的string交换,c++中的string不论是传出还是传入数据都是和C#对不上的,所以需要用到char*,中间还会涉及到一些编码问题。而c#中string和stringBuilder都可以在C++中被接受到。

[DllImport("Dll2")]
public static extern uint GetHash(string tar); //需要对应上参数类型和函数名

        如果需要C#传入一个字符串,在C++中接收并进行修改,然后再由C#中得到结果,则需要用到stringBuilder,stringBuilder与string最大的不同在于stringBuilder可以预先分配空间,能够被多次的修改,并且不产生新的未使用对象(而string拷贝多了都是创建一个新的对象,非常耗时间)。在传值的时候建议使用stringBuilder,这里再拿程序中用到的搜索功能样例。

C++中函数原型:

void articleInfo(char* 文章名, char* 数据库地址, char* 结果);//输入文章名,返回文章的所有相关信息    


/// <summary>
/// 输入文章名,返回文章的所有相关信息
/// </summary>
/// <param name="_articleName">文章名</param>
/// <param name="_saveUrl">文件保存路径</param>
/// <param name="pt">对外输出结果</param>
void articleInfo(char* _articleName, char* _saveUrl, char* pt)
{
    string ret;
    ... //文件计算过程
    //将结果与c#对接
    if (ret.length() > 0)
    {
        strcpy_s(pt, ret.length() + 1, ret.c_str()); //拷贝数据输出
    }
}

C#中:

using System.Text;
StringBuilder stringBuilder = new StringBuilder(50000);
[DllImport("Dll1")]
public static extern void articleInfo(String articleName, String saveUrl, StringBuilder pt);

        不过如果需要传输的字符串内容过多,可以考虑c++先写入磁盘文件,在通过C#中打开文件再IO解决(实际上本程序中的模糊搜索实现方式采用的就是这样,面对一些单词几百万的结果,C++会存储在文件中再通过C# IO读取)

        至此,一个简单的Dll程序就这样设计完成,这里展示下程序中实际用到的所有接口。

    class DLL
    {
        public Thread thread;
        StringBuilder stringBuilder = new StringBuilder(50000);

        [DllImport("Dll1")]
        public static extern void articleInfo(String articleName, String saveUrl, StringBuilder pt);
        [DllImport("Dll1")]
        public static extern void main_Reader(String authorName, String saveUrl, StringBuilder pt);
        [DllImport("Dll1")]
        public static extern bool CheckFilePathCorrect_Compatible(string filePath, StringBuilder refS);
        [DllImport("Dll1")]
        public static extern bool CheckFilePathCorrect(string filePath);
        [DllImport("Dll1")]
        public static extern void CoAuthor(string search_name, string _saveUrl, StringBuilder pt);
        [DllImport("Dll1")]
        public static extern void initial_fuzzy(string filePath);
        [DllImport("Dll1")]
        public static extern int fuzzy_search(string filePath, uint threadNum, string content);
        [DllImport("Dll1")]
        public static extern void release_fuzzy_searcher();
        [DllImport("Dll1")]
        public static extern void Keyword_Sort(uint year, string filePath); //年份排序
        [DllImport("Dll2")]
        public static extern uint GetHash(string tar); //需要对应上参数类型和函数名
        [DllImport("Dll2")]
        public static extern bool ChechFilePathCorrect_dblp(string saveUrl);
        [DllImport("Dll1")]
        public static extern bool initial_readers(uint totalThread, uint maxThread, bool debugText, string saveUrl);//建库
        [DllImport("Dll1")]
        public static extern bool Author_Sort(string saveUrl); //作者排序
        [DllImport("Dll1")]
        public static extern int Full_word_match_fuzzy_search(string filePath, uint threadNum, string content);
        [DllImport("Dll1")]
        public static extern uint Format_Hash4(string tar); //哈希值
//C++中的原型
/*
        using data_initial::Hash4;//通用字符串Hash函数          DWORD Hash4(const string& 需要hash的字符)
        using data_initial::initial_readers;//数据库初始化建库函数  bool initial_readers(const DWORD 总线程数(建议值:16), DWORD 最多同时运行线程数(建议值:4), bool 是否显示文本(建议值:False), char* 数据库地址)
        using Keyword_Sorting::Keyword_Sort;//年份热搜排序    void Keyword_Sort(DWORD 年份, char* 数据库地址)
        using Author_Sorting::Author_Sort;//作者发文量排序    bool Author_Sort(char* 数据库地址)
        using Elements_Searcher::articleInfo;//输入文章名,返回文章的所有相关信息    void articleInfo(char* 文章名, char* 数据库地址, char* 结果)
        using Elements_Searcher::CheckFilePathCorrect;//检查文件路径是否正确      bool CheckFilePathCorrect(char* 数据库地址)
        using Elements_Searcher::CheckFilePathCorrect_Compatible;//检查文件路径是否正确(兼容模式) bool CheckFilePathCorrect_Compatible(char* 数据库地址)
        using Elements_Searcher::main_Reader;//输入作者名字,返回作者发布的所有文章   void main_Reader(char* 作者名字, char* 数据库地址, char* 结果)
        using Elements_Searcher::CoAuthor;//输入作者名字,返回所有合作作者   void CoAuthor(char* 作者名字, char* 数据库地址, char* 结果)
        using Fuzzy_Searcher::initial_fuzzy;//初始化模糊搜索    void initial_fuzzy(char* 数据库地址)
        using Fuzzy_Searcher::fuzzy_search;//模糊搜索   bool fuzzy_search(char* 数据库地址, DWORD 线程数, char* 目标内容)
        using Fuzzy_Searcher::release_fuzzy_searcher;//释放模糊搜索的资源(需要重新初始化)    void release_fuzzy_searcher()
         */
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值