current working directory for running exe

This topic is 3098 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hi, My program loads some data from files that are in the same directory as its executable. It uses relative paths internally to find these files. If the program is run while the directory in the exe is the "current working directory", then everything goes fine. In Linux, this is ok only when running the program from a terminal inside that directory. In Windows, it works when doubleclicking the exe in explorer. However I now added a command line option to my program to open a file, and I tried in Windows explorer to do "Open with..." and then choose my program. The program can't start because it can't find its data files that are in the directory of its own exe. So I think the cause is that, if you do "Open With..." in Windows explorer, then it apparantly has the same effect as Linux has when running the program while having another current working directory. The relative paths to the data files don't work anymore... So basically this is a problem and I've got a few questions to be able to fix the problem: -is it indeed so that Windows's "open with" option runs the exe with a different current working directory, than the one in which the exe is? -what is the good way to load data files that belong to your program in Windows? -and what is the good way to do this in Linux? -can I keep the data files next to the exe for these good ways above? I prefer it that way for multiplatform reasons (imagine having the data files in some different folder on every OS) and to be able to easily install the program by unzipping it somewhere along with its exe and data files. -Is there a cross platform way to find out in which directory the executable/binary of your program that is running, is located? -I don't seem to find any settings in windows file associations to set a working directory, is there maybe a hidden setting for this or so? I know that what windows displays to the user related to file associations is very limited compared to what it internally can... Thanks! [Edited by - Lode on December 24, 2009 4:56:39 PM]

Share on other sites
As you've discovered, using relative paths in windows is rarely a good idea.

At the start of your windows app, you can call GetCommandLine(). The first argument in that string is (or should be) the fully qualified path to your app. Parse the string for your executable directory and prepend that directory string to your relative paths. I used a "canned" set of std::string's at the beginning of most of my apps to store "appPath," "resourcePath," etc., which I can then prepend to filenames, etc. E.g., string fileName = appPath; fileName.append("fileInAppDir.txt");

In windows, the user can create shortcuts with the option to start the app specifying any working directory. The GetCommandLine() method avoids the problems you've seen.

Share on other sites
Quote:
 Original post by BuckeyeAs you've discovered, using relative paths in windows is rarely a good idea.At the start of your windows app, you can call GetCommandLine(). The first argument in that string is (or should be) the fully qualified path to your app. Parse the string for your executable directory and prepend that directory string to your relative paths. I used a "canned" set of std::string's at the beginning of most of my apps to store "appPath," "resourcePath," etc.In windows, the user can create shortcuts with the option to start the app specifying any working directory. The GetCommandLine() method avoids the problems you've seen.

Hey, that's interesting, I checked the specification of GetCommandLine() on MSDN and it turns out to return the same as the "int argc, char* argv[]" arguments of the main function (which I use, it's an SDL application).

So basically, the first command line argument is always the full path to your exe on Windows? That's really handy!

So basically, I'd have to remove the last part (the filename of the exe) of that string and I'd have the path I want. This does sound a bit shady to me, is this method used in the industry?

Share on other sites
If the app is run from the command-line, that path is not the fully qualified path, but the command-line used to run the program. However, at that point the current working directory is the directory in the console, and SetCurrentDirectory works both with relative and absolute paths, so the resultant directory should still always be the directory the exe is in. I believe chdir works the same way on Unix.
You probably need some different code for Windows and Linux, unless you can use system("cd ..") or something.. if that even works.. I haven't tried it but it might. =)

To get the exe path you can use GetModuleFileName. I assume there's a similar one on Linux.

Share on other sites
Quote:
 Original post by Lode-is it indeed so that Windows's "open with" option runs the exe with a different current working directory, than the one in which the exe is?
I believe "Open With..." (and file associations in general) will start your program with the current working directory set to the directory where the file you're loading is. There are other things that can change the working directory as well (for example, GetOpenFileName will change it)

I do a similar thing as Buckeye in that I work out the path to the executable and then use fully-qualified paths to files that are relative the executable. I usually use GetModuleFileName to get the path, though (pass in NULL as the first argument to get the path to the executable).

Share on other sites
I know it's not very platform-friendly, but if you're using GetCommandLine with the intention of parsing the string for the directory, why not just use GetCurrentDirectory?

Share on other sites
GetModuleFileName will give you the fully qualified path to the exe, from which you can extract the exe directory. As far as I know, relying on the full path to be passed as the first argument is non-standard and subject to change in future.

I use the following to locate my exe directory:

std::string ExecutablePath(){    char c[MAX_PATH];    GetModuleFileName(GetModuleHandle(NULL),c,MAX_PATH);    std::string S=c;    return S.substr(0,S.find_last_of("\\/"))+"\\";}

This is only for reading files though - writing to the exe directory is considered bad form now as your exe probably won't have permission and you should write to the app data directory, found with ShGetKnownFolderPath.

Share on other sites
Regular users can't write to the common app-data directory either, so to use that method you must make your installer create a sub-directory in the app-data folder, and change permissions for it.

Share on other sites
Quote:
 GetCommandLine() on MSDN and it turns out to return the same as the "int argc, char* argv[]" arguments of the main function (which I use, it's an SDL application).

Note that the statement is only true if the application uses the "main" (vs. WinMain) function to start the application. The lpCmdLine argument in WinMain does not include the program name. That's why I generalized to the GetCommandLine function.

However, it appears, as mentioned by Aardvajk, that GetModuleFileName() would be the more reliable function to use.

@Guinnie: for the reasons mentioned above, the current directory may or may not be the directory for the executable, even at the start of the app.

Share on other sites
Quote:
 Original post by Erik RufeltRegular users can't write to the common app-data directory either, so to use that method you must make your installer create a sub-directory in the app-data folder, and change permissions for it.

Really? I didn't know that. How do you change the permissions? Can you post some code?

• 47
• 12
• 10
• 10
• 9
• Forum Statistics

• Total Topics
631373
• Total Posts
2999644
×