Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Getting Processes That Use A Module

module use file in use tool help library win api

  • Please log in to reply
No replies to this topic

#1 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 28 December 2012 - 12:21 AM

Overview

Have you ever had to replace or update a module only to get "file-in-use" error? When the module used only by your own application, the solution would be simple. Terminate your application. But sometimes you either use "public" module(s) or your own module that you have allowed to be used by other application. In this case you need to know which running processes that use the module, then you could choose to terminate them to proceed with the module's maintenance.

In this article I will show you how to get a list of running processes that use a module.


Tool Help Library

Fortunately for us, Windows has provided libraries to help us getting details on running processes. One of the easiest to use is Tool Help Library. It's the library we will use for our current problem.

Side note:

There is another article I have written previously that also dealt with Tool Help Library. It's about getting running processes information. If you interested, read it here.



Code Flow

Basically this is the flow of our routine


Get list of running processes
for each processes
Get list of modules
for each module
if the module is the same with our module
add the process to the returned list


Implementation

We will implement the solution as a procedure that will take two parameters. First parameter specifies the module, and the second one is an instance of TStrings to accept the list of processes that use the module. see inside the TStrings inside to We will name this procedure GetModuleUsers.

Since our code will use Tool Help Library, we are going to use TlHelp32 unit. Because in Delphi Tool Help Library is imported into this unit. So put TlHelp32 in your uses list.


Get List of Running Processes

This is done by taking a snapshot of currently running processes by calling Tool Help Library CreateToolhelp32Snapshot function, passing constant TH32CS_SNAPPROCESS for the first parameter (dwFlags), and 0 for the second one (th32ProcessID). Actually in this case th32ProcessID will simply be ignored. But it is a good practice to use "safe" value.


Walking the Processes

After getting the snapshot, details for each process can be obtained by using Tool Help Library Process32First and Process32Next. Call Process32First just once, to obtain the very first process information. The rest of the processes information should be obtained with Process32Next. Both functions return boolean value indicating whether there is next process available to query or not. You should stop querying once either of these two returns false.

Both functions require handle to the processes snapshot (which we got from previous call to CreateToolhelp32Snapshot with TH32CS_SNAPPROCESS) and variable to accept process details (if the call returns true).

When you through walking the processes (i.e. when either Process32First or Process32Next returns false), you need to "free" the snapshot. Do this using Windows API CloseHandle, passing the snapshot handle.

The following code pattern could be used for this case.

var
  // var to store handle to processes snapshot
  vProcessSnapshot: THandle;
  // var to store process' details
  vProcessEntry   : TProcessEntry32;
begin  
  // initiate the process information record
  vProcessEntry.dwSize := SizeOf(vProcessEntry);

  // Get snapshot of currently running processes
  vProcessSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  try
    // Get information of the first process
    if not Process32First(vProcessSnapShot, vProcessEntry) then Exit;

    repeat
      // here do what you need to do with the obtained process details
      ...
      ...
    until not Process32Next(vProcessSnapShot, vProcessEntry);

  finally
    CloseHandle(vProcessSnapShot);
  end;
end;


Get List of Currently Used Modules

We are still going to use CreateToolhelp32Snapshot to get list of modules currently used modules by a process. But this time we use constant TH32CS_SNAPMODULE for the first parameter (dwFlags), and the process id for second parameter (th32ProcessID). You get the process id information from, as you might already guessed, information returned by either Process32First or Process32Next previously.

TProcessEntry32 structure that we use to capture information returned by Process32First or Process32Next is simply an alias to PROCESSENTRY32 structure. I quote the structure details below.

typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
TCHAR szExeFile[MAX_PATH];
} PROCESSENTRY32, *PPROCESSENTRY32;


See the third member of this structure? Yes, it is what we are interested in.


Walking the Modules

Once we obtain the modules snapshot, we can retrieve details of each module using Module32First and Module32Next. Both functions expect two parameters. First parameter specifies the modules snapshot handle, and the second one a variable to store the module's details. The second parameter should be a variable of type TModuleEntry32 or similar.

Call Module32First just once to get the very first module information. Subsequent modules information should be fetched using Module32Next. Both functions return boolean value indicating whether there is next module available for querying. You should stop querying once any of them returns false.

You should note that the first module (the one returned by successful call to Module32First) always be the process' executable.

