2010-07-07 106 views
9

我已经看到很多从Google搜索返回的帖子,但是其中没有提到任何解决方案可以帮我解决这个问题。所以,我想我会尝试自己。Application.Quit()方法无法清除进程

的代码块之后:

PowerPoint.Application powerPoint = new Microsoft.Office.Interop.PowerPoint.Application(); 
powerPoint.Visible = Office.MsoTriState.msoTrue; 
Microsoft.Office.Interop.PowerPoint.Presentation ppt = null;enter code here 

我可以发出ppt.Quit();命令和Powerpoint将关闭,并且没有进程继续运行。

但是,如果此代码后,我这样做:

ppt = powerPoint.Presentations.Open(localCopyOfPPT, 
            Microsoft.Office.Core.MsoTriState.msoCTrue, 
            Microsoft.Office.Core.MsoTriState.msoTriStateMixed, 
            Microsoft.Office.Core.MsoTriState.msoTrue); 
ppt.Close(); 
powerPoint.Quit(); 

然后,退出()将无法工作。即使我关闭它,关于打开演示文稿的某些内容也会阻止Quit()正常工作,但它会显示。

任何人都有关于如何让应用程序退出正确的任何想法?

+0

如果您提供关于失败模式的更多详细信息而不是“Quit()将不起作用”,这将有所帮助。 – 2010-07-07 17:24:42

+0

对不起。我尝试使用Quit()方法的目的是防止应用程序离开正在运行的Powerpoint进程。 Quit()失败,因为它正在运行Powerpoint。它没有错误,但它也不会结束这个过程。 – Henry 2010-07-07 19:54:25

回答

6

以下KB Aritcle可能会帮助您解决问题的根本。 http://support.microsoft.com/kb/317109

您可能需要明确地在您的ppt实例上调用System.Runtime.InteropServices.Marshal.ReleaseComObject

+0

看起来像运行ReleaseComObject是票。我不得不声明一个Presentations对象,并在它和ppt对象上运行ReleaseComObject方法。一旦我释放了这两个对象,Application.Quit()就起作用,并且没有Powerpoint.exe进程继续运行。这解决了我用代码继承的一个问题,并且长期以来一直在唠叨我。非常感谢您的帮助。 – Henry 2010-07-08 12:04:29

3

powerPoint.Presentations.Open(..)

注意使用演示文稿的对象。 COM使用基于引用计数的手动内存管理,每个COM接口都有一个AddRef()和一个Release()方法。获取对象时,AddRef调用是自动的。当你完成它时,你必须调用Release()方法。在此处使用演示文稿对象会添加对演示文稿对象的引用。这反过来又添加了对内部应用程序对象的引用。

这与.NET框架中的内存管理非常不兼容。它是自动的,垃圾收集器负责照顾它。它也为COM对象所做的事情,互操作包装器有一个终结器,当它看到COM对象上没有.NET引用时,它会减少引用计数。

也许你看到了这里:PowerPoint不能退出,直到所有的对象引用被释放。直到垃圾收集器运行并且终结器线程完成后才能发生。您对Quit()方法的调用确实是而不是使垃圾收集器运行。只有GC.Collect()+ GC.WaitForPendingFinalizers可以做到这一点。

您也可以采取手动方法。它需要Marshal.ReleaseComObject()。这样做很难做到,请注意,您没有对代码中任何位置存储的Presentations对象的引用。您必须完全重写代码才能跟踪这些引用,以便可以在其上调用ReleaseComObject()。

我不能推荐这个。如果你真的真的想要PowerPoint退出,那么更好的方法是确保所有的引用都为空,并调用GC.Collect()和GC.WFPF。我也不能推荐这个。它最终会退出。不要担心。

2

我面对我的工作同样的问题...你试试下面的代码它的工作

PowerPoint.Application powerPoint = new Microsoft.Office.Interop.PowerPoint.Application(); 
    //powerPoint.Visible = Office.MsoTriState.msoTrue; 
    Microsoft.Office.Interop.PowerPoint.Presentation ppt = null; 

    try 
    { 
     ppt = powerPoint.Presentations.Open(localCopyOfPPT, 
              Microsoft.Office.Core.MsoTriState.msoCTrue, 
              Microsoft.Office.Core.MsoTriState.msoTriStateMixed, 
              Microsoft.Office.Core.MsoTriState.msoFalse); 
    ppt.Close(); 
    Marshal.FinalReleaseComObject(ppt); 
    }catch(){}finally 
    { 
     powerPoint.Quit(); 
     Marshal.FinalReleaseComObject(powerPoint); 
     GC.Collect(); 
    } 
3

替代你的问题。一旦工作完成,找到过程,然后杀死它。

代码:

Process[] processes = Process.GetProcessesByName("powerpnt"); 
for (int i = 0; i < processes.Count(); i++) 
{ 
    processes[i].Kill(); 
} 

命名空间: System.Diagnostics程序

+3

为什么不'Process.GetProcessesByName(“POWERPNT”)? – 2013-07-18 09:24:33

+1

这个解决了我的问题,谢谢, – 2013-09-02 07:18:22

1

如果您有PowerPoint的多个实例打开,你可以使用的东西沿着这些路线 - 这是我发现关闭PowerPoint应用程序时最简单的方法,当被要求退出时,它们不会清除。

这是我如何结束杀戮/关闭的PowerPoint(通过文件指定的路径已经打开)

