[原创]VC VB 的混合编译(三)多参数篇
发表于:
2005-10-20 18:53
12570
在上一回我们已经实现VB调用VC函数并传递一个long、窗口句柄、字符串指针、结构体指针的参数,并取得了函数的返回值。 这一回我们将实践一下如何传递多个参数。
打开上一回的两个工程(LinkWithVC, vcobj). 切换到VB在form上添加一个按钮 name: cmdTestStruct2, 标题 Test Struct 2。再在ModVC中添加如下代码
Public Function TestArg(lppt1 As POINTAPI, lppt2 As POINTAPI) As Long
Rem
End Function
在cmdTestStruct2的Click事件中
Private Sub cmdTestStruct2_Click()
Dim pt1 As POINTAPI, pt2 As POINTAPI
Call TestArg(pt1, pt2)
MsgBox "x= " & pt1.x & " y=" & pt1.y & vbCrLf & "x= " & pt2.x & " y=" & pt2.y
End Sub
好,现在生成EXE,必然不成功。我们打开log看会是什么错误信息,
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
Form1.OBJ : error LNK2001: unresolved external symbol "private: void __stdcall ModVC::TestArg(void)" (?TestArg@ModVC@@AAGXXZ)
F:\LinkWithVC\LinkWithVC.exe : fatal error LNK1120: 1 unresolved externals
我们看到连接器要求的函数声明和 无参数,1 个参数的相同,经过测试不能在VB模块声明的函数有多少个参数编译后都是 private: void __stdcall FunctionName(void ) 。
好了我们熟练的在VC的类中加上对应的TestArg函数。编译,生成EXE,通过。
下面来解决我们的难题,现在我们从VC程序的角度来说 函数声明是一样的参数个数却是不确定的。这时我们应该会想到C 函数中有一种可变参数的函数,这种函数要求至少有一个确定参数,然后使用一组宏获取其它参数。这里我们先复习一下 C语言中可变参数的用法
http://redcheek.net/blogview.asp?logID=67
复习完了我们知道函数该怎么写了,如下:
void ModVC::TestArg()
{
LPPOINT lppt1,lppt2;
va_list ap;
lppt1 = (LPPOINT)this;
va_start(ap,this);
lppt2 = va_arg(ap,LPPOINT);
lppt1->x = 123;
lppt1->y = 456;
lppt2->x = 321;
lppt2->y = 654;
}
这样子,能行吗,编译试试;
-------------------Configuration: vcobj - Win32 Release--------------------
Compiling...
ModVC.cpp
F:\LinkWithVC\vcobj\ModVC.cpp(72) : error C2102: '&' requires l-value
Error executing cl.exe.
ModVC.obj - 1 error(s), 0 warning(s)
显然编译失败了。
This 是一个 r-value,无法取地址。现在我们知道只要取得了this的地址我们的问题就解决了。那怎么知道this的地址呢。。。不知道大家有什么好方法没有,老实说,我没有,如果谁有更好的方法别忘了告诉我一声哦。
不过我有一个很笨的方法:跟踪调试程序在内存中找答案。
为了便于调试我更改函数内容为如下:
void ModVC::TestArg()
{
char p[256];
lstrcpy(p,"break here!");
_asm mov eax,1;
_asm mov eax,2;
_asm mov eax,3;
_asm mov eax,this;
_asm mov eax,4;
_asm mov eax,5;
_asm mov eax,6;
}
编译,生成EXE。我们现在使用ollydbg来调试 LinkWithVC.exe,打开这个程序,使用od的搜功能,搜索参考字符串,然后在 break here! 哪里设置一个断点。运行程序,点按钮,程序会在下面红色的地方中断。
004012C0 /$ 55 PUSH EBP
004012C1 |. 8BEC MOV EBP,ESP
004012C3 |. 81EC 00010000 SUB ESP,100
004012C9 |. 8D85 00FFFFFF LEA EAX,DWORD PTR SS:[EBP-100]
004012CF |. 68 30604000 PUSH LinkWith.00406030 ; /String2 = "break here!"
004012D4 |. 50 PUSH EAX ; |String1 = 0012F300
004012D5 |. FF15 C0104000 CALL DWORD PTR DS:[<&KERNEL32.lstrcpyA>] ; \lstrcpyA
004012DB |. B8 01000000 MOV EAX,1
004012E0 |. B8 02000000 MOV EAX,2
004012E5 |. B8 03000000 MOV EAX,3
004012EA |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
004012ED |. B8 04000000 MOV EAX,4
004012F2 |. B8 05000000 MOV EAX,5
004012F7 |. B8 06000000 MOV EAX,6
004012FC |. 8BE5 MOV ESP,EBP
004012FE |. 5D POP EBP
004012FF \. C2 0400 RETN 4
看看上面蓝色的代码,如是我们知道那条绿色的代码对应的源程序就是 mov eax, this;
如是 我们知道了this的地址就是 [ebp+8].程序代码下载
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课