Why can’t I use SHSetKnownFolderPath to change the location of FOLDERID_LocalAppData?

Raymond Chen

Raymond

A customer observed that their unit test started failing in Windows 10 version 1803. Specifically, it failed here:

SHSetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, temporaryDirectory);

with the error E_INVALID­ARG. What happened in Windows 10 version 1803 to make this call invalid?

The change to block relocation of the Local­App­Data folder, as well as its close personal friend Local­App­Data­Low, was an acknowledgement of reality: Earlier versions of Windows allowed you to relocate those directories, but the result was a corrupted user profile, forcing you to delete the user and start over.

The reason is that there are some system files in those directories which are perpetually locked and consequently cannot be moved to their new home. The next time the user logs on, the system tries to reopen the files and can’t, and things rapidly go downhill from there.

Relocation of these directories is blocked to prevent you from shooting yourself in the foot. It’s an acknowledgement of the reality that it not only doesn’t work, but leaves the user profile corrupted.

 

13 comments

Comments are closed.

  • Avatar
    Alex Martin

    I know it’s far too late to change any of this behavior, and I don’t want to start a flame war, but I will still say that this is an example of how Windows mishandles file locking.

    Could you make this work with a pending rename? It would mean a reboot, but it would work. Obviously not through the same interface, but if you had a new one that’s documented as moving the folder at the next reboot. Not that one needs to be introduced, but if this were needed that’s one way I think it might be doable.

    Edit to add: This wouldn’t fix this particular application, since it seems to be temporarily moving the AppData folder to do something online. Rebooting twice every time your application does [operation] would not be, um, very convenient.

        • Avatar
          Dave Bacher

          Just require the user to log out.

          When the user is logged out, you can move the directory. User Profile Service can keep a token, if it needs it, while it moves the directory. Then it can mount and update the registry, or just mklink /d and be done with it (which is all around safer). You can create a shadow at the time the move is requested and start copying files from the shadow, and at logout you can finalize whatever changed after the shadow.

          If you do it from the user profile service, you can ensure the user profile is unloaded before you make the change – and therefore no programs are accessing the user’s files.

          It’d be better to do OneDrive Desktop Sync this way also, when a system is enrolled or leaves, you’d be less likely to trash files in the process if software caches directories after calling the API for a path.

          • Avatar
            cheong00

            I hate to beat the dead horse, but can’t help but keep wondering who TH approve OneDrive’s action to move the Document folder on backup? Lots of my cross-platform software go broken because they store settings in Document folder with hard-coded path.

            For me, it hurts me more because the backup is not “per-machine”. My Visual Studio Projects from different time got mixed into a mess. (I switched back to my desktop for development when SP3 keyboard not working, so both machine have backup of same folder on different time)

            Fortunately they don’t go wipe the volume shadow copy backup so I can restore them to a known state.

            For a record, I’ve filed paid support for this, and this is not resolved over a year (since Nov 2018) They promised periodic update of status but I didn’t heard them back over half year.

          • Avatar
            Antonio Rodríguez

            @cheong00: TRWTF is storing application settings in the My Documents folder, and hard-coding the path to it. That’s exactly what the article’s LocalAppData is for. You don’t need for OneDrive to move it. The user can do as they wishes with it (hey, it’s their “My Documents” folder!), and you wouldn’t even get to complain about it.

            Also, if you are having problems because OneDrive mixed files from two machines, I guess you either don’t have it set up properly, or didn’t take into account the effects of the sync. OneDrive (or any other folder backup/sync software) isn’t a replacement for an actual version control system, and while you can use it as such, you have to take a short grip on it (and have a local backup) if you don’t want to have a disaster.

          • Avatar
            cheong00

            @Antonio: Regarding OneDrive mixing files from multiple machines, I think that’s not my fault. It’s Windows Security Settings claims I have problem not enabling it. And when I enable it it’s don’t provide much settings for me to set. As soon as it tells me sync complete, I found all the files have moved to another location, and my “Visual Studio Projects” folder contains multiple copies of files from different machine at different time.

            And if you tried to use OneDrive, you know there aren’t such setting exist to help you differentiate between files from different machines either.

  • Avatar
    Simon Clarkstone

    I remember fighting with this when trying to move all my Known Folders into an encrypted partition. Moving AppData/Local was a right pain due to magic files, and once moved, some things like the start menu and Edge wouldn’t launch. I eventually gave up and kept AppData/Local unencrypted. (I wanted to encrypt the whole disk but the tool I was using failed to do that without clear explanation, so I switched to having an encrypted partition stored as a giant 100GB file in admin’s Documents folder.)

    I’m glad to learn that experts agree that moving AppData/Local is painful or impossible, and it wasn’t just me struggling.

    • Avatar
      William Godfrey

      I had a Windows tablet with a small C: on flash memory and a D: on an SD card which was 16 times larger and almost empty. The C: was running low on space and I tried configuring it to use D: for temp files but it just wasn’t having it.

  • Avatar
    Steven Don

    I must wonder why that particular action was in a unit test. I can understand wanting to use a temporary folder to store your own app’s data when doing tests, but this seems like addressing a local problem by modifying global state. What legitimate purpose could that have served?

  • Avatar
    Joshua Hudson

    If you *really* want this, you should have carried out the procedure instead to encrypt your entire user profile.

    1) Log in as another user with admin
    2) Delete your entire profile
    3) Delete the path to your profile from the system registry
    4) Change new profile directory to something in the encrypted drive
    5) Log in as yourself with runas; this will create your new profile.
    6) Change new profile directory back *immediately* — don’t leave this changed setting lying around. It breaks Windows updates.

    It turns out Windows will load your profile from somewhere other than the profile directory, but only if it made it there. Just changing the location doesn’t work too good.