VB6写ActiveX COM组件比较方便,不仅PowerBASIC与VB6兼容性好,Delphi7与VB6兼容性也不错,但二者与FreeBASIC兼容性在字符串处理上差距比较大,FreeBASIC是C化的语言,可直接使用C指令。下面还是以实现MKI/CVI, MKL/CVL, MKS/CVS, MKD/CVD, CRC16为出发点,先说说VB6与FreeBASIC的字符串交互,然后VB6做成ActiveX与Delphi7交互就比较方便了。FreeBASIC和PowerBASIC一样拥有保留字MKI/CVI, MKL/CVL, MKS/CVS, MKD/CVD, 同时还拥有 lang -QB 后几乎QUICK BASIC的全部指令可用。
FreeBASIC写DLL入口出口模板做好的(是个形式需要,没实际内容),下载勇芳的FreeBASIC免安装直接运行,选用DLL模板然后写自己的函数。下面是实现 MKI 的代码,在FreeBASIC里即可用MKI,还有MKShort可用。
FUNCTION myMKI (ByVal Param1 AS Short) AS BSTR EXPORT
DIM I AS Short
DIM TString AS STRING
I = 0 : TString = ""
' code goes here
FOR I = 2 TO 1 STEP -1
TString=TString+RIGHT(("0"+LTRIM(HEX(ASC(MID(MKShort(Param1),I,1))))),2)
NEXT I
FUNCTION = StringToBStr(TString)
END FUNCTION
Function里 ByVal Param1 as Short,可以接收VB6的Integer,as BSTR是VB6用的字符串格式,CSDN的知识告诉我们它是宽字符,并且字符串前面有4个字节记录了字符串长度,而FreeBASIC里用的字符串是C格式的,接收了VB6整数直接处理没问题,但返回字符串给VB6不能直接返回,缺少四个字节的东西。StringToBSTR是为转换做的函数,函数里没做什么处理,而是用C的oleauto.h里的SysAllocString完成转换的,前面说了,FreeBASIC直接可用C的命令。
再看看MKS,也是用的MKS函数,也同样转换成BSTR返回给VB6。
FUNCTION myMKS (BYVAL Param1 AS SINGLE) As BSTR EXPORT
DIM I AS INTEGER
DIM TString AS STRING
I=0: TString=""
' code goes here
FOR I = 4 TO 1 STEP -1
TString=TString+RIGHT(("0"+LTRIM(HEX(ASC(MID(MKS(1.0*Param1),I,1))))),2)
NEXT I
FUNCTION = StringtoBStr(TString)
END FUNCTION
如果Function里接收VB6字符串,处理后返回给VB6字符串,不仅要StringtoBSTR转换,还要对接收的字符串进行BSTRtoString转换,看下面的代码。
FUNCTION myINSTRU (BYVAL Param1 AS BStr) As BSTR EXPORT
DIM LParam1 AS STRING
DIM RETURNSTR AS STRING
RETURNSTR = "UNKNOWN"
LParam1 = BStrToString(Param1)
SELECT CASE LParam1
CASE "VERSION"
RETURNSTR = "VERSION 1.00 9AUG2023"
CASE "AUTHOR"
RETURNSTR = "Mongnewer"
END SELECT
FUNCTION = StringToBstr(RETURNSTR)
END FUNCTION
BstrTostring的实现稍复杂一些,代码如下:
Function BStrToString(nBStr As BStr) As String '将VB里的字符串转换为FB里使用的字符串
Dim L As Long =Peek(Long,Cast(UInteger,nBStr) -4)
Dim ss As String = String(L,0)
memcpy StrPtr(ss),nBStr,L
Function = ss
End Function
取得VB6字符串的地址减4然后直接Peek从内存中读出来传送的字符串长度,再造一个这个长度的本地string,再把收到的BSTR的字符考贝到新建的字符之中,这样等长度字符就有了。字符串转换在FreeBASIC里勇芳做了细致的工作,更多更细代码下载开发环境都带齐了。
如果VB6传送前知道字符串长度,或是通过另外的参数同时传送长度值,那处理就更方便了。FreeBASIC可以在函数中定义 ByRef Param1 AS BStr , VB6那边也是ByRef,然后呢,宽字符直接考贝。Dim As String ss = "FreeBASIC One",StrCpyW(Param1, Cast(WString Ptr, StrPtr(ss))), 在VB6里看到字符串会被FreeBASIC改写了。
传送时FreeBASIC有Byref和Byval 类型 ptr指针可用,VB6有Byref和Varptr可用,Delphi有 Pchar等P指针可用,传送地址改写地址数据进行交互还是比较方便的,长度问题最简便的方法是传送时用另外的参数传送长度值。
VB6写ActiveX与上篇《Delphi7通过VB6之COM对象调用PowerBASIC写的DLL功能》博文类似Delphi7通过VB6之COM对象调用PowerBASIC写的DLL功能_Mongnewer的博客-CSDN博客
只是在函数声明时稍做改变
Private Declare Function myMKI Lib "MBFIEEE32FB.dll" Alias "MYMKI@4" (ByVal a As Integer) As String
Private Declare Function myCVI Lib "MBFIEEE32FB.dll" Alias "MYCVI@4" (ByVal b As String) As Integer
Private Declare Function myMKL Lib "MBFIEEE32FB.dll" Alias "MYMKL@4" (ByVal a As Long) As String
Private Declare Function myCVL Lib "MBFIEEE32FB.dll" Alias "MYCVL@4" (ByVal b As String) As Long
Private Declare Function myMKS Lib "MBFIEEE32FB.dll" Alias "MYMKS@4" (ByVal a As Single) As String
Private Declare Function myCVS Lib "MBFIEEE32FB.dll" Alias "MYCVS@4" (ByVal b As String) As Single
Private Declare Function myMKD Lib "MBFIEEE32FB.dll" Alias "MYMKD@8" (ByVal a As Double) As String
Private Declare Function myCVD Lib "MBFIEEE32FB.dll" Alias "MYCVD@4" (ByVal b As String) As Double
Private Declare Function myCRC16 Lib "MBFIEEE32FB.dll" Alias "MYCRC16@4" (ByVal a As String) As String
Private Declare Function myINSTRU Lib "MBFIEEE32FB.dll" Alias "MYINSTRU@4" (ByVal a As String) As String
函数名不变,Lib选的DLL文件变了,然后有个 Alias 名,FreeBASIC编译器会为每个函数加上别名,如果拿不准具体别外,可在终端窗口中 dumpbin /exports mbfieee32fb.dll ,库中的别名就都列出来了。 dumpbin 是装 studio 平台自带的工具,也能单独找到。
因为函数名不变,所以Delphi7调用时除引用的COM不同,其它可以保持不变。
VB6做COM可以粘接PowerBASIC,也可以粘接FreeBASIC,还可以在一个COM下同时粘接 PowerBASIC和FreeBASIC写的DLL,当然,也可以不用COM直连互通。这些东西都挺古老了,就不赘述了。