ShellExecute occupies directory - c++

My C++ program is in a directory (A). After running ShellExecute() through this program, I open an application XShell, close my C++ program, and then I find that in the resource monitor, the A directory is occupied by the program XShell I enabled. How to solve it?
ShellExecuteW(NULL, L"open", L"D:\\Program Files\\NetSarang\\Xshell 6\\Xshell.exe", NULL, NULL, SW_SHOWDEFAULT)
After the C++ program exits, XShell occupies my C++ program directory.
I hope that after opening an application through ShellExecute(), this application does not occupy the directory of the C++ program.

The directory is occupied because the secondary program is inheriting that directory as its working directory. To avoid that, you can specify the desired working directory that the secondary program should use in the lpDirectory parameter of ShellExecuteW():
https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew
[in, optional] lpDirectory
Type: LPCTSTR
A pointer to a null-terminated string that specifies the default (working) directory for the action. If this value is NULL, the current working directory is used. If a relative path is provided at lpFile, do not use a relative path for lpDirectory.
For example, you can specify "C:\\" (which should always exist and be accessible).

Related

Deleting running files

When I used the latest version of McAfee Antivirus, I noticed that the shred feature can delete running files and then asks you to restart your computer. Do anyone know how does it delete running files without closing them?
It may depend on the OS and file system types. On Linux and Unix like, deleting a file a just removing an entry from a folder. The file is actually deleted on last close if no folder entry points to it. So you can safely delete a file even if it is opened in another process.
On Windows the MSDN says:
The DeleteFile function fails if an application attempts to delete a file that has other handles open for normal I/O or as a memory-mapped file
Usual tricks include:
try to close all processes having handles on that file. For an executable it generally means terminating all its instances
mark the file for deletion on next reboot. As you say that McAfee asks to reboot the computer it likely uses that option. The MoveFileEx WINAPI function has provision for that. Extracts from MSDN page (emphasize mine)
BOOL WINAPI MoveFileEx(
_In_ LPCTSTR lpExistingFileName,
_In_opt_ LPCTSTR lpNewFileName,
_In_ DWORD dwFlags
);
... lpNewFileName [in, optional]
The new name of the file or directory on the local computer....
If dwFlags specifies MOVEFILE_DELAY_UNTIL_REBOOT and lpNewFileName is NULL, MoveFileEx registers the lpExistingFileName file to be deleted when the system restarts.

MFC CFileDialog and lpstrInitialDir

According to the documentation for the OPENFILENAME structure, the following algorithm is used to select the initial directory:
Windows 7:
If lpstrInitialDir has the same value as was passed the first time the application used an Open or Save As dialog box, the path most recently selected by the user is used as the initial directory.
Otherwise, if lpstrFile contains a path, that path is the initial directory.
Otherwise, if lpstrInitialDir is not NULL, it specifies the initial directory.
If lpstrInitialDir is NULL and the current directory contains any files of the specified filter types, the initial directory is the current directory.
Otherwise, the initial directory is the personal files directory of the current user.
Otherwise, the initial directory is the Desktop folder.
I'm using the following code to construct a file dialog:
CFileDialog dlgFile(bOpenFileDialog);
dlgFile.m_ofn.lpstrInitialDir = strSourcePath;
dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);
However, it ALWAYS opens the same default folder in strSourcePath. Does anyone know why? It should only use this directory the first time, and subsequent file opens should remember the last folder (bullet point 1. in the algorithm). I'm using VS2012 on Windows 7.
Here is the fix:
dlgFile.m_ofn.lpstrInitialDir = strSourcePath.GetBuffer(_MAX_PATH);
Don't forget to call strSourcePath.ReleaseBuffer(); when you done.
If you are using lpstrFile to specify filename, then you may need to prepend initial directory path to the filename.

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.

std::ifstream::open() not working

I am developing a prototype for a game, and certain gameplay rules are to be defined in an ini file so that the game designers can tweak the game parameters without requiring help from me in addition to a re-compile. This is what I'm doing currently:
std::ifstream stream;
stream.open("rules.ini");
if (!stream.is_open())
{
throw new std::exception("Rule file could not be opened");
}
// read file contents here
stream.close();
However, my stream never opens succesfully. Diving deep into the STL source during debugging reveals that _getstream() (as defined in stream.c) keeps on returning NULL, but I just can't figure out why this is. Help, anyone?
Edit: Rules.ini is in the same directory as the .exe file.
You are assuming that the working directory is the directory that your executable resides in. That is a bad assumption.
Your executable can be run from any working directory, so it's usually a bad idea to hard-code relative paths in your software.
If you want to be able to access files relative to the location of your executable, you should first determine the path of your executable and create a fully qualified path from that.
You can get the name of your executable by examining the argv[0] parameter passed to main(). Alternatively, if you're on Windows, you can get it with GetModuleFileName() by passing NULL as the first parameter.
Is the scope of your open stream correct.
"rules.ini" isn't a full path so it has to be relative so what is it relative to. Or do you need to use full path there.
(wild assumption here) you are using visual studio. During debug, your program is going to search the project directory for "rules.ini"
However, if you try executing your program from "myproject/debug/myexe.exe", it should run fine because it is going to search "/debug" for rules.ini
Like its been mentionned you should specify the full path because relative path tend to lead to errors