How to refer to current user folder in c++? [duplicate] - c++

As you all know, the appdata folder is this
C:\Users\*Username*\AppData\Roaming
on windows 7
Since my application will be deployed on all kinds of Windows OSes i need to be able to get the folder 100% percent of the time.
The question is how do you do it in C++? Since i don't know the the exact Windows OS it could be XP,Vista or 7 and most importantly i don't know what the Username is.

For maximum compatibility with all versions of Windows, you can use the SHGetFolderPath function.
It requires that you specify the CSIDL value for the folder whose path you want to retrieve. For the application data folder, that would be CSIDL_APPDATA.
On Windows Vista and later, you should use the SHGetKnownFolderPath function instead, which requires that you specify the folder's KNOWNFOLDERID value. Again, for the application data folder, the appropriate value is FOLDERID_RoamingAppData.
To use either of these functions from your C++ application, you'll need to include shlobj.h.

You can try the following:
char* appdata = getenv("APPDATA");
This code reads the environment variable APPDATA (you can also see it when you type SET in a command window). It is set by Windows when your system starts.
It will return the path of the user's appdata as an absolute path, including Username and taking into account whichever OS version they're using.

Perhaps fellow Googlers might find it interesting to have a look at std::filesystem. For instance, let's assume the default temp directory location and AppData directory structure in Windows 10:
#include <filesystem>
auto path = std::filesystem::temp_directory_path()
.parent_path()
.parent_path();
path /= "Roaming";
if (!std::filesystem::exists(path))
std::filesystem::create_directories(path);
In the case of OP, I am assuming this doesn't solve the problem. I do want to raise a word of caution against doing the above in a situation that requires a 100% robust implementation, as system configurations can easily change and break the above.
But perhaps new visitors to the question might find std::filesystem useful. Chances are, you're going to want to manipulate the items in the directory if you're looking for it, and for this, std::filesystem can be your friend.

If someone is looking for a simple implementation, here's mine:
#include <windows.h>
#include <shlobj.h>
#include <filesystem>
#include <iostream>
int main(void)
{
std::filesystem::path path;
PWSTR path_tmp;
/* Attempt to get user's AppData folder
*
* Microsoft Docs:
* https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
* https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
*/
auto get_folder_path_ret = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path_tmp);
/* Error check */
if (get_folder_path_ret != S_OK) {
CoTaskMemFree(path_tmp);
return 1;
}
/* Convert the Windows path type to a C++ path */
path = path_tmp;
/* Free memory :) */
CoTaskMemFree(path_tmp);
std::cout << path << std::endl;
return 0;
}

Use this Code to reads the environment variable "APPDATA"
Include stdio.h file in beginning
char *pValue;
size_t len;
errno_t err = _dupenv_s(&pValue, &len, "APPDATA");

Here is a simple implementation for old C++ versions :
#include <shlobj.h>
// ...
wchar_t* localAppDataFolder;
if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) {
std::cerr << "problem getting appdata folder" << std::endl;
}
else std::wcout << L"folder found: " << localAppDataFolder << std::endl;

Related

create custom filepath in C++

I need to create a fixed path for the System Drive or C: for most Windows devices. I Need to set C: as the fixed path and build off of it with added directories. So far my code works but wondering if there is a better way. I set it as a string. I know about SHGetKnownFolderPath and FOLDERID but haven't found one for just SYSTEM DRIVE. I am using C++ 17 and visual studio for this. This is for Windows only devices.
std::string dir = "C:\\";
fs::create_directory(dir + "_icons");
fs::permissions(dir, fs::perms::all);
With std::filesystem, you could start from a C:\ path and query its root_directory().
[Demo]
#include <filesystem>
namespace fs = std::filesystem;
int main() {
const fs::path c{ "C:\\" };
auto icons_dir_path{ c.root_directory() / "_icons" };
if (fs::create_directory(icons_dir_path)) {
fs::permissions(icons_dir_path, fs::perms::all);
}
}
Alternatively, you could follow #CaptainObvlious suggestion and:
Get the Windows folder installation via SHGetKnownFolderPath with FOLDERID_Windows as KNOWNFOLDERID.
Extract the drive from the path it returns (for example, via PathGetDriveNumber).
Then, let's say you got the drive in a windows_drive string, you could whether:
set std::string dir = windows_drive + ":\\"; in the code you posted, or
set const fs::path windows_drive_path{ windows_drive + ":\\" }; in my example above.
This should be a more robust solution as it would work no matter the drive where Windows is installed.

