Hard-coding "My Documents"? Fix Your Code


You’ve probably heard this warning before – don’t hard-code paths such as “\My Documents”. This path has changed in past versions of Windows Mobile so it is not safe to assume the directory structure. The correct way to obtain a device’s My Documents path is using the SHGetSpecialFolderPath API with a CSIDL_PERSONAL parameter. In managed code you can use System.Environment.GetFolderPath with various Environment.SpecialFolder constants.


I’m reemphasizing this because of some information I found out today. We’re localizing the My Documents path for various languages in the upcoming version of Windows Mobile (codename “Crossbow”). I was surprised to know that this path isn’t already localized, as it should be. After all, “My Documents” doesn’t mean much to a Japanese user. I’m not sure if any other folder paths will be localized at this time, but in general it’s very bad practice to assume any path (e.g. \Windows, \Storage Card etc.) If you’ve got code that does this, fix it by using APIs such as SHGetSpecialFolderPath, FindFirstFlashCard and SHGetDocumentsFolder.


You’ve still got some time before “Crossbow” devices hit the market, but it’s never too early to check your code for such defects.


Comments (15)

  1. dono says:

    In front of me are two Japanese Windows XP Pro. On the desktop is マイ ドキュメント (mai dokyumento -> My Documents). This is only at the _presentation_ level. Browsing up from the directory structure shows:

    C:Documents and Settings[UserName]My Documents .

    There is also マイ コンピュータ (mai konpyu-ta -> My Computer), マイ ネットワーク (mai nettowa-ku), スタート(suta-to, Start), コントロール パネル (kontoro-ru paneru -> Control Panel) etc.

    It’s "cool" to make it sound like English; however, it is often the case that people just learn what the function does without understand the real meaning. That’s often the state of translation in Japan.

    Tokyo, Japan

  2. dono says:

    I neglected my point.

    Is Crossbow in fact localizing the actual path name or only doing what XP does by localizing the presentation?

  3. ANOTHER PROBLEM says:

    Is your user name folder, Im on an enterprise domain and I change my alias fine, but this folder stays the SAME OLD NAME! WTF, why dont you just use the SID as the folder and when we VIEW it you translate the SID into the user name.  I all LAZYNESS and SHODDY DESIGN.

  4. Andy says:

    What’s the plan at Microsoft for fixing the DSOD issue that plagues all devices and all owners?

  5. Charlie says:

    What about a case where the user can change the locale and reboot? Does the device then rename all the SHXxxxx managed folders?

  6. Kim Nyberg says:

    This is an extremely stupid, app-breaking change without any real benefits for anyone. Sure, it’s easy to change your application so that it will work in future versions, but what about the old apps that are not developed by anyone any more, and that are still useful for a lot of people. I urge you to reconsider this, as one of the great benefits of Windows Mobile compared to Symbian/Series 60 is the backward compatibility.

    Kim Nyberg

  7. And changing it back to "My Documents" for every language once we finally get MUI for Pocket PC ?!

    I would say stick to "My Documents" and localise only the UI through single-language MUI-style localisation, so that it’s ready for the MUI switch.

  8. MSDNArchive says:

    Here’s some clarification:

    Windows desktop and Smartphone platforms have the logical file system path always named "My Documents". The UI is localized using MUI redirection. So as ‘dono’ pointed out above, the actual folder is named "My Documents", but it *appears* in a local language to the end-user based on MUI. But again, this is true only on desktop and Smartphone (not PPC).

    Pocket PC does not currently support MUI and as far as I know, there are no plans to add MUI support in the future. So on the PPC, the actual name of the "My Documents" folder will be localized.

    When the user changes the locale from Control Panel, the file names and directory names do not change. On the Smartphone, display names only change when the UI Language is changed.

    I hope this answers some of the questions people have asked above.

    Bottomline, please avoid hard coding the name or path of My Documents and other folders.

    -Mel

  9. Charlie says:

    So basically even though we "do the right thing" and get the path to our app (Program Files(or whatever)Xxxx) from the Shell, the fact that we store that complete path literal in the registry will be broken on a PPC machine if the locale is adjusted and rebooted?

    That’s sort of crappy guys. PPC should do it like SP is planned to.

  10. JJ says:

    The only crappy ting is the bad application code. Fix it!

    I’m all for the localization.

    I just wish lazy coders used API calls when they should.

    As being non US I have been living with poorly written applications and installers for years.

    This is not a new issue in Windows land!

  11. Charlie says:

    Oh come on – dynamically renaming the actual path to system components every time the locale changes is just plain dumb. This brings up all sorts of potential issues.

    What if the user sets the registry to have some path other than the default for one of those shell managed folders?

  12. DeathAxe says:

    Nice to read, as I am currently trying to translate these paths to german on a windows mobile 6.1. That’s why I give the sentence back to Microsoft: "Fix Your Code!!!" I found several system files such as shellres.dll.0407.mui tabres.dll.0407.mui and many other with hardcoded "My Documents" path which actually influence system behaviour.

  13. A few blogs I found detailing the API/Object/Library features for getting my documents and other associated…

  14. adnan says:

    Enumerating Storage Cards

    Because a device can have multiple storage cards with various names, your application cannot make any assumptions about the naming or path to a particular card. Pocket PC provides the FindFirstFlashCard and FindNextFlashCard functions to allow programmatic enumeration of storage cards.

    To determine whether your device has a storage card, call the FindFirstFlashCard and FindNextFlashCard functions. FindFirstFlashCard returns a search handle that FindNextFlashCard uses. It also returns a pointer to the first storage card, if any. FindNextFlashCard returns a pointer to the next storage card and a BOOL value indicating whether the search was successful. The following code example shows how to use FindFirstFlashCard and FindNextFlashCard to locate up to ten storage cards on a Pocket PC device:

    int index;

    int iNumOfFlashCard = 0;      // tTotal number of storage                   // cards

    BOOL bContinue = TRUE;       // If TRUE, continue

                     // searching

                     // If FALSE, stop searching.

    TCHAR szRootDirPath[MAX_PATH];   // Root directory path of

                     // storage cards.

    TCHAR szSCName[1000];        // String for storing the

                     // storage card name with

                     // the full path

    HANDLE hFlashCard;         // Search handle for storage

                     // cards

    WIN32_FIND_DATA *lpwfdFlashCard;  // Structure for storing

                     // card information.

    WIN32_FIND_DATA *lpwfdFlashCardTmp; // Structure for storing

                     // card information

                     // temporarily

    lpwfdFlashCardTmp = (WIN32_FIND_DATA *) LocalAlloc (LPTR, 10 * sizeof (WIN32_FIND_DATA));

    if (lpwfdFlashCardTmp == NULL)   // Failed allocate memory return;

    hFlashCard = FindFirstFlashCard (&lpwfdFlashCardTmp [0]);

    if (hFlashCard == INVALID_HANDLE_VALUE)

    {

      LocalFree (lpwfdFlashCardTmp);  // Free the memory.

      return;

    }

    while (bContinue)

    {

      iNumOfFlashCard += 1;

      // Search for the next storage card.

      bContinue = FindNextFlashCard (hFlashCard, &lpwfdFlashCardTmp

           [iNumOfFlashCard]);

    }

    FindClose (hFlashCard);          // Close the search handle.

    if (iNumOfFlashCard > 0)

    {

      // Allocate memory for lpwfdFlashCard.

      lpwfdFlashCard = (WIN32_FIND_DATA *) LocalAlloc (LPTR,

             iNumOfFlashCard * sizeof (WIN32_FIND_DATA));

      if (lpwfdFlashCard == NULL)      // Failed allocate memory

       return;

      // Assign lpwfdFlashCardTmp to lpwfdFlashCard

      for (index=0; index < iNumOfFlashCard; ++index)

      {

       lpwfdFlashCard [index] = lpwfdFlashCardTmp [index];

      }

      LocalFree (lpwfdFlashCardTmp);  // Free the memory.

    }

  15. adnan says:

    eonjoy man. if u have any sort of any issue regarding Pocket pc contact PPC guru to solve it.