Related
If I do
LoadLibrary("MyTest.dll")
Windows will locate and load it from "C:\TestFolder\Test\MyTest.dll", because "C:\TestFolder\Test\" is in %PATH% folder.
How can I emulate same function? I need to locate C:\TestFolder\Test\MyTest.dll (C:\TestFolder\Test\ is in %PATH%) by passing MyTest.dll as an argument to a function. Is there such an API? or a function?
P.S. I can't do LoadLibrary and then GetModuleHandle and finding Path, sometimes this DLL could be malicious DLL and I can't load it. So I need to find PATH without having to load it.
To load the DLL without running any malicious code inside, use LoadLibraryEx with the DONT_RESOLVE_DLL_REFERENCES and LOAD_LIBRARY_AS_DATAFILE flags.
Then you can use GetModuleFileName.
You should also read about all the other flags, which allow you to perform all the various searches Windows is capable of.
The accepted answer to this question will not work in all scenarios. More specifically, using GetModuleFileName together with LOAD_LIBRARY_AS_DATAFILE will only work if the library was already loaded prior without this flag. For example, it will work for a library like KERNEL32.DLL which is already loaded by the process, but it will not work with your own library being loaded into the process for the first time.
This is because, to quote The Old New Thing, a library loaded via LOAD_LIBRARY_AS_DATAFILE (or similar flags) doesn't get to play in any reindeer module games.
If you load a library with the LOAD_LIBRARY_AS_DATAFILE flag, then it
isn’t really loaded in any normal sense. In fact, it’s kept completely
off the books. If you load a library with the
LOAD_LIBRARY_AS_DATAFILE, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE, or
LOAD_LIBRARY_AS_IMAGE_RESOURCE flag (or any similar flag added in the
future), then the library gets mapped into the process address space,
but it is not a true module. Functions like GetModuleHandle,
GetModuleFileName, EnumProcessModules and
CreateToolhelp32Snapshot will not see the library, because it was
never entered into the database of loaded modules.
At that point, you might as well just use GetModuleHandle, since it'll only work with previously loaded libraries. Obviously not ideal, and doesn't actually answer the question of getting the path without executing DllMain.
What about the other flag, DONT_RESOLVE_DLL_REFERENCES? Well, technically yes it will work. However, you'll notice in the Microsoft documentation the following note.
Do not use this value; it is provided only for backward compatibility.
If you are planning to access only data or resources in the DLL, use
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE or LOAD_LIBRARY_AS_IMAGE_RESOURCE
or both.
The flag is only provided for backwards compatibility, and that is for good reason. To quote The Old New Thing a second time, DONT_RESOLVE_DLL_REFERENCES is a time bomb.
It is common for somebody to call GetModuleHandle to see if a DLL is
loaded, and if so, use GetProcAddress to get a procedure address and
call it. If the DLL had been loaded with DONT_RESOLVE_DLL_REFERENCES,
both the GetModuleHandle will succeed, but the resulting function will
crash when called. The code doing this has no idea that the DLL was
loaded with DONT_RESOLVE_DLL_REFERENCES; it has no way of protecting
itself.
Other threads will see the library is loaded. If they attempt to use the loaded library, as would be entirely normal to do, they will crash the program because it has not actually been initialized. So this flag, while it does work with GetModuleFileName, will cause instability in the program. Still not ideal.
So then, if we can't use DONT_RESOLVE_DLL_REFERENCES or LOAD_LIBRARY_AS_DATAFILE with GetModuleFileName, then what is the solution? Well, the solution is to not use GetModuleFileName - and instead use GetMappedFileName.
At this point, if you know what GetMappedFileName does, you may be confused. Normally, GetMappedFileName is used to get a filename from a File Mapping, created with the File Mapping API. Well, the secret is that under the hood, image loading is accomplished with MapViewOfFile. This is subtly hinted at by the Dbghelp documentation - for example, the ImageNtHeader documentation which states an image base must be...
The base address of an image that is mapped into memory by a call to
the MapViewOfFile function.
This means that not only is a module handle a pointer to a module, but also a mapped file pointer. Unlike GetModuleFileName however, GetMappedFileName has no concept of "the reindeer module games," so it works even with the LOAD_LIBARY_AS_DATAFILE flag of LoadLibraryEx. Not only that, but GetMappedFileName has an additional benefit over GetModuleFileName.
Something you might not know is that simply loading a library with LoadLibrary does not exclusively lock the DLL file. Try it yourself: write a simple program which loads your own library with LoadLibrary, and then while the program is running, cut and paste the DLL file to a different location. This will work (and yes, has always worked regardless of Windows version) so long as no other application has a lock on the DLL file. The File Mapping API just keeps on chugging, regardless of the DLL file's new location.
However, when you call GetModuleFileName, it will always return the path of the DLL file as of whenever the library was loaded with LoadLibrary. This has security ramifications. It would be possible to cut and paste the DLL file to a new location, and put a different one at the old location. If the path returned by GetModuleFileName is used to load the library again, it could actually result in loading a different DLL file altogether. As such, GetModuleFileName is only useful for the purpose of displaying the name or getting the DLL file name passed to LoadLibrary, and can't be depended upon for the current file path.
GetMappedFileName has no such issue, because it has no concept of when LoadLibrary was called. It returns an up to date path to the file, even if it has been moved while it's loaded.
There is one minor downside though: GetMappedFileName returns a device path, in the format of \Device\HarddiskVolume1\Example.DLL. This appears to be due to the File Mapping API originally being from DOS - why a "GetMappedFileNameEx" that returns a drive path doesn't exist is beyond me.
Thankfully, it's a resolvable issue. We can use QueryDosDevice to turn the device path into a drive path.
bool getFilePathNameFromMappedView(HANDLE process, LPVOID mappedView, std::string &filePathName) {
if (!process) {
return false;
}
if (!mappedView) {
return false;
}
CHAR mappedFileName[MAX_PATH] = "";
if (!GetMappedFileName(process, mappedView, mappedFileName, MAX_PATH - 1)) {
return false;
}
// the mapped file name is a device path, we need a drive path
// https://learn.microsoft.com/en-us/windows/win32/fileio/defining-an-ms-dos-device-name
const SIZE_T DEVICE_NAME_SIZE = 3;
CHAR deviceName[DEVICE_NAME_SIZE] = "A:";
// the additional character is for the trailing slash we add
size_t targetPathLength = 0;
CHAR targetPath[MAX_PATH + 1] = "";
// find the MS-DOS Device Name
DWORD logicalDrives = GetLogicalDrives();
do {
if (logicalDrives & 1) {
if (!QueryDosDevice(deviceName, targetPath, MAX_PATH - 1)) {
return false;
}
// add a trailing slash
targetPathLength = strnlen_s(targetPath, MAX_PATH);
targetPath[targetPathLength++] = '\\';
// compare the Target Path to the Device Object Name in the Mapped File Name
// case insensitive
// https://flylib.com/books/en/4.168.1.23/1/
if (!_strnicmp(targetPath, mappedFileName, targetPathLength)) {
break;
}
}
deviceName[0]++;
} while (logicalDrives >>= 1);
if (!logicalDrives) {
return false;
}
// get the drive path
filePathName = std::string(deviceName) + "\\" + (mappedFileName + targetPathLength);
return true;
}
GetLogicalDrives just gets a list of which drives are available (like C:, D:, etc.) in the form of a bitmask (where the first bit corresponds to A:, the second bit corresponds to B:, etc.) We then loop through the available drives, getting their paths, and comparing them against the one in the Mapped File Name. The result of this function is a path that could be passed to the CreateFile function.
The only source I could find for whether these device paths are case-insensitive or not was this book claiming that they used to be case-sensitive, but are case-insensitive as of Windows XP. I'm going to assume you are not targeting Windows 9x anymore, so I just compare them case-insensitively.
Hold on a second though: this still may not be enough. If your intention is, as mine was, to try and get a file handle to the DLL file, but using the DLL search path, then just getting the path and passing it to CreateFile opens us up to a filesystem race condition, like the kind explained in this LiveOverflow video. A technique like this could be abused by a hacker so the handle doesn't actually point to the file we want. There isn't any GetMappedFileHandle function, so what can we do?
I thought about this for a while, and here is the workaround I came up with. The idea is that we call our own getFilePathNameFromMappedView function once just to get the path to pass to CreateFile, and exclusively lock the file in place with the FILE_SHARE_READ flag. However, we then confirm, with a second call to getFilePathNameFromMappedView, that the file is still actually there. If the paths match, knowing that the file at that path is now locked, we can know for sure the handle we got is to the library that was actually loaded. If the file was moved before the call to CreateFile finished, however, the paths will not match, because GetMappedFileName returns the up to date path to the file. At that point, we can try again. I decided to do this as a recursive function, but you could decide to throw an error and have the caller handle it.
inline bool stringsCaseInsensitiveEqual(const char* leftHandSide, const char* rightHandSide) {
return !_stricmp(leftHandSide, rightHandSide);
}
bool getHandleFromModuleHandle(HMODULE moduleHandle, HANDLE &file) {
if (!moduleHandle) {
return false;
}
HANDLE currentProcess = GetCurrentProcess();
// pass the Module Handle as a Mapped View
// to get its current path
std::string filePathName = "";
if (!getFilePathNameFromMappedView(currentProcess, moduleHandle, filePathName)) {
return false;
}
// prevent the Example File from being written to, moved, renamed, or deleted
// by acquiring it and effectively locking it from other processes
file = CreateFile(filePathName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!file || file == INVALID_HANDLE_VALUE) {
return false;
}
bool recursive = false;
{
// we now know this path is now protected against race conditions
// but the path may have changed before we acquired it
// so ensure the File Path Name is the same as before
// so that we know the path we protected is for the Mapped View
std::string _filePathName = "";
if (!getFilePathNameFromMappedView(currentProcess, moduleHandle, _filePathName)) {
goto error;
}
if (!stringsCaseInsensitiveEqual(filePathName.c_str(), _filePathName.c_str())) {
// race condition occured
recursive = true;
goto error;
}
}
return true;
error:
if (file && file != INVALID_HANDLE_VALUE) {
if (!CloseHandle(file)) {
return false;
}
file = NULL;
}
if (recursive) {
return getHandleFromModuleHandle(moduleHandle, file);
}
return false;
}
Then we can call it like this...
HMODULE exampleModuleHandle = LoadLibraryEx("Example.DLL", NULL, LOAD_LIBRARY_AS_DATAFILE);
if (!exampleModuleHandle) {
return false;
}
// we want this to be a handle to the Example File
HANDLE exampleFile = NULL;
if (!getHandleFromModuleHandle(exampleModuleHandle, exampleFile)) {
return false;
}
This is just something I thought of, so let me know in the responses if there are issues with it.
Once you have a handle to the file, it can then be passed to GetFileInformationByHandle to confirm it is the same library as is loaded in another process, and subsequently closed with CloseHandle.
Well, the title say which is my problem
my .cpp code is:
GetPrivateProfileString("Server","MainDns","ServerDns",
g_DataBaseDns,sizeof(g_DataBaseDns),".\\Server.ini");
when I use:
GetPrivateProfileString("Server","MainDns","ServerDns",
g_DataBaseDns,sizeof(g_DataBaseDns),"..\\Server.ini");
and Put the ini file in the back folder: works normally!
What am I doing wrong?
You need to first call GetFullPathName() to obtain an absolute path, which is required according to the documentation for GetPrivateProfileString():
The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the Windows directory.
For example:
TCHAR sAbsolutePathBuffer[2048] = _T("");
if (GetFullPathName(TEXT("Server.ini"), sizeof(sAbsolutePathBuffer)/sizeof(TCHAR), sAbsolutePathBuffer, NULL))
{
GetPrivateProfileString(TEXT("Server"), TEXT("MainDns"), TEXT("ServerDns"),
g_DataBaseDns, sizeof(g_DataBaseDns), sAbsolutePathBuffer);
}
If I do
LoadLibrary("MyTest.dll")
Windows will locate and load it from "C:\TestFolder\Test\MyTest.dll", because "C:\TestFolder\Test\" is in %PATH% folder.
How can I emulate same function? I need to locate C:\TestFolder\Test\MyTest.dll (C:\TestFolder\Test\ is in %PATH%) by passing MyTest.dll as an argument to a function. Is there such an API? or a function?
P.S. I can't do LoadLibrary and then GetModuleHandle and finding Path, sometimes this DLL could be malicious DLL and I can't load it. So I need to find PATH without having to load it.
To load the DLL without running any malicious code inside, use LoadLibraryEx with the DONT_RESOLVE_DLL_REFERENCES and LOAD_LIBRARY_AS_DATAFILE flags.
Then you can use GetModuleFileName.
You should also read about all the other flags, which allow you to perform all the various searches Windows is capable of.
The accepted answer to this question will not work in all scenarios. More specifically, using GetModuleFileName together with LOAD_LIBRARY_AS_DATAFILE will only work if the library was already loaded prior without this flag. For example, it will work for a library like KERNEL32.DLL which is already loaded by the process, but it will not work with your own library being loaded into the process for the first time.
This is because, to quote The Old New Thing, a library loaded via LOAD_LIBRARY_AS_DATAFILE (or similar flags) doesn't get to play in any reindeer module games.
If you load a library with the LOAD_LIBRARY_AS_DATAFILE flag, then it
isn’t really loaded in any normal sense. In fact, it’s kept completely
off the books. If you load a library with the
LOAD_LIBRARY_AS_DATAFILE, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE, or
LOAD_LIBRARY_AS_IMAGE_RESOURCE flag (or any similar flag added in the
future), then the library gets mapped into the process address space,
but it is not a true module. Functions like GetModuleHandle,
GetModuleFileName, EnumProcessModules and
CreateToolhelp32Snapshot will not see the library, because it was
never entered into the database of loaded modules.
At that point, you might as well just use GetModuleHandle, since it'll only work with previously loaded libraries. Obviously not ideal, and doesn't actually answer the question of getting the path without executing DllMain.
What about the other flag, DONT_RESOLVE_DLL_REFERENCES? Well, technically yes it will work. However, you'll notice in the Microsoft documentation the following note.
Do not use this value; it is provided only for backward compatibility.
If you are planning to access only data or resources in the DLL, use
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE or LOAD_LIBRARY_AS_IMAGE_RESOURCE
or both.
The flag is only provided for backwards compatibility, and that is for good reason. To quote The Old New Thing a second time, DONT_RESOLVE_DLL_REFERENCES is a time bomb.
It is common for somebody to call GetModuleHandle to see if a DLL is
loaded, and if so, use GetProcAddress to get a procedure address and
call it. If the DLL had been loaded with DONT_RESOLVE_DLL_REFERENCES,
both the GetModuleHandle will succeed, but the resulting function will
crash when called. The code doing this has no idea that the DLL was
loaded with DONT_RESOLVE_DLL_REFERENCES; it has no way of protecting
itself.
Other threads will see the library is loaded. If they attempt to use the loaded library, as would be entirely normal to do, they will crash the program because it has not actually been initialized. So this flag, while it does work with GetModuleFileName, will cause instability in the program. Still not ideal.
So then, if we can't use DONT_RESOLVE_DLL_REFERENCES or LOAD_LIBRARY_AS_DATAFILE with GetModuleFileName, then what is the solution? Well, the solution is to not use GetModuleFileName - and instead use GetMappedFileName.
At this point, if you know what GetMappedFileName does, you may be confused. Normally, GetMappedFileName is used to get a filename from a File Mapping, created with the File Mapping API. Well, the secret is that under the hood, image loading is accomplished with MapViewOfFile. This is subtly hinted at by the Dbghelp documentation - for example, the ImageNtHeader documentation which states an image base must be...
The base address of an image that is mapped into memory by a call to
the MapViewOfFile function.
This means that not only is a module handle a pointer to a module, but also a mapped file pointer. Unlike GetModuleFileName however, GetMappedFileName has no concept of "the reindeer module games," so it works even with the LOAD_LIBARY_AS_DATAFILE flag of LoadLibraryEx. Not only that, but GetMappedFileName has an additional benefit over GetModuleFileName.
Something you might not know is that simply loading a library with LoadLibrary does not exclusively lock the DLL file. Try it yourself: write a simple program which loads your own library with LoadLibrary, and then while the program is running, cut and paste the DLL file to a different location. This will work (and yes, has always worked regardless of Windows version) so long as no other application has a lock on the DLL file. The File Mapping API just keeps on chugging, regardless of the DLL file's new location.
However, when you call GetModuleFileName, it will always return the path of the DLL file as of whenever the library was loaded with LoadLibrary. This has security ramifications. It would be possible to cut and paste the DLL file to a new location, and put a different one at the old location. If the path returned by GetModuleFileName is used to load the library again, it could actually result in loading a different DLL file altogether. As such, GetModuleFileName is only useful for the purpose of displaying the name or getting the DLL file name passed to LoadLibrary, and can't be depended upon for the current file path.
GetMappedFileName has no such issue, because it has no concept of when LoadLibrary was called. It returns an up to date path to the file, even if it has been moved while it's loaded.
There is one minor downside though: GetMappedFileName returns a device path, in the format of \Device\HarddiskVolume1\Example.DLL. This appears to be due to the File Mapping API originally being from DOS - why a "GetMappedFileNameEx" that returns a drive path doesn't exist is beyond me.
Thankfully, it's a resolvable issue. We can use QueryDosDevice to turn the device path into a drive path.
bool getFilePathNameFromMappedView(HANDLE process, LPVOID mappedView, std::string &filePathName) {
if (!process) {
return false;
}
if (!mappedView) {
return false;
}
CHAR mappedFileName[MAX_PATH] = "";
if (!GetMappedFileName(process, mappedView, mappedFileName, MAX_PATH - 1)) {
return false;
}
// the mapped file name is a device path, we need a drive path
// https://learn.microsoft.com/en-us/windows/win32/fileio/defining-an-ms-dos-device-name
const SIZE_T DEVICE_NAME_SIZE = 3;
CHAR deviceName[DEVICE_NAME_SIZE] = "A:";
// the additional character is for the trailing slash we add
size_t targetPathLength = 0;
CHAR targetPath[MAX_PATH + 1] = "";
// find the MS-DOS Device Name
DWORD logicalDrives = GetLogicalDrives();
do {
if (logicalDrives & 1) {
if (!QueryDosDevice(deviceName, targetPath, MAX_PATH - 1)) {
return false;
}
// add a trailing slash
targetPathLength = strnlen_s(targetPath, MAX_PATH);
targetPath[targetPathLength++] = '\\';
// compare the Target Path to the Device Object Name in the Mapped File Name
// case insensitive
// https://flylib.com/books/en/4.168.1.23/1/
if (!_strnicmp(targetPath, mappedFileName, targetPathLength)) {
break;
}
}
deviceName[0]++;
} while (logicalDrives >>= 1);
if (!logicalDrives) {
return false;
}
// get the drive path
filePathName = std::string(deviceName) + "\\" + (mappedFileName + targetPathLength);
return true;
}
GetLogicalDrives just gets a list of which drives are available (like C:, D:, etc.) in the form of a bitmask (where the first bit corresponds to A:, the second bit corresponds to B:, etc.) We then loop through the available drives, getting their paths, and comparing them against the one in the Mapped File Name. The result of this function is a path that could be passed to the CreateFile function.
The only source I could find for whether these device paths are case-insensitive or not was this book claiming that they used to be case-sensitive, but are case-insensitive as of Windows XP. I'm going to assume you are not targeting Windows 9x anymore, so I just compare them case-insensitively.
Hold on a second though: this still may not be enough. If your intention is, as mine was, to try and get a file handle to the DLL file, but using the DLL search path, then just getting the path and passing it to CreateFile opens us up to a filesystem race condition, like the kind explained in this LiveOverflow video. A technique like this could be abused by a hacker so the handle doesn't actually point to the file we want. There isn't any GetMappedFileHandle function, so what can we do?
I thought about this for a while, and here is the workaround I came up with. The idea is that we call our own getFilePathNameFromMappedView function once just to get the path to pass to CreateFile, and exclusively lock the file in place with the FILE_SHARE_READ flag. However, we then confirm, with a second call to getFilePathNameFromMappedView, that the file is still actually there. If the paths match, knowing that the file at that path is now locked, we can know for sure the handle we got is to the library that was actually loaded. If the file was moved before the call to CreateFile finished, however, the paths will not match, because GetMappedFileName returns the up to date path to the file. At that point, we can try again. I decided to do this as a recursive function, but you could decide to throw an error and have the caller handle it.
inline bool stringsCaseInsensitiveEqual(const char* leftHandSide, const char* rightHandSide) {
return !_stricmp(leftHandSide, rightHandSide);
}
bool getHandleFromModuleHandle(HMODULE moduleHandle, HANDLE &file) {
if (!moduleHandle) {
return false;
}
HANDLE currentProcess = GetCurrentProcess();
// pass the Module Handle as a Mapped View
// to get its current path
std::string filePathName = "";
if (!getFilePathNameFromMappedView(currentProcess, moduleHandle, filePathName)) {
return false;
}
// prevent the Example File from being written to, moved, renamed, or deleted
// by acquiring it and effectively locking it from other processes
file = CreateFile(filePathName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (!file || file == INVALID_HANDLE_VALUE) {
return false;
}
bool recursive = false;
{
// we now know this path is now protected against race conditions
// but the path may have changed before we acquired it
// so ensure the File Path Name is the same as before
// so that we know the path we protected is for the Mapped View
std::string _filePathName = "";
if (!getFilePathNameFromMappedView(currentProcess, moduleHandle, _filePathName)) {
goto error;
}
if (!stringsCaseInsensitiveEqual(filePathName.c_str(), _filePathName.c_str())) {
// race condition occured
recursive = true;
goto error;
}
}
return true;
error:
if (file && file != INVALID_HANDLE_VALUE) {
if (!CloseHandle(file)) {
return false;
}
file = NULL;
}
if (recursive) {
return getHandleFromModuleHandle(moduleHandle, file);
}
return false;
}
Then we can call it like this...
HMODULE exampleModuleHandle = LoadLibraryEx("Example.DLL", NULL, LOAD_LIBRARY_AS_DATAFILE);
if (!exampleModuleHandle) {
return false;
}
// we want this to be a handle to the Example File
HANDLE exampleFile = NULL;
if (!getHandleFromModuleHandle(exampleModuleHandle, exampleFile)) {
return false;
}
This is just something I thought of, so let me know in the responses if there are issues with it.
Once you have a handle to the file, it can then be passed to GetFileInformationByHandle to confirm it is the same library as is loaded in another process, and subsequently closed with CloseHandle.
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.
I have a program that is executed by another program. The program that is being executed needs files located at its own location [same folder]. If I call myfile.open("xpo.dll") I might get an error because I am not passing the [fullpath + name + extension]. The program that is being executed can vary paths depending on the installation path. Therefore, I was wondering if there is a way to get the application path [where the application is located] and set it so that when another program executes from another path everything might work properly...?
[Using C++ without .NET Framework]
Thanks.
Use GetModuleFileName and pass NULL for hModule.
DWORD GetModuleFileName(
HMODULE hModule, // handle to module
LPTSTR lpFilename, // path buffer
DWORD nSize // size of buffer
);
First off, I run into this problem in other languages a lot, and find Process Monitor (http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx) very useful for finding out what folder it is currently trying to access.
There is no standard function for doing this.
Just a thought, have you tried doing myfile.open "./xpo.dll"?
If it's a console application, you can use the POSIX getcwd function: http://www.dreamincode.net/code/snippet77.htm
If it's a Windows app and you can use the windows API, you can use GetModuleFileName... see the second reply to this question here: How do I get the directory that a program is running from?