Is there a generic way to reference the location of a user's Windows desktop (like ~/Desktop would for OS X)?
December 30, 2006 5:02 PM   Subscribe

Is there a generic way to reference the location of a user's Windows desktop (like ~/Desktop would for OS X)?

I can feed some XML into a program that then exports some more XML that I need to grab. I can even tell the program where to put the exported XML from the 1st file. I have a few users (with different names!) using this work flow.

I know that I can put in for the export to go to C:\Documents and Settings\john m\Desktop\out_put.xml, but I need a way to say this without having any one user's name in that string. In OS X, I would use ~/Desktop/out_put.xml and the file would be dropped on the current user's desktop.

Any suggestions?
posted by john m to Computers & Internet (21 answers total) 2 users marked this as a favorite
If the program understands environment variables, you can use %USERPROFILE%\Desktop\out_put.xml. If it's a command line program, then I'd recomend wrapping it with a cmd script. That's about the best I think you can do in Windows.
posted by sbutler at 5:09 PM on December 30, 2006

Using special folders. Use the get folder path function.
posted by delmoi at 5:12 PM on December 30, 2006

Also, what are you writing your program in? Java? .Net? Something using the win32 API?
posted by delmoi at 5:20 PM on December 30, 2006

keep in mind this only works if everyone is using the same localized version of Windows. I assume the Desktop is called something else in different locales (I bet that's true of OS X as well).
posted by mmascolino at 5:32 PM on December 30, 2006

"Get folder path" will work regardless of localization and Windows version, because its parameter is an enumerated value rather than a language-specific string. That's kind of the point.
posted by flabdablet at 5:34 PM on December 30, 2006

mmascolino: under OS X it's always Desktop, in my experience. Here's more information: Localizing Pathnames. I don't know how it works in Windows.
posted by sbutler at 5:39 PM on December 30, 2006

mmascolino: under OS X it's always Desktop, in my experience.

Not to derail, but if you're using Cocoa in Mac OS X, a good way to find the user's desktop folder is the Foundation NSSearchPathForDirectoriesInDomains() function. For Carbon apps, use FSFindFolder() instead.
posted by secret about box at 6:28 PM on December 30, 2006

Note also that in Windows "Documents and Settings" is not a fixed string at all. It is a localized string, it varies based on language. And besides, you can set it when you install Windows by using a response file. For example I chose to install mine to \Users so there would be no annoying space. So under no circumstances should you ever use that directory name in your app. Just call SHGetFolderPath() or whatever your language/framework calls it.
posted by Rhomboid at 6:57 PM on December 30, 2006

Response by poster: I'm not writing the application, I am feeding XML in and getting XML out from someone else's app. One of thge pieces of info contained in the feeder XML is the location of where the output data should be placed. It is here that I am trying to reference the user's desktop. So, I was looking for something that is not programmatic, but what exactly I'm not sure.

%USERPROFILE%\Desktop\out_put.xml didn't work, but that was the idea that I was looking for or something close. The app does not seem to understand environment variables.

I only have like 3 users, all on stock XP installs and speaking English, so localization is not an issue here at all.
posted by john m at 7:36 PM on December 30, 2006

you need to call getenv() to get the contents of environment variables inside your program. The whole %VAR% thing is just the syntax understood by cmd.exe for doing variable substitution.
posted by polyglot at 7:49 PM on December 30, 2006

If you're generating the input XML with sufficient control to specify a pathname in parts of it, why not just call Get Folder Path and embed its output into the XML?

Alternatively, if the input XML is coming out of some bastard GUI that you don't in fact control, could you do something like specifying %USER_DESKTOP_FOLDER%\output.xml in the GUI, then running the resulting XML file through a little filter script before it hits the second app? All the filter would have to do is call Get Folder Path and substitute the output for any occurrence of %USER_DESKTOP_FOLDER% - it wouldn't even need to parse the XML.
posted by flabdablet at 9:34 PM on December 30, 2006

Why not dump it into the temp dir, then remove it when your done? Why do you need to litter a desktop?
posted by SirStan at 9:35 PM on December 30, 2006

The app does not seem to understand environment variables.

It's not it's job to do that, it's the job of the shell. That is what everyone has been trying to say. If you invoke it from a command file (or possibly even just cmd /c "app.exe %foo%\bar" the shell should handle the expansion for you. And worst case, do what SirStan said and do a "move file.xml %foo%\bar" after running the app.
posted by Rhomboid at 9:41 PM on December 30, 2006

Oh, yeah: a trick I use for Firefox at one of the school sites I maintain might be of use to you.

We run a mix of Windows 98 and Windows XP workstations, only some of the Windows 98 workstations are set up with separate user profiles, and Firefox doesn't understand %ENVIRONMENT_VARIABLE_EXPANSION% inside its prefs.js configuration files - all of which makes it tricky to generate canned Firefox profiles with a default set of working extensions pre-installed.

The way I get around it is to have the user logon script subst a drive when the user logs on, in a way that depends on which OS version is running. The logon script ends up doing one of

subst U: "%USERPROFILE%" (for Windows XP)
subst U: "%WINDIR%" (for Windows 98 with no user profiles)


subst U: "%WINDIR%\Profiles\%USER%" (for Windows 98 with user profiles)

and Firefox is set up with the default profile pointing to

U:\Application Data\Mozilla\Firefox\Profiles\site.default\

which no longer needs environment variables expanded. It's kind of a kludge, but it works.
posted by flabdablet at 9:47 PM on December 30, 2006

SirStan: the Windows temp dir is also a special folder. "%TEMP%" usually expands to the same thing as "%USERPROFILE%\Local Settings\Temp".
posted by flabdablet at 9:49 PM on December 30, 2006

If you invoke it from a command file (or possibly even just cmd /c "app.exe %foo%\bar" the shell should handle the expansion for you.

I'm not certain that is correct on Windows—at least I'm pretty sure it didn't used to be that way.

I think the (logical) behavior described is a UNIXism, where the shell does the expansion of command-line arguments and as part of the launch process sets the resulting values into the argv of the the newly launched process. This does not provide a way for the process to get the unexpanded command-line string that was used to start it.

COMMAND.COM and cmd.exe, I think, do less, relying instead on the launched process to parse its own command-line arguments. At least that's why I've always figured commands such as

    move *.txt *.old

behave as most new users would expect them to, while on UNIX, a similar command might have been expanded to something like this by the time the actual process gets hold of it:

    mv file1.txt file2.txt file3.txt *.old

Which, of course, will only succeed if there is a directory named "*.old" in the current directory.

And, yes, "*.old" is a valid name for a file/directory on most UNIXes.
posted by BaxterG4 at 1:42 AM on December 31, 2006

You're confusing wildcard expansion with variable expansion, they are apples and oranges. You are very correct that the traditional unix behavior is that shells expand globs, and the traditional Windows behavior is that programs must process their own globs. But that is not what we are talking about here. Try running cmd /c "notepad %windir%\system.ini" on any Windows system -- you should see notepad open with the correct file, and if you inspect the command line of the notepad process using Process Explorer you will see that the filename was expanded by the shell, and that the program had no idea that there ever was a %-variable involved.
posted by Rhomboid at 3:16 AM on December 31, 2006

Fascinating. It had never crossed my mind that cmd might expand environment variables since it doesn't expand filesystem wildcards. I figured either the shell would do both or neither. Has it been like that since early DOS?
posted by BaxterG4 at 4:04 AM on December 31, 2006

The command interpreter not expanding wildcards is not so much a deficiency as a deliberate design decision, and it's been there since CP/M: the CP/M filesystem API (and every API descended from it, including Windows) has always had directory search functions that accepted wildcards as parameters. Which means that in Windows you can do

rename *.mod *.mpg

to get the same effect that Unix shells would need

for f in *.mod; do mv "$f" "${f%mod}mpg"; done

to achieve.

AFAIK and all its descendants have done environment variable expansion inside batch files since the first version that supported environment variables in any form; cmd.exe does environment variable expansion at the command prompt too.
posted by flabdablet at 5:14 AM on December 31, 2006

Yes, I'm pretty sure it has always been that way. Raymond Chen alludes to this somewhat in this article, where he talks about the fact that environment expansion was originally done immediately when each line was read (as opposed to the moment before it is about to be executed) due to memory constraints present in MS DOS 1.0, and how that default behavior has remained to this day for backwards compatibility. It's sad to say that some aspects of how our modern Windows PCs work still can be traced back to design tradeoffs made in the early 80s in order to support the IBM XT with 128KB RAM and a single 360K floppy drive. I'm not entirely sure why, but apparently in 1983 it was more memory efficient to have the command processor not do any of the glob expansion and instead rely on the individual program to do argument processing, and so that's what they did. But not for environment variable expansion, which I guess was primarily a thing used in batch files so it had to be done by the command processor. Unix on the other hand tended to evolve on a line of much more capable hardware platforms, typically with hardware memory management (and thus paging and protection and so on), so I guess it was more feasible to write a proper shell there.
posted by Rhomboid at 6:03 AM on December 31, 2006

Thanks guys, really interesting! (In a very won't-get-you-kissed-on-New-Year's-Eve kind of way.)
posted by BaxterG4 at 9:29 AM on December 31, 2006

« Older Vegas, Baghad, and the NCAA: Name that tune!   |   What do I do about my stalker? Newer »
This thread is closed to new comments.