Page 1 of 2 12 LastLast
Results 1 to 40 of 54

Thread: Virtual ListView - Show Subitem Text in TileView

  1. #1

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Virtual ListView - Show Subitem Text in TileView

    I seems like LVM_SETTILEINFO and setting LVTILEVIEWINFO '.cLines' yields no results.
    -How to achieve multiline in tileview (virtual listview)

    LucasMKG
    ?
    Attached Images Attached Images  
    Last edited by LucasMKG; Feb 22nd, 2016 at 07:36 AM.

  2. #2
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView MultiLine Text

    The other lines are just subitems. You have to add the columns, then when responding to LVN_GETDISPINFO supply the text as a normal subitem and also provide a response for LVIF_COLUMNS where you set puColumns, piColFmt(optional), and cColumns (the same as you would normally).

    If you're not familiar with piColFmt, it's probably because no VB project has ever included it.
    Code:
    Public Type LVITEM 'LVITEMW  ' was LV_ITEM
      mask As LVITEM_mask
      iItem As Long
      iSubItem As Long
      State As LVITEM_state
      StateMask As LVITEM_state
      pszText As Long
      cchTextMax As Long
      iImage As Long
      lParam As Long
    '#If (WIN32_IE >= &H300) Then
      iIndent As Long
    '#End If
    '#If (WIN32_IE >= &H501) Then
      iGroupId As Long
      cColumns As Long
      puColumns As Long
    '#End If
    '#If (WIN32_IE >= &H600) Then
      piColFmt As Long 'array of certain LVCFMT_ for each subitem
      iGroup As Long 'for single item in multiple groups in virtual listview
    '#End If
    End Type
    Edit: I'm having a lot of trouble setting the text however. Looks like another VB memory ****up. The iSubItems it requests for text after tile view are set are garbage in the 40-64000 range, so it winds up showing a different number of subitems on mouseover, none with the correct text.

    Also be advised MSDN says it's not supported, so who knows if it really can't be done or if it requires some extra unknown steps.
    The problem seems to be setting which columns are to be displayed. Which should be done by .puColumns. It does request LVIF_COLUMNS in LVN_GETDISPINFO, but I haven't found a way of setting it that works. Tried the normal way of setting it to VarPtr(cols(0)), no luck, and also tried Copymemory .puColumns, ByVal VarPtr(col(0)), 4&/elements*4bytes/long -again, no luck.
    Last edited by fafalone; Feb 8th, 2016 at 10:57 PM.

  3. #3

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView MultiLine Text

    fafalone,

    When you mention using 'LVIF_COLUMNS' then I was trying to figure the ©UniListView by (Dana Seaman - www.cyberactivex.com) code, but somehow its not responding:

    Code:
    Friend Property Get fSubItemShowInTile(ByVal lIndex As Long, ByVal lSubItemIndex As Long) As Boolean
       '
       If (m_lMajor >= 6) Then
          ReDim lOrigCols(0 To fColumnCount - 1) As Long
          m_tLVW.puColumns = VarPtr(lOrigCols(0))
          pGetStyle lIndex - 1, LVIF_COLUMNS
          If (m_tLVW.cColumns > 0) Then
             Dim i                As Long
             For i = 0 To m_tLVW.cColumns - 1
                If (lOrigCols(i) = lSubItemIndex) Then
                   fSubItemShowInTile = True
                End If
             Next i
          End If
       End If
       '
    End Property
    
    Friend Property Let fSubItemShowInTile(ByVal lIndex As Long, ByVal lSubItemIndex As Long, ByVal bState As Boolean)
       '
       If (m_lMajor >= 6) Then
          ' Check what we already have:
          ReDim lOrigCols(0 To fColumnCount - 1) As Long
          Dim lOrigColCount    As Long
    
          m_tLVW.puColumns = VarPtr(lOrigCols(0))
          pGetStyle lIndex - 1, LVIF_COLUMNS
          lOrigColCount = m_tLVW.cColumns
    
          Dim lFoundIndex      As Long
          Dim i                As Long
          Dim lNewCols()       As Long
          Dim tSANew           As SAFEARRAY1D
    
          lFoundIndex = -1
          For i = 0 To lOrigColCount - 1
             If (lOrigCols(i) = lSubItemIndex) Then
                lFoundIndex = i
                Exit For
             End If
          Next i
    
    
          If (bState) Then
             ' adding
             If (lFoundIndex = -1) Then
                ReDim lNewCols(0 To lOrigColCount) As Long
                For i = 0 To lOrigColCount - 1
                   lNewCols(i) = lOrigCols(i)
                Next i
                lNewCols(lOrigColCount) = lSubItemIndex
                m_tLVW.cColumns = lOrigColCount + 1
                m_tLVW.puColumns = VarPtr(lNewCols(0))
                pSetIStyle lIndex - 1, LVIF_COLUMNS
             Else
                ' nothing to do
             End If
          Else
             ' removing
             If (lFoundIndex = -1) Then
                ' nothing to do
             Else
                If (lOrigColCount = 1) Then
                   ' clearing:
                   m_tLVW.cColumns = 0
                   m_tLVW.puColumns = 0
                   pSetIStyle lIndex - 1, LVIF_COLUMNS
                Else
                   ' modifying
                   ReDim lNewCols(0 To lOrigColCount - 2) As Long
                   For i = lFoundIndex To lOrigColCount - 2
                      lNewCols(i) = lOrigCols(i + 1)
                   Next i
                   m_tLVW.cColumns = lOrigColCount - 1
                   m_tLVW.puColumns = VarPtr(lNewCols(0))
                   pSetIStyle lIndex - 1, LVIF_COLUMNS
                End If
             End If
    
          End If
    
       End If
    
    End Property
    - Attached, please find the source of the above code (UniListView.zip)


    LucasMKG
    Attached Files Attached Files
    Last edited by LucasMKG; Feb 8th, 2016 at 11:56 PM.

  4. #4
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView MultiLine Text

    That looks like the non-virtual way of doing it. In virtual mode you can't do a LVM_SETTILEINFO on an LVITEM, you have to respond to the LVN_GETDISPINFO request for LVIF_COLUMNS just like other LVIF_'s.. If (.mask And LVIF_COLUMNS) = LVIF_COLUMNS Then

  5. #5

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView MultiLine Text

    I checked this http://stackoverflow.com/questions/1...tems-to-appear

    # ListView_SetTileViewInfo is used together with LVN_GETDISPINFO

    - and still can't figure out the LVIF_TEXT part...how to display the '.cColumns; .puColumns'... in the .pszText (or StringToPointer VarPtr(ArgList(0)), .pszText)?

    The important bits are colored, so I have:

    Code:
    'Seal.added.based on ©Krool
    Public Property Let TileViewLines(ByVal Value As Long)
    'extended-tile view mode to show sub-items
        If Not (m_lHGHwnd = 0) Then
            Dim LVTVI As LVTILEVIEWINFO
            With LVTVI
                .cbSize = LenB(LVTVI)
    'rem.Seal            .dwMask = LVTVIM_COLUMNS
                .dwFlags = LVTVIF_AUTOSIZE                          'Seal.added: based on © 2016 Microsoft (Nikita Leontiev) - Thread 'Listview extended tile mode'
                .dwMask = LVTVIM_COLUMNS Or LVTVIM_LABELMARGIN      'Seal.added: based on © 2016 Microsoft (Nikita Leontiev) - Thread 'Listview extended tile mode'
                SendMessage m_lHGHwnd, LVM_GETTILEVIEWINFO, 0, ByVal VarPtr(LVTVI)
                .cLines = Value
                
                'Seal.added: based on © 2016 Microsoft (Nikita Leontiev) - Thread 'Listview extended tile mode'
                If m_bIsXp Then             'to work correctly under XP
                    Dim r As RECT
                    With r
                        .Bottom = 10
                        .left = 1
                        .Right = 1
                        .top = 10
                    End With
                    .RCLabelMargin = r
                End If
                SendMessage m_lHGHwnd, LVM_SETTILEVIEWINFO, 0, ByVal VarPtr(LVTVI)
            End With
        End If
    
        PropertyChanged "TileViewLines"
    
    End Property
    
    'NB: Trimmed down version
    Public Function ColumnAdd(ByVal lColumn As Long, _
                              ByVal sText As String, _
                              ByVal lWidth As Long, _
                              Optional ByVal eAlign As ECAColumnAlign = ecaColumnLeft, _
                              Optional ByVal lIcon As Long = -1, _
                              Optional ByVal bColumnHeaderIconOnRight As Boolean = False, _
                              Optional ByVal eColumnTag As ECSColumnSortTags = ecsSortAuto, _
                              Optional ByVal bColumnHeaderCheckBox As Boolean = False, _
                              Optional ByVal bColumnHeaderSplitButton As Boolean = False)
    
    '*/ create column headers
    
    Dim bFirst As Boolean
    Dim uLVC   As LVCOLUMN
    Dim uHDI   As HDITEM
    Dim uHDW   As HDITEMW
    
        If Not (m_lHGHwnd = 0) Then
            m_lHdrHwnd = HeaderHwnd()
            If Not (m_lHdrHwnd = 0) Then
                '/* unicode nt
                With uLVC
                    .pszText = StrPtr(sText)
                    .cchTextMax = LenB(sText)
                    .cx = lWidth
                    .fmt = eAlign
                    'extended-tile view mode to show sub-items
                    .Mask = LVCF_TEXT Or LVCF_WIDTH Or LVCF_FMT Or LVCF_SUBITEM         'Seal.modified.added: LVCF_SUBITEM : based on © 2016 Stack Exchange Inc. (push 22) : Thread 'c++ Virtual ListView in Tile view, can't get subitems to appear'
                    If ColumnCount > 1 Then .iSubItem = (ColumnCount - 1)               'Seal.modified.adapted: .iSubItem : based on © 2016 Stack Exchange Inc. (push 22) : Thread 'c++ Virtual ListView in Tile view, can't get subitems to appear'
                End With
                '/* add the column
                If m_bIsNt Then
                    ColumnAdd = (SendMessageW(m_lHGHwnd, LVM_INSERTCOLUMNW, lColumn, uLVC) > -1)
                '/* no unicode
                Else
                    ColumnAdd = (SendMessageA(m_lHGHwnd, LVM_INSERTCOLUMNA, lColumn, uLVC) > -1)
                End If
    End Function
    
    'NB: Trimmed down version
    'from my WndProc (GXISubclass_WndProc)
             '/* list change callback
                Case LVN_GETDISPINFOW, LVN_GETDISPINFOA 
                    If Not (m_eGridMode = eGrid) Then CreateListItems lParam, lCode
    
    'NB: Trimmed down version
    Private Function CreateListItems(ByRef lParam As Long, ByRef lCode As Long) As Long
    
    Dim lItem   As Long
    Dim sTemp   As String
    Dim tDisp   As NMLVDISPINFOW
    
        CopyMemory tDisp, ByVal lParam, Len(tDisp)
        With tDisp.Item
            lItem = .iItem
            '/* list item text
            If ((.Mask And LVIF_TEXT) = LVIF_TEXT) Then
                        sTemp = m_cGridItem(lItem).Text(.iSubItem)
                '/ copy text
                If Len(sTemp) > .cchTextMax Then
                    sTemp = left$(sTemp, .cchTextMax)
                End If
    If m_eGridMode = eLvwViewTile Then
    
    'x******************************************************************************
    'Seal.added: based on © 2016 Microsoft (Nikita Leontiev) - Thread 'Listview extended tile mode'
    'extended-tile view mode to show sub-items
    EDIT::
        Dim Buffer(1 To 19) As Long
        Dim ArgList() As Long, i As Long
        ReDim ArgList(0 To (ColumnCount - 1)) As Long
        For i = 1 To (ColumnCount)
            ArgList(i-1) = Buffer(i)
        Next i 
    ::
    'then in LVN_GETDISPINFO
    '...
    'UINT uint_array[] = {1,2,3};
    'if (pItem_param -> mask & LVIF_COLUMNS)
    '{
    '     pItem_param->puColumns = uint_array;
    '     pItem_param->cColumns = 3;
    '}
        If (.Mask And LVIF_COLUMNS) = LVIF_COLUMNS Then
            .cColumns = m_lTileViewLines                'The size of this array
            .piColFmt = LVCFMT_LEFT                     'Seal.modified.added: LVCFMT_LEFT : based on © 2016 Stack Exchange Inc. (push 22) : Thread 'c++ Virtual ListView in Tile view, can't get subitems to appear'
            .puColumns = VarPtr(ArgList(0))
        End If
    '    StringToPointer .puColumns, .pszText
    '******************************************************************************
    Else
                Select Case lCode           'Seal.Modified
                Case LVN_GETDISPINFOW       'Unicode
                    StringToPointer sTemp, .pszText
                Case LVN_GETDISPINFOA       'ANSI
                    lstrtoptr .pszText, sTemp
                End Select
    End If
            End If
    '....
    '....
    end with
    Last edited by LucasMKG; Feb 11th, 2016 at 12:26 AM.

  6. #6
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView MultiLine Text

    Are you getting the other lines showing up, just not with the right text?

    I just don't understand where these garbage values for iSubItem are coming from. Group view is a problem too. Without it, I can muddle through and get static text to appear (that is, can't look up based on given iSubItem, but can always set it to a particular one if an invalid isubitem is passed). But with it, that doesn't even work and the 2nd line tile text is always the same as the first, despite the static text being assigned.

    It's just not looking good for groupview, but tiles without groups we might be able to get a workaround going.

    Code:
                        If (.mask And LVIF_TEXT) = LVIF_TEXT Then
                                    Debug.Print "isubitem " & .iItem & "," & .iSubItem
                            Select Case .iSubItem
                                Case 0
                                    .pszText = StrPtr(VLItems(.iItem).sText)
                                Case 1 To 3
    '                                .pszText = StrPtr("subitem " & .iSubItem)
                                    .pszText = StrPtr(VLItems(.iItem).sSubItems(.iSubItem - 1))
                                Case Else
                                    If bTiles Then
                                        .pszText = StrPtr(VLItems(.iItem).sSubItems(2))
                                    End If
    See the debug statement there? That's what is reporting requested subitems as 101, 45000, 64000.. garbage. But always setting it to 2 works and shows subitem 2 as the 2nd tile line, but if groups are enabled the second tile line just stays the same as the first line, even though Case Else executes.

    Code:
                        If (.mask And LVIF_COLUMNS) = LVIF_COLUMNS Then
                            .cColumns = 1
    '                        CopyMemory .puColumns, ByVal VarPtr(lCol(0)), 4&
    '                        Debug.Print "ptr=" & VarPtr(lCol(0))
                            .puColumns = VarPtr(lCol(0))
                        End If
    Nothing I've tried there works; it always requests the garbage subitem values.
    Last edited by fafalone; Feb 11th, 2016 at 08:29 PM.

  7. #7

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView MultiLine Text

    its worse 'If (.Mask And LVIF_COLUMNS) = LVIF_COLUMNS Then' isn't firing

    - at least you're able to have the second tile line..but how? since 'If (.Mask And LVIF_COLUMNS) = LVIF_COLUMNS Then' isn't firing.

    - setting '.Mask = LVIF_IMAGE Or LVIF_TEXT Or LVIF_STATE Or LVIF_COLUMNS' before 'If (.Mask And LVIF_COLUMNS) = LVIF_COLUMNS Then' results in a crush.


    Quote Originally Posted by fafalone View Post
    ..But always setting it to 2 works and shows subitem 2 as the 2nd tile line..
    - how exactly did you get the 2nd tile line to show?..(i.e 'lCol' settings & every component involved)

    LucasMKG
    Last edited by LucasMKG; Feb 12th, 2016 at 04:20 AM.

  8. #8
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView MultiLine Text

    Nothing special just a normal LVM_SETTILEVIEW routine.. I'm a little leery of the one you're using because it's overwriting your mask (which shouldn't include label margins unless actually setting them, which your code doesn't unless it's XP) and flags with the LVM_GETTILEVIEWINFO result.. so it may very well be passed back missing the LVTVIM_COLUMNS mask and autosize flag.
    The one I use to switch it on:
    Code:
    Public Sub SetTileView(hWnd As Long)
    
    Dim tLVI As LVTILEVIEWINFO
    
    Call SendMessage(hWnd, LVM_SETVIEW, LV_VIEW_TILE, ByVal 0&)
    
       tLVI.cbSize = Len(tLVI)
       
       Call SendMessage(hWnd, LVM_GETTILEVIEWINFO, 0, tLVI)
       tLVI.dwMask = LVTVIM_COLUMNS
       tLVI.cLines = 2
       Call SendMessage(hWnd, LVM_SETTILEVIEWINFO, 0, tLVI)
    bTiles = True
    End Sub
    And one step to absolutely take is to confirm it's working in a standard listview before trying it when LVS_OWNERDATA is enabled.

  9. #9

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView MultiLine Text

    fafalone,

    thanks...after adding the below line, it worked:
    'Call SendMessage(hWnd, LVM_SETVIEW, LV_VIEW_TILE, ByVal 0&)'

    - it works even if '.cLine > 2'

    Code:
    'virtual listview
    'in the DISPINFO (Case LVN_GETDISPINFOW, LVN_GETDISPINFOA)
    
            '/* list item text
            If (.Mask And LVIF_TEXT) = LVIF_TEXT Then
                    Select Case .iSubItem
                    Case 0
                        sTemp = m_cGridItem(lItem).Text(0)
                    Case Else
                        If (m_eGridMode = eLvwViewTile) Then
                            sTemp = m_cGridItem(lItem).Text(m_lTileViewLines)
                        Else
                            sTemp = m_cGridItem(lItem).Text(.iSubItem)
                        End If
            End If
    now..I'm debugging the whole 'extended-tile view mode to show sub-items' feature..for seamless integration with vhGrid.

    LucasMKG
    - as the author of vhGrid - John Underhill (Steppenwolfe) send his shout out to 'Carles 'da man!' PV, for his awesome api listview'
    - I'm sending my shout-out to Fafalone 'da genius', for his wisdom impartation.
    Last edited by LucasMKG; Feb 15th, 2016 at 05:40 AM.

  10. #10
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView MultiLine Text

    It works completely normally? No trouble with .iSubItem values? In group mode too?

  11. #11

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView MultiLine Text

    but faf,
    it's unresolved, since the 'sequence of subitems lines' as per '.puColumns' are not showing...and currently it shows all subitem lines of the last column or whatever the value of m_lTileViewLines'..(it should show variable subitem lines as per '.puColumns' sequence).

    - is it possible to manipulate subitem lines with an array or something?

    LucasMKG
    ?
    Last edited by LucasMKG; Feb 16th, 2016 at 06:17 AM.

  12. #12

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Virtual ListView - Show Subitem Text in TileView

    .iSubItem Mod m_lTileViewLines ...produces some logical data.

    LucasMKG
    ..../.
    Last edited by LucasMKG; Feb 22nd, 2016 at 07:35 AM.

  13. #13

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    - how to set ' puColumns[0]'. . . since 'puColumns = VarPtr(array(0))' seem not to work.

    Code:
    For correct behavior we should write
    if (pItem_param -> mask &
    LVIF_COLUMNS)
    {
    pItem_param -> puColumns[0] =
    1;
    pItem_param -> puColumns[1] = 2;
    pItem_param -> puColumns[2] = 3;
    pItem_param->cColumns = 3;
    }
    in LVN_GETDISPINFO.
    Answered in
    http://social.msdn.microsoft.com/Forums/en-US/windowsuidevelopment/thread/c520ad3e-dbab-4ed1-
    98eb-22288ffb640c
    EDIT:::
    -Setting puColumns(20) As long...doesn't help.

    Code:
    Public Type LVITEM
      ....
      iGroupId As Long
      cColumns As Long
      puColumns(20) As Long
      ...

    LucasMKG
    .....
    Last edited by LucasMKG; Feb 23rd, 2016 at 01:39 AM.

  14. #14

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    typed on my MobilePhone::

    another option...it might be to manage it myself:

    - if i remove:
    'If (.Mask And
    LVIF_COLUMNS) = LVIF_COLUMNS' ...i still get subitem text in tileview.
    - i then insert this code to get logical data (but i have extra m_lTileViewLines in LVN_GETDISPINFO)
    Code:
    If (m_eGridMode = eLvwViewTile)
    Static Once As Boolean
    Static slCnt As Long
    Static slCol As Long
    If Once = False Then
    slCol = 0
    .iSubItem  = slCol
    slCnt = slCnt + 1
    If slCnt = (m_lTileViewLines + 1) Then Once = True
    Else
    If slCol = m_lTileViewLines Then slCol = - 1
    slCol = slCol + 1
    .iSubItem = slCol
    End If
    the issue about the above code is that, i can't figure out how '.iSubItem' in tileview should behave when '.clines' are set.

    LucasMKG
    ..

  15. #15
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    It's not behaving at all is the main problem.. I get either 0 or some large number, like 48038 or 64802, makes no sense whatsoever and ive tried a dozen different ways to try to get it sending the right numbers.. Nothing helps. I really think it's just not implemented. Only solution i can think of is the nuclear option: just owner draw it.

  16. #16

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    This might mean something after all:
    - Attached, pls find (xls zipped file) :: data extracted from '.iSubItem' : from 2 TileView Items: where # is the number of m_lTileViewLine

    LucasMKG
    not giving-up.
    Attached Files Attached Files

  17. #17
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    Not sure what I'm looking at.

    There's the deeper problem too.. the text keeps changing back and forth as the mouse moves between the main item text, which shouldn't even be one of the 2nd/3rd lines, and the text it's supposed to be (on the 3rd line; the 2nd line is always the same as the first)

    It's just random garbage. Like VB is randomizing which pointer is chooses with every paint.


    And the first detail line (2nd line overall and first gray line) is ALWAYS the same as the main item text. Even explicitly setting it, verified it's called. .pszText = StrPtr("***").. ignored, text= "Item 1", StrPtr(public string).. ignored, text= "Item 1"
    Last edited by fafalone; Feb 26th, 2016 at 09:19 PM.

  18. #18

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    It might be that if 'ISubItemCallback' is implemented...'TileView' will behave.
    -Remember that we should be able to view items like in the attached image...it might explain why item data updates when the mouse pointer is on that item..

    LucasMKG
    TOL
    Attached Images Attached Images  
    Last edited by LucasMKG; Feb 29th, 2016 at 04:15 AM.

  19. #19
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    The item in 'Other' is the only tileview item.

    The other items use subitem controls, which is proving to be the most complicated issue yet***. Timo already figured it out, but is one of those 'it's my secret code you can have it in a few years' guys


    Also Explorer isn't the best example as it almost certainly uses many customizations that aren't even accessible to outsiders or are simply owner drawn.


    *** - The main problem is I can't figure out for the life of me how to approach converting this mess to VB:
    Code:
            if(SUCCEEDED(hr)) {
    152              IPropertyControlBase* pControl = *reinterpret_cast<IPropertyControlBase**>(ppObject);
    153              CComBSTR themeAppName = L"";
    154              CComBSTR themeIDList = L"";
    155              WCHAR pSubAppNameBuffer[300] = {0};
    156              LPWSTR pSubAppName = pSubAppNameBuffer;
    157              ATOM valueSubAppName = reinterpret_cast<ATOM>(GetPropW(*this, L"#43281"));
    158              if(valueSubAppName) {
    159                  GetAtomNameW(valueSubAppName, pSubAppNameBuffer, 300);
    160                  if(lstrlenW(pSubAppNameBuffer) == 1 && pSubAppNameBuffer[0] == L'$') {
    161                      pSubAppNameBuffer[0] = L'\0';
    162                  }
    163              } else {
    164                  pSubAppName = NULL;
    165              }
    166              themeAppName = pSubAppName;
    167              WCHAR pSubIDListBuffer[300] = {0};
    168              LPWSTR pSubIDList = pSubIDListBuffer;
    169              ATOM valueSubIDList = reinterpret_cast<ATOM>(GetPropW(*this, L"#43280"));
    170              if(valueSubIDList) {
    171                  GetAtomNameW(valueSubIDList, pSubIDListBuffer, 300);
    172                  if(lstrlenW(pSubIDListBuffer) == 1 && pSubIDListBuffer[0] == L'$') {
    173                      pSubIDListBuffer[0] = L'\0';
    174                  }
    175              } else {
    176                  pSubIDList = NULL;
    177              }

    Edit: There mere presence of ISubItemCallback stabilized painting for the tiles, but still didn't help with .iSubItem random numbers. So it's now possible to have a single additional line; but only when not in group mode. Group mode is crashing right now; probably because it's calling GetSubItemControl and there's no code there yet.
    Last edited by fafalone; Feb 29th, 2016 at 12:42 PM.

  20. #20
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Virtual ListView - Show Subitem Text in TileView

    Quote Originally Posted by fafalone View Post
    *** - The main problem is I can't figure out for the life of me how to approach converting this mess to VB:
    Untested!!!

    Code:
    If SUCCEEDED(hr) Then
        Dim pControl        As IPropertyControlBase: GetMem4 ppObject, pControl
        Dim themeAppName    As String:               themeAppName = ""
        Dim themeIDList     As String:               themeIDList = ""
        Dim pSubAppName     As String:               pSubAppName = String$(300&, 0)
        Dim valueSubAppName As Integer:              valueSubAppName = CInt(GetPropW(GetLngFromPtr(this), StrPtr("#43281")))
    
        If valueSubAppName Then
            GetAtomNameW valueSubAppName, StrPtr(pSubAppName), 300&
            If Left$(pSubAppName, 2&) = "$" & vbNullChar Then pSubAppName = ""
        Else
            pSubAppName = vbNullString
        End If
    
        themeAppName = pSubAppName
    
        Dim pSubIDList      As String:               pSubIDList = String$(300&, 0)
        Dim valueSubIDList  As Integer:              valueSubIDList = CInt(GetPropW(GetLngFromPtr(this), StrPtr("#43280")))
    
        If valueSubIDList Then
            GetAtomNameW valueSubIDList, StrPtr(pSubIDList), 300&
            If Left$(pSubIDList, 2&) = "$" & vbNullChar Then pSubIDList = ""
        Else
            pSubIDList = vbNullString
        End If
    Code:
    Private Declare Function GetAtomNameW Lib "kernel32.dll" (ByVal nAtom As Integer, ByVal lpBuffer As Long, ByVal nSize As Long) As Long
    Private Declare Function GetMem4 Lib "msvbvm60.dll" (ByVal Addr As Long, ByRef RetVal As Long) As Long
    Private Declare Function GetPropW Lib "user32.dll" (ByVal hWnd As Long, ByVal lpString As Long) As Long
    
    Public Function GetLngFromPtr(ByVal Ptr As Long) As Long
        GetMem4 Ptr, GetLngFromPtr
    End Function
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  21. #21
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    What is the 'this' in CInt(GetPropW(GetLngFromPtr(this), StrPtr("#43281")))?

    In the C++ code it refers to a class block; perhaps ObjPtr(Me)?

    For reference let me post the whole file:
    Code:
    // SubItemControlsView.h : interface of the CSubItemControlsView class
    //
    /////////////////////////////////////////////////////////////////////////////
    
    #pragma once
    
    #include "IListView.h"
    #include "ISubItemCallback.h"
    #include "IPropertyValue.h"
    #include "IPropertyValueImpl.h"
    #include "IDrawPropertyControl.h"
    #include "SubItemControls.h"
    
    // {13E88673-D30C-46ba-8F2E-97C5CD024E73}
    DEFINE_GUID(CLSID_CSubItemControlsView, 0x13e88673, 0xd30c, 0x46ba, 0x8f, 0x2e, 0x97, 0xc5, 0xcd, 0x2, 0x4e, 0x73);
    
    
    class CSubItemControlsView :
        public CComObjectRootEx<CComMultiThreadModel>,
        public CComCoClass<CSubItemControlsView, &CLSID_CSubItemControlsView>,
        public CWindowImpl<CSubItemControlsView, CListViewCtrl>,
       	public ISubItemCallback
    {
    	static const int ITEMCOUNT = 9;
    public:
    	DECLARE_WND_SUPERCLASS(NULL, CListViewCtrl::GetWndClassName())
    
    	BOOL PreTranslateMessage(MSG* pMsg)
    	{
    		pMsg;
    		return FALSE;
    	}
    
    	BEGIN_COM_MAP(CSubItemControlsView)
    		COM_INTERFACE_ENTRY_IID(IID_ISubItemCallback, ISubItemCallback)
    	END_COM_MAP()
    
    	BEGIN_MSG_MAP(CSubItemControlsView)
    		MESSAGE_HANDLER(WM_CREATE, OnCreate)
    	END_MSG_MAP()
    
    // Handler prototypes (uncomment arguments if needed):
    //	LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
    //	LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
    //	LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
    
    	//////////////////////////////////////////////////////////////////////
    	// implementation of ISubItemCallback
    	virtual STDMETHODIMP GetSubItemTitle(int subItemIndex, LPWSTR pBuffer, int bufferSize)
    	{
    		return E_NOTIMPL;
    	}
    
    	virtual STDMETHODIMP GetSubItemControl(int itemIndex, int subItemIndex, REFIID requiredInterface, LPVOID* ppObject)
    	{
    		return BeginSubItemEdit(itemIndex, subItemIndex, 0, requiredInterface, ppObject);
    	}
    
    	virtual STDMETHODIMP BeginSubItemEdit(int itemIndex, int subItemIndex, int /*mode*/, REFIID requiredInterface, LPVOID* ppObject)
    	{
    		if(!ppObject) {
    			return E_POINTER;
    		}
    		if(subItemIndex != 1) {
    			return E_NOINTERFACE;
    		}
    
    		HRESULT hr = E_NOINTERFACE;
    		IPropertyDescription* pPropertyDescription = NULL;
    		PROPVARIANT propertyValue = {0};
    		PropVariantInit(&propertyValue);
    		PROPVARIANT* pPropertyValue = &propertyValue;
    
    		switch(itemIndex) {
    			case 0:
    				hr = CoCreateInstance(CLSID_CInPlaceMLEditBoxControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				if(!pPropertyDescription) {
    					PSGetPropertyDescriptionByName(L"System.Generic.String", IID_PPV_ARGS(&pPropertyDescription));
    				}
    				break;
    			case 1:
    				hr = CoCreateInstance(CLSID_CCustomDrawPercentFullControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				break;
    			case 2:
    				hr = CoCreateInstance(CLSID_CRatingControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				break;
    			case 3:
    				if(requiredInterface == IID_IDrawPropertyControl) {
    					hr = CoCreateInstance(CLSID_CStaticPropertyControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				} else {
    					hr = CoCreateInstance(CLSID_CInPlaceEditBoxControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				}
    				if(!pPropertyDescription) {
    					PSGetPropertyDescriptionByName(L"System.Generic.String", IID_PPV_ARGS(&pPropertyDescription));
    				}
    				break;
    			case 4:
    			case 5:
    				hr = CoCreateInstance(CLSID_CBooleanControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				if(!pPropertyDescription) {
    					PSGetPropertyDescriptionByName(L"System.Generic.Boolean", IID_PPV_ARGS(&pPropertyDescription));
    				}
    				break;
    			case 6:
    				hr = CoCreateInstance(CLSID_CInPlaceCalendarControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				if(!pPropertyDescription) {
    					PSGetPropertyDescriptionByName(L"System.Generic.DateTime", IID_PPV_ARGS(&pPropertyDescription));
    				}
    				break;
    			case 7:
    				hr = CoCreateInstance(CLSID_CInPlaceDropListComboControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				if(!pPropertyDescription) {
    					PSGetPropertyDescriptionByName(L"System.Photo.MeteringMode", IID_PPV_ARGS(&pPropertyDescription));
    				}
    				break;
    			case 8:
    				hr = CoCreateInstance(CLSID_CHyperlinkControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				break;
    			/*case 9:
    				if(requiredInterface == IID_IDrawPropertyControl) {
    					hr = CoCreateInstance(CLSID_CCustomDrawMultiValuePropertyControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				} else {
    					hr = CoCreateInstance(CLSID_CInPlaceMultiValuePropertyControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				}
    				if(!pPropertyDescription) {
    					PSGetPropertyDescriptionByName(L"System.Keywords", IID_PPV_ARGS(&pPropertyDescription));
    				}
    				break;
    			case 10:
    				hr = CoCreateInstance(CLSID_CCustomDrawProgressControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				break;
    			case 11:
    				hr = CoCreateInstance(CLSID_CIconListControl, NULL, CLSCTX_INPROC_SERVER, requiredInterface, ppObject);
    				break;*/
    		}
    		if(SUCCEEDED(hr)) {
    			IPropertyControlBase* pControl = *reinterpret_cast<IPropertyControlBase**>(ppObject);
    			CComBSTR themeAppName = L"";
    			CComBSTR themeIDList = L"";
    			WCHAR pSubAppNameBuffer[300] = {0};
    			LPWSTR pSubAppName = pSubAppNameBuffer;
    			ATOM valueSubAppName = reinterpret_cast<ATOM>(GetPropW(*this, L"#43281"));
    			if(valueSubAppName) {
    				GetAtomNameW(valueSubAppName, pSubAppNameBuffer, 300);
    				if(lstrlenW(pSubAppNameBuffer) == 1 && pSubAppNameBuffer[0] == L'$') {
    					pSubAppNameBuffer[0] = L'\0';
    				}
    			} else {
    				pSubAppName = NULL;
    			}
    			themeAppName = pSubAppName;
    			WCHAR pSubIDListBuffer[300] = {0};
    			LPWSTR pSubIDList = pSubIDListBuffer;
    			ATOM valueSubIDList = reinterpret_cast<ATOM>(GetPropW(*this, L"#43280"));
    			if(valueSubIDList) {
    				GetAtomNameW(valueSubIDList, pSubIDListBuffer, 300);
    				if(lstrlenW(pSubIDListBuffer) == 1 && pSubIDListBuffer[0] == L'$') {
    					pSubIDListBuffer[0] = L'\0';
    				}
    			} else {
    				pSubIDList = NULL;
    			}
    			themeIDList = pSubIDList;
    			HFONT hFont = GetFont();
    			COLORREF textColor = static_cast<COLORREF>(SendMessage(LVM_GETTEXTCOLOR, 0, 0));
    			if(textColor == CLR_NONE) {
    				textColor = GetSysColor(COLOR_WINDOWTEXT);
    			}
    
    			LPWSTR pBuffer = reinterpret_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), 0, (1024 + 1) * sizeof(WCHAR)));
    			if(pBuffer) {
    				LVITEMW item = {0};
    				item.iSubItem = subItemIndex;
    				item.cchTextMax = 1024;
    				item.pszText = pBuffer;
    				SendMessage(LVM_GETITEMTEXTW, itemIndex, reinterpret_cast<LPARAM>(&item));
    				if(itemIndex == 1 || itemIndex == 2 || itemIndex == 7) {
    					PROPVARIANT tmp;
    					PropVariantInit(&tmp);
    					InitPropVariantFromString(item.pszText, &tmp);
    					PropVariantChangeType(pPropertyValue, tmp, 0, VT_UI4);
    					PropVariantClear(&tmp);
    				} else if(itemIndex == 4 || itemIndex == 5) {
    					PROPVARIANT tmp;
    					PropVariantInit(&tmp);
    					InitPropVariantFromString(item.pszText, &tmp);
    					PropVariantChangeType(pPropertyValue, tmp, 0, VT_BOOL);
    					PropVariantClear(&tmp);
    				} else if(itemIndex == 6) {
    					PROPVARIANT tmp;
    					PropVariantInit(&tmp);
    					InitPropVariantFromString(item.pszText, &tmp);
    					PropVariantChangeType(pPropertyValue, tmp, 0, VT_FILETIME);
    					PropVariantClear(&tmp);
    				} else {
    					InitPropVariantFromString(item.pszText, pPropertyValue);
    				}
    				HeapFree(GetProcessHeap(), 0, pBuffer);
    				pBuffer = NULL;
    			}
    
    			CComPtr<IPropertyValue> pPropertyValueObj = NULL;
    			if(SUCCEEDED(IPropertyValueImpl::CreateInstance(NULL, IID_IPropertyValue, reinterpret_cast<LPVOID*>(&pPropertyValueObj))) && pPropertyValueObj && SUCCEEDED(pPropertyValueObj->InitValue(*pPropertyValue))) {
    				if(pPropertyDescription) {
    					ATLVERIFY(SUCCEEDED(pControl->Initialize(pPropertyDescription, static_cast<IPropertyControlBase::PROPDESC_CONTROL_TYPE>(0))));
    				}
    				pControl->SetValue(pPropertyValueObj);
    				ATLVERIFY(SUCCEEDED(pControl->SetTextColor(textColor)));
    				if(hFont) {
    					ATLVERIFY(SUCCEEDED(pControl->SetFont(hFont)));
    				}
    				ATLVERIFY(SUCCEEDED(pControl->SetWindowTheme(themeAppName, themeIDList)));
    			} else {
    				pControl->Destroy();
    				hr = E_NOINTERFACE;
    			}
    
    			if(pPropertyDescription) {
    				pPropertyDescription->Release();
    				pPropertyDescription = NULL;
    			}
    		}
    
    		return hr;
    	}
    
    	virtual STDMETHODIMP EndSubItemEdit(int itemIndex, int subItemIndex, int /*mode*/, IPropertyControl* pPropertyControl)
    	{
    		ATLASSUME(pPropertyControl);
    		if(!pPropertyControl) {
    			return E_POINTER;
    		}
    
    		BOOL modified = FALSE;
    		pPropertyControl->IsModified(&modified);
    		if(modified) {
    			CComPtr<IPropertyValue> pPropertyValue = NULL;
    			if(SUCCEEDED(pPropertyControl->GetValue(IID_IPropertyValue, reinterpret_cast<LPVOID*>(&pPropertyValue))) && pPropertyValue) {
    				PROPVARIANT propertyValue;
    				PropVariantInit(&propertyValue);
    				if(SUCCEEDED(pPropertyValue->GetValue(&propertyValue))) {
    					LPWSTR pBuffer = NULL;
    					if(SUCCEEDED(PropVariantToStringAlloc(propertyValue, &pBuffer)) && pBuffer) {
    						SetItemText(itemIndex, subItemIndex, pBuffer);
    						CoTaskMemFree(pBuffer);
    					}
    
    					PropVariantClear(&propertyValue);
    				}
    			}
    		}
    
    		return pPropertyControl->Destroy();
    	}
    
    	virtual STDMETHODIMP BeginGroupEdit(int /*groupIndex*/, REFIID /*requiredInterface*/, LPVOID* ppObject)
    	{
    		ATLASSUME(ppObject);
    		return E_NOINTERFACE;
    	}
    
    	virtual STDMETHODIMP EndGroupEdit(int /*groupIndex*/, int /*mode*/, IPropertyControl* pPropertyControl)
    	{
    		ATLASSUME(pPropertyControl);
    		if(!pPropertyControl) {
    			return E_POINTER;
    		}
    
    		return pPropertyControl->Destroy();
    	}
    
    	virtual STDMETHODIMP OnInvokeVerb(int /*itemIndex*/, LPCWSTR pVerb)
    	{
    		WCHAR pBuffer[1024];
    		StringCchPrintfW(pBuffer, 1024, L"Invoke verb: %s", pVerb);
    		MessageBoxW(pBuffer);
    		return S_OK;
    	}
    	// implementation of ISubItemCallback
    	//////////////////////////////////////////////////////////////////////
    
    	LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
    	{
    		LRESULT lr = DefWindowProc(uMsg, wParam, lParam);
    
    		SetExtendedListViewStyle(LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT, LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT);
    		SetWindowTheme(*this, L"Explorer", NULL);				// make the list view look a bit nicer
    		SetView(LV_VIEW_TILE);
    		LVTILEVIEWINFO tileInfo = {0};
    		tileInfo.cbSize = sizeof(LVTILEVIEWINFO);
    		tileInfo.dwMask = LVTVIM_COLUMNS;
    		tileInfo.cLines = 2;
    		SetTileViewInfo(&tileInfo);
    
    		// setup the callback interface
    		if(IsWin7()) {
    			IListView_Win7* pLvw = NULL;
    			SendMessage(LVM_QUERYINTERFACE, reinterpret_cast<WPARAM>(&IID_IListView_Win7), reinterpret_cast<LPARAM>(&pLvw));
    			if(pLvw) {
    				ISubItemCallback* pSubItemCallback = NULL;
    				QueryInterface(IID_ISubItemCallback, reinterpret_cast<LPVOID*>(&pSubItemCallback));
    				pLvw->SetSubItemCallback(pSubItemCallback);
    				pLvw->Release();
    			}
    		} else {
    			IListView_WinVista* pLvw = NULL;
    			SendMessage(LVM_QUERYINTERFACE, reinterpret_cast<WPARAM>(&IID_IListView_WinVista), reinterpret_cast<LPARAM>(&pLvw));
    			if(pLvw) {
    				ISubItemCallback* pSubItemCallback = NULL;
    				QueryInterface(IID_ISubItemCallback, reinterpret_cast<LPVOID*>(&pSubItemCallback));
    				pLvw->SetSubItemCallback(pSubItemCallback);
    				pLvw->Release();
    			}
    		}
    
    		InsertColumns();
    		InsertItems();
    
    		return lr;
    	}
    
    	void InsertColumns(void)
    	{
    		TCHAR pColumnText[51];
    		for(int i = 0; i < 3; i++) {
    			StringCchPrintf(pColumnText, 50, _T("Column %i"), i + 1);
    			InsertColumn(i, pColumnText, 0, 200);
    		}
    	}
    
    	void InsertItems(void)
    	{
    		HIMAGELIST hImageList = NULL;
    		SHGetImageList(SHIL_SMALL, IID_IImageList, reinterpret_cast<LPVOID*>(&hImageList));
    		SetImageList(hImageList, LVSIL_SMALL);
    
    		TCHAR pItemText[51];
    		LVITEM item = {0};
    		item.mask = LVIF_COLUMNS;
    		item.cColumns = 2;
    		item.puColumns = new UINT[item.cColumns];
    		item.puColumns[0] = 1;
    		item.puColumns[1] = 2;
    
    		PROPVARIANT pv;
    		LPWSTR pBuffer = NULL;
    		for(int i = 0; i < ITEMCOUNT; i++) {
    			StringCchPrintf(pItemText, 50, _T("Item %i"), i + 1);
    			InsertItem(LVIF_IMAGE | LVIF_TEXT, i, pItemText, 0, 0, i % 3, 0);
    			StringCchPrintf(pItemText, 50, _T("Item %i, SubItem 2"), i + 1);
    			SetItemText(i, 2, pItemText);
    			switch(i) {
    				case 0:
    					SetItemText(0, 1, _T("This text\r\nconsists of\r\n3 lines"));	// multi-line edit
    					break;
    				case 1:
    					SetItemText(1, 1, _T("46"));																	// percent bar
    					break;
    				case 2:
    					SetItemText(2, 1, _T("3"));																		// rating
    					break;
    				case 3:
    					SetItemText(3, 1, _T("Some Text"));														// single-line edit
    					break;
    				case 4:
    					SetItemText(4, 1, _T("-1"));																	// boolean check mark
    					break;
    				case 5:
    					SetItemText(5, 1, _T("-1"));																	// checkbox drop-down list
    					break;
    				case 6:
    					PropVariantInit(&pv);
    					pv.vt = VT_FILETIME;
    					GetSystemTimeAsFileTime(&pv.filetime);
    					if(SUCCEEDED(PropVariantToStringAlloc(pv, &pBuffer)) && pBuffer) {
    						SetItemText(6, 1, pBuffer);																	// calendar
    						CoTaskMemFree(pBuffer);
    						pBuffer = NULL;
    					}
    					break;
    				case 7:
    					SetItemText(7, 1, _T("2"));																		// drop-down list
    					break;
    				case 8:
    					SetItemText(8, 1, _T("<a id=\"Open http://www.timosoft-software.de\">http://www.timosoft-software.de</a>"));	// hyperlink
    					break;
    			}
    			item.iItem = i;
    			SetItem(&item);
    		}
    		delete[] item.puColumns;
    
    		SetView(LV_VIEW_DETAILS);
    	}
    };
    The rest of it is pretty straight forward and easy to convert with a couple exceptions...

    VB doesn't allow LPVOID (As Any) in an implemented interface prototype; so I've made it IPropertyControlBase since it should be either that or an interface that inherits from it like IPropertyControl.

    As always, all things PROPVARIANT are a phenomenally painful experience in VB. Any way to not use them?

  22. #22
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Virtual ListView - Show Subitem Text in TileView

    Quote Originally Posted by fafalone View Post
    What is the 'this' in CInt(GetPropW(GetLngFromPtr(this), StrPtr("#43281")))?

    In the C++ code it refers to a class block; perhaps ObjPtr(Me)?
    Well, the 1st parameter of the GetProp function is supposed to be an hWnd, so I guess the this pointer probably points to the ListView's hWnd value. That this pointer confuses me as well, because from what I understand, it is analogous to the Me keyword (i.e., they both point to a specific instance of the class).

    Quote Originally Posted by fafalone View Post
    As always, all things PROPVARIANT are a phenomenally painful experience in VB. Any way to not use them?
    Sorry, I'm not familiar yet with PROPVARIANTs...
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  23. #23

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    but it seems like dilettante converts PROPVARIANT like this "...the returned value is a PROPVARIANT, so we first convert it to a Variant for use in VB6', in this thread http://earlier137.rssing.com/browser...78609&item=165

    LucasMKG
    'ISubItemCallback' will be implemented in VB6...its a matter of, how soon.

  24. #24
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    Yeah for simple cases that works fine, but you start running into problems before you get to half the complexity of what's going on here.

    Another issue that's got me really concerned is the iSubItem bad values are showing up in ISubitemCallback_GetSubitemControl et al. too... This has the potential to ruin everything

  25. #25

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    translate all the easy bits first and then throw the difficult code here...i reckon VBForums has C++ fluent programmers

    LucasMKG
    loading....

  26. #26

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    fafalone,
    How far are you with the implementation of ISubItemCallback..and have you sorted out PROPVARIANTs?

    LucasMKG
    ...just making follow-ups

  27. #27
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    I haven't really worked on it... The challenges just looked so problematic i got discouraged, then distracted with the massive expansion to my TLB (CoreAudio and DirectShow). It's not just a matter of translating cpp to vb... It appears vb may not even be receiving the proper data. I'll take another look tonight, but we might also consider talking to Timo.. I believe he got it working in VB, but unfortunately he says he won't release the code until he retires, however many years that is. But maybe we can gain some insights. It's also possible we might have to fall back on a cpp Dll for some things.

  28. #28
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: Virtual ListView - Show Subitem Text in TileView

    being able to subclass any COM object's vtable entry, means resorting to cpp is not needed.

  29. #29
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    Yes because clearly I've not considered that technique.

  30. #30

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    Quote Originally Posted by fafalone View Post
    What is the 'this' in CInt(GetPropW(GetLngFromPtr(this), StrPtr("#43281")))?
    hi, faf
    have a look at this GetLngFromPtr(VarPtr(&HADC0FFEE))
    http://codebank121.rssing.com/chan-4715191/all_p3.html, it might
    help

    LucasMKG
    ....

  31. #31

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    Quote Originally Posted by Bonnie West View Post
    Well, the 1st parameter of the GetProp function is supposed to be an hWnd, so I guess the this pointer probably points to the ListView's hWnd value.
    Bonnie West is on the money
    GetProp (handle, "# 43280")
    https://translate.google.com/transla...ml&prev=search check post no. 28

  32. #32

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    GetAtomName might need Windows ATOM API Wrapper, please consider this

  33. #33
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    I've got the GetPropW calls working; it is indeed meant for the hWnd

    GetPropW(hLVVG, StrPtr("#43281")) returns 49154
    then GetAtomNameW valueSubAppName, ByVal StrPtr(pSubAppName), 300& returns "explorer"

    Now my BeginSubItemEdit function executes all the way through with seemingly successful calls, but still it's just a blank display (and a single call, despite that there should be multiple controls) that if interacted with has the border smeared then crashes

    Here's the latest desperate attempt...
    Code:
    Public Function BeginSubItemEditVB(ByVal This As ISubItemCallback, ByVal itemIndex As Long, ByVal subItemIndex As Long, ByVal nMode As Long, requiredInterface As UUID, ppObjectPtr As Long) As Long  ' ppObject As IPropertyControlBase)
    Debug.Print "BeginSubItemEditVB idx=" & itemIndex & "," & subItemIndex & " nMode=" & nMode & ",reqi data1=0x" & Hex$(requiredInterface.Data1) & ",last=0x" & Hex$(requiredInterface.Data4(7))
    Dim pddpc As IDrawPropertyControl
    Dim ppc As IPropertyControl
    Dim pdpc As oleexp.IUnknown
    
    If (ppObjectPtr = 0) Then
        Debug.Print "BeginSubitemEdit.No object"
        BeginSubItemEditVB = E_POINTER
        Exit Function
    Else
        If subItemIndex <> 1 Then
            BeginSubItemEditVB = E_NOINTERFACE
            Exit Function
        End If
        If requiredInterface.Data1 = IID_IDrawPropertyControl.Data1 Then
    '        Debug.Print "set pddpc " & ppObjectPtr
    '        vbaObjSetAddRef pdpc, ppObjectPtr
    ''        Set pdpc = PtrToObj(ppObjectPtr)
    '        Debug.Print "post-vbset"
    ''        Set pdpc = pddpc
    ''                Debug.Print "post-set"
    
        ElseIf requiredInterface.Data1 = IID_IPropertyControl.Data1 Then
    '        Debug.Print "set ppc " & ppObjectPtr
    ''        vbaObjSetAddRef ppc, ppObjectPtr
    '        Set ppc = PtrToObj(ppObjectPtr)
    '        Debug.Print "post-vbobjset"
    '        Set pdpc = ppc
    '        Debug.Print "post-set"
    
        Else
            Debug.Print "req iface unknown, ==0x" & Hex$(requiredInterface.Data1)
            BeginSubItemEditVB = E_POINTER
            Exit Function
        End If
    End If
    Dim hr As Long
    hr = E_NOINTERFACE
    Dim pPropertyDescription As IPropertyDescription
    Dim propertyValue As Variant
    Debug.Print "BeginSubItemEditVB creating instance..."
    Select Case itemIndex
        Case 0
            hr = CoCreateInstance(CLSID_CInPlaceMLEditBoxControl, 0&, CLSCTX_INPROC_SERVER, requiredInterface, ppObjectPtr)
            PSGetPropertyDescriptionByName StrPtr("System.Generic.String"), IID_IPropertyDescription, pPropertyDescription
        Case 1
            hr = CoCreateInstance(CLSID_CCustomDrawPercentFullControl, 0&, CLSCTX_INPROC_SERVER, requiredInterface, ppObjectPtr)
        Case 2
            hr = hr = CoCreateInstance(CLSID_CRatingControl, 0&, CLSCTX_INPROC_SERVER, requiredInterface, ppObjectPtr)
        Case 3
            If (requiredInterface.Data1 = IID_IDrawPropertyControl.Data1) Then
                hr = CoCreateInstance(CLSID_CStaticPropertyControl, 0&, CLSCTX_INPROC_SERVER, requiredInterface, ppObjectPtr)
            Else
                hr = CoCreateInstance(CLSID_CInPlaceEditBoxControl, 0&, CLSCTX_INPROC_SERVER, requiredInterface, ppObjectPtr)
            End If
            PSGetPropertyDescriptionByName StrPtr("System.Generic.String"), IID_IPropertyDescription, pPropertyDescription
        Case 4, 5
            hr = CoCreateInstance(CLSID_CBooleanControl, 0&, CLSCTX_INPROC_SERVER, requiredInterface, ppObjectPtr)
            PSGetPropertyDescriptionByName StrPtr("System.Generic.Boolean"), IID_IPropertyDescription, pPropertyDescription
        Case 6
            'todo: datetime
        Case 7
            hr = CoCreateInstance(CLSID_CInPlaceDropListComboControl, 0&, CLSCTX_INPROC_SERVER, requiredInterface, ppObjectPtr)
             PSGetPropertyDescriptionByName StrPtr("System.Photo.Metering"), IID_IPropertyDescription, pPropertyDescription
        Case 8
            hr = CoCreateInstance(CLSID_CHyperlinkControl, 0&, CLSCTX_INPROC_SERVER, requiredInterface, ppObjectPtr)
    End Select
    'If (pdpc Is Nothing) Then
        Debug.Print "BeginSubItemEditVB create instance  0x" & Hex$(hr)
    'Else
    '    Debug.Print "BeginSubItemEditVB instance created; obj is valid"
    ''    ppObjectPtr = ObjPtr(pdpc)
    'End If
    
    If hr = S_OK Then
        Debug.Print "S_OK"
        Dim pControl As IPropertyControlBase
        
    '    Set pdpc = PtrToObj(ppObjectPtr)
        vbaObjSet pControl, ppObjectPtr
        Debug.Print "post-vbaset"
    '    Set pControl = pdpc
        
        Dim themeAppName As String, themeIDList As String
        Dim pSubAppNameBuffer(300) As Integer
        Dim valueSubAppName As Long
        Dim pSubAppName As String
        pSubAppName = String$(300, 0)
        valueSubAppName = GetPropW(hLVVG, StrPtr("#43281"))
    '    valueSubAppName = GetPropW(ObjPtr(This), StrPtr("#43281"))
        Debug.Print "BeginSubItemEditVB GetProp 1=" & valueSubAppName
        If valueSubAppName Then
    '        GetAtomNameW valueSubAppName, VarPtr(pSubAppNameBuffer(0)), 300
    
            GetAtomNameW valueSubAppName, ByVal StrPtr(pSubAppName), 300&
            If Left$(pSubAppName, 1&) = "$" & vbNullChar Then pSubAppName = ""
        Else
            pSubAppName = vbNullString
        End If
        Debug.Print "BeginSubItemEditVB AtomName1=" & pSubAppName
        themeAppName = pSubAppName
    
        Dim pSubIDList      As String:               pSubIDList = String$(300&, 0)
        Dim valueSubIDList  As Long:              valueSubIDList = GetPropW(hLVVG, StrPtr("#43280")) 'GetPropW(ObjPtr(This), StrPtr("#43280"))
        Debug.Print "BeginSubItemEditVB GetProp2=" & valueSubIDList
        If valueSubIDList <> "0" Then
            GetAtomNameW valueSubIDList, StrPtr(pSubIDList), 300&
            If Left$(pSubIDList, 1&) = "$" & vbNullChar Then pSubIDList = ""
        Else
            pSubIDList = "" 'vbNullString
        End If
        Debug.Print "BeginSubItemEditVB AtomName2=" & pSubIDList
        themeIDList = pSubIDList
        Dim hFont As Long: hFont = SendMessage(hLVVG, WM_GETFONT, 0&, ByVal 0&)
        Dim textColor As Long
        textColor = SendMessage(hLVVG, LVM_GETTEXTCOLOR, 0&, ByVal 0&)
        If textColor = CLR_NONE Then
            textColor = GetSysColor(COLOR_WINDOWTEXT)
        End If
        Debug.Print "BeginSubItemEditVB font get"
    '    Dim pBuffer As String: pBuffer
        
        
        
        
        
        
        
        Dim tmp As Variant
        Dim tmp2 As Variant
        
        Select Case itemIndex
            Case 1, 2, 7
                tmp = CLng(VLItems(itemIndex).sSubItems(0))
                VariantToPropVariant tmp, tmp2
                PropVariantChangeType propertyValue, tmp2, 0, VT_UI4
    '            PropVariantClear tmp
        
            Case 4, 5
                tmp = CBool(VLItems(itemIndex).sSubItems(0))
                VariantToPropVariant tmp, tmp2
                PropVariantChangeType propertyValue, tmp2, 0, VT_BOOL
    '            PropVariantClear tmp
            Case Else
                 tmp = CStr(VLItems(itemIndex).sSubItems(0))
                VariantToPropVariant tmp, tmp2
                PropVariantChangeType propertyValue, tmp2, 0&, VT_LPWSTR 'It would be a VT_BSTR before this
               
        
        End Select
        Debug.Print "BeginSubItemEditVB setting value to " & tmp & "..."
        Dim pPropertyValueObj As IPropertyValue
        Set pPropertyValueObj = New cPropValue
        pPropertyValueObj.InitValue propertyValue
        Debug.Print "InitValue"
            If (pPropertyDescription Is Nothing) = False Then
                Debug.Print "initializing..."
                pControl.Initialize pPropertyDescription, 1
            End If
            Debug.Print "setting value..."
            pControl.SetValue pPropertyValueObj
            Debug.Print "setting textcolor..."
            pControl.SetTextColor textColor
            Debug.Print "setting font..."
            If hFont Then pControl.SetFont hFont
            Debug.Print "setting theme..."
            pControl.SetWindowTheme StrPtr(themeAppName), StrPtr(themeIDList)
        Debug.Print "BeginSubItemEditVB out"
    End If
    
    End Function
    It gets right up through 'Out', but it's nothing displayed and crashville after then, with no other methods are entered. The GetProp/GetAtomName issues have been resolved, I'm now intimately familiar with PROPVARIANT's so confident I'm doing those right... the object pointer is non-zero like it should be and CoCreateInstance is returning S_OK...


    I think it might be time to concede getting real subitem controls in VB is just beyond my ability
    Reached out to Timo on the project page for his CodeProject example too see if he ever got it working in VB (he did finally release his control source but it wasn't actually in VB, just C like the dmo).
    Last edited by fafalone; Oct 13th, 2019 at 02:06 AM.

  34. #34

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    Quote Originally Posted by fafalone View Post
    ...
    Public Function BeginSubItemEditVB(ByVal This As ISubItemCallback, ByVal itemIndex As Long, ByVal subItemIndex As Long, ByVal nMode As Long, requiredInterface As UUID, ppObjectPtr As Long) As Long ' ppObject As IPropertyControlBase)

    ...Reached out to Timo ... I've got the ppObject As Long to get a pointer... but it's not zero when received... I can't turn it into IPropertyControlBase with CopyMemory or vbaObjSetAddref before CoCreateInstance... I can call CoCreateInstance with that pointer and that returns S_OK, but then to call its methods afterwards CopyMemory/vbaObjSetAddref both still fail; vbaObjSet alone (not incrementing the reference counter) gives me a non-null object, but when I call .SetValue or .Initialize, execution just stops. No error, not frozen, just stops at that line and does nothing.
    'ppObject' is trying to spoil thing
    Last edited by LucasMKG; Oct 13th, 2019 at 04:56 AM.

  35. #35

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    ... double post
    Last edited by LucasMKG; Oct 13th, 2019 at 07:02 AM.

  36. #36
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    I got it so execution doesn't stop; it returns from all the calls on it, but then just doesn't display anything (even the text of the listitem in the Name column doesn't show up) and eventually crashes whenever you touch the form.
    Last edited by fafalone; Oct 13th, 2019 at 05:08 AM.

  37. #37

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    seems like you removed IID_PPV_ARGS

  38. #38
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,651

    Re: Virtual ListView - Show Subitem Text in TileView

    IID_PPV_ARGS is just a language feature that automatically looks up the IID for whatever interface you've passed it and fills in the argument for it. So if you've got a method with riid As UUID, ppv As Any, you'd have your variable declared already as e.g. IShellFolder psf;, so IID_PPV_ARGS(psf) would fill in both parameters instead of you manually entering IID_IShellFolder, psf.

    VB doesn't support that language feature however, so you'll always see it written out fully in VB code.

    If you have MyFunction(arg1, arg2) there's no mechanism that would allow you to call it as MyFunction(SingleCall()) and have SingleCall fill in both.
    Last edited by fafalone; Oct 13th, 2019 at 10:46 AM.

  39. #39

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    ok, I see
    Instead of catching ppObject in the 'Public Function BeginSubItemEditVB'
    why not QueryInterface the ppObject just below the 'Public Function BeginSubItemEditVB'?

    Code:
    // query interface for the return value
    	HRESULT hResult = pShellExt->QueryInterface(riid, ppObject);
    
    or 
    	// query interface for the a pointer
    	HRESULT hResult = pClassFactory->QueryInterface(riid, ppReturn);
    something like that...check this out

    LucasMKG
    ?
    Last edited by LucasMKG; Oct 16th, 2019 at 02:12 AM.

  40. #40

    Thread Starter
    Hyperactive Member LucasMKG's Avatar
    Join Date
    Jun 2015
    Location
    South Africa (ZAR)
    Posts
    338

    Re: Virtual ListView - Show Subitem Text in TileView

    looks like i'll have to look deeply at this, picking random cherries (throwing a dice - hoping for solution) clearly ain't working

    LucasMKG
    ..loading

Page 1 of 2 12 LastLast

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