|
本帖最后由 菜鸟学飞 于 2011-10-27 18:42 编辑
这里的代码和原理来自于download和amicy 的多线程代码,VB完美的运行多线程已经有好长一段时间了,似乎感觉少有人用这个东西,本人闲来无事 整理了一下代码,在这里向VB多线程新手推广一下.
代码我已经整理成了两个函数
值得注意的是 如果你要使用多线程或者用VB写DLL 那么请将你的程序入口改为sub main(工程属性 > 启动对象 设置为 sub main)- '============================================
- '| 函 数 名 | VBCreateThread
- '| 说 明 | 创建一个线程(Create a thread)
- '| 参 数 | lpStartAddress: 线程函数地址(thread function address )
- '| 参 数 | lpParam: 线程参数(thread param)
- '| 参 数 | lpThreadId: 线程ID(tid)
- '| 返 回 值 | 返回线程句柄(hThread)
- '============================================
- Public Function VBCreateThread(ByVal lpStartAddress As Long, ByVal lpParam As Long, Optional ByRef lpThreadId As Long = 0) As Long
- '======================================================
- '| 函 数 名 | InitVB
- '| 说 明 | 初始化VB运行库(Init vb runtime),仅仅使用在DllMain的开头,在你的线程代码里面不需要调用这个东西
- '| 参 数 | 无 (void)
- '| 返 回 值 | 无 (void)
- '注意!!!!!!!!!
- '为了防止错误 必须将程序入口设置为 sub main (工程属性 > 启动对象 设置为 sub main)
- '因为多线程时候会重复调用 sub main或者fromload
- '注意!!!!!!
- 'InitVB函数会对sub main做处理 InitVB会删除 sub main 的代码
- '所以 如果你要重复多次调用 sub main 请另写代码
- '如果程序是是DLL 请在dllmain的开头 初始化VB运行库(InitVB)
- '=======================================================
- Public Function InitVB() As Long
复制代码 如果你是在EXE中使用这个代码 创建多线程如下即可
(需要注意的是,在你的线程函数里面不需要你自己初始化线程环境等
VBCreateThread统统都给你处理好了,线程函数可以参考后面的线程代码)- VBCreateThread AddressOf TestThread, 888
- '888是线程的参数
复制代码 如果你想用vb写DLL(包括在DLL中hook api,显示窗口等)那么请如下操作- '注意 在DLL MAIN里面 需要初始化VB运行库(InitVB) 才能创建线程
- Public Function DllMain(ByVal hinstdll As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long 'VB标准DLL入口函数
- Const DLL_PROCESS_ATTACH As Long = 1
- Const DLL_THREAD_ATTACH As Long = 2
- Const DLL_PROCESS_DETACH As Long = 0
- Const DLL_THREAD_DETACH As Long = 3
- Select Case fdwReason
- Case DLL_PROCESS_ATTACH
-
- '初始化VB 运行库
- InitVB
- '创建线程
- VBCreateThread AddressOf TestThread, 888
-
- Case DLL_THREAD_ATTACH
- Case DLL_PROCESS_DETACH
- Case DLL_THREAD_DETACH
- End Select
- DllMain = 1
- End Function
复制代码 至于线程函数的代码可以参考下面(线程函数里面不需要InitVB或者做其他初始化VB多线程的事情)- Public Function TestThread(ByVal lpParam As Long) As Long
- 'frmMain 是已经设计好的一个窗体
- Dim a As New frmMain
- MsgBox "收到的线程参数是:" & lpParam
- '显示模式窗口 必须是模式否则窗口一闪(要想非模式窗口请自己处理消息循环)
- a.Show 1
- MsgBox "Thread exit"
- Unload a
- Set a = Nothing
- End Function
复制代码 所有的完整代码都在这里:注入VB写的DLL 显示窗口 用winsock控件进行 网络通信的
代码可以编译EXE 也可以编译成标准DLL
顺便广告:编译DLL需要下载本人的VB多功能编译插件
http://www.vbgood.com/thread-107527-1-1.html
关于VB dll注入其他进程HOOK API 顺便说几句:
如果你想HOOK一个API比如:OpenProcess,你的HOOK处理函数是:MyOpenProcess,那MyOpenProcess里面你要非常非常小心的写代码,因为目标程序有可能是多个线程调用OpenProcess,而这些线程都是宿主程序建立的线程,没有初始化VB(initVB),如果在MyOpenProcess里面没有处理好 那结果就是崩溃.
我一般的解决方法是:
1、去掉msvbvm60.__vbaSetSystemError ,往__vbaSetSystemError 入口写入ret指令 让其无效,这样调用API就不会出错
副作用就是整个进程里面都不能不能使用 Err.LastDllError,当然你可以自己调用GetLastError,或者不用.
Public Sub KillvbaSetSystemError()
Dim DllFunAddr As Long
DllFunAddr = GetProcAddress(LoadLibrary("msvbvm60"), "__vbaSetSystemError")
WriteProcessMemory -1, ByVal DllFunAddr, &HC3C3C3C3, 4, ByVal 0
End Sub
2、hook处理函数里面(MyOpenProcess)里面不能使用字符串(数组也会经常出错),将所有参数类型定义为long,使用字符串API来处理字符串(如wcscpy)
3、如果hook处理函数里面(MyOpenProcess)里面会涉及非常复杂的操作那么可以将这个操作独立到另外的进程(或者其他已经初始化好的VB线程),使用SendMessage通信(或者其他方式通信),这时hook函数就会只涉及 复制少量参数,传递给主程序,主程序返回值判断,由于操作放到了主程序(或者其他已经初始化好的VB线程),处理代码就不会考虑VB多线程的问题.
CreateProcess例子
Public Function CreateProcessCallBack(ByVal a As Long, ByVal lpApplicationName As Long, ByVal lpCommandLine As Long, ByVal lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal lpCurrentDriectory As Long, ByVal lpStartupInfo As Long, ByVal lpProcessInformation As Long, ByVal b As Long) As Long
Dim tmpp As Long
Dim tmpProcessinf As PROCESS_INFORMATION
'通过共享内存获取信息
GetData ShareMem
'判断主控程序的窗口句柄是否有效
If IsWindow(ShareMem.AntiHwnd) <> 0 Then
'将参数写入到共享内存里面 这里不是线程安全的 有可能会崩溃
tmpp = pShareMem + 12
Call wcscpy(ByVal tmpp, ByVal lpApplicationName)
tmpp = pShareMem + 12 + 1000
Call wcscpy(ByVal tmpp, ByVal lpCommandLine)
If SendMessage(ShareMem.AntiHwnd, &H400, 0, ByVal 0) = 0 Then '发送消息
CreateProcessCallBack = 0 '拒绝启动
Else
'允许启动
tmpp = dwCreationFlags
dwCreationFlags = dwCreationFlags Or CREATE_SUSPENDED '打上挂起标记
CreateProcessCallBack = CreateProcessJmpBack(a, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDriectory, lpStartupInfo, lpProcessInformation, b)
CopyMemory tmpProcessinf, ByVal lpProcessInformation, LenB(tmpProcessinf)
InjectMyself tmpProcessinf.hProcess '在挂起的进程中注入DLL
If (tmpp And CREATE_SUSPENDED) <> CREATE_SUSPENDED Then '如果有挂起标记则不恢复运行
ResumeThread tmpProcessinf.hThread '恢复运行
End If
End If
Else
CreateProcessCallBack = CreateProcessJmpBack(a, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDriectory, lpStartupInfo, lpProcessInformation, b)
End If
End Function
补充内容 (2011-11-4 12:54):
注意
多线程都会调用VBDllGetClassObject 这个函数有个很严重的问题 会清空当前模块的所有全局变量
关于这个问题 暂无解决办法
问题详见http://www.vbgood.com/thread-107708-1-2.html
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
评分
-
查看全部评分
|