2010-12-16 24 views
0

我想写一个屏幕截图的应用程序,抓取屏幕快照,保存到一个文件,打开Paint.NET与该文件,然后上传当用户完成编辑在Paint.NET该文件的编辑文件的服务。如何知道用户何时在Paint.NET中完成编辑文件?

我有其他的东西排序覆盖。如何检测图像在Paint.NET中完成编辑的时间?

我正在使用.NET 3.5,C#。

我可以用一个FileSystemWatcher来检测特定文件的变化。但是第一次文件改变并不一定表明Paint.NET已经完成。我可以等待Paint.NET退出 - 我想通过检查Windows中的进程列表并检测Paint.NET何时不在那里。但是用户可以在不实际关闭Paint.NET的情况下完成编辑文件。

如果我必须告诉用户关闭Paint.NET,以表示该文件就可以上传,我想我能做到这一点。但我希望避免这种额外的要求。

如果Paint.NET保存一个文件在编辑时打开进行读取,那么我想我可以试着看看。但是如何?也许通过轮询,试图用FileShare.None打开文件。

有没有更好的方法?


编辑 - 不,Paint.NET不保留文件打开,甚至不读。我可以打开一个图像文件FileShare.None没有问题,即使它正在被Paint.NET显示/编辑。所以这个想法是行不通的。


Paint.NET是否有一个Remoting接口,在那里我可以询问它打开了哪些文件?这将适合我的目的。

回答

0

与此摆弄一点点之后,我觉得UI自动化将满足。使用.NET 3.0中新增的System.Windows.Automation类,我可以查询计算机上其他Windows的内容,并且可以找到给定进程ID的窗口。所以这是一个问题

  • 找到PaintDotNet。通过在System.Diagnostics.Process.GetProcesses
  • 为PaintDotNet应用
  • 检查窗口的"name" property的主窗口获得所述AutomationElement搜索EXE过程。
  • 当它从“myfile.jpg”变成别的东西时,我知道Paint.NET有 停止编辑该文件。
  • 如果我得到一个ElementNotAvailableException,那意味着Paint.NET已经退出。

我没有测试这个非常多,但是,这个代码似乎为我的目的工作:

public void Run() 
{ 
    var shortFileName = Path.GetFileName(_filename); 
    System.Console.WriteLine("Waiting for PDN to finish with {0}", shortFileName); 

    var s= from p in Process.GetProcesses() 
     where p.ProcessName.Contains("PaintDotNet.exe") 
     select p; 

    if (s.Count()==0) 
    { 
     System.Console.WriteLine("PDN is not running."); 
     return; 
    } 

    var process = s.First(); 
    var window = AutomationElement.RootElement.FindChildByProcessId(process.Id); 

    string name = 
     window.GetCurrentPropertyValue(AutomationElement.NameProperty) as string; 

    if (!name.StartsWith(shortFileName)) 
    { 
     System.Console.WriteLine("PDN appears to NOT be editing the file."); 
    } 
    else 
    { 
     try 
     { 
      int cycles = 0; 
      do 
      { 
       System.Threading.Thread.Sleep(800); 
       name = window.GetCurrentPropertyValue(AutomationElement.NameProperty) as string; 
       if (!name.StartsWith(shortFileName)) break; 
       cycles++; 
       System.Console.Write("."); 
      } while (cycles < 24); 

      if (!name.StartsWith(shortFileName)) 
       System.Console.WriteLine("PDN is done."); 
      else 
       System.Console.WriteLine("Timeout."); 
     } 
     catch (ElementNotAvailableException) 
     { 
      System.Console.WriteLine("PDN has exited."); 
     } 
    } 
} 

FindChildByProcessId方法是this blog post扩展方法。它看起来像这样:

public static class AutomationExtensions 
{ 
    public static AutomationElement FindChildByProcessId(this AutomationElement element, int pid) 
    { 
     var cond = new PropertyCondition(AutomationElement.ProcessIdProperty, pid); 
     var result = element.FindChildByCondition(cond); 
     return result; 
    } 

    public static AutomationElement FindChildByCondition(this AutomationElement element, Condition cond) 
    { 
     var result = element.FindFirst(TreeScope.Children, cond); 
     return result; 
    } 
} 

这似乎有点非正统,但它,它只是工作。最棘手的部分是时间 - 你需要等待足够长的时间让应用程序启动,可以是1秒,也可以是7秒。然后尝试使用UIAutomation类附加到它。

0

不幸的是,没有更好的办法。像Microsoft Outlook这样的应用程序在编辑附件时遇到同样的问题。你可以尝试采取全面的方法做出最好的猜测。

例如,当您的应用程序脱壳而出,以Paint.NET(或不管他们有关联的编辑器),你可以检查,看看是否该文件已经改变,如果他们这样做,也许提示后再次变得活跃。如果流程关闭,您可以将其作为一个非常确定的标志,表明他们已经完成并跳过提示。如果文件系统观察检测的变化,你可以排队的,直到Paint.NET不再活动等

但在编辑它的许多应用程序将不会举行任何类型的锁在文件上。我很确定Paint.NET不会。 Office等应用程序可能会这样做,这可能是为什么从Outlook编辑Word/Excel附件比纯文本文件更可靠的原因。

相关问题