Welcome

首页 / 软件开发 / .NET编程技术 / .NET相关问题: Restart Manager和泛型方法编译

.NET相关问题: Restart Manager和泛型方法编译2012-01-26 MSDN Stephen Toub问:在应用程序尝试访问文件时,我收到了拒绝访问错误,原因是其他应用程序正在使用该文件。以前,我使用 Sysinternals (microsoft.com/technet/sysinternals) 的工具来确定是哪个应用程序,但我希望能够通过编程的方式从我的应用程序中发现这一点。是否能够通过编程的方式确定哪些进程当前正在使用某个特定文件?

问:在应用程序尝试访问文件时,我收到了拒绝访问错误,原因是其他应用程序正在使用该文件。以前,我使用 Sysinternals (microsoft.com/technet/sysinternals) 的工具来确定是哪个应用程序,但我希望能够通过编程的方式从我的应用程序中发现这一点。是否能够通过编程的方式确定哪些进程当前正在使用某个特定文件?

答:已经有几个人问过我这个问题了,但每次都无法回答,因为迄今为止,我还没有找到答案。您可以通过内核模式驱动程序获得有关当前由任意进程打开的文件的信息,但是迄今为止还没有已记录的用户模式 Win32® 或 Microsoft® .NET Framework API 可以提供该信息。但是,随着 Windows Vista™ 的发布,通过一些技巧,可以从用户模式应用程序中确定此信息。但 API 文档还没有给这个方法进行适当地命名。相反,想得稍微远一点,您会惊奇地发现 Restart Manager API。

答:已经有几个人问过我这个问题了,但每次都无法回答,因为迄今为止,我还没有找到答案。您可以通过内核模式驱动程序获得有关当前由任意进程打开的文件的信息,但是迄今为止还没有已记录的用户模式 Win32® 或 Microsoft® .NET Framework API 可以提供该信息。但是,随着 Windows Vista™ 的发布,通过一些技巧,可以从用户模式应用程序中确定此信息。但 API 文档还没有给这个方法进行适当地命名。相反,想得稍微远一点,您会惊奇地发现 Restart Manager API。

Restart Manager API 是 Windows Vista 的新增功能,其目的是为了减少软件安装过程中需要系统重新启动的次数。软件安装和升级需要系统重新启动的主要原因是,正在运行的进程占用着安装程序需要访问的文件。Restart Manager API 通过允许安装程序有秩序地关闭 Restart Manager 发现的占用安装程序需要访问的资源的应用程序来解决这一冲突。在此过程中,Restart Manager API 允许安装程序查询占用着前面安装程序需要的资源的进程。然而,最妙的是,任何应用程序都可被视为“安装程序”。因此,任何应用程序都可以使用这些 Restart Manager API 来查询正在占用特定资源的其他进程。因此,我可以编写一个方法(将参数作为到冲突文件的路径),该方法可以使用 Restart Manager API 收集使用该文件的进程列表。

.NET Framework 3.0 不包含 Restart Manager API 的托管等效项,因此我需要通过神奇的 P/Invoke 提供自己的等效项。我的目的是需要访问四个函数,从 rstrtmgr.dll 可以访问所有这四个函数,每个函数的 P/Invoke 定义都显示在图 1 中(注意,除了这四个函数之外,Restart Manager API 还包含很多其他函数,但只需这四个函数就能实现我的目的了)。

Figure 1 主要 Restart Manager API 的 P/Invoke 声明

[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,  UInt32 nFiles, string[] rgsFilenames,  UInt32 nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications,  UInt32 nServices, string[] rgsServiceNames);[DllImport(“rstrtmgr.dll”)]static extern int RmGetList(uint dwSessionHandle,  out uint pnProcInfoNeeded, ref uint pnProcInfo,  [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,  RmConsole = 5,  RmCritical = 1000}