The equivelant code %SystemDrive% in batch translated into C++

To anyone that can help Please,
(My operating system is Windows XP)
I have looked on the this forum but have not found a similair answer that I could use or adapt to suite this particular situation. I will try to explain (I apologise in advance if my question seems confusing)
I am constructing a batch file that will call a C++ program (.exe) The C++ program is hard coded to the C: drive. By the way I did not write the C++ program as I am incapable of writing in C++ but would like to exchange the C: in C++ for what would be in batch %SystemDrive%. The line of code in C++ reads as follows:
SetSfcFileException(0, L"c:\\windows\\system32\\calc.exe",-1);
// Now we can modify the system file in a complete stealth.
}
The bit of code I would like to alter in the above code is C: or "C" to change it to %systemDrive% but in C++ code language, in effect change the hard coded part of the C++ program to read a System path variable within XP.
I have also looked elsewhere on the net but have not found a suitable answer as I do Not want to break the C++ code you see.
The C++ code was obtained from the folowing website written by Abdellatif_El_Khlifi:
https://www.codeproject.com/Articles/14933/A-simple-way-to-hack-Windows-File-Protection-WFP-u
Many Thanks for any help given,
David
The search term you should be looking for is Known Folders.
Specifically, calling SHGetKnownFolderPath() with the FOLDERID_System identifier, one of the many IDs found here.
That's for Vista or better. For earlier than that (such as XP), you have to use CSIDL values, CSIDL_SYSTEM (see here for list) passed into SHGetFolderPath().
You can still use the pre-Vista ones but I think they're just thin wrappers around the newer ones.
This is the simplest console application I could come up with that shows this in action (Visual Studio 2019):
#include <iostream>
#include <shlobj_core.h>
#include <comutil.h>
int main()
{
PWSTR path = NULL;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_System, 0, NULL, &path);
_bstr_t bstrPath(path);
std::string strPath((char*)bstrPath);
std::cout << "Path is '" << strPath << "'\n";
}
and the output on my system is:
Path is 'C:\WINDOWS\system32'
This is not really answering my own question, well it is but in a alternative manner, many ways to skin a cat so to speak!
Here is one encouraging bit of news though I have stumbled across the very thing I need called WFPReplacer, it is a commandline windows utility that pretty well does what I want & generally in the same manner. it disables WFP for both singular files & can be used for wholesale switching off of WFP if the right file is replaced. All I need to do is write a batch file as a front end to back up the system files I want to disable use WFPReplacer.exe. So if in the event of the proceedings the routine gets stuffed I can revert back to the backed up files. I think this program uses the same type of embedded coding but is written in Delphi/pascal, it is called Remko Weijnen's Blog (Remko's Blog) "replacing Wfp protected files".
I generally like to leave whatever I am doing on a positive note. So just in case someone else lands on this forum & is trying to accomplish a similair exercise here is the code that one can compile (This is not my code it belongs to Remko Weijnen's Blog (Remko's Blog)) Please be advised it is NOT C++ it is a commandline exe Delhi/Pascal found at this link, so all credits belong to him. The link is:
https://www.remkoweijnen.nl/blog/2012/12/05/replacing-wfp-protected-files/
DWORD __stdcall SfcFileException(RPC_BINDING_HANDLE hServer, LPCWSTR lpSrc, int Unknown)
{
RPC_BINDING_HANDLE hServerVar; // eax#2
int nts; // eax#6
__int32 dwResult; // eax#7
DWORD dwResultVar; // esi#9
int v8; // [sp+8h] [bp-8h]#1
int v9; // [sp+Ch] [bp-4h]#1
LOWORD(v8) = 0;
*(int *)((char *)&v8 + 2) = 0;
HIWORD(v9) = 0;
if ( !hServer )
{
hServerVar = _pRpcHandle;
if ( !_pRpcHandle )
{
hServerVar = SfcConnectToServer(0);
_pRpcHandle = hServerVar;
if ( !hServerVar )
return 0x6BA; // RPC_S_SERVER_UNAVAILABLE
}
hServer = hServerVar;
}
nts = SfcRedirectPath(lpSrc, (int)&v8);
if ( nts >= 0 )
dwResult = SfcCli_FileException((int)hServer, v9, Unknown).Simple;
else
dwResult = RtlNtStatusToDosError(nts);
dwResultVar = dwResult;
MemFree(v9);
return dwResultVar;
}
Also as one further warning (Unless you know what you are doing!!!) do not attempt to use this program, ALWAYS ALWAYS ALWAYS backup your system files before deletion or alteration.
What this program will do is disarm WFP for 60 seconds whilst you intercange or amend your files. Example usage for example is:
WfpReplacer.exe c:\windows\Notepad.exe (Errorlevel true or false will be produced on execution).
Best Regards
David

