VB6 调用 Nim 生成的 DLL

关于 Nim

Nim 是德国人 开发的编程语言,最初叫 Nimrod。Nim 有下面几个特点:

  • 强制缩进语法
  • AST 操控
  • 编译到 C
  • 静态编译 .exe 或 dll
  • 指针
  • gc

Nim 的标准库还可以,一些常用的算法、网络库都有,也有不少的 wrapper 库。

生成 DLL

Nim 可以很方便地生成 Dll 文件,只需要在导出的 proc 中加入编译指令 {.stdcall, exportc, dynlib.};编译时使用参数:nim c --app:dll -d:release src.nim

例如

proc return_multiply*(a, b: int): int {.stdcall, exportc, dynlib.} =
    a * b

有一点需要注意的是,(似乎)因为编译器的问题,DLL 导出的函数名可能会编写的时候不一致,可以用 Dependency Walker 之类的工具查看。

比如上面的例子,导出的函数 return_multiply ,以 stdcall 调用方式编译后,入口为 return_multiply@8

VB6 代码,只需要声明就可以使用 DLL 中的函数。

Public Declare Function return_multiply Lib "test.dll" Alias "return_multiply@8" (ByVal a As Long, ByVal b As Long) As Long

对于简单的数据类型,VB6 与外部 DLL 交互还是比较简单的,问题是实际编程中更常见的复合数据类型,像字符串之类的应该如何处理。

VB6 字符串

VB6 是一个 IDE 也是一个语言。话说 MS 早期便是造 Basic 工具起家的,传说 Bill Gate 也参与编写当年 Basic 解释器的代码。VB 的发展几乎是 COM 组件的发展吏了,VB 也可以也认为是一个 MS 官方提供的 COM 组件快速使用工具。VB 的底层设计主要就是为了 COM 组件设计的。

COM 组件又复杂无庞大,是 Windows 的基础技术之一,就算 Windows 10 估计也留有不少古老代码。

VB 字符串类型实际上一种名为 BSTR 的 COM 字符串。因为 COM 组件被设计为可用于不同语言之间交互,所以在字符串设计上,是采用独立的做法。

BSTR 可以包含 NULL 字符串;由被调用者申请内存,调用者释放内存,并提供统一的内存申请释放方法;一个 BSTR 字符串由两部组成,第一部分表示字符串字节长度,第二部分是字符数组,字符数组不以 NULL 为终结标志。

一个 VB 字符串,实际是一个指向一个 BSTR 字符数组的第一个字符的指针。所有在与 C 代码交互时,一个 VB 字符串相当于一个 char* 指针,可以直接用于需要 cstring 的地方。

对于字符串必须要考虑编码问题。VB6 内部是 Unicode 编码的,但对外全部都是 ASCII。当年在开发 VB6 的时候,Windows API 只有 A 版本,字符串不编码之间的转换由编译器自动完成。可以这样认为,VB6 还不是一个完全体,可惜已经没有 VB7 了。

另一个与 VB 字符串相关的就是 LPSTR 类型,相当一部分的 Windows API 包含有 LPSTR 类型的参数。MS 官方是这样定义 LPSTR

The LPSTR type and its alias PSTR specify a pointer to an array of 8-bit characters, which MAY be terminated by a null character.

typedef char* PSTR, *LPSTR;

LPSTR 是 PSTR 的一个别名,是一个 8 位字符数组的指针,这个数组可能不是以 NULL 字符结尾的。大部分情况下 BSTRLPTSTR 是指的同样的数据结构,可以互换。

Nim 示例

根据 VB 的这些特点,写一个简单的字符串处理函数。

import encodings

const
    vbCodePage = "GB2312"
    vbTrue* = 1
    vbFalse* = 0

type
    VBString* = cstring
    VBBoolean* = int32
    
proc fromVBString*(a: VBString): string =
    return encodings.convert($a, "UTF-8", vbCodePage)
    
proc `$` (a: VBString): string =
    return fromVBString(a)

proc toVBString*(a: string): VBString =
    return VBString(encodings.convert(a, vbCodePage, "UTF-8"))

Nim 的字符串是 UTF-8 编码的,VB 的字符串是按系统 CodePage 编码的(中文环境下为 GB2312),需要一些编码转换操作,使用 Nim 标准库 encodings 实现。

下面实现一个 MD5 计算函数让 VB 调用。

import md5

proc build*(str: string): string =
    result = md5.getMD5(str)
# 计算 MD5
#
proc md5sum*(str: VBString): VBString {.stdcall, exportc, dynlib.} =
    return md5sum.build($str)

转载于:https://my.oschina.net/yuekcc/blog/775990

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值