Windows, relative paths and elevation - windows

I'm getting mad with what (in my mind) should be an easy task:
On my desktop (but could be anywhere) I have a folder "project", a "console.msc" and another folder "files" inside.
"console.msc" have a task that runs file1.bat and it works if I use full paths but it doesn't with relative ones.
c:\users\user1\Desktop\project\files\file1.bat WORKS
.\files\file1.bat
DOESN'T WORK
I see that all the time, the custom mmc is lauched with elevated privileges (good, I want it) but the relative path used to call file1.bat just doesn't work and the error returned is "Windows cannot find [..]"
Does anybody know how to tell Windows to keep the current folder the mmc is run? Any clues welcomed! :-)

Running a process with elevated privileges might result in different working directory for that process, that's why relative paths are not working.
If you do not want to use absolute paths, you have to find a way to get path to a directory where your application is located, and then append the relative paths to that.
You don't specify how you are running your tasks, but if it's from another .BAT file, then full path to the batch file's directory is stored under %~dp0 variable. You can look up answers to this question for more details.
And you can also always use tool like Process Explorer to view information about your running process, including working directory (it's called Current directory there).

Related

How does AutoHotkey determine which executable is launchable with a mere `.exe` name?

In my experience, #f::Run mailmaster will launch mailmaster.exe when pressing #f, but throws when doing #f::Run QQMusic:
I had to provide the full path for QQMusic.exe whereas I didn't have to provide the full path for mailmaster.exe.
According to the documentation:
Run can launch Windows system programs from any directory. Note that executable file extensions such as .exe can be omitted.
Run notepad
Since both mailmaster.exe and QQMusic.exe are non-system programs and they are not included in the Path environment variable, why AutoHotkey is giving different behaviors for them?
And performance-wise, providing the full path versus just the .exe name, which is faster?
It's specified in the documentation:
Target
A document, URL, executable file (.exe, .com, .bat, etc.), shortcut (.lnk), or system verb to launch (see remarks). If Target is a local file and no path was specified with it, A_WorkingDir will be searched first. If no matching file is found there, the system will search for and launch the file if it is integrated ("known"), e.g. by being contained in one of the PATH folders.
So pretty much if it's found in PATH.
You can try this for example by typing notepad, mailmaster and QQMusic in cmd or powershell. Notepad is found in PATH, and on your system I'm assuming mailmaster is as well, and QQMusic isn't.
You should get the same results as with the AHK Run command.
As for performance, I don't know, I guess this is something you could benchmark.
I'd guess that providing the full path is more efficient.
But maybe finding something from PATH is very well optimized on the the Windows side of things, so maybe there is little to no difference.

Windows Screensaver Installation Location

I have written my own screensaver, which makes use of additional files located at the same directory as the screensaver executable (.scr file).
If I right-click on the screensaver and select 'Test', all is well, those extra files are found.
But if I right-click and click on 'Install' to install the screensaver, it seems to not be able to find those files anymore.
Does the installation process make another copy of screensaver, or maybe change the working directory? If so, what directory is it in?
It's a Windows 7 desktop.
So far I have searched in Windows folder, Program Files, Program Files (x86).
UPDATE:
So, I added the following bit of code to determine the executable's location.
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName
It appears that the screensaver is running from the directory where I put it, from the original file. However, after installing it, the only way I can reach files in the same folder from the executable is if I use full paths. If I run it as Test, I can simply use filenames only.
This should be a clue as to what is going on, I think. The above function, if I run it as Test, returns long file names, but if I run it as Installed, it returns short file names. I think that when Installed, it runs as some kind of a special process, or maybe a child process, which also interferes with file access.
What is going on?
I added a piece of code to determine the current working directory, and found that when running the screensaver in Installed mode, the current working directory becomes C:\Windows\system32, which would of course explain how files are referenced.
Environment.CurrentDirectory

Working directories of files used in Windows applications

Where does an application look when a file is searched for? Where is it created? It's rarely realistic to always specify the absolute path. E.g. I tried saving text files that were going to be used in a Visual Studio 2010 app in the local bin of the project solution, but always got a run-time error.
It's usually the folder it was called from. You can find it using _getcwd: http://msdn.microsoft.com/en-us/library/sf98bd4y%28VS.80%29.aspx
If you use a relative path, the path you supply is combined with the working directory of the process.
It's very hard to maintain control over the working directory of a GUI process. That's because GUI processes tend to be started in lots of different ways. What's more, file dialogs have a tendency to change working directory. Finally, the working directory is shared between all threads in the process, and can be changed by any thread. There are lots of pitfalls.
So in a GUI process I suggest that you never use relative paths. Or, if you do use relative paths, you convert them to absolute paths before using them. And perform that conversion against a well-defined root path.
Unless you are writing a portable app, you should not expect to be able to save to the directory which contains the executable file. On modern systems executable files are often located in read-only directories.
If you want to save user settings, save them at an appropriate location in the user's profile.
On the other hand, if you are wanting to read files, that you never modify, then it's reasonable to store them alongside the executable. But even in that case, open the file using a full absolute path. Create that path by combining the directory which contains the executable, with the relative path to the file.
So, to summarise, you said:
It's rarely realistic to always specify the absolute path.
But I disagree. I would counter that using an absolute path is very often the best option. But you don't have to hard code the absolute path. You can, and should, create it at runtime.

LoadLibrary from another DLL

The DLL lookup path, as described in MSDN is:
The directory where the executable module for the current process is located.
The current directory.
The Windows system directory. The GetSystemDirectory function retrieves the path of this directory.
The Windows directory. The GetWindowsDirectory function retrieves the path of this directory.
The directories listed in the PATH environment variable.
Which brings up the following doubt:
Suppose I have an executable in some directory, say: c:\execdir\myexe.exe and it loads a DLL that's found in PATH and is located in c:\dlldir\mydll.dll. Now, suppose mydll.dll tries to load another DLL with LoadLibrary. Which directory will be looked at first - c:\dlldir or c:\execdir?
I think that the lookup rules quoted above say it's going to be c:\execdir because that's allegedly "the directory where the executable module for the current process is located", but it would be nice to get a confirmation from another source.
EDIT: Also, is c:\dlldir\ looked at at all? After all, it's neither where the .exe is located, nor the "current directory" (if that is meant in the general sense).
P.S. I'm interested in both Windows XP and 7.
Yes, it is the executable directory first and it was realised this could lead to a security vulnerability under certain circumstances. There is advice on that page for ensuring your application is not compromised via this mechanism.

Proper usage of the windows user profile directory

I need to create a directory inside a windows users 'home' directory (c:\Documents and Settings\someusername\ or c:\users\someusername\). This directory will exist permanently but will only contain temporary files.
What is is the best location for this directory within the users profile if I want to be a good citizen? I should note that my program will be run by (possibly) non-admin users and will only need access to their own profile, but they must have permission to create the folder.
Using My Documents\NameOfMyApp\ is possible I guess, but that seems intrusive.
Is there a better location for this type of data, and a specific MFC call to access it?
I'd consider using the AppData directory. You can get its location with SHGetSpecialFolderLocation passing it CSIDL_APPDATA; (or a number of alternatives -- nearly every version of Windows adds a new replacement for SHGetSpecialFolderLocation, SHGetSpecialFolderPath, or (often) both).
Take a look at the following win32 calls:
GetUserProfileDirectory
GetAllUsersProfileDirectory
GetDefaultUserProfileDirectory
You probably want to use GetUserProfileDirectory and put your data in a sub-directory with your appname.
You will definitely want to use the function because there is no "\documents and settings" folder on vista and up, they changed to it "\user".
Being a good application citizen, you should use:
[drive]:\Documents and Settings[username]\Application Data[AppName] or
[drive]:\Documents and Settings[username]\Local Settings\Application Data[AppName]
(On Vista and Win7, "Documents and Settings" is replaced, most sensibly with "Users")
The environment variable USERPROFILE will provide the, you guessed it, User Profile Path.
The TEMP path provides the path to the user's individual temp directory
If the temp files aren't user-specific, you could use C:\temp
EDIT: If you are to use a user-specific location, I highly recommend that you use the environment variables (USERPATH on XP and 2000) rather than hard-coding the paths.
-Waldo
P.S. Thank you for asking this. I see bad behaviour from Waaaay too many applications. The root of the C: drive is not where you should be dumping things! At the very least, (test for the presence of, creating if necessary, and) use C:\Temp.

Resources