如何判断用户何时在Paint.NET中编辑文件?

时间:2010-12-16 02:32:36

标签: .net windows filesystemwatcher

我想写一个截图应用程序抓取屏幕截图,将其保存到文件中,使用该文件打开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接口,我可以在其中查询它已打开的文件?这符合我的目的。

2 个答案:

答案 0 :(得分:0)

不幸的是,没有更好的方法。编辑附件时,Microsoft Outlook等应用程序也存在同样的问题。您可以尝试通过采用上述方法进行最佳猜测。

例如,当您的应用程序在炮轰到Paint.NET(或者它们关联的任何编辑器)后再次变为活动状态时,您可以检查文件是否已更改,如果已完成则可能会提示。如果该过程关闭,您可以使用它作为一个非常明确的标志,表明它们已完成并跳过提示。如果文件系统观察程序检测到更改,则可以将这些更改排队,直到Paint.NET不再处于活动状态等等。

但是许多应用程序在编辑文件时不会对文件进行任何锁定。我很确定Paint.NET没有。像Office那样的应用程序可能就是为什么从Outlook编辑Word / Excel附件比纯文本文件更可靠的原因。

答案 1 :(得分:0)

稍微摆弄一下,我认为UI Automation会满足。使用.NET 3.0中新增的System.Windows.Automation类,我可以查询机器上其他Windows的内容,并且可以找到给定进程ID的窗口。

这是一个问题
  • 通过System.Diagnostics.Process.GetProcesses
  • 中的搜索找到PaintDotNet.exe进程
  • 获取PaintDotNet应用程序主窗口的AutomationElement
  • 检查该窗口的"name" property
  • 当它从“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类附加到它。