boost::filesystem::relative() cannot access the file because it is being used by another process

When accessing some network drives, the functions relative(path, base_path) and canonical(path, base_path) throw an exception. The message is always:
The process cannot access the file because it is being used by another process
I've observed this behavior only on some shared network drives that were operated by our IT department and contain symbolic links. I was not able to provoke the same issue on local drives or on shared drives from an adjacent computer. Our suspicion is that the archive/backup solution used on the network drives is also a driver here. The known factors are these so far:
The drive must be a network share (drive etc.)
The path needs to contain a symbolic link component
The drive operates under a backup/archive solution
My questions are:
is this a potential bug in boost::filesystem?
are there any potential boost::filesystem tricks that I've missed that would solve the issue?
One possible workaround would be to re-implement the relative() function to use only path manipulation and does not access the filesystem. But I'd like to avoid the re-implementation.
An small sample program that may exhibit the problem if the tested path has the issue:
#include <vector>
#include <string>
#include <tuple>
#include <boost/filesystem.hpp>
#include <boost/system/error_code.hpp>
using namespace std;
using namespace boost::filesystem;
using boost::system::error_code;
int main()
{
vector<string> testpaths = {
"< path to a directory which is to test >",
};
for(auto & line : testpaths)
{
if(line.empty()) continue; // skip empty lines
cout << " path: " << line << " ";
path testpath(line.c_str());
// simplified testing, use parent of parent
path basepath = testpath.parent_path().parent_path();
boost::system::error_code ec;
path relpath = relative(testpath, basepath, ec);
if(ec) cout << " ---> error: " << ec.message();
else cout << " ok, relative: " << relpath.string();
cout << endl;
}
}
I had the same problem where the path only contains a directory using boost 1.65.1:
unexpected exception: boost::filesystem::weakly_canonical: The process cannot access the file because it is being used by another process;
This also only happens on a network drive when the path contains a symbolic link.
It seems that this is a synchronization problem. Obviously using boost:filesystem the same symbolic link can not be accessed in parallel.
I defined a custom function that encapsulates and synchronizes the access to weakly_canonical:
static boost::recursive_mutex sgCanonicalMutex;
boost::filesystem::path CanonicalPath(const boost::filesystem::path inPath)
{
boost::recursive_mutex::scoped_lock lk(sgCanonicalMutex);
return boost::filesystem::weakly_canonical(inPath);
}
After that change the problem did not occur anymore.
There also is a note about the underlying system error code ERROR_SHARING_VIOLATION in the documentation of boost::filesystem::status. See https://www.boost.org/doc/libs/1_70_0/libs/filesystem/doc/reference.html
I think that the root cause is in the boost sources:
boost\libs\filesystem\src\operations.cpp
The function read_symlink contains
handle_wrapper h(
create_file_handle(p.c_str(), GENERIC_READ, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0));
The third parameter (value 0) is the dwShareMode passed to CreateFileW (see https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilew).
This parameter possibly should be FILE_SHARE_READ. This is still left unchanged in the latest boost 1.70.
I was hitting this problem in a multi-process situation, so the lock solution by #RED SOFT ADAIR would not help. Until the Boost fix is released, I implemented this:
auto full_path = boost::filesystem::path(path_str).lexically_normal();
MY_ASSERT(boost::filesystem::exists(full_path), "Path normalization of '%s' resulted in non-existing path '%s'",
path_str.c_str(), full_path.string().c_str());
This worked out fine through the tests I created to expose this problem. lexically_normal operates on the path string, so it does not care about existence of the path. But it's prone to misinterpretations, when links are involved inside the path.
As of Aug./Sept. 2020 this issue also appeared for RStdio 1.2.5033 and 1.3.1073 - created an issue with RStudio dev on gihtub.
They expect their next boost update to fix this bug (again).
Putting this here although it is an RStudio topic - in case someone runs into this from the RStudio side.

