Use relative file path with LoadImage - c++

I am attempting to load a file from a relative file path in win32 via the LoadImage function. The URL I am using definitely exists as I am, for testing purposes, using the same URL as an added bitmap in the resource file.
Image = (HBITMAP)LoadImage(NULL, "..\\..\\Images\\Mage default.bmp",
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
However, it is returning error code 2, indicating the file can't be found. I have googled the issue at some length, and referred to MSDN, and I can't find anything stating how to use a relative file path with LoadImage.
It seems to work fine with LoadBitmap and a pre-defined bitmap, but doesn't seem to work in this case. Any help would be much appreciated

First of all, check that the file exist and current directory is the one you expected.
Also, you can use function like GetFullPathName to convert relative path to absolute.

The relative path you have is computed based on your process/run time working directory and not on your static files location in compile time.

This may be an old post, but having stumbled across this problem (in my case, a header file) and found an answer, here it is:
If referencing a relative path, the first directory is not preceeded by a backslash.
In this example, the line would be:
(HBITMAP)LoadImage(NULL,"Images\\Mage default.bmp",...

Related

Can't open a file in C/C++ using eclipse cdt

I have a medium size program I'm developing using eclipse, I can't show the content because it would be too large. At some point I have some lines of fopen, I'm basically trying to create a new file and printing inside such file a content that has been derived from some processing.
So my line is something like a classic
FILE* f = fopen(filename,"w");
where filename is a char array large enough. However the FILE* returned is 0, and when I check the errno it is number 2, which means that the file doesn't exists.
However that's the point, I was trying to create a new file.
Is there something you could suggest that can I further check?
It's worth to note I'm running this stuff on unix, not windows.
Is the value of filename an absolute path or a relative one? If it's the latter, then probably the process you run hasn't the cwd (current working directory) you think it has.
Try using an absolute path, if that works then
use the chdir system call at the begin of main to set the cwd
Your filename might be incorrectly built, or you have no access to the path, or parts of the path don't exist.
Try a simple and clearly legal path first, like C:\\Temp\\x.x or something similar. if this works, it is not your code, but the filename.

What is the default or starting directory for a VS solution?

My Scenario:
I want to use an image file, "ship.png", in a project I am working on in Visual Studio 2013.
Every path I use returns NULL, so I am confused on where to start my path string. I am trying to load it into an object of type GDI+ class 'Image' by using "FromFile()".
// image is defined previously and is a Image*.
image = Image::FromFile(L"ship.png");
// When I debug, image is still NULL like it is when it is initialized.
My Question:
What directory does the program begin in? I would assume the exe file, but I tried using a path curtailed to that scenario and it still returned NULL.
I have also tried putting the image file directly into the directory where the solution file resides and the one where the exe file resides with the path "ship.png" and in both cases it is still NULL.
Any ideas? If you are experienced in GDI+ and have never heard of this, then I am probably doing something wrong with it, as it has a very confusing and convoluted (in my opinion) API.
Solution for Specified Problem Found:
I needed to insert the following code before the action:
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
And this code after:
GdiplusShutdown(gdiplusToken);
Now image is no longer null.
Thanks for reading.
Default place where VS would look for that file is directory with your source files (*.cpp files)

How to use fstream objects with relative path?

Do I always have to specify absolute path for objects instantiated from std::fstream class? In other words, is there a way to specify just relative path to them such as project path?
You can use relative paths as well. But they are relative to the environment you call your executable from.
This is OS dependent but all the major systems behave more or less the same AFAIK.
Windows example:
// File structure:
c:\folder\myprogram.exe
c:\myfile.txt
// Calling command from folder
c:\folder > myprogram.exe
In the above example you could access myfile.txt with "c:/myfile.txt" or "../myfile.txt". If myprogram.exe was called from the root c:\ only the absolute path would work, but instead "myfile.txt" would work.
As Rob Kennedy said in the comments there's really nothing special about paths regarding fstream. But here is a code example using a relative path:
#include <fstream>
int main() {
std::ifstream ifs("../myfile.txt");
... // Do something sensible with the file
}
If you have an .exe file running from C:\Users\Me
and you want to write a file to C:\Users\Me\You\text.txt,
then all what you need to do is to add the current path operator ., so:
std::ifstream ifs(".\\you\\myfile.txt");
will work
You can use relative paths. They're treated the same as relative paths for any other file operations, like fopen; there's nothing special about fstream in that regard.
Exactly how they're treated is implementation-defined; they'll usually be interpretted relative to your process's current working directory, which is not necessarily the same as the directory your program's executable file lives in. Some operating systems might also provide a single working directory shared by all threads, so you might get unexpected results if a thread changes the working directory at the same time another thread tries to use a relative path.
Say you have a src folder directly under your project directory and the src folder contains another tmp_folder folder which contains a txt file named readMe.txt. So the txt file can be read in this way
std::ifstream fin("../src/tmp_folder/readMe.txt");
The behaviour is OS specific. Therefore, the best way to handle this IMHO is to make it somebody else's problem. Read the path to the file to open as a string from the user (e.g: command line argument, config file, env variable etc..) then pass that string directly to the constructor of fstream. Document that this is how your program behaves.
I wrote more about path manipulation here: https://stackoverflow.com/a/40980510/2345997
You can specify a path relative to current directory. On Windows you may call GetCurrentDirectory to retrieve current directory or call SetCurrentDirectory to set current directory. There are also some CRT functions available.
On linux also:
// main.cpp
int main() {
ifstream myFile("../Folder/readme.txt");
// ...
}
Assuming the folder structure is something like this:
/usr/Douments/dev/MyProject/main.cpp
/usr/Documents/dev/MyProject/Folder/readme.txt
What I ended up using was a relative path as identified on How to open a file with relative path in C++? which ended up being:
myFile.open("../Release/frequency.dat", ios::in);
*changing myFile to whatever your variable is.

Efficiently List All Sub-Directories in a Directory

Please see edit with advice taken so far...
I am attempting to list all the directories(folders) in a given directory using WinAPI & C++.
Right now my algorithm is slow & inefficient:
- Use FindFirstFileEx() to open the folder I am searching
- I then look at every file in the directory(using FindNextFile()); if its a directory file then I store its absolute path in a vector, if its just a file I do nothing.
This seems extremely inefficient because I am looking at every file in the directory.
Is there a WinAPI function that I can use that will tell me all the sub-directories in a given directory?
Do you know of an algorithm I could use to efficiently locate & identify folders in a directory(folder)?
EDIT:
So after taking the advice I have searched using FindExSearchLimitToDirectories but for me it still prints out all the files(.txt, etc.) & not just folders. Am I doing something wrong?
WIN32_FIND_DATA dirData;
HANDLE dir = FindFirstFileEx( "c:/users/soribo/desktop\\*", FindExInfoStandard, &dirData,
FindExSearchLimitToDirectories, NULL, 0 );
while ( FindNextFile( dir, &dirData ) != 0 )
{
printf( "FileName: %s\n", dirData.cFileName );
}
In order to see a performance boost there must be support at the file system level. If this does not exist then the system must enumerate every single object in the directory.
In principle, you can use FindFirstFileEx specifying the FindExSearchLimitToDirectories flag. However, the documentation states (emphasis mine):
This is an advisory flag. If the file system supports directory filtering, the function searches for a file that matches the specified name and is also a directory. If the file system does not support directory filtering, this flag is silently ignored.
If directory filtering is desired, this flag can be used on all file systems, but because it is an advisory flag and only affects file systems that support it, the application must examine the file attribute data stored in the lpFindFileData parameter of the FindFirstFileEx function to determine whether the function has returned a handle to a directory.
However, from what I can tell, and information is sparse, FindExSearchLimitToDirectories flag is not widely supported on desktop file systems.
Your best bet is to use FindFirstFileEx with FindExSearchLimitToDirectories. You must still perform your own filtering in case you meet a file system that doesn't support directory filtering at file system level. If you get lucky and hit upon a file system that does support it then you will get the performance benefit.
If you're using FindFirstFileEx, then you should be able to specify the _FINDEX_SEARCH_OPS::FindExSearchLimitToDirectories option (to be used as the fSearchOp param in FindFirstFileEx) to limit the first search (and any subsequent FindNextFile()) calls to directories.

GetModuleFileName returns path in 8.3 format

I call this function to get path to exe. GetModuleFileName(NULL, ...
The problem is that sometimes it returns the short path (8.3) instead of a normal long path.
MSDN specifies that
The string returned will use the same format that was specified when the module was loaded. Therefore, the path can be a long or short file name, and can use the prefix "\\?\".
How can I avoid this behavior and force Api to return full path ?
You cannot avoid it - if the dll is loaded with a short name, that's what you get.
Use GetLongPathName to convert if needed.
You cannot. Use GetFullPathName to get the full path.
See also the Remarks section in the page you linked to:
The global variable _pgmptr is automatically initialized to the full path of the executable file, and can be used to retrieve the full path name of an executable file.