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.
Related
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).
What happens when an executable tries to access a .DLL that isn't loaded ?
Does it try to find it at system32 folder and load it or something else?
Also can someone please explain to me where in the ram .DLL are saved and referenced, I tried researching online but didn't find many good answers...
Thanks in advance
The best description for the search processed used that I've been able to find is in the documentation for LoadLibrary at MSDN. An excerpt from the Remarks section of that documentation:
When no path is specified, the function searches for loaded modules whose base name matches the base name of the module to be loaded. If the name matches, the load succeeds. Otherwise, the function searches for the file.
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. If a relative path is specified, the entire relative path is appended to every token in the DLL search path list. To load a module from a relative path without searching any other path, use GetFullPathName to get a nonrelative path and call LoadLibrary with the nonrelative path. For more information on the DLL search order, see Dynamic-Link Library Search Order.
The search path can be altered using the SetDllDirectory function. This solution is recommended instead of using SetCurrentDirectory or hard-coding the full path to the DLL.
If a path is specified and there is a redirection file for the application, the function searches for the module in the application's directory. If the module exists in the application's directory, LoadLibrary ignores the specified path and loads the module from the application's directory. If the module does not exist in the application's directory, LoadLibrary loads the module from the specified directory. For more information, see Dynamic Link Library Redirection.
If you call LoadLibrary with the name of an assembly without a path specification and the assembly is listed in the system compatible manifest, the call is automatically redirected to the side-by-side assembly.
Let's say I have this at the top of a module:
Public Declare Function getCustomerDetails Lib "CustomerFunctions" () As Long
If I am running the program from the VB6 IDE, where should CustomerFunctions.dll be located?
If I am running the program executable, where should CustomerFunctions.dll be located?
When loading a standard DLL (rather than an ActiveX or COM dll), Windows applies the following rules;
If SafeDllSearchMode is turned on:
The Program directory.
The system directory. Either (Windows\System32 or Windows\SysWow64 depending if you are running on 64 bit or not).
The 16-bit system directory (Windows\System).
The Windows directory.
The current directory.
All directories that in the PATH environment variable.
If SafeDllSearchMode is disabled, the search order is as follows:
The Program directory.
The current directory.
The system directory. Either (Windows\System32 or Windows\SysWow64 depending if you are running on 64 bit or not).
The 16-bit system directory (Windows\System).
The Windows directory.
All directories that in the PATH environment variable.
My personal preference (rather than litter the System or Windows directory) is to create a developmentDLLs directory somewhere and add it to the PATH variable. When distributing the application place the DLL in the program's App directory. This way you have the least chance of interferring with other DLL's. For complete information on the loading of the DLL's see the MSDN.
Since this is not an ActiveX DLL, somewhat different rules apply.
When running in the IDE you could place it in either c:\windows\system32 or in the directory from which VB6 is running (e.g. c:\program files\microsoft visual studio...).
When running the program executable outside of VB6, you can place the DLL into either c:\windows\system32 or the application directory.
Keep in mind that I gave you a technical answer (e.g. placing the file into c:\windows\system32), which will work. However, the trend in the last decade has been to isolate the necessary components into the application directory.
I'm beginner in programming. Can somebody please explain (by simple words) what do I have inside the bin directory of program?
What is this PATH environment variable of windows, how does it work (please don't think that I don't know how to use Google, I just want to understand it more clearly)?
You usually put all the binary files for a program in the bin directory. This would be the executable itself and any dlls (dynamic link libraries) that the program uses.
This isn't essential as Windows use the PATH environment variable to look for dlls your program needs. This is a list of folders that Windows searches, in order, when it can't find a dll (say) in the current directory.
So if you want to have a dll used by more than one program you could put it in a location already on the PATH or add a new folder to the PATH.
I want to put my dependent files in the app directory.
I seem to remember that you can force VB6 to use the files in the local directory only.
Any hints?
You may also want to try setting up Reg-Free COM for your project. There's a freeware called Unattended Make My Manifest that will do most of the work for you.
Placing component libraries in the EXE folder (with or without .local files) can be deleterious to the hygiene of target machines too.
VB6 programs will register the components here via the self-reg entrypoint behind your back if they are not previously registered. Then if the application is moved or removed you leave the user with a broken reigistration - possibly fatal to subsequently installed applications using some of the same components. This is probably fine though for application specific components, i.e. your own DLL or OCX that will never be needed by another application.
The .local trick was really not meant for use with VB6 programs and if it is used your installer needs to be aware and properly install and register the components if they are not already on the machine. It was meant as a manual hack to get around DLL version compatibility problems on individual machines, not a deployment strategy.
Move up to SxS application and assembly manifests (Reg-Free COM and more) for a better solution. DLL/COM Redirection (.local) was a good try but it has many warts.
Clay Nichol's answer about the search order is not quite correct. That search order only applies to non-COM components. I.e. only some DLLs, and not OCXs. If you register your COM objects, they will be used from the directory where they are registered regardless of what's in the local directory, unless you use reg-free COM or a .local file.
EDIT:
MakeMyManifest is well spoken of as an automatic tool for creating manifests for VB6 projects, haven't tried it myself.
DirectCOM also has fans, again I haven't tried it.
EDIT The MMM website is down. I see here that the author was having trouble with their hosting and has provided another location to get Make My Manifest - download it here.
There is a semi-automatic technique to generate reg-free COM manifests. You can create the manifests with Visual Studio 2008 (you can use a free version like Visual Basic Express Edition). Then make a couple of edits by hand to make the manifests suitable for use from VB6. See this section of this MSDN article for step-by-step instructions - ignore the rest of the article which is about ClickOnce.
It can be sort of confusing because every version of windows, the rules change. Older versions of Windows search the path before the current directory.
A simple solution without manifests:
If your executable file is A.EXE, add a (0-byte, empty) file in the same directory named A.EXE.local -- for older versions of Windows this puts the app directory ahead of the path in the search order.
Found it myself:
Windows does look in the App Directory first:
If SafeDllSearchMode is enabled, the search order is as follows:
The directory from which the application loaded.
The system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The current directory.
The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.
If SafeDllSearchMode is disabled, the search order is as follows:
1. The directory from which the application loaded.
2. The current directory.
3. The system directory. Use the GetSystemDirectory function to get the path of this directory.
4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.
according to : http://msdn.microsoft.com/en-us/library/ms682586.aspx
But you can redirect where it looks for .dll's using a Manifest:
http://msdn.microsoft.com/en-us/library/aa375365(VS.85).aspx