I'm a .net developer mostly, doing something small in C++ so im having a little trouble.
I'm loading another C++ dll using hInst = LoadLibrary(TEXT("mydll.dll")); and I came to realize that this looks for the dll I'm trying to load in 'C:\' or in 'system32'.
Can someone show me how to load the dll from the current directory (without knowing what the current directory is ahead of time) ??
I know I should be using something like GetFullPathName but I'm having a little trouble getting it to work on my own...
The process current directory can be acquired using the function GetCurrentDirectory():
TCHAR bufCurrentDirectory[MAX_PATH + 1] = { 0 };
DWORD dwNumCharacters = ::GetCurrentDirectory(MAX_PATH, bufCurrentDirectory);
if(dwNumCharacters == 0) error();
Now the path to the process's current directory is in bufCurrentDirectory, unless the function failed. Just append "\\mydll.dll" onto the path, and you have an absolute path to the DLL.
Since the current directory of a process is somewhat variable, it may be better to use the path of the executable. To get the path of the current executable, you can do:
TCHAR bufExePath[MAX_PATH + 1] = { 0 };
DWORD dwNumCharacters = ::GetModuleFileName(NULL, bufExePath, MAX_PATH);
if(dwNumCharacters == 0) error();
Now bufExePath contains the entire path to the exe, including "\\my.exe". Replace my.exe with mydll.dll, and you'll have the absolute path to the DLL. I would recommend this method over the GetCurrentDirectory() method due to security concerns.
I believe loading from current directory is the default and first search. See the MSDN reference
The first directory searched is the
directory containing the image file
used to create the calling process
(for more information, see the
CreateProcess function). Doing this
allows private dynamic-link library
(DLL) files associated with a process
to be found without adding the
process's installed directory to the
PATH environment variable
http://msdn.microsoft.com/en-us/library/ms684175(v=vs.85).aspx
Use GetCurrentDirectory.
Related
I already know how to set a relative working directory path and access resources inside of visual studio. However, when I build my solution and move the exe to a separate file I have to include all the resources in the same directory as the exe. I'd prefer to have a folder with said resources alongside the exe to keep things clean. Is there a macro I need to use? Is the working directory the right setting to change for this?
example
Sorry for this incredibly basic question, but I think I lack the vocabulary to accurately describe the issue.
For a Windows solution, GetModuleFileName to find the exact path of your EXE. Then a simple string manipulation to make a resource path string.
When you program starts, you can use this to ascertain the full path of your EXE.
std::string pathToExe(MAX_PATH, '\0');
GetModuleFileName(nullptr, szPathToExe.data(), MAX_PATH); // #include <windows.h> to get this function declared
On return, szPathToExe will be something like "C:\\Path\\To\\Your\\Program\\Circle.exe"
Then strip off the file name to get the absolute path
std::string resourceFolderPath = szPathToExe;
size_t pos = strPath.find_last_of("\\");
strPath = strPath.substr(0, pos+1); //+1 to include the backslash
Then append your resource folder name and optionally another trailing backslash.
resourceFolderPath += "res\\";
Then change all your I/O calls to open files relative to resourceFolderPath
You should probably add reasonable error checking to the above code such as validating the return code from GetModuleFileName and find_last_of calls.
In many cases to load some newer API one would use a construct as such:
(FARPROC&)pfnZwQueryVirtualMemory = ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "ZwQueryVirtualMemory");
But then, considering a chance of Dll hijacking, is it better to specify a DLL's absolute path, as such. Or is it just an overkill?
WCHAR buff[MAX_PATH];
buff[0] = 0;
if(::GetSystemDirectory(buff, MAX_PATH) &&
::PathAddBackslash(buff) &&
SUCCEEDED(::StringCchCat(buff, MAX_PATH, L"ntdll.dll")))
{
(FARPROC&)pfnZwQueryVirtualMemory = ::GetProcAddress(::GetModuleHandle(buff), "ZwQueryVirtualMemory");
}
else
{
//Something went wrong
pfnZwQueryVirtualMemory = NULL;
}
The problem with the latter method is that it doesn't always work (for instance with Comctl32.dll.)
You don't have to do anything special for ntdll.dll and kernel32.dll because they are going to be loaded before you get the chance to do anything, they are also on the known-dlls list.
The dll hijacking issues often include auxiliary libraries. Take version.dll for example, it is no longer on the known-dlls list so explicitly linking to it is problematic, it needs to be loaded dynamically.
The best solution is a combination of 3 things:
Call SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32) if it is available (Win8+ and updated Win7).
Call LoadLibrary with the full path (GetSystemDirectory) before calling GetModuleHandle.
Don't explicitly link to anything other than kernel32, user32, gdi32, shlwapi, shell32, ole32, comdlg32 and comctl32.
If SetDefaultDllDirectories is not available then it is really hard to protect yourself if you don't control the application directory because various Windows functions will delay-load dlls like shcore.dll without full paths (especially the shell APIs). SetDllDirectory("") helps against the current/working directory but there is no good application directory workaround for unpatched pre-Win8 systems, you just have to test with Process Monitor and manually load the problematic libraries early in WinMain.
The application directory is a problem because some users just put everything in the downloads folder and run it from there. This means you might end up with a malicious dll in your application directory.
in the directory containing my exe I have a folder called "saves".
I want to display the files this directory contains.
I used the code found here:
Listing directory contents using C and Windows
Now the tricky part.
if I use .\\saves\\ as my directory it tells me that the path could not be found.
However if I use ..\\release\\saves\\ it works fine. But that's stupid. I don't want to go to the parent folder and than go back. Especially regarding that I don't know what name the user gives to the directory containing the exe (in my case it's "release" but who knows what the user does :-D).
I read through this: http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx#fully_qualified_vs._relative_paths but it didn't help very much.
I also tried saves\\ or .\saves\\ but it doesn't work either.
I hope somebody can tell me how to fix this.
You're actually doing nothing wrong in code -- you've been launching the project from Visual Studio, which sets the Working Directory to the parent of the Release/Debug folders.
Go to Project->Settings(Properties)->Configuration Properties->Debugging->Working Directory
You can also run the exe outside of VS and the relative paths will behave like you expect.
If it is relative from the path to the executable, and not from the path of the current working directory, you could use GetModuleFileName() to obtain the full path to the executable. Then, remove the name of the executable from the end of the path and build the paths using that:
std::string executable_directory_path()
{
std::vector<char> full_path_exe(MAX_PATH);
for (;;)
{
const DWORD result = GetModuleFileName(NULL,
&full_path_exe[0],
full_path_exe.size());
if (result == 0)
{
// Report failure to caller.
}
else if (full_path_exe.size() == result)
{
// Buffer too small: increase size.
full_path_exe.resize(full_path_exe.size() * 2);
}
else
{
// Success.
break;
}
}
// Remove executable name.
std::string result(full_path_exe.begin(), full_path_exe.end());
std::string::size_type i = result.find_last_of("\\/");
if (std::string::npos != i) result.erase(i);
return result;
}
I would use boost::filesystem
http://www.boost.org/doc/libs/1_53_0/libs/filesystem/doc/index.htm.
As a bonus you will get operating system independent code.
I think your mistake was using \\saves\\and forgeting to specify a search parameter/string
You should use:
saves\\*
this will search for any file or folder
The following answer gives a solution using C#, I was wondering what the equivalent would be if one were using only c++ (not c++\cli)
System.IO.Directory.SetCurrentDirectory(System.AppDomain.CurrentDomain.BaseDirectory);
Is there anything in boost that might do the trick?
Based on this problem I've been having: Correctly creating and running a win32 service with file I/O
SetCurrentDirectory (in Win32):
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365530%28v=vs.85%29.aspx
current_path in boost::filesystem:
http://www.boost.org/doc/libs/1_51_0/libs/filesystem/doc/reference.html#current_path
The equivalent for BaseDirectory might be GetModuleFileName (with a null handle for the first argument), followed by GetFullPathName to get the directory from the executable path.
Use SetCurrentDirectory WINAPI.
There is one more answer available at What is the difference between _chdir and SetCurrentDirectory in windows?
Perhaps there is a need for Module Name as well(Seems from comments),Here is one from my old store:-
int main()
{
char path[MAX_PATH]={0};
GetModuleFileName(0,path,MAX_PATH);
}
In Windows, the complete equivalent of
System.IO.Directory.SetCurrentDirectory ( System.AppDomain.CurrentDomain.BaseDirectory )`
would be:
// Get full executable path
char buffer[MAX_PATH];
GetModuleFileName(NULL, buffer, MAX_PATH);
// Get executable directory
boost::filesystem::path path(buffer);
path = path.parent_path();
// Set current path to that directory
boost::filesystem::current_path( path );
Note that there is no platform-agnostic way to get an application's directory, as C++ doesn't recognize the concept of directories in the standard. Boost doesn't appear to have an equivalent function either.
Where should I store the application installation folder for application to reffer ?
I believe what you're looking for is the GetModuleFileName function, which you can use like so:
// get the full path to the current executable
wchar_t fullPath[MAX_PATH];
GetModuleFileName(NULL, fullPath, MAX_PATH);
// cut the string at the last slash, because we just want the directory
// not the actual executeable file name.
TCHAR *lastSlash = wcsrchr(fullPath, L'\\');
lastSlash = 0;
// directory where the executable is location is fullPath
This will work regardless of the current working directory and in general, this is how I do all "relative path" stuff (that is, I never actually use relative paths, they're always absolute paths, based off the value returned from the function above).
You can use the registry for storing installation folders.
::GetModuleFileName(NULL, out_lpPathName, in_size) will give you full path of your executable file.
ApplicationData folder, even not admin access can help to access you install data. use SHGetSpecialFolderPath with CISDL CSIDL_APPDATA
In the registry. To be specific, under HKEY_LOCAL_MACHINE\SOFTWARE\YourCompanyName\YourApplicationName\ if you installed your app for all users (i.e. in \Program Files), and under HKEY_CURRENT_USER\SOFTWARE\YourCompanyName\YourApplicationName\ if you installed it for a single user only.