在上一回我们已经实现VC,VB代码的混合编译,并成功的在VB代码中调用了VC代码中的一个无参数的函数,并取得了函数的返回值. 这一回我们将实践一下如何调用带参数的函数.
打开上一会的两个工程(LinkWithVC, vcobj). 切换到VB在form上添加一个按钮 name: cmdTestLong, 标题 TestLong. 在form上添加一个文本框txtInput 内容填 8. 再在ModVC中添加如下代码:
Public Function TestLong(ByVal lng As Long) As Long
TestLong = -1
End Function
在cmdTestLong的Click事件中添加代码 msgbox Testlong(clng(txtInput.Text))
现在我们来生成EXE. 显然生成会失败,打开log文件看看.
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
[lib]
1=User32.lib
Settings段的lib 表示 [lib]段中的lib数目。 在lib段 我按照顺序1=…,2=… 添加我们要连接的lib即可,当然也可以是obj文件。
好我们再来操作,生成EXE,OK。运行点击TestHwnd。好了我们看到TextBox中的文字变成了 VC: Hello VB 。
我们再来试试字符串。
在form上添加一个按钮TestString 在ModVC中添加函数
Public Function TestString(ByVal s As String) As Long
Rem nothing
End Function
TestString的Click事件中添加如下代码
Private Sub CmdTestString_Click()
Dim s As String
s = Space(256) '为s分配空间
Call TestString(s)
MsgBox s
End Sub
在VC中添加同名函数
void ModVC::TestString()
{
char* p;
_asm mov p,eax; //取得参数(TextBox的句柄)
memset(p,0,256);//我们知道字符串的长度是256
lstrcpy(p,"VC: Hello VB");
}
编译,生成EXE,运行,点击TestString按钮,。。。咦,显示的是乱码!!??这是因为VB中的String用的是Unicode,VC中复制的不是。转一下就可以了。就在vb中转吧vb有一个函数很方便。把msgbox s 改为 MsgBox StrConv(s, vbUnicode),再生成EXE运行,这次OK了。
接下来我们再试试传递结构体。函数参数格式的声明我们可以参考一下VB中API函数的声明。我来个简单点的结构体 POINTAPI, 用VB的 API Viewer 找到
Public Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Public Type POINTAPI
x As Long
y As Long
End Type
参照这个我们在ModVC中添加函数
Public Function TestStruct(lppt As POINTAPI) As Long
Rem
End Function
在form上添加一个按钮TestStruct,在Click中添加代码
Private Sub cmdTestStruct_Click()
Dim pt As POINTAPI
Call TestStruct(pt)
MsgBox "x= " & pt.x & " y=" & pt.y
End Sub
在VC类中添加同名同类型函数。
void ModVC::TestStruct()
{
POINT *pt;
_asm mov pt,eax;//获取 指针参数
pt->x = 123;
pt->y = 456;
}
编译运行。。。。我们会发现 非法操作。大概是说引用了0x00000000处的内存。看这个内存地址我们会知道 在vc中引用了一个空指针,那就是说eax的值是0。那则么回事参数没有在eax里面,参数跑哪里去了?在其它寄存器?不太可能。。。那会在哪里呢,我们总不能凭空变出来一个参数吧。想想C++类中有什么可以用的符号?嗯,有一个 this 指针。会是它吗,熟悉VC的人应该知道在调用类成员函数时会先将该类的this指针存放到 eax 中。看来他们有很大的关系。那就动手试试。函数改为如下:
void ModVC::TestStruct()
{
POINT *pt=(POINT)this;
pt->x = 123;
pt->y = 456;
}
再编译,生成EXE运行。OK!成功了,看到了 x= 123 y=456 .
我们再回过头来看看前面的函数 ,都假设把this 当着参数试试,经过测试假设成立。如是我们知道this 就是传递过来的参数,当参数是long是,同时eax中也有这个参数值的一个副本。
到现在看来似乎是大功告成了,还没有!还有一个难题,this就只有一个,如果要传递2个,3个,4个。。。参数怎么办呢?