How to open a folder in %appdata% with C++?

As you all know, the appdata folder is this
C:\Users\*Username*\AppData\Roaming
on windows 7
Since my application will be deployed on all kinds of Windows OSes i need to be able to get the folder 100% percent of the time.
The question is how do you do it in C++? Since i don't know the the exact Windows OS it could be XP,Vista or 7 and most importantly i don't know what the Username is.
For maximum compatibility with all versions of Windows, you can use the SHGetFolderPath function.
It requires that you specify the CSIDL value for the folder whose path you want to retrieve. For the application data folder, that would be CSIDL_APPDATA.
On Windows Vista and later, you should use the SHGetKnownFolderPath function instead, which requires that you specify the folder's KNOWNFOLDERID value. Again, for the application data folder, the appropriate value is FOLDERID_RoamingAppData.
To use either of these functions from your C++ application, you'll need to include shlobj.h.
You can try the following:
char* appdata = getenv("APPDATA");
This code reads the environment variable APPDATA (you can also see it when you type SET in a command window). It is set by Windows when your system starts.
It will return the path of the user's appdata as an absolute path, including Username and taking into account whichever OS version they're using.
Perhaps fellow Googlers might find it interesting to have a look at std::filesystem. For instance, let's assume the default temp directory location and AppData directory structure in Windows 10:
#include <filesystem>
auto path = std::filesystem::temp_directory_path()
.parent_path()
.parent_path();
path /= "Roaming";
if (!std::filesystem::exists(path))
std::filesystem::create_directories(path);
In the case of OP, I am assuming this doesn't solve the problem. I do want to raise a word of caution against doing the above in a situation that requires a 100% robust implementation, as system configurations can easily change and break the above.
But perhaps new visitors to the question might find std::filesystem useful. Chances are, you're going to want to manipulate the items in the directory if you're looking for it, and for this, std::filesystem can be your friend.
If someone is looking for a simple implementation, here's mine:
#include <windows.h>
#include <shlobj.h>
#include <filesystem>
#include <iostream>
int main(void)
{
std::filesystem::path path;
PWSTR path_tmp;
/* Attempt to get user's AppData folder
*
* Microsoft Docs:
* https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
* https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
*/
auto get_folder_path_ret = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path_tmp);
/* Error check */
if (get_folder_path_ret != S_OK) {
CoTaskMemFree(path_tmp);
return 1;
}
/* Convert the Windows path type to a C++ path */
path = path_tmp;
/* Free memory :) */
CoTaskMemFree(path_tmp);
std::cout << path << std::endl;
return 0;
}
Use this Code to reads the environment variable "APPDATA"
Include stdio.h file in beginning
char *pValue;
size_t len;
errno_t err = _dupenv_s(&pValue, &len, "APPDATA");
Here is a simple implementation for old C++ versions :
#include <shlobj.h>
// ...
wchar_t* localAppDataFolder;
if (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &localAppDataFolder) != S_OK) {
std::cerr << "problem getting appdata folder" << std::endl;
}
else std::wcout << L"folder found: " << localAppDataFolder << std::endl;

