检测在C#中使用openas_rundll打开选定的程序 [英] detect selected program opened using openas_rundll in c#

查看:152
本文介绍了检测在C#中使用openas_rundll打开选定的程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我打开使用带有openas_rundll在C#中的帮助打开文件对话框的文件。

I am opening a file using openfile dialog with the help of openas_rundll in c#.

Process.Start("rundll32.exe", string.Format("shell32.dll,OpenAs_RunDLL \"{0}\"", tempFilePath));

现在我要检测该程序用来打开该文件。我想跟踪的过程。

Now I want to detect which program is used to open the file. I want to trace the process.

我的目标是要删除的文件,当用户关闭程序。请告诉我怎样才能做到这一点。我需要紧急援助。

My goal is to delete the file when user close the program. Please tell me how can I achieve this. I need an urgent help.

推荐答案

您可以尝试找到它PY父进程ID赶时刻实际的应用程序被关闭。如果你找到了,你可以等待它,只要它是可以接受关闭。由于杰里米 - 默里获得的 GetAllProcessParentPids 的方法

You can try to catch the moment when actual app is closed by finding it py parent process id. If you found it, you can wait it to close as long as it is acceptable. Thanks jeremy-murray for GetAllProcessParentPids method:

public void StartProcessAndWathTillTerminated(string tempFilePath)
{
    // Show app selection dialog to user
    Process rundll32 = Process.Start("rundll32.exe", string.Format("shell32.dll,OpenAs_RunDLL {0}", tempFilePath));
    int rundll32id = rundll32.Id;

    // Wait till dialog is closed
    while (!rundll32.HasExited)
    {
        System.Threading.Thread.Sleep(50);
    }

    // Get all running processes with parent id
    Dictionary<int, int> allprocparents = GetAllProcessParentPids();

    int openedAppId = 0;
    // Loop throu all processes
    foreach (var allprocparent in allprocparents)
    {
        // Found child process, started by our rundll32.exe instance
        if (allprocparent.Value == rundll32id)
        {
            openedAppId = allprocparent.Key;
            break;
        }
    }

    // Check if we actually found any process. It can not be found in two situations:
    // 1) Process was closed too soon, while we was looking for it
    // 2) User clicked Cancel and no application was opened
    // Also it is possible that chesen application is already running. In this
    // case new instance will be opened by rundll32.exe for a very short period of 
    //time needed to pass file path to running instance. Anyway, this case falls into case 1).

   //If we ca not find process explicitly, we can try to find it by file lock, if one exists:
   //I'm using here a code snippet from http://stackoverflow.com/a/1263609/880156,
   //which assumes that there are possible more than one lock on this file. 
   //I just take first. 
   if (openedAppId==0)
    {
        Process handleExe = new Process();
        handleExe.StartInfo.FileName = "handle.exe";
        handleExe.StartInfo.Arguments = tempFilePath;
        handleExe.StartInfo.UseShellExecute = false;
        handleExe.StartInfo.RedirectStandardOutput = true;
        handleExe.Start();           
        handleExe.WaitForExit();
        string outputhandleExe = handleExe.StandardOutput.ReadToEnd();

        string matchPattern = @"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
        foreach(Match match in Regex.Matches(outputhandleExe, matchPattern))
        {
            openedAppId  = int.Parse(match.Value);
            break;
        }
    }


    if (openedAppId != 0)
    {
        Process openedApp = Process.GetProcessById(openedAppId);
        while (!openedApp.HasExited)
        {
            System.Threading.Thread.Sleep(50);
        }
    }
    // When we reach this position, App is already closed or was never started.
}


public static Dictionary<int, int> GetAllProcessParentPids()
{
    var childPidToParentPid = new Dictionary<int, int>();

    var processCounters = new SortedDictionary<string, PerformanceCounter[]>();
    var category = new PerformanceCounterCategory("Process");

    // As the base system always has more than one process running, 
    // don't special case a single instance return.
    var instanceNames = category.GetInstanceNames();
    foreach(string t in instanceNames)
    {
        try
        {
            processCounters[t] = category.GetCounters(t);
        }
        catch (InvalidOperationException)
        {
            // Transient processes may no longer exist between 
            // GetInstanceNames and when the counters are queried.
        }
    }

    foreach (var kvp in processCounters)
    {
        int childPid = -1;
        int parentPid = -1;

        foreach (var counter in kvp.Value)
        {
            if ("ID Process".CompareTo(counter.CounterName) == 0)
            {
                childPid = (int)(counter.NextValue());
            }
            else if ("Creating Process ID".CompareTo(counter.CounterName) == 0)
            {
                parentPid = (int)(counter.NextValue());
            }
        }

        if (childPid != -1 && parentPid != -1)
        {
            childPidToParentPid[childPid] = parentPid;
        }
    }

    return childPidToParentPid;
}



更新

似乎有成功的100%保证无解的原因有很多。
我认为,通过发现RUNDLL32.EXE启动的进程是所有其他中最坚实的。如果失败了,你仍然能够用一些其他的方法来确定进程ID完成它。

It seems that there is no solution with 100% guarantee of success due to many reasons. I think that finding a process started by rundll32.exe is most solid among all other. If it fails, you still able to complete it with some other methods to determine process id.

据我所知,还有其他一些方法可以找到这个文件是仍在使用。 WINWORD.EXE,例如,在创建同一目录下的一些临时文件,并关闭时删除它们。所以,如果你能赶上的临时文件片刻删除,那么你可以假设程序被关闭。

As far as i know, there are several other ways to find that file is still used. Winword.exe, for example, creates some temp files in same directory and removes them when it closes. So if you able to catch a moment of temp files deleting then you may assume that program been closed.

其他程序可能会将您的文件通过它设置一个锁打开。如果是这样,你可以找到发现锁所有者的计划。我用外部程序handle.exe的解决方案,从这个答案 http://stackoverflow.com/a/1263609/880156 ,所以来看看。

Other programs may hold your file open by setting a lock on it. If so, you can find that program by finding lock owner. I used a solution with external program handle.exe from this answer http://stackoverflow.com/a/1263609/880156, so take a look.

我不得不提,那有可能是没有永久文件锁的。它依赖于程序结构。例如,如果用Firefox打开HTML文件时,它读取文件一样快,它可以和关闭它并不会留下文件锁定不动了。在这种情况下,即使你找到某种进程名(如firefox.exe),您将无法在用户关闭与您的文件标签找到一个时刻。

I have to mention, that there may be no permanent file lock at all. It depend on program architecture. For example, if you open html file with Firefox, it reads file as fast as it can and closes it and does not leave file locked no more. In this case, even if you somehow find process name (e.g. "firefox.exe"), you will not able to find a moment when user closes a tab with your file.

如果我是你,我会实现这个解决方案仍然不理想,以后我会型升级它,如果它是必要的。

If i were you, i would implement this solution, that still not ideal, and i would updgrade it later if it is necessary.

这篇关于检测在C#中使用openas_rundll打开选定的程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