/// <summary> 
    /// Close open PowerPoint document 
    /// </summary> 
    /// <param name="path">Path to document</param> 
    /// <param name="saveChanges">Save changes to document</param> 
    public void PowerPointCloseOpenDocument(String path, Boolean saveChanges = true) 
    { 
     ppApp = getPowerPointApp(path); 
     PowerPoint.Presentation pp = null; 

     if (!String.IsNullOrEmpty(path)) 
     { 
      foreach (PowerPoint.Presentation p in ppApp.Presentations) 
      { 
       if (p.FullName.Equals(path, StringComparison.CurrentCultureIgnoreCase)) 
       { 
        try 
        { 
         pp = p; 
        } 
        catch (Exception) 
        { } 
        break; 
       } 
      } 
     } 
     if(saveChanges) 
     { 
      if(pp!=null) 
      { 
       pp.Save(); 
      } 
     } 
     if(pp!= null) 
     { 
      Marshal.FinalReleaseComObject(pp); 
     } 
     if(null != ppApp) 
     { 
      Marshal.FinalReleaseComObject(ppApp); 
     } 
     var procs = FileUtil.WhoIsLocking(path); 
     if(procs!= null) 
     { 
      foreach(var proc in procs) 
      { 
       proc.Kill(); 
      } 
     } 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
    } 

private PowerPoint.Application getPowerPointApp(String path = "") 
    { 
     try 
     { 
      PowerPoint.Application ppapp = null; 
      try 
      { 
       if (!String.IsNullOrEmpty(path)) 
       { 
        ppapp = ((PowerPoint.Presentation)System.Runtime.InteropServices.Marshal.BindToMoniker(path)).Application; 
       } 
      } 
      catch (Exception) { } 
      if (ppapp == null) 
      { 
       try 
       { 
        ppapp = (PowerPoint.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("PowerPoint.Application"); 
       } 
       catch (Exception) 
       { 
        ppapp = new PowerPoint.Application(); 
        ppapp.Visible = Microsoft.Office.Core.MsoTriState.msoTrue; 
       } 
      } 
      if (ppapp != null) 
      { 
       ppapp.DisplayAlerts = Microsoft.Office.Interop.PowerPoint.PpAlertLevel.ppAlertsNone; 
      } 
      try { ppapp.Activate(); } 
      catch (Exception) { } 
      return ppapp; 
     } 
     catch (Exception) 
     { 
      return (PowerPoint.Application)Activator.CreateInstance(Type.GetTypeFromProgID("PowerPoint.Application")); 
     } 
    } 

文件的Util类为您提供了目前锁定文件的进程列表。

static public class FileUtil 
{ 
    [StructLayout(LayoutKind.Sequential)] 
    struct RM_UNIQUE_PROCESS 
    { 
     public int dwProcessId; 
     public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; 
    } 

    const int RmRebootReasonNone = 0; 
    const int CCH_RM_MAX_APP_NAME = 255; 
    const int CCH_RM_MAX_SVC_NAME = 63; 

    enum RM_APP_TYPE 
    { 
     RmUnknownApp = 0, 
     RmMainWindow = 1, 
     RmOtherWindow = 2, 
     RmService = 3, 
     RmExplorer = 4, 
     RmConsole = 5, 
     RmCritical = 1000 
    } 

    [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; 
    } 

    [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", CharSet = CharSet.Auto)] 
    static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey); 

    [DllImport("rstrtmgr.dll")] 
    static extern int RmEndSession(uint pSessionHandle); 

    [DllImport("rstrtmgr.dll")] 
    static extern int RmGetList(uint dwSessionHandle, 
           out uint pnProcInfoNeeded, 
           ref uint pnProcInfo, 
           [In, Out] RM_PROCESS_INFO[] rgAffectedApps, 
           ref uint lpdwRebootReasons); 

    /// <summary> 
    /// Find out what process(es) have a lock on the specified file. 
    /// </summary> 
    /// <param name="path">Path of the file.</param> 
    /// <returns>Processes locking the file</returns> 
    /// <remarks>See also: 
    /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx 
    /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing) 
    /// 
    /// </remarks> 
    static public List<Process> WhoIsLocking(string path) 
    { 
     uint handle; 
     string key = Guid.NewGuid().ToString(); 
     List<Process> processes = new List<Process>(); 

     int res = RmStartSession(out handle, 0, key); 
     if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker."); 

     try 
     { 
      const int ERROR_MORE_DATA = 234; 
      uint pnProcInfoNeeded = 0, 
       pnProcInfo = 0, 
       lpdwRebootReasons = RmRebootReasonNone; 

      string[] resources = new string[] { path }; // Just checking on one resource. 

      res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null); 

      if (res != 0) throw new Exception("Could not register resource."); 

      //Note: there's a race condition here -- the first call to RmGetList() returns 
      //  the total number of process. However, when we call RmGetList() again to get 
      //  the actual processes this number may have increased. 
      res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); 

      if (res == ERROR_MORE_DATA) 
      { 
       // Create an array to store the process results 
       RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; 
       pnProcInfo = pnProcInfoNeeded; 

       // Get the list 
       res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); 
       if (res == 0) 
       { 
        processes = new List<Process>((int)pnProcInfo); 

        // Enumerate all of the results and add them to the 
        // list to be returned 
        for (int i = 0; i < pnProcInfo; i++) 
        { 
         try 
         { 
          processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); 
         } 
         // catch the error -- in case the process is no longer running 
         catch (ArgumentException) { } 
        } 
       } 
       else throw new Exception("Could not list processes locking resource."); 
      } 
      else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result."); 
     } 
     finally 
     { 
      RmEndSession(handle); 
     } 

     return processes; 
    }  
}