Creating protable .exe files from my C++ code

Hello,

I have a VS2010 C++ project which outputs a text file.

I just want to use the executable that is developed by the compiler so that I can run it on different systems.

However, what I want to achieve is that the output text file should be stored in the same folder as my executable, even after moving the exe to a new location.

In order to achieve this, where do I store the output text file (what address should I give in my source code?) in my source code before I compile it and generate an executable?

Thanks in advance,
Best regards aye,
Redbeard
Use GetModuleFileName() to find where your executable is.
http://www.google.com/search?btnI=1&q=msdn+GetModuleFileName

1
2
3
4
5
6
7
#include <windows.h>
std::string GetExePath()
  {
  char filename[ MAX_PATH ];
  GetModuleFileName( NULL, filename, MAX_PATH );
  return filename;
  }

However, you should know that the directories where executables are stored are not always writable, especially in newer versions of Windows. You should either ask the user where to write or just put it in the "My Documents" folder.
Here is a version (maybe not the most recent) of my "portable" getExecutableDirectory() :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
	/**
	* Returns the absolute path of the current executable file.
	* There is always a / or a \ at the end of the path and the buffer is terminated by '\0'
	* Returns NULL on error
	* The string pointed to by the return value is a global variable.
	* You should use/copy the result of the function right after it's call or an other fonction might change the value of the string
	* do not try to free the pointer returned by the function
	*/
	const char * const getExecutableDirectory(){
		#ifdef WIN32
		if(GetModuleFileName(NULL, pathBuf, MAX_PATH)==0)
			return NULL;
		#else
			char procAddress[32];
			procAddress[0] = pathBuf[0] = 0;
			sprintf(procAddress, "/proc/%i/exe", getpid());
			readlink(procAddress,pathBuf, MAX_PATH);
		#endif
		/**
		* Extraction of the executable directory from the executable absolute path
		*/
#ifdef WIN32
		static const char os_specific_slash = '\\';
#else
		static const char os_specific_slash = '/';
#endif
		char * RESTRICT ptr = pathBuf + (strlen(pathBuf)-2);
		while((*ptr)!= os_specific_slash){
			ptr--;
		}
		*(ptr+1)='\0';

		return pathBuf;
	}

pathBuf is a global variable somewhere else, an array of MAX_PATH+1 chars. It could be static in the function i guess
And PATH_MAX must be defined as MAX_PATH when in Linux
Note that you don't actually need getpid() in the above code:
readlink("/proc/self/exe",pathBuf,MAX_PATH);

What with the global array, it does not appear to be thread-safe either.
It should return a std::string and use no global variables.
Alas, "self" is less portable than using the PID.
Also, on *nixen, you need to use PATH_MAX instead of MAX_PATH. :-)
I never said that my function is perfect, it was just to provide something that can help.

Yes it is not threadsafe. I was planning to make the global array local. That way i can save the result and return it directly on the next calls, since the executable path won't change for the lifetime of a process. I'm not sure if a function that uses system code, that can return different errors based on conditions external to the function can be considered threadsafe anyways (but please let's keep the thread on the original topic)

About the MAX_PATH/PATH_MAX mix, i have a header that defines one as the other based on the OS, so that i can always use the same, so i just forgot which one was on which system :P I try to never write OS specific code, except in those helper functions.

I agree with the comment of the second post, try tu use such function only to access program resource data. User data should be placed in the user directory, or the working directory set at the start of the program depending on the case

About working in specific directories, i'd also add to never set the current directory in your code then use relative paths. Because you don't know if an other thread of a library in your program won't change the current directory. Or a library using it doesn't know that you use it too in a different thread. Instead, you can save your wanted working directory absolute path in a variable, then just before file access, regenerate an absolute path with the working directory+relative path

Uh... Can't OP just use relative paths?
IDK, but the CWD is not guaranteed to be the same directory as the executable.
Aside

1. To get the actual, localized path of the user's document folder, you can use SHGetFolderPath / SHGetKnownFolderPath / etc. You need to see MSDN for details as this set of function has been replaced and then replaced again. The exact function you need depends on how old a version of Windows you need to support.

Calling SHGetFolderPath with CSIDL_MYDOCUMENTS or SHGetKnownFolderPath with FOLDERID_Documents will return the path to the user's document folder. e.g. "C:\Documents and Settings\Andy\My Documents" on my system, or the language specific alternative.

MSDN lists assorted other CSIDLs / known folders IDs.

2. Once you know where the executable is located, you can use SetCurrentDirectory() to change the current working directory if you want to.
Last edited on
Topic archived. No new replies allowed.