FAQ
I'm using python (with wxPython, PySQLite, etc) under Windows,
and I think that by staying with old versions of Windows (NT, 98),
I may not be doing what new versions like. Are there new rules
under Windows 2000 or XP that restrict in which folders users can or
should be saving their data? Do the python libs or the python
win32api give me any function that I can call to find out where I
should be creating output files for users? I guess I can check
for C:\Documents and Settings\<username>" and create data files
there if I find it, but is there any more reasonable way to know
where data should go? Is there any way to find an output folder
where all users should have read and write privileges so that
shared data can go there? Of course, I'd like to run on Win95, 98,
NT, 2k, XP, and be aa good citizen on all.

Any pythonically canonical or vice versa solutions to this one?

Al

Search Discussions

  • Andrew Clover at Jun 13, 2003 at 1:10 pm

    achrist at easystreet.com wrote:

    Are there new rules under Windows 2000 or XP that restrict in which folders
    users can or should be saving their data?
    They're not entirely new; paths like this have been configurable back to
    Win9X, and are in any case likely to be different on different language
    installations.
    Do the python libs or the python win32api give me any function
    that I can call to find out where I should be creating output files
    for users?
    Don't know of anything Python-specific, but you can use the winreg module:

    http://www.python.org/doc/current/lib/module--winreg.html

    to read the contents of the registry, eg. key:

    \Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders

    --
    Andrew Clover
    mailto:and at doxdesk.com
    http://www.doxdesk.com/
  • Tim Golden at Jun 13, 2003 at 1:30 pm
    achrist at easystreet.com wrote in message news:<3EE993CB.F2CE7D39 at easystreet.com>...
    I'm using python [...] under Windows.
    Are there new rules [...] that restrict in which
    folders users can or should be saving their data?
    Have a look at this (recent) thread:
    http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&th=6f2409ae2369aa76&rnum=8

    Not necessarily a complete answer. I don't believe there are any
    "rules", in Python or otherwise. However, Microsoft would rather like
    you to save things in "My Documents", "My Pictures", "My Rubbish Bin"
    and so on, and the easiest way to find them is discussed in the above
    thread (and a few others if you care to Google back through this
    newsgroup).

    TJG
  • Chris Tavares at Jun 15, 2003 at 4:26 am
    "Dennis Lee Bieber" <wlfraed at ix.netcom.com> wrote in message
    news:u42tr-km3.ln1 at beastie.ix.netcom.com...
    [ ... snip ... ]
    I'm still configuring my new laptop -- doing a full backup with 3rd
    party installed software first, THEN I'm going to risk Partition Magic
    on it to create my "data" partition. Will still take some time to get
    all the applications configured. Is there some easy way to define M$'s
    "My <bleeping this & that>" to use a separate partition?
    Grab a copy of TweakUI for your version of Windows - available as part of
    the Powertoys distributions from Microsoft. There's a gui in there to move
    the Documents and Settings directory to whatever drive & directory you want.

    -Chris, being ashamedly unpythonic, but hopefully helpful.
  • Achrist at Jun 15, 2003 at 4:31 am
    I've got similar trouble with my WinNT machine, which is why I won't
    default to put data into the folders that MS sets up on C: if the
    OS is old. My drive is aN ibm 20 Gb, but the BIOS can't handle a
    partition bigger than 8 Gb, so it's divided into drives C:, D:, I:,
    and J:, using special software from IBM. This special software
    will make the C: drive any size that you want, as long as you
    want it to be exactly 2 Gb. Since MS automatically puts all kinds of
    things useful and otherwise on C:, I don't have space there for
    anything that I can put anywhere else.

    I guess that with new systems you are supposed to be happy with
    huge folders of programs and data on C:. IDK.


    Al

    Dennis Lee Bieber wrote:
    Tim Golden fed this fish to the penguins on Friday 13 June 2003 06:30
    am:
    Not necessarily a complete answer. I don't believe there are any
    "rules", in Python or otherwise. However, Microsoft would rather like
    you to save things in "My Documents", "My Pictures", "My Rubbish Bin"
    and so on, and the easiest way to find them is discussed in the above
    thread (and a few others if you care to Google back through this
    newsgroup).
    Which I consider a pain -- It wouldn't be so bad if M$ had the
    foresight to mandate that those (what I consider "dynamic" directories)
    were automatically placed on a separate PARTITION, so that run-away
    data files don't kill what I consider a "system software" (static)
    partition.

    I'm still configuring my new laptop -- doing a full backup with 3rd
    party installed software first, THEN I'm going to risk Partition Magic
    on it to create my "data" partition. Will still take some time to get
    all the applications configured. Is there some easy way to define M$'s
    "My <bleeping this & that>" to use a separate partition?
  • Eddy Buhler at Jun 13, 2003 at 2:49 pm
    Hi,

    on Windows 9x, everything is under c:\windows for all users - those
    "Pseudo"-OS's do not really support multiple users with separate (and
    restricted to that user) user files etc.

    On Windows NT, there is a profiles folder unter WINNT, and in Windows 2000
    and XP you have c:\documents... (well, on systems with ENGLISH directory
    names, at least...).

    What I DO know is that unter Windows NT and Windows 2000 and Windows XP
    alike you can use environment variables to determine the correct directory.

    Try entering "set" in a shell/dos box, and you should somewhere find a
    variable called "USERPROFILE" and similar ones directing you to the right
    folders.

    Windows 9x will probably have to be handled manually though, and since I do
    not use these anymore, I cannot suggest anything great there.

    SInce I am fairly new to Python, I can't from the top of my head tell you
    the functions to evaluate environment variables, but my first guess would be
    something in the os module, and my second guess would be in the sys module.

    Hope that helps,
    Eddy Buhler
  • Achrist at Jun 13, 2003 at 5:47 pm
    Thanks to all for the advice. To recap:

    It looks like this is all OS-version-specific. I guess I'd like to
    just put the data into the application directory on OS's prior to
    Win2k. If you upgrade a system from Win98 or NT to WinXP is the
    user screwed by having all their data in the wrong place anyhow?

    Trying to figure out how to figure out which OS version I'm dealing
    with, I try:
    import win32api
    win32api.GetVersionEx()
    (4, 0, 1381, 2, 'Service Pack 6')

    I infer that the major version is the first value in the tuple
    returned, and that if I see 4 or less, I've got an old system
    where I can allow or encourage the user to do what I've usually
    done, ie put data into a sub-folder of the app directory. (File
    save dialogs start someplace within the application folder).

    If the major version is 5 or more, I've got 2k or XP or something
    newer (maybe worse?), and I should look in the registry at

    1. For 1-user data

    HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellFolders\

    My choice of registry value names may be "AppData", "Local AppData",
    and "Personal". I'll probably go with "AppData", if I find it. Any
    suggestions which is preferred? Anything else to look at on newer
    Windows versions?

    2. If I don't find anything, I try:

    C:\Documents and Settings\<username>\Application Data\

    3. For data shared among several users:

    HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellFolders\

    Where I find a value named "Common AppData". Anything else to look at on
    newer Windows versions?

    4. If I don't find anything, I try:

    C:\Documents and Settings\All Users\Application Data\

    File save dialogs for Win2k or newer will start in a subfolder of
    the folder found by steps 1-4.

    The python win32api should make all of this duck soup. Any pitfalls?


    Al
  • JanC at Jun 13, 2003 at 6:17 pm

    achrist at easystreet.com schreef:

    It looks like this is all OS-version-specific. I guess I'd like to
    just put the data into the application directory on OS's prior to
    Win2k. If you upgrade a system from Win98 or NT to WinXP is the
    user screwed by having all their data in the wrong place anyhow?
    There must be some information about this on Microsoft's MSDN site or in
    their knowledge base or something like that.
    I know there is information for the OS generations separately.
    (So you'll still have to compare Win95, Win 98, WinNT, Win2K, WinXP, ...)

    --
    JanC

    "Be strict when sending and tolerant when receiving."
    RFC 1958 - Architectural Principles of the Internet - section 3.9
  • Peter Hansen at Jun 13, 2003 at 6:18 pm

    achrist at easystreet.com wrote:
    If you upgrade a system from Win98 or NT to WinXP is the
    user screwed by having all their data in the wrong place anyhow?
    Is it even possible to upgrade a Win98 or NT box to WinXP? Or
    does it require a fresh install in either case or both cases?

    (Note: one could argue that if a user is working with _any_ of
    these OSes, they're already "screwed", but that's another story. :-)

    -Peter
  • JanC at Jun 13, 2003 at 6:25 pm

    Peter Hansen <peter at engcorp.com> schreef:

    Is it even possible to upgrade a Win98 or NT box to WinXP? Or
    does it require a fresh install in either case or both cases?
    It is possible but it's not a good idea IMHO.

    --
    JanC

    "Be strict when sending and tolerant when receiving."
    RFC 1958 - Architectural Principles of the Internet - section 3.9
  • Achrist at Jun 13, 2003 at 9:08 pm
    Just for the sake of discussion, and because this is a Python
    newsgroup, here's my code based on comments here, etc:

    The two functions for clients to call are GetSharedOutputDir()
    and GetUserOutputDir(). If you are running on a pre-Win2K
    OS, you've got to create a function GetRegistryAppDataDir() to
    return wherever the installer or equivalent thought the data
    should go. Presumably this will work ok, because if the user
    moves the data, they will also change the registry setting (maybe).
    For win2K or newer, we read the Shell Folders and go from there.

    BTW, notice how good MS is about making "CurrentVersion" one word
    and "Shell Folders" two words, just to brighten up our day with a
    little variety.

    Comments very welcome,


    Al


    # -------------------Code Follows --------------------------

    import os
    import os.path
    import win32api
    import win32con
    import whatever.else.you.need


    def GetSharedOutputDir(appName="MyApp"):
    if OsIsPreWin2K():
    return GetAppSharedDataSubdir()
    else:
    return GetRegistrySharedDataSubdir(appName)

    def GetUserOutputDir(appName="MyApp", userName=""):
    if not userName:
    try:
    userName = win32api.GetUserName()
    except:
    userName = ""
    if userName:
    if OsIsPreWin2K():
    return GetAppUserDataSubdir(userName, appName)
    else:
    return GetRegistryUserDataSubdir(userName, appName)
    else:
    return GetSharedOutputDir(appName)

    #================================================================
    # None of the functions below here should be called by the client
    #================================================================

    def OsIsPreWin2K():
    try:
    versionInfo = win32api.GetVersionEx()
    return versionInfo[0] <= 4
    except:
    return True

    def GetAppSharedDataSubdir():
    try:
    # Installer can create application data path
    # Smart user can change this registry value to move their data
    # Write Function GetRegistryAppDataDir() to run on pre-Win2k
    dirName = GetRegistryAppDataDir()
    if dirName:
    if not os.path.exists(dirName):
    os.makedirs(dirName)
    if not os.path.isdir(dirName):
    return os.getcwd()
    else:
    return os.getcwd()
    except:
    return os.getcwd()

    def OpenRegistryKey( registrySection, regKeys ):
    if regKeys:
    theKey = win32api.RegOpenKeyEx(registrySection, regKeys[0],
    0, # Reserved, Must Be Zero
    win32con.KEY_READ # Privileges
    Requested
    )
    for subKey in regKeys[1:]:
    theKey = win32api.RegOpenKeyEx(theKey, subKey,
    0, # Reserved, Must Be Zero
    win32con.KEY_READ # Privileges
    Requested
    )
    return theKey
    else:
    return None

    def GetRegistrySharedDataSubdir(appName):
    try:
    registryKeyHandle = OpenRegistryKey(
    win32con.HKEY_LOCAL_MACHINE,
    [ "Software",
    "Microsoft",
    "Windows" ,
    "CurrentVersion",
    "Explorer",
    "Shell Folders" ]
    )
    (valueObject, valueType ) = win32api.RegQueryValueEx(
    registryKeyHandle,
    "Common AppData"
    )
    if 1 == valueType:
    answer = valueObject
    else:
    answer = `valueObject`
    if not answer.strip():
    return GetStandardWindowsSharedDataDirectory(appName)
    else:
    answer = os.path.join( answer, appName )
    if not os.path.exists(answer):
    os.makedirs(answer)
    return answer
    except:
    return GetStandardWindowsSharedDataDirectory(appName)

    def GetStandardWindowsSharedDataDirectory(appName):
    try:
    answer = "C:\\Documents and Settings"
    answer = os.path.join( answer, "\\All Users" )
    answer = os.path.join( answer, "\\Application Data")
    answer = os.path.join( answer, appName )
    if not os.path.exists(answer):
    os.makedirs(answer)
    return answer
    except:
    return os.getcwd()

    def GetAppUserDataSubdir(userName, appName):
    try:
    # Installer can create application data path
    # Smart user can change this registry value to move their data
    # Write Function GetRegistryAppDataDir() to run on pre-Win2k
    dirName = GetRegistryAppDataDir()
    if not dirName:
    dirName = os.getcwd()
    if dirName:
    if not os.path.exists(dirName):
    os.makedirs(dirName)
    if not os.path.isdir(dirName):
    dirName = os.getcwd()
    dirName = os.path.join(dirName, userName)
    if not os.path.exists(dirName):
    os.makedirs(dirName)
    if not os.path.isdir(dirName):
    dirName = os.getcwd()
    return dirName
    else:
    return os.getcwd()
    except:
    return os.getcwd()

    def GetRegistryUserDataSubdir(userName, appName):
    try:
    dirName = GetRegistryUserDataValue("AppData")
    if not dirName:
    dirName = GetRegistryUserDataValue("Personal")
    if not dirName:
    dirName = GetRegistryUserDataValue("Local AppData")
    if not dirName.strip():
    return GetStandardWindowsUserDataDirectory(appName,
    userName)
    else:
    dirName = os.path.join( dirName, appName )
    if not os.path.exists(dirName):
    os.makedirs(dirName)
    return dirName
    except:
    return GetStandardWindowsUserDataDirectory(appName, userName)

    def GetRegistryUserDataValue(valueName):
    try:
    registryKeyHandle = OpenRegistryKey(
    win32con.HKEY_CURRENT_USER,
    [ "Software",
    "Microsoft",
    "Windows" ,
    "CurrentVersion",
    "Explorer",
    "Shell Folders" ]
    )
    (valueObject, valueType ) = win32api.RegQueryValueEx(
    registryKeyHandle,
    valueName
    )
    if 1 == valueType:
    answer = valueObject
    else:
    answer = `valueObject`
    if not os.path.exists(answer):
    os.makedirs(answer)
    return answer
    except:
    return ""

    def GetStandardWindowsUserDataDirectory(appName, userName):
    try:
    answer = "C:\\Documents and Settings"
    answer = os.path.join( answer, userName )
    answer = os.path.join( answer, "\\Application Data")
    answer = os.path.join( answer, appName )
    if not os.path.exists(answer):
    os.makedirs(answer)
    return answer
    except:
    return os.getcwd()
  • JanC at Jun 15, 2003 at 1:28 am

    achrist at easystreet.com schreef:

    The two functions for clients to call are GetSharedOutputDir()
    and GetUserOutputDir(). If you are running on a pre-Win2K
    OS, you've got to create a function GetRegistryAppDataDir() to
    return wherever the installer or equivalent thought the data
    should go. Presumably this will work ok, because if the user
    moves the data, they will also change the registry setting (maybe).
    For win2K or newer, we read the Shell Folders and go from there.
    My Win98SE system with MSIE 5.5 & Office 2K installed and using a login
    name has:

    HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
    - AppData
    - Local AppData
    - Personal

    HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\explorer\Shell Folders
    - Common AppData
    - Personal


    But I'm almost sure a "virgin" Win98SE (or earlier) install doesn't have
    all of these keys...

    --
    JanC

    "Be strict when sending and tolerant when receiving."
    RFC 1958 - Architectural Principles of the Internet - section 3.9
  • Tim Golden at Jun 16, 2003 at 10:03 am

    Dennis Lee Bieber:
    Is there some easy way to define M$'s "My <bleeping this & that>"
    to use a separate partition?
    Someone, somewhere recently has pointed out that TweakUI and various
    other tools from Microsoft and elsewhere will do this. If you're
    administering an NT domain (which you're obviously not on your
    own laptop, unless you have delusions of grandeur) then the NT
    Policies will allow you to do this as well.

    [http://groups.google.com/groups?q=tweakui+group:comp.lang.python.*&hl=en&lr
    =&ie=UTF-8&group=comp.lang.python.*&selm=OzSGa.44430%24rO.4390296%40newsread
    1.prod.itd.earthlink.net&rnum=1]

    In fact, there is a lot to be known about MS Windows in its various
    incarnations that isn't known by the casual user, and not even by
    the administrators in some cases. As a rule, direct access to the
    registry is not the best way to read/write system info (unless of
    course there is no other), not least because it changes so damned
    often: what looked like a stable lookup in Win98 suddenly isn't there
    when you get to Win2k.
    Functions like SHGetSpecialFolderPath, available via the shell module
    in win32all will get pretty much anything you like of the [My Documents]
    variety, regardless of the environment, changes of location, use of
    domain etc. At least, I've used them across a mixed Win2k / Win9x
    setup with no problems at all.

    Examples:

    from win32com import storagecon
    from win32com.shell import shell, shellcon

    def desktop (common=0):
    return shell.SHGetSpecialFolderPath (0, (shellcon.CSIDL_DESKTOP,
    shellcon.CSIDL_COMMON_DESKTOPDIRECTORY)[common])

    def application_data (common=0):
    return shell.SHGetSpecialFolderPath (0, (shellcon.CSIDL_APPDATA,
    shellcon.CSIDL_COMMON_APPDATA)[common])

    def personal_folder ():
    return shell.SHGetSpecialFolderPath (0, shellcon.CSIDL_PERSONAL)
    my_documents = personal_folder

    etc. etc.

    TJG

    ________________________________________________________________________
    This e-mail has been scanned for all viruses by Star Internet. The
    service is powered by MessageLabs. For more information on a proactive
    anti-virus service working around the clock, around the globe, visit:
    http://www.star.net.uk
    ________________________________________________________________________
  • Achrist at Jun 16, 2003 at 4:25 pm

    Tim Golden wrote:
    In fact, there is a lot to be known about MS Windows in its various
    incarnations that isn't known by the casual user, and not even by
    the administrators in some cases. As a rule, direct access to the
    registry is not the best way to read/write system info (unless of
    course there is no other), not least because it changes so damned
    often: what looked like a stable lookup in Win98 suddenly isn't > there
    when you get to Win2k.
    Functions like SHGetSpecialFolderPath, available via the shell module
    in win32all will get pretty much anything you like of the [My > Documents]
    variety, regardless of the environment, changes of location, use of
    domain etc. At least, I've used them across a mixed Win2k / Win9x
    setup with no problems at all.

    Examples:

    from win32com import storagecon
    from win32com.shell import shell, shellcon

    def desktop (common=0):
    return shell.SHGetSpecialFolderPath (0, (shellcon.CSIDL_DESKTOP,
    shellcon.CSIDL_COMMON_DESKTOPDIRECTORY)[common])

    def application_data (common=0):
    return shell.SHGetSpecialFolderPath (0, (shellcon.CSIDL_APPDATA,
    shellcon.CSIDL_COMMON_APPDATA)[common])

    def personal_folder ():
    return shell.SHGetSpecialFolderPath (0, shellcon.CSIDL_PERSONAL)
    my_documents = personal_folder
    This looks to be exactly what I need, if I can get it to work ...

    Are these not portable to WinNT? On NT 4.0 SP6, I get:
    from win32com import storagecon
    from win32com.shell import shell, shellcon
    shell.SHGetSpecialFolderPath (0, (shellcon.CSIDL_DESKTOP,
    ... shellcon.CSIDL_COMMON_DESKTOPDIRECTORY)[0])
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    pywintypes.com_error: (-2147467263, 'Not implemented', None, None)
    shell.SHGetSpecialFolderPath (0, (shellcon.CSIDL_APPDATA,
    ... shellcon.CSIDL_COMMON_APPDATA)[0])
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    pywintypes.com_error: (-2147467263, 'Not implemented', None, None)


    Al
  • Achrist at Jun 20, 2003 at 6:05 pm
    OK. Here's the next level conundum of this maze of what goes where
    and who can do what under Windows. If I distribute an app as a
    one file distro using py2exe or the McMillan installer, when it runs
    IIRC it wants to explode itself back into multiple pieces that are
    deleted at the end of the run. I'm guessing that this means that
    the user must have privileges to create files in the program's
    directory. Is that so?

    If Windows is promoting or enforcing a policy of "programs here" and
    "files there", with administrator privileges required to create a
    file or write to the program files folder, isn't this going to be a
    problem? Best solution if so?


    Al
  • Thomas Heller at Jun 20, 2003 at 6:28 pm

    achrist at easystreet.com writes:

    OK. Here's the next level conundum of this maze of what goes where
    and who can do what under Windows. If I distribute an app as a
    one file distro using py2exe or the McMillan installer, when it runs
    IIRC it wants to explode itself back into multiple pieces that are
    deleted at the end of the run. I'm guessing that this means that
    the user must have privileges to create files in the program's
    directory. Is that so?
    py2exe doesn't have a one file option. Always you have at least two
    files (but possibly more), your exe and the pythonxx.dll. py2exe never
    creates files by itself.

    I don't know too much about installer, but IMO it explodes its files in
    the temp directory, otherwise the onefile executable wouldn't be able to
    run from CD rom.

    Thomas
  • Tim Golden at Jun 16, 2003 at 4:27 pm
    achrist at easystreet.com> This looks to be exactly what I need, if I can get
    it to work ...
    achrist at easystreet.com> Are these not portable to WinNT? On NT 4.0 SP6, I
    get:

    [snip error messages]

    Ahh. I rather thought that the win32 shell stuff was universal (on win32, at
    least). I don't have an NT4 box here, so I'll have to try it when I get
    home. Can anyone else confirm, or cast light on this?

    TJG

    ________________________________________________________________________
    This e-mail has been scanned for all viruses by Star Internet. The
    service is powered by MessageLabs. For more information on a proactive
    anti-virus service working around the clock, around the globe, visit:
    http://www.star.net.uk
    ________________________________________________________________________
  • Tim Golden at Jun 17, 2003 at 11:18 am
    Tim Golden <tim.golden at viacom-outdoor.co.uk> wrote in message news:<mailman.1055781148.14465.python-list at python.org>...
    achrist at easystreet.com> This looks to be exactly what I need, if I can get
    it to work ...
    achrist at easystreet.com> Are these not portable to WinNT? On NT 4.0 SP6, I
    get:

    [snip error messages]

    Ahh. I rather thought that the win32 shell stuff was universal (on win32, at
    least). I don't have an NT4 box here, so I'll have to try it when I get
    home. Can anyone else confirm, or cast light on this?

    TJG
    Answering myself...

    WinNT (and maybe Win95) don't support SHGetSpecialFolderPath directly;
    instead, you have to use SHGetSpecialFolderLocation and then
    SHGetPathFromIDList. If you wish, have a butchers at my winshell
    module (http://tgolden.sc.sabren.com/python/winshell.html), a
    convenience wrapper round these sort of things. If nothing else, you
    can look at the code and see what I'm talking about.

    Since Win2K (and maybe Win98) also support the two-level SHGet...,
    I've recoded my module to use that rather than try to do
    platform-specific juggling, which smacks of browser-sniffing a little
    too much for my liking.

    TJG

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedJun 13, '03 at 9:05a
activeJun 20, '03 at 6:28p
posts18
users8
websitepython.org

People

Translate

site design / logo © 2022 Grokbase