Results 1 to 22 of 22

Thread: [VB6] Adding Custom Tasks and Items to the Jump List (Taskbar Right-click)

Threaded View

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    7,654

    Lightbulb [VB6] Adding Custom Tasks and Items to the Jump List (Taskbar Right-click)


    cJump v1.0
    Adding to the Jump List with ICustomDestinationList

    This project has been a long time coming. Started working on porting a C++ example to VB6 way back in 2014, and wasn't able to get it working despite many many hours playing around with interface definitions. Had tons of hope when Olaf was able to get things working using vbRichClient5 (see this thread). But of course I wanted to use the interfaces through oleexp rather than RC5. Simply changing out the calls in his project still left things not working, and I had tons of frustration as I'd spend countless hours, give up, and revisit and repeat over the years. Today I found the problem; I re-did the conversion, only this time included the class, and it worked. So more hours and hours thinking it needed to be done from a class, until I traced it to a single call and single problem: I had declared an API call wrong, and had copy/pasted the right version into the class. That's that held this all up for 5 years and countless hours trying to figure out the problem.

    When you click on one of the items, it launches a new instance of your app with the information on what was clicked passed through the command line, retrieved with the Command$() function in VB. Note that this means nothing will happen if you click an item without having compiled an exe first (and I get an error clicking an item from the IDE in the new instance, but it works fine when compiled). You can then handle the command in any number of ways; have the new instance perform the task, or use various IPC methods to notify the first instance of your app and then exit before loading anything (note that this it not shown in the demo, the demo just creates a block for a non-empty command line).

    Requirements
    Windows 7 or newer
    oleexp v4.5 or higher (Released 01 Aug 2018)
    (Older oleexp versions *might* work with or without slight changes, but I had been playing around with the interfaces quite a bit trying to get them to work, so I'm not sure which versions work, which versions don't, or which versions need the calls to be different)

    Code

    Using oleexp allows simplifying things quite a bit, here's the class:
    Code:
    Option Explicit
    'cJump v1.0: Using Jump Lists in VB6
    'by fafalone
    '
    'Requires oleexp.tlb v4.5 or higher
    
    'This is a version of Olaf's demonstration class of doing this with vbRichClient5, to use
    'the relavent interfaces through oleexp instead
    
    Private Declare Function SetCurrentProcessExplicitAppUserModelID Lib "shell32" (ByVal psID As Long) As Long 'NOT STRING NOT STRING NOT STRING
    
    Private pCDL As ICustomDestinationList
    
    Public Function InitList(sAppID As String, Optional nMinSlot As Long) As IObjectArray
    SetCurrentProcessExplicitAppUserModelID StrPtr(sAppID)
    Set pCDL = New DestinationList
    pCDL.SetAppID StrPtr(sAppID)
    pCDL.BeginList nMinSlot, IID_IObjectArray, InitList
    End Function
     
    Public Sub AddToList(pList As oleexp.IObjectCollection, Optional sTitle As String, Optional sArgs As String, Optional sToolTip As String, Optional ByVal nIconID As Long)
    Dim hr As Long
    Dim pLink As ShellLinkW
    Dim pStore As IPropertyStore
    
    Set pLink = New ShellLinkW
    pLink.SetPath App.Path & "\" & App.EXEName & ".exe"
    pLink.SetArguments sArgs
    pLink.SetDescription sToolTip
    pLink.SetIconLocation "imageres.dll", -nIconID
      
    hr = pLink.QueryInterface(IID_IPropertyStore, pStore)
    
    If sTitle <> "" Then
        Dim vTitle As Variant
        vTitle = CVar(sTitle)
        pStore.SetValue PKEY_Title, vTitle
        pStore.Commit
    Else
        pStore.SetValue PKEY_AppUserModel_IsDestListSeparator, CVar(True)
        pStore.Commit
    End If
    
    pList.AddObject ByVal ObjPtr(pLink)
    End Sub
    
    
    Public Sub AddUserTasks(pList As IObjectCollection)
    pCDL.AddUserTasks ByVal ObjPtr(pList)
    End Sub
    
    Public Sub AppendCategory(sCat As String, pList As IObjectCollection)
    pCDL.AppendCategory ByVal StrPtr(sCat), ByVal ObjPtr(pList)
    End Sub
    
    Public Sub AbortList()
    pCDL.AbortList
    End Sub
    
    Public Sub CommitList()
    pCDL.CommitList
    End Sub
    
    '-------------------
    'You can remove the following if you have mIID.bas in your project
    Private Sub DEFINE_UUID(Name As UUID, L As Long, w1 As Integer, w2 As Integer, B0 As Byte, b1 As Byte, b2 As Byte, B3 As Byte, b4 As Byte, b5 As Byte, b6 As Byte, b7 As Byte)
      With Name
        .Data1 = L
        .Data2 = w1
        .Data3 = w2
        .Data4(0) = B0
        .Data4(1) = b1
        .Data4(2) = b2
        .Data4(3) = B3
        .Data4(4) = b4
        .Data4(5) = b5
        .Data4(6) = b6
        .Data4(7) = b7
      End With
    End Sub
    Private Function IID_IObjectArray() As UUID
    Static iid As UUID
     If (iid.Data1 = 0) Then Call DEFINE_UUID(iid, &H92CA9DCD, CInt(&H5622), CInt(&H4BBA), &HA8, &H5, &H5E, &H9F, &H54, &H1B, &HD8, &HC9)
      IID_IObjectArray = iid
    End Function
    Private Function IID_IPropertyStore() As UUID
    Static iid As UUID
     If (iid.Data1 = 0) Then Call DEFINE_UUID(iid, &H886D8EEB, CInt(&H8CF2), CInt(&H4446), &H8D, &H2, &HCD, &HBA, &H1D, &HBD, &HCF, &H99)
      IID_IPropertyStore = iid
    End Function
    'End of mIID.bas section
    '-----------------------------
    
    '-----------------------------
    'You can remove the following if you have mPKEY.bas in your project
    Private Sub DEFINE_PROPERTYKEY(Name As PROPERTYKEY, L As Long, w1 As Integer, w2 As Integer, B0 As Byte, b1 As Byte, b2 As Byte, B3 As Byte, b4 As Byte, b5 As Byte, b6 As Byte, b7 As Byte, pid As Long)
      With Name.fmtid
        .Data1 = L
        .Data2 = w1
        .Data3 = w2
        .Data4(0) = B0
        .Data4(1) = b1
        .Data4(2) = b2
        .Data4(3) = B3
        .Data4(4) = b4
        .Data4(5) = b5
        .Data4(6) = b6
        .Data4(7) = b7
      End With
      Name.pid = pid
    End Sub
    Private Function PKEY_Title() As PROPERTYKEY
    Static pkk As PROPERTYKEY
     If (pkk.fmtid.Data1 = 0&) Then Call DEFINE_PROPERTYKEY(pkk, &HF29F85E0, &H4FF9, &H1068, &HAB, &H91, &H8, &H0, &H2B, &H27, &HB3, &HD9, 2)
    PKEY_Title = pkk
    End Function
    Private Function PKEY_AppUserModel_IsDestListSeparator() As PROPERTYKEY
    Static pkk As PROPERTYKEY
     If (pkk.fmtid.Data1 = 0&) Then Call DEFINE_PROPERTYKEY(pkk, &H9F4C2855, &H9F79, &H4B39, &HA8, &HD0, &HE1, &HD4, &H2D, &HE1, &HD5, &HF3, 6)
    PKEY_AppUserModel_IsDestListSeparator = pkk
    End Function
    'End of mPKEY.bas section
    '---------------------------
    I've included the relevant sections of mIID and mPKEY in the class so those are not required.

    Using it is pretty simple, again this is pretty much just a conversion of Olaf's version:
    Code:
    Public cJL As New cJump
    Private Sub CreateJumpList(sID As String)
    cJL.InitList sID
      
    Dim MyCat As New EnumerableObjectCollection
    cJL.AddToList MyCat, "Item 1", "/cat /arg1", "ToolTip 1", 14
    cJL.AddToList MyCat, "Item 2", "/cat /arg2", "ToolTip 2", 23
    cJL.AppendCategory "Custom Category", MyCat
      
    Dim Tasks As New EnumerableObjectCollection
    cJL.AddToList Tasks, "Task 1", "/task /arg1", "ToolTip Task 1", 47
    cJL.AddToList Tasks, "Task 2", "/task /arg2", "ToolTip Task 2", 78
    cJL.AddToList Tasks 'Leave blank for separator
    cJL.AddToList Tasks, "Task 3", "/task /arg3", "ToolTip Task 3", 86
    cJL.AddUserTasks Tasks
    
    cJL.CommitList
    End Sub
    The class uses imageres.dll for the icons, the trailing numbers above are icon indexes within it, but you can change that to anything else with the .SetIconLocation call in AddToList.



    ITaskbarList
    For anyone curious, yes you can use both ICustomDestinationList (this project) with ITaskbarList3/4 (overlay icons, progress, change thumbnail area, and add buttons -- see this demo project). The buttons/changed thumbnail of the latter only appear when the taskbar icon is hovered over, whereas the jump list only appears upon a right-click; so none of the features in either project conflict with any others and can be present in the same taskbar item.



    Download cJump class and demo project:
    Attached Files Attached Files
    Last edited by fafalone; Sep 13th, 2019 at 06:54 PM. Reason: NOT STRING

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width