Q: When the application tried to access the file, I received an Access denied error because the file was being used by another application. Previously, I used the Sysinternals (microsoft.com/technet/sysinternals) tool to determine which application it was, but I wanted to be able to programmatically discover this from my application. Can you programmatically determine which processes are currently using a particular file?
Q: When the application tried to access the file, I received an Access denied error because the file was being used by another application. Previously, I used the Sysinternals (microsoft.com/technet/sysinternals) tool to determine which application it was, but I wanted to be able to programmatically discover this from my application. Can you programmatically determine which processes are currently using a particular file?
A: A few people have asked me this question, but I can't answer it every time, because so far I haven't found the answer. You can obtain information about files that are currently open by any process through kernel-mode drivers, but so far there is no documented user-mode win32® or Microsoft®.net Framework APIs that can provide this information. However, with the release of Windows Vista™, there are some tricks you can use to determine this information from a user-mode application. However, the API documentation has not been properly named for this method. Instead, think a little further and you'll be surprised to find the restart Manager API.
A: A few people have asked me this question, but I can't answer it every time, because so far I haven't found the answer. You can obtain information about files that are currently open by any process through kernel-mode drivers, but so far there is no documented user-mode win32® or Microsoft®.net Framework APIs that can provide this information. However, with the release of Windows Vista™, there are some tricks you can use to determine this information from a user-mode application. However, the API documentation has not been properly named for this method. Instead, think a little further and you'll be surprised to find the restart Manager API.
The restart Manager API is a new feature of Windows Vista to reduce the number of system reboots that are required during software installation. The main reason that software installation and upgrades require a system reboot is that the running process occupies the files that the installer needs to access. The Restart Manager API resolves this conflict by allowing the installer to orderly shut down applications found by restart Manager that occupy the resources the installer needs to access. During this process, the restart Manager API allows the installer to query the processes that occupy the resources required by the previous installer. However, the best of all is that any application can be considered an "installer." Therefore, any application can use these restart Manager APIs to query other processes that are consuming specific resources. So, I can write a method that takes a parameter as a path to a conflicting file, and it can use the restart Manager API to collect a list of the processes that use the file.
The. NET Framework 3.0 does not contain managed equivalents for the restart Manager API, so I need to provide my own equivalents through the magic P/invoke. My goal is to access four functions, all of which can be accessed from Rstrtmgr.dll, and the p/invoke definition of each function is shown in Figure 1 (note that the restart Manager API contains many other functions, in addition to these four functions, But only these four functions can achieve my purpose.
Figure 1 P/invoke Declaration of the main restart Manager API
[DllImport ("Rstrtmgr.dll", CharSet = CharSet.Unicode)] static extern int rmstartsession (out uint Psessionhandle,
int dwsessionflags, string strsessionkey);
[DllImport ("Rstrtmgr.dll")] static extern int rmendsession (UINT psessionhandle); [DllImport ("Rstrtmgr.dll", CharSet = CharSet.Unicode)] static extern int rmregisterresources (UINT psessionhandle, UINT3 2 Nfiles, string[] rgsfilenames, UInt32 napplications, [in] rm_unique_process[] rgapplications, UInt32 nservices, Stri
Ng[] rgsservicenames); [DllImport ("Rstrtmgr.dll")] static extern int rmgetlist (UINT dwsessionhandle, out uint pnprocinfoneeded, ref uint Pnproc
Info, [in, out] rm_process_info[] Rgaffectedapps, ref uint lpdwrebootreasons);
Private Const int rmrebootreasonnone = 0;
Private Const int cch_rm_max_app_name = 255;
Private Const int cch_rm_max_svc_name = 63;
[StructLayout (layoutkind.sequential)] struct rm_unique_process {public int dwprocessid;
Public FILETIME Processstarttime; } [StructLayout (Layoutkind.sequential, CharSet = charset.unicode)] struct Rm_process_info {public rm_unique_process PROCESS;
[MarshalAs (UnmanagedType.ByValTStr, SizeConst = cch_rm_max_app_name + 1)] public string strappname;
[MarshalAs (UnmanagedType.ByValTStr, SizeConst = cch_rm_max_svc_name + 1)] public string strserviceshortname;
Public Rm_app_type Applicationtype;
public UINT Appstatus;
public UINT Tssessionid;
[MarshalAs (Unmanagedtype.bool)] public Bool brestartable; Enum Rm_app_type {rmunknownapp = 0, Rmmainwindow = 1, Rmotherwindow = 2, Rmservice = 3, Rmexplorer = 4, RmC Onsole = 5, rmcritical = 1000}