Similar with processes snapshot, you also need to "free" the modules snapshot using CloseHandle.

The following code pattern could be used for our case of walking the used modules. Note that the code assumes variable vProcessID has valid process id.

var
  // var to store handle to modules snapshot
  vModuleSnapshot: THandle;
  // var to store process' details
  vModuleEntry   : TModuleEntry32;
begin  
  // initiate the module information record
  vModuleEntry.dwSize := SizeOf(vModuleEntry);

  // Get snapshot of currently used modules of process associated with vProcessID
  vModuleSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, vProcessID);
  try
    // Get information of the first module, i.e. the executable of the process
    if Module32First(vModuleSnapShot, vModuleEntry) then
    begin
      // here do what you need to do with the process' executable information
      ...
      ...
      while Module32Next(vModuleSnapShot, vModuleEntry) do
      begin
        // here do what you need to do with the "real" used module details
        ...
        ...
      end;
    end;

  finally
    CloseHandle(vProcessSnapShot);
  end;
end;

TModuleEntry32 is an alias to MODULEENTRY32/tagMODULEENTRY32 structure. And I quote the declaration below.

typedef struct tagMODULEENTRY32 {
DWORD dwSize;
DWORD th32ModuleID;
DWORD th32ProcessID;
DWORD GlblcntUsage;
DWORD ProccntUsage;
BYTE *modBaseAddr;
DWORD modBaseSize;
HMODULE hModule;
TCHAR szModule[MAX_MODULE_NAME32 + 1];
TCHAR szExePath[MAX_PATH];
} MODULEENTRY32, *PMODULEENTRY32;


For our case we will be interested with szExePath member. Because this field specifies the file name and path of the module. By comparing to this field we could determine if the process is using our module or not.


Full Implementation

Below is the final code of our GetModuleUsers procedure.

uses
  ...
  , TlHelp32  // Tool Help Library is imported in this unit
  ...
  ;

procedure GetModuleUsers(const AModule: string; AUsers: TStrings);
var
  vProcessEntry: TProcessEntry32;
  vProcessSnapShot:THandle;
  vModuleSnapShot: THandle;
  vModuleEntry: TModuleEntry32;
begin
  // Get snapshot of currently running processes
  vProcessSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  try
    // initiate the process information record
    vProcessEntry.dwSize := SizeOf(vProcessEntry);

    // Get information of the first process
    if not Process32First(vProcessSnapShot, vProcessEntry) then Exit;

    // For each process:
    repeat
      // initiate the module information record
      vModuleEntry.dwSize := SizeOf(vModuleEntry);

      // get snapshot of modules used by the current process
      vModuleSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
                           vProcessEntry.th32ProcessID);
      try
        // get information of first module of current process
        if Module32First(vModuleSnapShot, vModuleEntry) then

          // here we ignore information returned from Module32First, because it
          // always returns detail of the process' executable

          // for each module
          while Module32Next(vModuleSnapShot, vModuleEntry) do
          begin
            // if the path of the module matches the checked module, add the
            // process into the "users" list
            if SameText(AModule, vModuleEntry.szExePath) then
              AUsers.Add(vProcessEntry.szExeFile);
          end;

      finally
        CloseHandle(vModuleSnapShot);
      end;

    until not Process32Next(vProcessSnapShot, vProcessEntry);

  finally
    CloseHandle(vProcessSnapShot);
  end;
end;


Demo Project

For this article I put together a demo project to show how to use GetModuleUsers. It's a simple Delphi application. With it you can type in or use file open dialog to specify a dynamic-link library file and then check which processes currently using it. Full source code of the demo project is available for download from the link given at the end of this article.

  • Upon running the demo project you will be presented with a display like shown below.

    RunTime_00.png
  • Now let's pick a module. For this show we will use a module from Windows that many applications will definitely use, user32.dll. Click on the small button at the right of the edit box to pop up an Open File dialog, and browse to System32 folder under your Windows folder. Once there find and select file user32.dll.

    RunTime_01_OpenModuleDialog.png
  • Now click on Check button to get a list of processes that use user32.dll. The list will be presented in the memo. Like shown below.

    RunTime_03_ProcessesList.png


There, now you have got the list of processes that use your module. Armed with this information, you can terminate the processes should you need to. We will talk about how to terminate a process in near future.

Attached File  Demo_Project1.zip   214.57KB   535 downloads
  • 1




Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download