Results 1 to 14 of 14

Thread: Enum items in Devices and Printers possible on x64?

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,892

    Enum items in Devices and Printers possible on x64?

    While there's a specific alternative folder for printers, I'm interested also in the list of Devices in the Devices and Printers control panel; e.g. webcam, keyboard, monitor, etc etc. Now normally you should be able to get the Control Panel's IShellFolder, ParseDisplayName by GUID, and use the pidl from there, or any number of similar methods. After a rather infuriating hour where every method to obtain a pointer specifically to Devices And Printers failed, despite confirming the GUID on my system, the problem seems to be that it and the vast majority of other Control Panel objects are 64-bit, so you can't get a reference to them in a 32-bit app.

    e.g. the quickest way:
    Code:
    Dim pidlcp As Long, pidlDNP As Long
    Dim pch As Long
    Dim psfcp As IShellFolder
    
    pidlcp = ILCreateFromPathW(StrPtr("::{21EC2020-3AEA-1069-A2DD-08002B30309D}"))
    SHBindToObject Nothing, pidlcp, Nothing, IID_IShellFolder, psfcp
    psfcp.ParseDisplayName 0&, 0&, StrPtr("::{A8A91A66-3A7D-4424-8D24-04E180695C7A}"), pch, pidlDNP, 0&
    Debug.Print "pidlcp=" & pidlcp & ",pidlDNP=" & pidlDNP
    Creates the IShellFolder fine, but that and every other method of getting a device enumeration can't resolve the folder (pidlDNP=0). And from what I've read, this is because my app is 32-bit and the control panel applet is 64-bit.
    Can anyone think of a workaround? Or possibly another reason why it's not working?

    Edit: Browsing Control Panel derived and similar virtual locations isn't generally a problem when things have their own KNOWNFOLDERID entry... it's just the ones without...
    Last edited by fafalone; Oct 15th, 2018 at 12:11 AM.

  2. #2
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,227

    Re: Enum items in Devices and Printers possible on x64?

    Quote Originally Posted by fafalone View Post
    After a rather infuriating hour where every method to obtain a pointer specifically to Devices And Printers failed, despite confirming the GUID on my system, the problem seems to be that it and the vast majority of other Control Panel objects are 64-bit, so you can't get a reference to them in a 32-bit app.
    Did you test on a 32-bit Win10 virtual machine that you *can* actually get a reference to them?

    cheers,
    </wqw>

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,892

    Re: Enum items in Devices and Printers possible on x64?

    Just tested it on x86 Windows
    Code:
    Dim siDev As IShellItem
    SHCreateItemFromParsingName StrPtr("::{21EC2020-3AEA-1069-A2DD-08002B30309D}" & "\" & "::{A8A91A66-3A7D-4424-8D24-04E180695C7A}"), Nothing, IID_IShellItem, siDev
    Dim pEnum As IEnumShellItems
    Dim siChild As IShellItem
    Dim lpName As Long, sName As String
    Dim pc As Long
    
    siDev.BindToHandler 0&, BHID_EnumItems, IID_IEnumShellItems, pEnum
    Do While pEnum.Next(1&, siChild, pc) = S_OK
        siChild.GetDisplayName SIGDN_NORMALDISPLAY, lpName
        sName = LPWSTRtoStr(lpName)
        Text1.Text = Text1.Text & vbCrLf & "Device=" & sName
    Loop

    Device=JON-WIN7VM
    Device=USB Tablet
    Device=Generic Non-PnP Monitor
    Device=USB Flash Memory
    Device=Fax
    Device=Microsoft XPS Document Writer


    So that at least confirms it is indeed a x64 issue. No idea why every other
    (ps if anyone was going to try running the above code it depends on oleexp.tlb/mIID.bas)

    Edit: Ran my browser on the x86 VM too...

    Have to figure out why there's a duplicate of everything, but it gets the names, icons, and other properties all fine.

    It's a whole control panel issue... the left is what it looks like running on 32-bit Windows, the right 64-bit:
    Last edited by fafalone; Oct 15th, 2018 at 06:52 PM.

  4. #4
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,227

    Re: Enum items in Devices and Printers possible on x64?

    I think this is expected behavior. There are two separate copies of Control Panel. In x64 Control Panel you can see 32-bit entries with (32-bit) suffix e.g. ODBC (32-bit).

    Apparently a 32-bit application can enum only 32-bit entries from the Control Panel on x64 OS. Here is a short article discussing 32-bit Control Panel entries.

    cheers,
    </wqw>

  5. #5

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,892

    Re: Enum items in Devices and Printers possible on x64?

    Right, now how can I work around that?

    I mean obviously there's manually reading the hardware list off of something like WMI's Win32_PNPDevice then somehow figuring out icons , proper names, etc, but that seems excessively complicated. Would really like to find a way to get that existing list.

  6. #6
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,227

    Re: Enum items in Devices and Printers possible on x64?

    For printers only I'm enumerating CSIDL_PRINTERS like this: https://stackoverflow.com/a/1183185/40691

    Here is how I'm retrieving icons/tooltips for each printer. This is a function from a class that feeds a combobox with list of printers with icons the way MS Office print dialogs are implemented like this:



    cheers,
    </wqw>

  7. #7

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,892

    Re: Enum items in Devices and Printers possible on x64?

    Yeah anything with its own FOLDERID/CSIDL is fine. Network Connections like shown in the 1st post, Printers:


    But the Printers folder doesn't include all the other devices, which is what I'm trying to get.

    Edit: But that code has a much better way to get the InfoTip though, so thanks for that. I had been manually creating it by getting PKEY_PropList_InfoTip then reading those properties. Though I am curious, why use IDataObject and clipboard functions to get the device name? It always seems to return the same thing as SHGDN_NORMAL?
    Last edited by fafalone; Oct 18th, 2018 at 01:46 AM.

  8. #8
    Lively Member
    Join Date
    Feb 2006
    Posts
    106

    Re: Enum items in Devices and Printers possible on x64?

    Quote Originally Posted by wqweto View Post
    </wqw> This is a function from a class that feeds a combobox with list of printers with icons the way MS Office print dialogs are implemented like this:
    Can you post a small sample how to use cPrintersCombo.cls

    Error user define type not define
    Code:
    Private m_uTimerData  As FireOnceTimerData
    Thank you
    Last edited by cliv; Apr 15th, 2024 at 06:44 AM.

  9. #9

    Thread Starter
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    5,892

    Re: Enum items in Devices and Printers possible on x64?

    Oh by the way, looks like I never posted the solution to the original question. While there's no way to enumerate 64bit control panel items from a 32bit program (although ucShellBrowse is now available in 64bit thanks to twinBASIC), you *can* enumerate the full 'Devices and Printers' folder from VB6/32bit by creating an IShellItem with SHCreateItemFromParsingName StrPtr("shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\8\::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}"), Nothing, IID_IShellItem, isi

    Don't recall how I figured it out, was years ago.


    @wqweto -- I'm curious about what you're doing with the pidls there... seems like you're just dereferencing it then feeding a new pidl? Is there a reason for doing that? For example I do it, when I want to retain XP compatibility, like this:

    Code:
    Sub EnumPrinters()
        Dim pidlRel As LongPtr
        Dim psfPr As IShellFolder
        Dim pEnum As IEnumIDList
        Dim pItem As IShellItem
        Dim lpName As LongPtr
        GetPrinters psfPr
        If (psfPr Is Nothing) = False Then
            psfPr.EnumObjects 0, SHCONTF_NONFOLDERS, pEnum)
            Do While pEnum.Next(1, pidlRel) = S_OK
                SHCreateShellItem 0, ObjPtr(psfPr), pidlRel, pItem
                pItem.GetDisplayName SIGDN_NORMALDISPLAY, lpName 
                Debug.Print "Printer: " & LPWSTRtoStr(lpName)
            Loop
        End If
    End Sub
    Sub GetPrinters(psf As IShellFolder)
        Static gPrinters As IShellFolder
        If gPrinters Is Nothing Then
            Dim psfDesktop As IShellFolder
            SHGetDesktopFolder psfDesktop 
            Dim pidl As LongPtr
            SHGetSpecialFolderLocation 0, CSIDL_PRINTERS, pidl)
            psfDesktop.BindToObject pidl, 0, IID_IShellFolder, gPrinters 
            If gPrinters Is Nothing Then
                Debug.Print "Failed to obtain priters folder."
            Else
                Debug.Print "Got printers folder."
            End If
        End If
        Set psf = gPrinters
    End Sub
    (I was having some trouble with IShellFolder.GetDisplayNameOf; it returned ANSI marked as Unicode; but the basic IShellItem was available on XP as was SHCreateShellItem)
    Last edited by fafalone; Apr 15th, 2024 at 11:56 AM.

  10. #10
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,227

    Re: Enum items in Devices and Printers possible on x64?

    Quote Originally Posted by fafalone View Post
    @wqweto -- I'm curious about what you're doing with the pidls there... seems like you're just dereferencing it then feeding a new pidl?
    I see a pointer, I dereference it :-))

    This is like an API which returns LPWSTR which has to be CoTaskMemFree'd. Usually one copies the string to a BSTR immediately and deallocates memory to prevent leaks and then pass StrPtr(sTemp) instead to LPCSTR parameters. Completely unnecessasy, can use the original pointer as it is just a Long and pass it around and finally deallocate it but still the majority of VB6 code does the conversion.

    Here I just "dereference" the PIDL to a ByteArray and deallocate it. Completely unnecessary but it works and prevents leaks from End button. Besides, PIDLs are glorified PathNames we always had as strings but PIDLs are implemented as linked lists, so why not "faltten" this recursive ADT to a ByteArray manually as an excercise.

    cheers,
    </wqw>

  11. #11
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,227

    Re: Enum items in Devices and Printers possible on x64?

    Quote Originally Posted by cliv View Post
    Can you post a small sample how to use cPrintersCombo.cls
    Not possible as I don't have handy owner-drawn combobox in standard controls to implement the UI in the screenshot. Bummer!

    cheers,
    </wqw>

  12. #12
    Lively Member
    Join Date
    Feb 2006
    Posts
    106

    Re: Enum items in Devices and Printers possible on x64?

    Quote Originally Posted by wqweto View Post
    Not possible
    cheers,
    </wqw>
    Ok! Thanks for the code anyway
    I use simplified version post by you on stackoverflow ... but icon display with black background. Haw can i change?
    Last edited by cliv; Apr 16th, 2024 at 04:13 AM.

  13. #13
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,227

    Re: Enum items in Devices and Printers possible on x64?

    Quote Originally Posted by cliv View Post
    Ok! Thanks for the code anyway
    I use simplified version post by you on stackoverflow ... but icon display with black background. Haw can i change?
    The original code is doing this

    Code:
    If bEnabled Then
        Call ImageList_Draw(vElem(ucsIdxSmallImageList), vElem(ucsIdxSmallIconIndex), hDC, Left + (m_lIndent + 6 - m_cxSmall) \ 2, Top + (Bottom - Top - m_cySmall) \ 2, ILD_TRANSPARENT Or -bSelected * ILD_BLEND25)
    Else
        Call ImageList_DrawEx(vElem(ucsIdxSmallImageList), vElem(ucsIdxSmallIconIndex), hDC, Left + (m_lIndent + 6 - m_cxSmall) \ 2, Top + (Bottom - Top - m_cySmall) \ 2, 0, 0, -1, oMemDC.TranslateColor(vbButtonFace), ILD_TRANSPARENT Or ILD_BLEND50)
    End If
    How do you paint the icon? Do you pass ILD_TRANSPARENT flag?

    Edit: Updated the public gist to latest version (ugly and battle-hardened production code) and now it uses MST for fire-once timers and subclassing. Still needs our custom owner-drawn combobox to compile so a FYI code only.

    cheers,
    </wqw>

  14. #14
    Lively Member
    Join Date
    Feb 2006
    Posts
    106

    Re: Enum items in Devices and Printers possible on x64?

    Quote Originally Posted by wqweto View Post
    ... pass ILD_TRANSPARENT flag?
    cheers,
    </wqw>
    Thanks

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