VB6调用Windows7任务栏进度条的ITaskbarList3接口
来源:互联网 发布:图片转矢量图软件 编辑:程序博客网 时间:2024/05/29 19:59
如果说上次我发的那个直接调用R0函数的是鸡肋的话,这次这个就是有很好的实际应用的东西。
大家都知道COM接口,COM就是一个虚函数表指针,VB6虽然支持COM的thiscall调用,可必需通过引用,而如果一些COM接口没有给基于VB6的引用,那VB6就残了,比如IStream之类的,这次的ITaskbarList3也是一样。
我们先看看看一个COM接口在内存中的结构,这里我用VB6的方式写,大家理解起来会很简单。
如果我们声明一个变量,这个变量是一个COM对象,然后调用xx函数真正初始化了这个对象,COM指针就指向一个虚函数表,此时COM在Win32内存中是这样的,伪代码如下:
Type Com
Type IUnknown
QueryInterface + 0
AddRef + 4
Release + 8
End Type
Function1 + 12
Function2 + 16
Function3 + 20
···
End Type
恩,可以理解为COM指针就是一个表的内存区域,然后这个内存区域里面就是这样一张虚函数表,调用时,编译器根据索引*4取得需要调用的虚函数的地址,然后进行调用。
我们再追寻下一个COM对象的诞生过程:
声明COM对象变量(x86下这是一个4字节的指针)
调用**函数初始化这个变量,**函数进行一个new class操作,IUnknown引用+1,初始化class内的各种此对象需要内部变量之类的等等,这就是为什么call这个COM成员函数时需要压入COM指针,因为那就是一个伪class指针,记录了一些这个class需要使用的数据。
此时一个新的class数据被分配出来,建立虚函数表,把class的基地址写入4字节的程序内变量。
程序调用class的某个成员函数,根据虚函数表取到函数地址,压入class基地址,函数代码内从这个class提取相关变量等,执行代码。
我们再来看看一个COM函数的原形:
void test(int a,int b);
真正的原形是:
void test(this,int a,int b);
this即为class指针,这是对程序员不可见的。我们称此为thiscall,也就是stdcall的一个变种。(可以去看看cdecl、stdcall、thiscall的文章)
添加一个Module1,复制代码:
这代码就是根据ITaskbarList3的CLSID和IID通过CoCreateInstance创建出来一个COM对象指针,然后调用里面的虚函数,实现Windows7下任务栏进度条效果。
关于ITaskbarList3的其他函数说明自己看MSDN就行了,理解套用代码就一样调用,其他的COM接口也一样。比如什么XMLLite的那些东西。。。
有人会问,上面的SetProgressValue不是3个参数么,为什么我们调用的时候传入了5个参数?!
看原形,SetProgressValue是一个dword的hwnd,2个ULONGULONG的进度参数,ULONGULONG这个玩意是8字节,压栈的时候分2个4字节压,所以我们就写成了4个参数,也就是分开了。就像那个FILETIME差不多。再简单一点,一个ULONGULONG=2个ULONG=2个dword
好了、长篇大论就写到这里,撸管睡觉去。
大家都知道COM接口,COM就是一个虚函数表指针,VB6虽然支持COM的thiscall调用,可必需通过引用,而如果一些COM接口没有给基于VB6的引用,那VB6就残了,比如IStream之类的,这次的ITaskbarList3也是一样。
我们先看看看一个COM接口在内存中的结构,这里我用VB6的方式写,大家理解起来会很简单。
如果我们声明一个变量,这个变量是一个COM对象,然后调用xx函数真正初始化了这个对象,COM指针就指向一个虚函数表,此时COM在Win32内存中是这样的,伪代码如下:
Type Com
Type IUnknown
QueryInterface + 0
AddRef + 4
Release + 8
End Type
Function1 + 12
Function2 + 16
Function3 + 20
···
End Type
恩,可以理解为COM指针就是一个表的内存区域,然后这个内存区域里面就是这样一张虚函数表,调用时,编译器根据索引*4取得需要调用的虚函数的地址,然后进行调用。
我们再追寻下一个COM对象的诞生过程:
声明COM对象变量(x86下这是一个4字节的指针)
调用**函数初始化这个变量,**函数进行一个new class操作,IUnknown引用+1,初始化class内的各种此对象需要内部变量之类的等等,这就是为什么call这个COM成员函数时需要压入COM指针,因为那就是一个伪class指针,记录了一些这个class需要使用的数据。
此时一个新的class数据被分配出来,建立虚函数表,把class的基地址写入4字节的程序内变量。
程序调用class的某个成员函数,根据虚函数表取到函数地址,压入class基地址,函数代码内从这个class提取相关变量等,执行代码。
我们再来看看一个COM函数的原形:
void test(int a,int b);
真正的原形是:
void test(this,int a,int b);
this即为class指针,这是对程序员不可见的。我们称此为thiscall,也就是stdcall的一个变种。(可以去看看cdecl、stdcall、thiscall的文章)
我随便找了一个程序,截取其调用一个COM成员函数时的代码:
好了,理解了这些基本的东西,我们就可以动手了。
ITaskbarList3这个COM对象的声明在Windows 7 SDK的Shobjidl.h文件中,C style如下:
typedef struct ITaskbarList3Vtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in REFIID riid, /* [annotation][iid_is][out] */ __RPC__deref_out void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( __RPC__in ITaskbarList3 * This); ULONG ( STDMETHODCALLTYPE *Release )( __RPC__in ITaskbarList3 * This); HRESULT ( STDMETHODCALLTYPE *HrInit )( __RPC__in ITaskbarList3 * This); HRESULT ( STDMETHODCALLTYPE *AddTab )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd); HRESULT ( STDMETHODCALLTYPE *DeleteTab )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd); HRESULT ( STDMETHODCALLTYPE *ActivateTab )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd); HRESULT ( STDMETHODCALLTYPE *SetActiveAlt )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd); HRESULT ( STDMETHODCALLTYPE *MarkFullscreenWindow )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [in] */ BOOL fFullscreen); HRESULT ( STDMETHODCALLTYPE *SetProgressValue )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [in] */ ULONGLONG ullCompleted, /* [in] */ ULONGLONG ullTotal); HRESULT ( STDMETHODCALLTYPE *SetProgressState )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [in] */ TBPFLAG tbpFlags); HRESULT ( STDMETHODCALLTYPE *RegisterTab )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwndTab, /* [in] */ __RPC__in HWND hwndMDI); HRESULT ( STDMETHODCALLTYPE *UnregisterTab )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwndTab); HRESULT ( STDMETHODCALLTYPE *SetTabOrder )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwndTab, /* [in] */ __RPC__in HWND hwndInsertBefore); HRESULT ( STDMETHODCALLTYPE *SetTabActive )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwndTab, /* [in] */ __RPC__in HWND hwndMDI, /* [in] */ DWORD dwReserved); HRESULT ( STDMETHODCALLTYPE *ThumbBarAddButtons )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [in] */ UINT cButtons, /* [size_is][in] */ __RPC__in_ecount_full(cButtons) LPTHUMBBUTTON pButton); HRESULT ( STDMETHODCALLTYPE *ThumbBarUpdateButtons )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [in] */ UINT cButtons, /* [size_is][in] */ __RPC__in_ecount_full(cButtons) LPTHUMBBUTTON pButton); HRESULT ( STDMETHODCALLTYPE *ThumbBarSetImageList )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [in] */ __RPC__in_opt HIMAGELIST himl); HRESULT ( STDMETHODCALLTYPE *SetOverlayIcon )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [in] */ __RPC__in HICON hIcon, /* [string][unique][in] */ __RPC__in_opt_string LPCWSTR pszDescription); HRESULT ( STDMETHODCALLTYPE *SetThumbnailTooltip )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [string][unique][in] */ __RPC__in_opt_string LPCWSTR pszTip); HRESULT ( STDMETHODCALLTYPE *SetThumbnailClip )( __RPC__in ITaskbarList3 * This, /* [in] */ __RPC__in HWND hwnd, /* [in] */ __RPC__in RECT *prcClip); END_INTERFACE } ITaskbarList3Vtbl;SetProgressValue为第10个函数,那函数地址就是(10-1)*4,为了更易懂,我们可以把一个COM函数的Vtbl列成VB6里面的Enum。
添加一个Module1,复制代码:
Private Declare Function CallWindowProcW& Lib "user32" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long)Private Declare Function LocalAlloc& Lib "kernel32" (ByVal f&, ByVal s&)Private Declare Function LocalFree& Lib "kernel32" (ByVal m&)Private Declare Sub PutMem1 Lib "msvbvm60" (ByVal Ptr As Long, ByVal NewVal As Byte)Private Declare Sub PutMem2 Lib "msvbvm60" (ByVal Ptr As Long, ByVal NewVal As Integer)Private Declare Sub PutMem4 Lib "msvbvm60" (ByVal Ptr As Long, ByVal NewVal As Long)Private Declare Sub PutMem8 Lib "msvbvm60" (ByVal Ptr As Long, ByVal NewVal As Currency)Public Function CallCOMInterface&(ByVal CComPtr&, ByVal dwMemberIndex&, ParamArray pParam())Dim i%, offset&Dim hMem&hMem = LocalAlloc(0, ((UBound(pParam) + 2) * 5) + 5 + 6 + 1) '//申请代码内存offset = hMemFor i = UBound(pParam) To 0 Step -1 '//压入参数PutMem1 offset, &H68 'push Paramoffset = offset + 1PutMem4 offset, pParam(i)offset = offset + 4NextPutMem1 offset, &H68 'push COM point,压入COM指针PutMem4 offset + 1, CComPtroffset = offset + 5PutMem1 offset, &HA1 'mov eax,dword ptr ds:CComPtr,eax=CComPtr指针第一个函数地址PutMem4 offset + 1, CComPtroffset = offset + 5PutMem1 offset, &HFF 'call dword ptr ds:eax + dwMemberIndex * 4,根据Win32下COM表结构,一个函数地址长度4字节PutMem1 offset + 1, &H90PutMem4 offset + 2, dwMemberIndex * 4offset = offset + 6PutMem1 offset, &HC3 'retnPutMem1 offset + 1, &H90 '//nop一行代码CallCOMInterface = CallWindowProcW(hMem, 0, 0, 0, 0) 'callLocalFree hMem '//释放内存End Function再添加一个Form1,一个Command1,复制代码:
Private i&Private Enum ITaskbarList3QueryInterfaceAddRefRelease'IUnknownHrInitAddTabDeleteTabActivateTabSetActiveAltMarkFullscreenWindowSetProgressValueSetProgressStateRegisterTabUnregisterTabSetTabOrderSetTabActiveThumbBarAddButtonsThumbBarUpdateButtonsThumbBarSetImageListSetOverlayIconSetThumbnailTooltipSetThumbnailClipEnd EnumPrivate Type GUIDData1 As LongData2 As IntegerData3 As IntegerData4(7) As ByteEnd TypePrivate Declare Function IIDFromString& Lib "ole32 " (ByVal ID As Long, ByVal IDs As Long)Private Declare Function CLSIDFromString& Lib "ole32 " (ByVal ID As Long, ByVal IDs As Long)Private Declare Function CoCreateInstance& Lib "ole32 " (ByVal CLSID As Long, ByVal Outer As Long, ByVal Context As Long, ByVal IID As Long, Obj As Any)Private Function CreateW7Task&()Dim CID As GUID, IID As GUID, objW7Task&CLSIDFromString StrPtr("{56FDF344-FD6D-11d0-958A-006097C9A090}"), VarPtr(CID)IIDFromString StrPtr("{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}"), VarPtr(IID)CoCreateInstance VarPtr(CID), 0, 1, VarPtr(IID), objW7TaskCreateW7Task = objW7TaskEnd FunctionPrivate Sub Command1_Click()Dim j&For j = 0 To 10000Me.Caption = CallCOMInterface(i, SetProgressValue, Me.hWnd, j, 0, 10000, 0)NextEnd SubPrivate Sub Form_Load()i = CreateW7TaskEnd Sub点击Command1测试效果。
这代码就是根据ITaskbarList3的CLSID和IID通过CoCreateInstance创建出来一个COM对象指针,然后调用里面的虚函数,实现Windows7下任务栏进度条效果。
关于ITaskbarList3的其他函数说明自己看MSDN就行了,理解套用代码就一样调用,其他的COM接口也一样。比如什么XMLLite的那些东西。。。
有人会问,上面的SetProgressValue不是3个参数么,为什么我们调用的时候传入了5个参数?!
看原形,SetProgressValue是一个dword的hwnd,2个ULONGULONG的进度参数,ULONGULONG这个玩意是8字节,压栈的时候分2个4字节压,所以我们就写成了4个参数,也就是分开了。就像那个FILETIME差不多。再简单一点,一个ULONGULONG=2个ULONG=2个dword
好了、长篇大论就写到这里,撸管睡觉去。
- VB6调用Windows7任务栏进度条的ITaskbarList3接口
- Windows7 任务栏功能的开发
- 操作 Windows7 任务栏的快捷方式
- Windows7下VB6的安装方法~
- 急!还原windows7任务栏的 资源管理器图标
- 不为人知的Windows7任务栏大揭秘【lpxt】
- Windows7任务栏无法删除图标的解决办法
- ^^ 创建setup类型的进度条(vb6) ^^
- ^^ 创建setup类型的进度条(vb6) ^^
- ^^ 创建setup类型的进度条(vb6)
- VB6下接口的实现
- windows7 任务栏突然消息
- windows7 任务栏 启动 参数
- VB6中的任务栏图标编程
- windows7,windows8的任务栏上也有“显示桌面”的快捷方式
- windows7不能将程序快捷方式附加到任务栏的解决办法
- vb6.0 做的ocx 安全接口
- 双色进度条控件,很酷的效果 开发:VB6
- 扩展EGL支持Google App Engine Datastore数据存储
- Clueful:监控你手机中滥用数据的应用
- 使用Rexsee在线创建Android应用的Hello World程序
- 第十四周任务(二)
- PHP中的CURL函数库一览
- VB6调用Windows7任务栏进度条的ITaskbarList3接口
- 汉化以及创建和管理内容(Drupal笔记二)
- ASP.NET上传图片代码
- find 和 grep 命令 常用实用例子
- 十大高明的Google搜索技巧
- php-Arrays 函数-array_unshift-在数组开头插入一个或多个单元
- 使用MbrFix软件卸载Linux系统
- Ubuntu安装配置Mysql
- Java判断字符串是否为数字