dcsimg
Results 1 to 15 of 15

Thread: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

  1. #1

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,527

    VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    In Windows XP, the recommended practice to find special folders was to call SHGetFolderPath(), but this was deprecated starting in Windows Vista. From Vista on, we're supposed to use SHGetKnownFolderPath(). Unfortunately, it's extremely hard to find easy-to-use code for SHGetKnownFolderPath without having to add unnecessary references or components to your project. (typelibs, or scripting objects.)

    Thanks to Randy Birch's excellent sample code, here's an easy-to-use module that lets you identify special folders using API calls, no references or components needed. Simply add the attached module to your project, then call the following function:

    ?KnownFolder(enumerated value)

    You can call the following from the debug window to see a list of known folders and their values:

    KnownFolderList


    The module contains two compiler directives:
    Code:
    #Const IncludeVirtualFolders = False
    #Const IncludeDebugListing = True
    Of the 88 total known folders, only 54 return any value for me. The rest are listed as virtual folders by Randy Birch's sample project. I've moved these 34 virtual folders to the end of the enumeration and wrapped them in compiler directives, letting you easily prevent them from being included. This helps reduce clutter in the enumeration dropdown.

    The second compiler directive lets you discard the KnownFoldersList() debug window output routines to reduce the size of the code in your finished project.

    Here's the known folder enumeration for reference:
    Code:
    Public Enum KnownFolderEnum
        kfUserProfiles
        kfUser
        kfUserDocuments
        kfUserContacts
        kfUserDesktop
        kfUserDownloads
        kfUserMusic
        kfUserPictures
        kfUserSavedGames
        kfUserVideos
        kfUserAppDataRoaming
        kfUserAppDataLocal
        kfUserAppDataLocalLow
        kfUserCDBurning
        kfUserCookies
        kfUserFavorites
        kfUserGameTasks
        kfUserHistory
        kfUserInternetCache
        kfUserLinks
        kfUserNetHood
        kfUserPrintHood
        kfUserQuickLaunch
        kfUserRecent
        kfUserSavedSearches
        kfUserSendTo
        kfUserStartMenu
        kfUserStartMenuAdminTools
        kfUserStartMenuPrograms
        kfUserStartMenuStartup
        kfUserTemplates
        kfPublic
        kfPublicDesktop
        kfPublicDocuments
        kfPublicDownloads
        kfPublicMusic
        kfPublicPictures
        kfPublicVideos
        kfPublicStartMenu
        kfPublicStartMenuAdminTools
        kfPublicStartMenuPrograms
        kfPublicStartMenuStartup
        kfPublicGameTasks
        kfPublicTemplates
        kfProgramData
        kfWindows
        kfSystem
        kfSystemX86
        kfSystemFonts
        kfSystemResourceDir
        kfProgramFilesX86
        kfProgramFilesCommonX86
        kfProgramFiles
        kfProgramFilesCommon
    #If IncludeVirtualFolders = True Then
        kfAddNewPrograms
        kfAppUpdates
        kfChangeRemovePrograms
        kfCommonOEMLinks
        kfComputerFolder
        kfConflictFolder
        kfConnectionsFolder
        kfControlPanelFolder
        kfGames
        kfInternetFolder
        kfLocalizedResourcesDir
        kfNetworkFolder
        kfOriginalImages
        kfPhotoAlbums
        kfPlaylists
        kfPrintersFolder
        kfProgramFilesX64
        kfProgramFilesCommonX64
        kfRecordedTV
        kfRecycleBinFolder
        kfSampleMusic
        kfSamplePictures
        kfSamplePlaylists
        kfSampleVideos
        kfSEARCH_CSC
        kfSEARCH_MAPI
        kfSearchHome
        kfSidebarDefaultParts
        kfSidebarParts
        kfSyncManagerFolder
        kfSyncResultsFolder
        kfSyncSetupFolder
        kfTreeProperties
        kfUsersFiles
    #End If
    #If IncludeDebugListing = True Then
        kfKnownFolders
    #End If
    End Enum
    The order of the enumerated values doesn't matter, so feel free to pick and choose any of the virtual folders to include by moving them above the compiler directive. Be sure to make the same change to the two functions: KnownFolderGUID() and KnownFolderName(). Alternately, you could move many (most?) of the values to inside the directive to streamline the enumerated list, showing only those values you might actually need.
    Attached Files Attached Files
    Last edited by Ellis Dee; May 15th, 2016 at 06:45 PM.

  2. #2

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,527

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Finally figured out how to attach the module to the OP. (It wouldn't work in Firefox; I was reduced to use Microsoft Edge. *shudder*)

  3. #3
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,410

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    This is great for a simple path query.. but just wanted to mention that if you're going to be doing more work with known folders besides just getting the path, there's many advantages to using the feature rich IKnownFolderManager/IKnownFolder shell interfaces, which even lets you load by the legacy CSIDL if you're not familiar with the new known folder GUIDs yet. The example here shows how to load all sorts of info about a folder, and the 2nd post shows how to pop up a menu filled with special folders and their icons with just a few lines of code: [VB6, Vista+] Code snippet: KnownFolders made easy with IKnownFolderManager

  4. #4

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,527

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by fafalone View Post
    This is great for a simple path query.. but just wanted to mention that if you're going to be doing more work with known folders besides just getting the path, there's many advantages to using the feature rich IKnownFolderManager/IKnownFolder shell interfaces, which even lets you load by the legacy CSIDL if you're not familiar with the new known folder GUIDs yet. The example here shows how to load all sorts of info about a folder, and the 2nd post shows how to pop up a menu filled with special folders and their icons with just a few lines of code: [VB6, Vista+] Code snippet: KnownFolders made easy with IKnownFolderManager
    For sure, if you need extended interaction with known folders (like writing your own custom-made Explorer replacement -- which might not be a bad idea in terms of privacy) then that's an excellent tool.

    If you just need to know where the paths are and nothing else, that seems like tremendous overkill. The module attached to the OP (now moved to the bottom of the post) is much more lightweight and easy to incorporate in your project. Which is only to be expected considering how much less it does. heh.

  5. #5
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,866

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    The old flat API calls and ActiveX API in Shell32 still work fine for most purposes and are not going anywhere. There are only a few special folders added post-XP that you really need to call SHGetKnownFolderPath() for in most normal applications anyway.

    The only one I've really found all that useful is FOLDERID_Public, and even that isn't needed very often.

    As for "easy to use" examples of calling it in VB6 go, we've had tons of examples dating back to 2006 when Vista was in pre-release, far earlier than Randy Birch's thorough but more than a little over-the-top example. Rolling your own is pretty trivial anyway, the MSDN documentation is pretty clear and the call is almost trivial, so pretty much every example boils down to the very same thing anyway.


    See KNOWNFOLDERID for a list of the available GUIDs, or find them in your Windows SDK header files (i.e. in the KnownFolders.h file).

    Here's a concise rendition:

    Code:
    Option Explicit
    
    'Define any of these you require:
    Public Const FOLDERID_ProgramData As String = "{62AB5D82-FDC1-4DC3-A9DD-070D1D495D97}"
    Public Const FOLDERID_Public As String = "{DFDF76A2-C82A-4D63-906A-5644AC457385}"
    
    Private Const S_OK As Long = 0
    Private Const WIN32_NULL As Long = 0
    
    Private Declare Sub CoTaskMemFree Lib "ole32" (ByVal hMem As Long)
    
    Private Declare Function CLSIDFromString Lib "ole32" ( _
        ByVal lpszGuid As Long, _
        ByRef pGuid As Byte) As Long
    
    Private Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyW" ( _
        ByVal lpString1 As Long, _
        ByVal lpString2 As Long) As Long
    
    Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenW" ( _
        ByVal lpString As Long) As Long
    
    Private Declare Function SHGetKnownFolderPath Lib "shell32" ( _
        ByRef rfid As Byte, _
        ByVal dwFlags As Long, _
        ByVal hToken As Long, _
        ByRef pszPath As Long) As Long
    
    Public Function GetKnownFolder(ByVal KnownFolderID As String) As String
        'Returns empty String on any error.
        Dim guidKFID(15) As Byte
        Dim pszPath As Long
    
        If CLSIDFromString(StrPtr(KnownFolderID), guidKFID(0)) = S_OK Then
            If SHGetKnownFolderPath(guidKFID(0), 0, WIN32_NULL, pszPath) = S_OK Then
                GetKnownFolder = Space$(lstrlen(pszPath))
                lstrcpy StrPtr(GetKnownFolder), pszPath
                CoTaskMemFree pszPath
            End If
        End If
    End Function
    Very similar code has been posted here in answers to question threads numerous times.

  6. #6

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,527

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by dilettante View Post
    Very similar code has been posted here in answers to question threads numerous times.
    Got any links? I searched high and low but never found any on these forums.

    EDIT: I do like the core logic of yours better. It's a touch cleaner and tighter. But I think an enumeration of the values is a far superior approach for something like this compared to just declaring constants.

    EDIT 2: Actually, Randy's method appears to support unicode, while yours does not. Do I have that right?
    Last edited by Ellis Dee; May 17th, 2016 at 09:39 PM.

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

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by Ellis Dee View Post
    EDIT 2: Actually, Randy's method appears to support unicode, while yours does not. Do I have that right?
    according to https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx SHGetKnownFolderPath is unicode only.

  8. #8
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,866

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by Ellis Dee View Post
    But I think an enumeration of the values is a far superior approach for something like this compared to just declaring constants.
    Well you are always free to make up a lookup table keyed by some made up Enum, but since these are GUIDs there isn't any natural enumeration defined anywhere or used anywhere in Windows.

    As I said above it would be a rare "real" program that ever needed more than just a few of these folder paths anyway.

  9. #9
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,866

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by Ellis Dee View Post
    Got any links? I searched high and low but never found any on these forums.
    Well one example is Class: PathLinks - Tame App.Path Under Vista+ which shows one application of SHGetKnownFolderPath() calls.

    There are a few more too, but perhaps they don't turn up in searches because SHGetKnownFolderPath() was just used as the minor tool it is within code snippets.

  10. #10

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,527

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by dilettante View Post
    Well you are always free to make up a lookup table keyed by some made up Enum, but since these are GUIDs there isn't any natural enumeration defined anywhere or used anywhere in Windows.
    Agreed. Which is exactly what I did, and why I consider this module easy to use.

    As I said above it would be a rare "real" program that ever needed more than just a few of these folder paths anyway.
    Quote Originally Posted by dilettante View Post
    There are a few more too, but perhaps they don't turn up in searches because SHGetKnownFolderPath() was just used as the minor tool it is within code snippets.
    You know, your condescending schtick wears very thin very quickly.

  11. #11

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,527

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by DEXWERX View Post
    according to https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx SHGetKnownFolderPath is unicode only.
    Ah, fair enough. I was confused by Randy's use of lstrlenW vs dilettante's lstrlen, but I think it's just because Randy uses a byte array where dilettante uses a string directly.

    Normally when I see a "...W" function I think unicode, and then seeing the same function without the "W" I think "not unicode."

  12. #12
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by Ellis Dee View Post
    Ah, fair enough. I was confused by Randy's use of lstrlenW vs dilettante's lstrlen, but I think it's just because Randy uses a byte array where dilettante uses a string directly.

    Normally when I see a "...W" function I think unicode, and then seeing the same function without the "W" I think "not unicode."
    Quote Originally Posted by dilettante
    Code:
    Private Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyW" ( _
        ByVal lpString1 As Long, _
        ByVal lpString2 As Long) As Long
    
    Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenW" ( _
        ByVal lpString As Long) As Long


    Thanks for sharing this, Ellis. Given the low quality of the forum's in-built search function, I feel like "the more the merrier" when it comes to good code samples.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

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

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by Ellis Dee View Post
    Ah, fair enough. I was confused by Randy's use of lstrlenW vs dilettante's lstrlen, but I think it's just because Randy uses a byte array where dilettante uses a string directly.

    Normally when I see a "...W" function I think unicode, and then seeing the same function without the "W" I think "not unicode."
    Ah. That's an issue inherent in looking at mostly VB6 code. C/C++ typically Alias's the different API's (through typedef) to either A or W.
    That way you only use "lstrlen" in code, and then you're a typedef away from switching the entire app to use ANSI or Unicode APIs.

    I alias all APIs to the W version similar to dilettante. It just makes it easier to compare to C/C++.
    As a community, we really need to just get away from posting _any_ code that isn't Unicode compliant.
    Last edited by DEXWERX; May 19th, 2016 at 08:25 AM.

  14. #14
    Addicted Member
    Join Date
    May 2011
    Posts
    230

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    Quote Originally Posted by dilettante View Post

    Code:
    Public Function GetKnownFolder(ByVal KnownFolderID As String) As String
        'Returns empty String on any error.
        Dim guidKFID(15) As Byte
        Dim pszPath As Long
    
        If CLSIDFromString(StrPtr(KnownFolderID), guidKFID(0)) = S_OK Then
            If SHGetKnownFolderPath(guidKFID(0), 0, WIN32_NULL, pszPath) = S_OK Then
                GetKnownFolder = Space$(lstrlen(pszPath))
                lstrcpy StrPtr(GetKnownFolder), pszPath
                CoTaskMemFree pszPath
            End If
        End If
    End Function
    is it me or this is prone to "crash"?
    according to MS documentation, I read about lstrlen:
    Determines the length of the specified string (not including the terminating null character).

    Then, on lstrcpy:
    The buffer must be large enough to contain the string, including the terminating null character.

    wich is not the case here ? Correct me if I'm wrong plz.


    still... some interesting link:

    For clarification
    guidKFID(15) or guidKFID(0 to 15) is right but using the GUID type would be more "by the book"

    according to MS documentation
    https://support.microsoft.com/en-us/kb/183544
    The GUID is declared as:

    Code:
    Private Type GUID
      Data1 As Long
      Data2 As Integer
      Data3 As Integer
      Data4(0 to 7) As Byte
    End Type
    In vb6, Long=4 bytes, Integer=2 bytes, therefore, 4+2+2+8=16

    Private Declare Function CLSIDFromString Lib "ole32.dll" (ByVal lpszProgID As Long, ByRef pCLSID As GUID) As Long
    Last edited by VbNetMatrix; Sep 29th, 2016 at 12:42 AM. Reason: made huge technical mistake

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

    Re: VB6: Windows 10 Known Folders / SHGetKnownFolderPath

    There's always an implied Null terminating Wide char at the end of a BSTR, that's not included in the length.

    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx

Posting Permissions

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



Featured


Click Here to Expand Forum to Full Width