0xAA55 发表于 2014-4-3 20:11:16

【混合编程】VB6与VC++的合体编程(不使用DLL)

转载请注明出处:http://www.0xaa55.com/thread-445-1-1.html
我觉得这应该是史无前例的。我是先驱者。。膜拜我吧

首先我来说一下原理:
VB6的IDE会把VB的工程编译成OBJ,然后用LINK完成链接。那么最后VB生成的OBJ去哪了呢?其实是被VB的IDE自动删除了。我们要做的就是截取VB还没完成链接的时候VB的IDE产生的OBJ文件,然后把它们和VC++产生的OBJ一起链接,以此来实现合体编程。这个的好处就是VB写界面方便而VC++能做到许多VB做不到的事,两者取长补短,互利共生。

首先打开VB6的IDE的文件夹。可以看到VB的LINK.EXE。VB就是用它完成链接的。

这个时候果断自己写一个LINK.EXE换掉这个原先的LINK.EXE!不过先备份旧的LINK.EXE,很简单,直接改名为LINK1.EXE就行了。
然后把自己写的LINK.EXE放进来。自己写的LINK.EXE有个特点,就是,它会卡住!这样我们就能趁它卡住的时候,找到工程文件里面的OBJ文件然后把它复制出来了。
那么我这里提供了一份我自己写的“假LINK.EXE”。压缩包里面有四个文件,两个批命令和两个EXE,这两个EXE一个是真LINK.EXE的备份,一个是假LINK.EXE的备份,双击GENEXE.BAT后就会自动把链接器换成真LINK.EXE,双击GENOBJ.BAT则会自动链接器换成假LINK.EXE。
下载地址:

下载后解压到你的VB的IDE的文件夹里面即可。

好,接下来准备编译得到OBJ。我准备了这么一个工程,它只有一个窗体和一个模块,我们要做的就是把这个模块换成VC++的OBJ,实现合体。

上图这个工程我会在后面提供下载。
我们要用VC++实现这个模块提供的函数!
那么先开始编译吧。
首先双击GENOBJ.BAT,换上假的链接器。

然后打开工程,文件->生成XXX.exe
只见它一卡,然后我们的假LINK就出来了。如下图所示:

没错!就是这样!我们现在就打开记事本把刚才的链接命令记下来。


看见了吧?这个是OBJ!我们看到了OBJ!
别急。创建OBJ文件夹。把得到的OBJ都丢进去。

好的,VB的IDE已经可以不鸟它了,接下来我们需要用VC++写一个代替modCOrCPP.obj的程序。
准备好了吗?
好,我们打开VC++,建立一个新的控制台程序。

讨厌预编译头,所以把它弄掉。

然后我们新建一个modCOrCPP.cpp,如下。

接下来就是写代码的部分了。这可是重点!
首先说一下就是VB的OBJ是个什么规律。
大家可以看到modCOrCPP只有四个函数:Sub VCPPSub()

End Sub

Function VCPPFunction() As Long

End Function

Sub VCPPSubWithParam(ByVal A As Long, ByVal B As Long)

End Sub

Function VCPPFuncWidthParam(ByVal A As Long, ByVal B As Long) As Long

End Function我们只要能用VC++实现这4个函数就行了。
我们用WinHex打开VB生成的modCOrCPP.obj,看最底部:

可以看出这个OBJ导出了四个符号:
?VCPPSub@modCOrCPP@@AAGXXZ
?VCPPFunction@modCOrCPP@@AAGXXZ
?VCPPSubWithParam@modCOrCPP@@AAGXXZ
?VCPPFuncWidthParam@modCOrCPP@@AAGXXZ
根据符号修饰我们会发现VB导出的这四个函数的原型其实用VC++是像下面这样的:class modCOrCPP
{
private:
    void _stdcall VCPPSub(void);
    void _stdcall VCPPFunction(void);
    void _stdcall VCPPSubWithParam(void);
    void _stdcall VCPPFuncWidthParam(void);
};没错,无论你怎么声明,它的原型都是【void _stdcall 类名::私有函数(void);】这种规律的,产生的符号也都是【?函数名@类名@@AAGXXZ】这样的。(我这里解释一下,结尾的“AAGXXZ”的意思是这个函数没有返回值,也没有参数列表,是一个类的私有成员函数,而且是_stdcall风格的)
这样我们怎样获取参数信息呢?只能通过裸函数了。
比如有个VB的函数,它的定义是Function foo() as Long那么它产生的符号翻译成VC++的函数原型就成了void _stdcall 类名::foo(void);
这个时候我们需要做的就是重新写一个函数,然后让这个类的导出函数跳转到这个函数,如下:static long bar(void)
{
    return 233;//设置返回值
}
_declspec(naked)void 类名::foo()
{
    _asm jmp bar;//直接跳走
}这样就行了。OBJ就能产生同样的符号了。
在VC6的界面下编译modCOrCPP.cpp->modCOrCPP.obj,然后我们在Debug、Release文件夹里面找到这个文件:modCOrCPP.obj,复制到VB的那堆OBJ里面,覆盖掉原先的OBJ文件,嗯,还记得之前打开过的记事本吧?