How do I get the directory that a program is running from?

Is there a platform-agnostic and filesystem-agnostic method to obtain the full path of the directory from where a program is running using C/C++? Not to be confused with the current working directory. (Please don't suggest libraries unless they're standard ones like clib or STL.)
(If there's no platform/filesystem-agnostic method, suggestions that work in Windows and Linux for specific filesystems are welcome too.)
Here's code to get the full path to the executing app:
Variable declarations:
char pBuf[256];
size_t len = sizeof(pBuf);
Windows:
int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;
Linux:
int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
pBuf[bytes] = '\0';
return bytes;
If you fetch the current directory when your program first starts, then you effectively have the directory your program was started from. Store the value in a variable and refer to it later in your program. This is distinct from the directory that holds the current executable program file. It isn't necessarily the same directory; if someone runs the program from a command prompt, then the program is being run from the command prompt's current working directory even though the program file lives elsewhere.
getcwd is a POSIX function and supported out of the box by all POSIX compliant platforms. You would not have to do anything special (apart from incliding the right headers unistd.h on Unix and direct.h on windows).
Since you are creating a C program it will link with the default c run time library which is linked to by ALL processes in the system (specially crafted exceptions avoided) and it will include this function by default. The CRT is never considered an external library because that provides the basic standard compliant interface to the OS.
On windows getcwd function has been deprecated in favour of _getcwd. I think you could use it in this fashion.
#include <stdio.h> /* defines FILENAME_MAX */
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
char cCurrentPath[FILENAME_MAX];
if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
{
return errno;
}
cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
This is from the cplusplus forum
On windows:
#include <string>
#include <windows.h>
std::string getexepath()
{
char result[ MAX_PATH ];
return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}
On Linux:
#include <string>
#include <limits.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
return std::string( result, (count > 0) ? count : 0 );
}
On HP-UX:
#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
struct pst_status ps;
if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
return std::string();
if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
return std::string();
return std::string( result );
}
If you want a standard way without libraries: No. The whole concept of a directory is not included in the standard.
If you agree that some (portable) dependency on a near-standard lib is okay: Use Boost's filesystem library and ask for the initial_path().
IMHO that's as close as you can get, with good karma (Boost is a well-established high quality set of libraries)
I know it is very late at the day to throw an answer at this one but I found that none of the answers were as useful to me as my own solution. A very simple way to get the path from your CWD to your bin folder is like this:
int main(int argc, char* argv[])
{
std::string argv_str(argv[0]);
std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}
You can now just use this as a base for your relative path. So for example I have this directory structure:
main
----> test
----> src
----> bin
and I want to compile my source code to bin and write a log to test I can just add this line to my code.
std::string pathToWrite = base + "/../test/test.log";
I have tried this approach on Linux using full path, alias etc. and it works just fine.
NOTE:
If you are on windows you should use a '\' as the file separator not '/'. You will have to escape this too for example:
std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));
I think this should work but haven't tested, so comment would be appreciated if it works or a fix if not.
Filesystem TS is now a standard ( and supported by gcc 5.3+ and clang 3.9+ ), so you can use current_path() function from it:
std::string path = std::experimental::filesystem::current_path();
In gcc (5.3+) to include Filesystem you need to use:
#include <experimental/filesystem>
and link your code with -lstdc++fs flag.
If you want to use Filesystem with Microsoft Visual Studio, then read this.
No, there's no standard way. I believe that the C/C++ standards don't even consider the existence of directories (or other file system organizations).
On Windows the GetModuleFileName() will return the full path to the executable file of the current process when the hModule parameter is set to NULL. I can't help with Linux.
Also you should clarify whether you want the current directory or the directory that the program image/executable resides. As it stands your question is a little ambiguous on this point.
On Windows the simplest way is to use the _get_pgmptr function in stdlib.h to get a pointer to a string which represents the absolute path to the executable, including the executables name.
char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
Maybe concatenate the current working directory with argv[0]? I'm not sure if that would work in Windows but it works in linux.
For example:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
char the_path[256];
getcwd(the_path, 255);
strcat(the_path, "/");
strcat(the_path, argv[0]);
printf("%s\n", the_path);
return 0;
}
When run, it outputs:
jeremy#jeremy-desktop:~/Desktop$ ./test
/home/jeremy/Desktop/./test
For Win32 GetCurrentDirectory should do the trick.
You can not use argv[0] for that purpose, usually it does contain full path to the executable, but not nessesarily - process could be created with arbitrary value in the field.
Also mind you, the current directory and the directory with the executable are two different things, so getcwd() won't help you either.
On Windows use GetModuleFileName(), on Linux read /dev/proc/procID/.. files.
Just my two cents, but doesn't the following code portably work in C++17?
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main(int argc, char* argv[])
{
std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}
Seems to work for me on Linux at least.
Based on the previous idea, I now have:
std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");
With implementation:
fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
static auto exe_parent_path = fs::path(exe_path).parent_path();
return exe_parent_path / filename;
}
And initialization trick in main():
(void) prepend_exe_path("", argv[0]);
Thanks #Sam Redway for the argv[0] idea. And of course, I understand that C++17 was not around for many years when the OP asked the question.
Just to belatedly pile on here,...
there is no standard solution, because the languages are agnostic of underlying file systems, so as others have said, the concept of a directory based file system is outside the scope of the c / c++ languages.
on top of that, you want not the current working directory, but the directory the program is running in, which must take into account how the program got to where it is - ie was it spawned as a new process via a fork, etc. To get the directory a program is running in, as the solutions have demonstrated, requires that you get that information from the process control structures of the operating system in question, which is the only authority on this question. Thus, by definition, its an OS specific solution.
#include <windows.h>
using namespace std;
// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
const unsigned long maxDir = 260;
char currentDir[maxDir];
GetCurrentDirectory(maxDir, currentDir);
return string(currentDir);
}
For Windows system at console you can use system(dir) command. And console gives you information about directory and etc. Read about the dir command at cmd. But for Unix-like systems, I don't know... If this command is run, read bash command. ls does not display directory...
Example:
int main()
{
system("dir");
system("pause"); //this wait for Enter-key-press;
return 0;
}
Works with starting from C++11, using experimental filesystem, and C++14-C++17 as well using official filesystem.
application.h:
#pragma once
//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>
namespace std {
namespace filesystem = experimental::filesystem;
}
#endif
std::filesystem::path getexepath();
application.cpp:
#include "application.h"
#ifdef _WIN32
#include <windows.h> //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h> //readlink
#endif
std::filesystem::path getexepath()
{
#ifdef _WIN32
wchar_t path[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, path, MAX_PATH);
return path;
#else
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
#endif
}
For relative paths, here's what I did. I am aware of the age of this question, I simply want to contribute a simpler answer that works in the majority of cases:
Say you have a path like this:
"path/to/file/folder"
For some reason, Linux-built executables made in eclipse work fine with this. However, windows gets very confused if given a path like this to work with!
As stated above there are several ways to get the current path to the executable, but the easiest way I find works a charm in the majority of cases is appending this to the FRONT of your path:
"./path/to/file/folder"
Just adding "./" should get you sorted! :) Then you can start loading from whatever directory you wish, so long as it is with the executable itself.
EDIT: This won't work if you try to launch the executable from code::blocks if that's the development environment being used, as for some reason, code::blocks doesn't load stuff right... :D
EDIT2: Some new things I have found is that if you specify a static path like this one in your code (Assuming Example.data is something you need to load):
"resources/Example.data"
If you then launch your app from the actual directory (or in Windows, you make a shortcut, and set the working dir to your app dir) then it will work like that.
Keep this in mind when debugging issues related to missing resource/file paths. (Especially in IDEs that set the wrong working dir when launching a build exe from the IDE)
A library solution (although I know this was not asked for).
If you happen to use Qt:
QCoreApplication::applicationDirPath()
Path to the current .exe
#include <Windows.h>
std::wstring getexepathW()
{
wchar_t result[MAX_PATH];
return std::wstring(result, GetModuleFileNameW(NULL, result, MAX_PATH));
}
std::wcout << getexepathW() << std::endl;
// -------- OR --------
std::string getexepathA()
{
char result[MAX_PATH];
return std::string(result, GetModuleFileNameA(NULL, result, MAX_PATH));
}
std::cout << getexepathA() << std::endl;
This question was asked 15 years ago, so the existing answers are now incorrect. If you're using C++17 or greater, the solution is very straightforward today:
#include <filesystem>
std::cout << std::filesystem::current_path();
See cppreference.com for more information.
On POSIX platforms, you can use getcwd().
On Windows, you may use _getcwd(), as use of getcwd() has been deprecated.
For standard libraries, if Boost were standard enough for you, I would have suggested Boost::filesystem, but they seem to have removed path normalization from the proposal. You may have to wait until TR2 becomes readily available for a fully standard solution.
Boost Filesystem's initial_path() behaves like POSIX's getcwd(), and neither does what you want by itself, but appending argv[0] to either of them should do it.
You may note that the result is not always pretty--you may get things like /foo/bar/../../baz/a.out or /foo/bar//baz/a.out, but I believe that it always results in a valid path which names the executable (note that consecutive slashes in a path are collapsed to one).
I previously wrote a solution using envp (the third argument to main() which worked on Linux but didn't seem workable on Windows, so I'm essentially recommending the same solution as someone else did previously, but with the additional explanation of why it is actually correct even if the results are not pretty.
As Minok mentioned, there is no such functionality specified ini C standard or C++ standard. This is considered to be purely OS-specific feature and it is specified in POSIX standard, for example.
Thorsten79 has given good suggestion, it is Boost.Filesystem library. However, it may be inconvenient in case you don't want to have any link-time dependencies in binary form for your program.
A good alternative I would recommend is collection of 100% headers-only STLSoft C++ Libraries Matthew Wilson (author of must-read books about C++). There is portable facade PlatformSTL gives access to system-specific API: WinSTL for Windows and UnixSTL on Unix, so it is portable solution. All the system-specific elements are specified with use of traits and policies, so it is extensible framework. There is filesystem library provided, of course.
The linux bash command
which progname will report a path to program.
Even if one could issue the which command from within your program and direct the output to a tmp file and the program
subsequently reads that tmp file, it will not tell you if that program is the one executing. It only tells you where a program having that name is located.
What is required is to obtain your process id number, and to parse out the path to the name
In my program I want to know if the program was
executed from the user's bin directory or from another in the path
or from /usr/bin. /usr/bin would contain the supported version.
My feeling is that in Linux there is the one solution that is portable.
Use realpath() in stdlib.h like this:
char *working_dir_path = realpath(".", NULL);
The following worked well for me on macOS 10.15.7
brew install boost
main.cpp
#include <iostream>
#include <boost/filesystem.hpp>
int main(int argc, char* argv[]){
boost::filesystem::path p{argv[0]};
p = absolute(p).parent_path();
std::cout << p << std::endl;
return 0;
}
Compiling
g++ -Wall -std=c++11 -l boost_filesystem main.cpp