Using Application Profiling to Detect Dynamic Dependencies


Dependency Walker version 2.0 adds application profiling, a technique used to watch a running application to see what modules it loads. This allows Dependency Walker to detect dynamically loaded modules that are not necessarily reported in any on the import tables of other modules. Dependency Walker's profiler can also detect when a module fails to initialize, which often results in the "The application failed to initialize properly" error.

When a module is first opened by Dependency Walker, it is immediately scanned for all implicit, delay-load, and forwarded dependencies (for more information on dependency types, see the Types of Dependencies Handled By Dependency Walker section). Once all the modules have been scanned, the results are displayed. In addition to these known dependencies, modules are free to load other modules at run-time without any prior warning to the operating system. These types of dependencies are known as dynamic or explicit dependencies. There is really no way to detect dynamic dependencies without actually running the application and watching it to see what modules it loads at run-time. This is exactly what Dependency Walker's application profiling does.

For profiling to work, the module you open in Dependency Walker has to be an executable file (usually ends with .EXE) that is designed to run on the system you are working with. If not, the Start Profiling menu option and toolbar button will not be enabled. When you choose to profile an application, your application should begin to run. As your application runs, Dependency Walker will gather information and log it to the Log View, as well as update the other views.

It is the job of the user to "exercise" the application to ensure that all dynamic dependencies are found. Usually dynamic dependencies are only loaded when needed. For example, modules related to printing might only be loaded if the application actually prints. In a case like this, if the application does not perform a print while being profiled, then Dependency Walker will not detect those modules related to printing. Other modules might only get loaded if an error occurs in the application. Scenarios like these might be hard to produce. Because of this, It is impossible to guarantee that all dynamic dependencies are found, but the more an application is exercised, the better the odds are of finding them.

Dependency Walker's application profiler tracks every module that gets loaded and attempts to determine which module actually requested the file to be loaded. This allows dynamically loaded modules to be inserted into the Module Dependency Tree View as a child of the module that actually loaded the module.

The profiler works by hooking particular function calls in the remote process being profiled. On Windows 95, Windows 98, and Windows Me, only non-system modules can be hooked. The result is that when a system module dynamically loads another module, the profiler cannot tell who the parent module is for the dynamically loaded module. Parentless modules like these will be added to the root of the Module Dependency Tree View. All modules that are loaded due to a system-wide hook will also be added to the root of the Module Dependency Tree View since these types of modules are loaded directly by the OS and have no parent module. Even though Dependency Walker may not be able to detect the parent of a dynamic dependency, it does guarantee that all modules that get loaded by the application will be detected.

One final benefit of the profiler is that it can correct the paths of any modules that may have been incorrectly determined during the initial implicit module scan. When you first open a module in Dependency Walker, it recursively scans all the import and export tables of modules to build the initial module hierarchy. Only file names are stored in these tables, so dependency walker uses the rules you have set up in the Module Search Order Dialog to determine the full path to each module. During profiling, Dependency Walker examines the real path of each module as they load and compares them to the modules in the tree. If a module loads from a different path than Dependency Walker expected it to load from, then it will update the module hierarchy and other views to reflect the change.