Basically, I was hoping to sort of keep my files sorted instead of having them all in the same folder as my executable, but referencing files in sub folders relative to my executable has proven difficult.
// DEFINES
#define IMAGE_BACKGROUND "\\content\\images\\background.bmp"
#define FONT_MAIN "\\content\\fonts\\sai.ttf"
The above code obviously does not work.
I read supposedly args[0] is somehow my path? Anyone care to elaborate a little more?
int main(int argc, char* args[])
{
I should mention that Boost.Filesystem is a nice library that can help you out.
args[0] is the full path name (well, but that is also decided by the OS and shell, so you may get a short file name which is not full) to your "executable file", not its folder. you must truncate it.
try splitpath and joinpath.
args[0] is the name used to call your executable, which is not necessarily the full path of your executable. You're interested in the working directory of your executable, which is OS-dependent.
In any case, you have to be careful with relative paths. If your user calls your program from a different directory, your working directory may be something unexpected, and you won't properly reference your files.
Since you're in Windows, you can use the GetModuleFileName function (see the documentation) to get the full name of your executable, like so:
GetModuleFileName(NULL, buffer, length);
Have you tryed doing:
#define IMAGE_BACKGROUND "\content\images\background.bmp"
That might be the problem (as i have used images from sub folders like that before)
This code should work:
#define IMAGE_BACKGROUND "\\content\\images\\background.bmp"
int main(int argc, char* args[])
{
char buf[512];
int endOfPath = strrchr(args[0], '\\') - args[0];
strncpy_s(buf, sizeof(buf), args[0], endOfPath);
strcat(buf, IMAGE_BACKGROUND);
Like the other person said, args[0] is the full path of the executeble, so you can't use that as is. The strrchr function (TWO r's in the middle) finds the last occurrence of a given character and returns a pointer to it. Assuming that you are using one-byte characters, subtracting args[0] from the returned pointer will give you the number of characters between the two pointers -- When you subtract two pointers, your actually subtracting the memory addresses, so what you're left with is an offset, or distance between the pointers. This distance is like the index of the character that was found.
I then use the strncpy_s function to copy endOfPath number of characters from args[0] to our temporary buffer. Now, if your program path was
"C:\Windows\Users\Me\Desktop\myProgram\theProgram.exe"
the buf variable will contain
"C:\Windows\Users\Me\Desktop\myProgram"
I then used the strcat (conCATenation) function to append your constant onto the end.
Note that with your #define, the "\\" is REQUIRED in C/C++, and also note that the " marks will be included where ever you use IMAGE_BACKGROUND.
After those lines of code, buf will contain:
"C:\Windows\Users\Me\Desktop\myProgram\content\images\background.bmp"
Hope that helps and is not too confusing...
I actually solved it by using the following code, thank you all for the responses:
// DEFINES
#define IMAGE_BACKGROUND ".\\content\\images\\background.png"
#define IMAGE_BLUEBLOCK ".\\content\\images\\blueblock.png"
#define FONT_MAIN ".\\content\\fonts\\sai.ttf"
Turns out the . gets the "working path directory".
Related
I've looked at a lot of examples for WideCharToMultiByte, etc. This question is more about testing.
I downloaded another language set, Chinese, Simplified China to my machine. Then using the virtual keyboard I created a directory on C:\ with some Chinese characters in the path, and placed a file inside the directory.
I'm trying to see that I get the correct filename by testing _wfopen with my path. I also have the same file in another location for testing:
//setlocale(LC_ALL, "zh-CN");
//setlocale(LC_ALL, "Chinese_China.936");
setlocale(LC_ALL, "");
wchar_t* outfilename = L"C:\\特殊他\\和阿涛和润\\bracket3holes.sat";
//wchar_t* outfilename = L"C:\\heather\\bracket3holes.sat";
wchar_t w[] = L"r";
FILE* foo = _wfopen(outfilename, w);
First I tried without setting locale, then I tried various combinations of setting locale to the language I downloaded (therefore the language of the path).
_wfopen works fine with the C:\heather path, but always returns a NULL pointer with the unicode path.
What am I missing? Any insight would be greatly appreciated. Note my code must be compilable back to vc9.
--- Based on the feedback, I saved the file as UTF-8 with BOM, added const before the wchar_t declarations, and now in the debugger I do see the right string and the file pointer is no longer null.
Thank you for your help. I'm still trying to wrap my head around this all, we're trying to transition from const char* to unicode-friendly.
This question has been asked before, but pretty much all the answers boil down to the realpath function. Which doesn't work for paths that do not exist. I need a solution that will, and I want to call a POSIX or OS X framework function rather than hand-parse strings.
To reiterate: I need a function that takes an arbitrary path string and returns the equivalent path with no "./" or ".." elements.
Is there such a solution?
Are you sure there can be such a solution? I believe that not (because some directories could be typos or symbolic links to be created).
What do you expect your betterrealpath function to return for /tmp/someinexistentdirectory/foobar ? Perhaps the user intent was a symbolic link from his $HOME to /tmp/someinexistentdirectory ? Or perhaps it is a typo and the user wants /tmp/someexistentdirectory/foobar ...? And what about /tmp/someinexistentdirectory/../foobar? Should it be canonicalized as /tmp/foobar? Why?
Maybe using first dirname(3), then doing realpath(3) on that, then appending the basename(3) of the argument should be enough? In C something like:
const char*origpath = something();
char*duppath = strdup(origpath);
if (!duppath) { perror("strdup"); exit(EXIT_FAILURE); };
char*basepath = basename(duppath);
char*dirpath = dirname(duppath);
char*realdirpath = realpath(dirpath, NULL);
if (!realdirpath) { perror("realpath"); exit(EXIT_FAILURE); };
char* canonpath = NULL;
if (asprintf(&canonpath, "%s/%s", realdirpath, basepath) <= 0)
{ perror("asprintf"); exit(EXIT_FAILURE); };
free (duppath), duppath = NULL;
basepath = NULL, dirpath = NULL;
/// use canonpath below, don't forget to free it
Of course that example won't work for /tmp/someinexistentdirectory/foobar but would work for /home/violet/missingfile, assuming your home directory is /home/violet/ and is accessible (readable & executable) ...
Feel free to improve or adapt to C++ the above code. Don't forget to handle failures.
Remember that i-nodes are central to POSIX filesystems. A file (including a directory) can have one, zero, or several file paths... A directory (or a file) name can be rename-d by some other running process...
Perhaps you want to use a framework like Qt or POCO; they might provide something good enough for you...
Actually, I suggest you to code your betterrealpath function entirely yourself, using only syscalls(2) on Linux. You'll then have to think about all the weird cases... Also, use strace(1) on realpath(1) to understand what it is doing...
Alternatively, don't care about non-canonical paths containing ../ or symbol links in directories, and simply prepend the current directory (see getcwd(3)) to any path not starting with / .......
I successfully write to a file in the folder which run example:
// I run "test" executable file in "TestWrite File" folder
const char *path="/home/kingfisher/Desktop/TestWrite File/xml/kingfisher.txt";
std::ofstream file(path); //open in constructor
std::string data("data to write to file");
file << data;
However, If I try to write with dynamic path: *path = "/xml/kingfisher.txt", it goes wrong (in Windows, it will be fine)!! How I can write with dynamic path like above (not a specific path)? Thanks!
If by dynamic you mean relative, you need to get rid of the leading /, since that makes it an absolute path:
path = "xml/kingfisher.txt";
Just be aware that this file is relative to your current working directory so you will probably need to ensure that it is set to /home/kingfisher/Desktop/TestWrite File for this to work.
If, by dynamic, you mean changable, you can change it whenever you want:
const char *path = "/tmp/dummy";
:
path = "/home/.profile"; // Note path, NOT *path
The const simply means you're not permitted to change the data behind the pointer. You're able to change the pointer itself at will.
Not sure what you mean by "dynamic path"; a dynamic path is one that
will be read dynamically (and so will probably be in an std::string).
On the other hand, you seem to be confusing absolute path and relative
path. If the filename begins with a '/' (under Unix), or with a '/'
or a '\\', possibly preceded by "d:" under
Windows, it is absolute; the search for the file will start at the root
of the file system (on the specified drive in the case of Windows). In
all other cases, it is relative; the search for the file will start at
the current working directory. In your example, both
"/home/kingfisher/Desktop/TestWrite File/xml/kingfiger.txt" and
"/xml/kingfisher.txt" are absolute. If the current working directory
is "/home/kingfisher/Desktop/TestWrite File", then
"xml/kingfisher.txt" should find the file specified by the first
absolute pathname.
*path = "/xml/kingfisher.txt"
This is incorrect since it attempts to dereferences your const char* and modify the contents. This is undefined behaviour since the data is const.
Just declare your path to be a std::string to begin with:
std::string path = "/home/kingfisher/Desktop/TestWrite File/xml/kingfisher.txt";
Then later you can assign any other value you like to the std string and it's operator= will dynamically change it's internals for you:
path = "my/new/path";
You can use this with ofstream just as before and if you need to pass it to a function which expects a const char * just pass path.c_str().
I am trying to hard code into C++ program to look for config.ini in the same directory as the executable, without knowing the complete path to the file. I am trying to find a way to make a local reference to the executable.
Basically load ("./config.ini")
without doing
("C:\foo\bar\config.ini")
There isn't really any guaranteed portable way of doing this, but I like to use this code because it works in the vast majority of cases (unless symlinks or other magic is involved):
boost::filesystem::current_path(boost::filesystem::path(argv[0]).remove_filename());
If you are willing to use platform specific code look at GetModuleFileName on Windows and a mix of getpid, reading from /proc and readlink on Linux.
You want GetModuleFilename() on Windows (pass NULL to get filename of current executable). Otherwise, call boost::filesystem::initial_path() early in the program (see Boost docs in link for the reason to do this early). That should cover most of the situations.
Edit
Brain malfunction. We always start our programs from the executable's directory, so the boost::initial_path() thing works, but it won't work so well if you start the program from another direcory. Sorry for the confusion on that. On Windows, though, I'd get the path from GetModuleFilename and use boost::path to manipulate the result.
For windows, this will get the directory containing the excutable as a c++ string:
#include <windows.h>
#include <string>
#include <iostream>
using namespace std;;
string ExePath() {
char buffer[MAX_PATH];
GetModuleFileName( NULL, buffer, MAX_PATH );
string::size_type pos = string( buffer ).find_last_of( "\\/" );
return string( buffer ).substr( 0, pos);
}
You can then just tag the name of your config file on the end.
For Windows:
#include <direct.h>
char cur_path[FILENAME_MAX];
if (!_getcwd(cur_path, sizeof(cur_path)))
{
// deal with error
}
cur_path[sizeof(cur_path) - 1] = '/0'; // adding \0 at the end of the string
printf("Current dir: %s", cur_path);
A platform-agnostic solution was discussed here:
How do I get the directory that a program is running from?
I am programing under C++, MFC, windows.
I want to delete a folder into recycle bin.
How can I do this?
CString filePath = directorytoBeDeletePath;
TCHAR ToBuf[MAX_PATH + 10];
TCHAR FromBuf[MAX_PATH + 10];
ZeroMemory(ToBuf, sizeof(ToBuf));
ZeroMemory(FromBuf, sizeof(FromBuf));
lstrcpy(FromBuf, filePath);
SHFILEOPSTRUCT FileOp;
FileOp.hwnd = NULL
FileOp.wFunc=FO_DELETE;
FileOp.pFrom=FromBuf;
FileOp.pTo = NULL;
FileOp.fFlags=FOF_ALLOWUNDO|FOF_NOCONFIRMATION;
FileOp.hNameMappings=NULL;
bRet=SHFileOperation(&FileOp);
Any thing wrong with the code above?
It always failed.
I found the problem:
filePath should be : "c:\abc" not "c:\abc\"
The return value from SHFileOperation is an int, and should specify the error code. What do you get?
i know it is not the right way but if you cant find a solution you can try this..
download file nircmd.exe or another exe that can empty recycle bin.
then you call these functions by system("nircmd.exe emptybin")
You have found a solution that works, however it's only by accident. The actual problem here is that the pFrom parameter is in a special format. According to the MSDN docs for SHFILEOPTS, it stores a list of file paths, each one null-terminated, and an extra null after the last one.
In your case this happens to work because the FromBuf array is longer than the filename and all the entries are initialised to zero. The more general solution is to create a buffer that is long enough for the filename and then add two nul characters after it. Note that Windows filenames can be longer than _MAX_PATH, eg see https://learn.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#maximum-path-length-limitation