Setting the current directory of a running app in C++ - c++

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.

Related

Visual Studio C++ How to Specify Relative Resource Path For Final Build

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.

Get executable path with AssocQueryString in C++

Helo! I need to query application full path in C++, like "meshlab" -> "C:\Program Files\VCG\MeshLab\meshlab.exe"
This information is present in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths, but I don't want to work with registry directly, so I am using AssocQueryString like this:
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <Shlwapi.h>
int main()
{
char* executablePath = nullptr;
DWORD executablePathLen = 0;
std::string shortName = "mspaint";
HRESULT res = AssocQueryStringA(ASSOCF_OPEN_BYEXENAME,
ASSOCSTR_EXECUTABLE,
shortName.c_str(),
NULL,
executablePath,
&executablePathLen);
executablePath = new char[executablePathLen];
res = AssocQueryStringA(ASSOCF_OPEN_BYEXENAME,
ASSOCSTR_EXECUTABLE,
shortName.c_str(),
NULL,
executablePath,
&executablePathLen);
std::cout << executablePath; // prints: C:\Windows\system32\mspaint.exe
delete[] executablePath;
std::cin.get();
}
For mspaint it works as expected, but for meshlab it doesn't. HRESULT is ERROR_NO_ASSOCIATION
Any ideas what I missed?
UPDATE:
Also works well with foobar200 from C:\Program Files (x86)\foobar2000\foobar2000.exe
I suspect it must be related to 32/64 bit registry. I am using Windows 10 64 bit, and my application is 64 bit
I believe ASSOCF_OPEN_BYEXENAME:ASSOCSTR_EXECUTABLE searches HKEY_CLASSES_ROOT\Applications.
ShellExecuteEx searches the "normal directories" and the App Paths key:
Finding an Application Executable
When the ShellExecuteEx function is called with the name of an executable file in its lpFile parameter, there are several places where the function looks for the file. We recommend registering your application in the App Paths registry subkey. Doing so avoids the need for applications to modify the system PATH environment variable.
The file is sought in the following locations:
The current working directory.
The Windows directory only (no subdirectories are searched).
The Windows\System32 directory.
Directories listed in the PATH environment variable.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
(HKEY_CURRENT_USER is also used on recent versions of Windows)
The Assoc API is more focused on file associations.
If you are just going to execute the file then you should just use ShellExecuteEx. If you just want to find the fully qualified path you can use some helper functions to do some of the work for you:
FindExecutable seems promising but it has some compatibility workarounds and it will also find the executable used to open registered types (c:\foo\bar.txt might resolve to c:\Windows\Notepad.exe etc. because it uses ASSOCSTR_EXECUTABLE),
If you want to look for extensions like .exe and .bat automatically you can use PathResolve(..., PRF_REQUIREABSOLUTE|PRF_VERIFYEXISTS|PRF_TRYPROGRAMEXTENSIONS|PRF_DONTFINDLNK) but you must be careful that the search string does not contain \ nor :.
If you only want to look for a .exe you must manually append the extension if it is not present and then call PathFindOnPath(, NULL).
Neither of these functions looks in the App Paths key, they do not use the exact same search order as ShellExecuteEx (system32 before %windir%?) and they are most likely limited to MAX_PATH.
If those functions (or your own equivalent version) fail then you can check the App Paths key. When reading from the registry you must append .exe if there is no extension and use a helper function like SHQueryValueEx that will expand REG_EXPAND_SZ strings.

Opening a file with a certain program changes that programs working directory?

I have a file saved to my desktop, when I open it with my program the working directory changes to the desktop, this means my program can not load in some files it needs as it searches for these in the working directory. Is there a way I can stop the working directory from changing like this?
There's a flag you can set to avoid the current directory from changing called OFN_NOCHANGEDIR
http://msdn.microsoft.com/en-us/library/ms646839(v=vs.85).aspx
You can just save your working directory at startup and use absolute paths. In fact, it's better to always open files with absolute paths, unless you really want to rely on the current working directory.
You would be better off determining the processes location, then using it as the key for where to find the other files? There are many ways that programs can be launched, which effect the working directory.
See: The answer here for a good description of how to get the processes location and strip out the executable filename (look in the comments)
Essentially, you use:
GetModuleFileName or GetModuleFileNameEx.
and then:
PathRemoveFileSpec to remove the file name
Opening a file doesn't change your current directory. Perhaps you using the common open file dialog? Here is an article that will explain all about how that changes your current directory.
use SetCurrentDirectory to do that.
You can locate the executable by using GetModuleFileName
TCHAR szFileName[MAX_PATH];
GetModuleFileName( NULL, szFileName, MAX_PATH )
... then compute the correct directory
SetCurrentDirectory(path);

C++ LoadLibrary() from the current path

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.

Application path location in MS windows

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.