-
Oct 15th, 2018, 12:00 AM
#1
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.
-
Oct 15th, 2018, 04:12 AM
#2
Re: Enum items in Devices and Printers possible on x64?
 Originally Posted by fafalone
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>
-
Oct 15th, 2018, 05:33 PM
#3
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.
-
Oct 16th, 2018, 04:35 AM
#4
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>
-
Oct 16th, 2018, 01:30 PM
#5
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.
-
Oct 17th, 2018, 07:20 AM
#6
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>
-
Oct 17th, 2018, 08:24 PM
#7
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.
-
Apr 15th, 2024, 06:39 AM
#8
Lively Member
Re: Enum items in Devices and Printers possible on x64?
 Originally Posted by wqweto
</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.
-
Apr 15th, 2024, 11:17 AM
#9
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.
-
Apr 16th, 2024, 03:57 AM
#10
Re: Enum items in Devices and Printers possible on x64?
 Originally Posted by fafalone
@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>
-
Apr 16th, 2024, 03:59 AM
#11
Re: Enum items in Devices and Printers possible on x64?
 Originally Posted by cliv
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>
-
Apr 16th, 2024, 04:08 AM
#12
Lively Member
Re: Enum items in Devices and Printers possible on x64?
 Originally Posted by wqweto
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.
-
Apr 16th, 2024, 04:44 AM
#13
Re: Enum items in Devices and Printers possible on x64?
 Originally Posted by cliv
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>
Last edited by wqweto; Apr 16th, 2024 at 04:57 AM.
-
Apr 17th, 2024, 12:14 AM
#14
Lively Member
Re: Enum items in Devices and Printers possible on x64?
 Originally Posted by wqweto
... 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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|