在这一整行链接器命令的前面加上一个“LINK ”,再把所有要链接的OBJ文件的文件路径去掉只保留文件名,在这整行命令的结尾按下回车,打个“@pause”,然后保存到你的OBJ文件夹,存为“BUILD.BAT文件”


还没完呢,接下来大家需要找到原先的VB的LINK.EXE和它所依赖的MSPDB60.DLL,把它们一起放到你的OBJ文件夹里面。


接下来双击BUILD.BAT,发现好像缺少了一些LIB。这个时候果断去VC++的Lib文件夹里面找到需要的LIB放到工程文件夹。

经过我的研究发现你需要把KERNEL32.LIB、USER32.LIB、LIBC.LIB、UUID.LIB、OLDNAMES.LIB这几个VC++的默认库全部放到你的OBJ文件夹。然后修改BUILD.BAT,在它的最前面LINK的后面加个空格,加上“KERNEL32.LIB USER32.LIB ”然后再次双击BUILD.BAT就会发现链接成功了。
打开EXE,点击上面的四个按钮,它们都正常运行啦~~赞一个


最后给出各种下载地址。
全部工程下载:**** Hidden Message *****

元始天尊 发表于 2014-4-3 21:54:25

以后就可以吧vb程序变成vc的了

山顶的一棵草 发表于 2014-4-11 12:20:00

看到了C 艹 :funk:

0x0208 发表于 2014-4-19 13:08:37

这样合体后的VC程序,是不是还是需要VB的运行库?

0xAA55 发表于 2014-4-19 18:36:00

0x0208 发表于 2014-4-19 05:08
这样合体后的VC程序,是不是还是需要VB的运行库?

对。是不是觉得略操蛋了点儿

0x0208 发表于 2014-4-20 10:38:12

0xAA55 发表于 2014-4-19 18:36
对。是不是觉得略操蛋了点儿

忙活半天,它不还是VB。

0xAA55 发表于 2014-4-20 15:08:08

0x0208 发表于 2014-4-20 02:38
忙活半天,它不还是VB。

你要这么说也行,但是你也可以说它是C、C艹

stlcours 发表于 2016-6-3 18:05:33

这个实在是有意思~~

唐凌 发表于 2017-3-29 18:01:01

原来就是中断link啊。。。那能不能自己通过批处理或命令行直接调用c2来编译vb的代码呢?

0xAA55 发表于 2017-3-29 19:27:05

tangptr@126.com 发表于 2017-3-29 18:01
原来就是中断link啊。。。那能不能自己通过批处理或命令行直接调用c2来编译vb的代码呢? ...

那是中断c2,你要做啥?

唐凌 发表于 2017-3-30 12:46:50

0xAA55 发表于 2017-3-29 19:27
那是中断c2,你要做啥?

C2难道不是把vb代码编译到obj的玩意么。。。

bigwind 发表于 2017-3-30 18:38:42

谢谢分享

阿呆在上海 发表于 2017-10-23 18:16:42

这个看不懂,但是觉得很高级

白天 发表于 2017-10-25 02:26:22

MARK,有时间研究研究

机械机械 发表于 2017-11-3 08:32:03

厉害:):):):):)

lyl_420819 发表于 2017-11-17 14:21:02

学习了,谢谢分享。

西北老狼 发表于 2017-12-24 15:28:50

这个感觉听着有可行性,目前正适合我的需要

搬砖工 发表于 2018-4-23 12:42:37

这个可以增加我装逼的词库量

watermelon 发表于 2018-6-9 08:29:39

膜拜,学习一下

Mradxz 发表于 2018-6-15 16:02:07

下个文件就走:lol
页: [1] 2
查看完整版本: 【混合编程】VB6与VC++的合体编程(不使用DLL)