0

I'm trying to create a short method that opens an image in the default image viewer, and after time milliseconds closes it.

Right now it looks like this:

    public static async void OpenImage(string path, int time)
    {
        var process = new Process();
        process.StartInfo.FileName = path;
        process.Start();
        await Task.Delay(time);
        process.Kill()
        process.Close()
    }

I can see the image, but then process.Kill() throws an InvalidOperationException, "No process is associated with this object."

Have I missed something or is there any other way to do it?


Update:

Also tested this now:

    public static async void OpenImage(string path, int time)
    {
        var process = Process.Start(path)
        await Task.Delay(time);
        process.Kill()
        process.Close()
    }

But then Process.Start() returns null. So maybe I have to call on the .exe directly like faljbour commented?

Chris O'Neill
  • 1,742
  • 12
  • 14
MilleB
  • 1,470
  • 2
  • 19
  • 32
  • I think your process terminated before you called kill on it, if you remove the kill() and close(), your exception might go away – faljbour Feb 22 '15 at 18:37
  • But then it will never close? I can still see that the image viewer is open so it's not that it close before I call on kill(). That's why I'm a bit confused by the exception. – MilleB Feb 22 '15 at 18:40
  • would you post the code the calls this OpenImage method, I would like to see what is in path. – faljbour Feb 22 '15 at 18:44
  • It's a bit long to post, but the path is just a normal path to an image on my computer, for example "C:\SomeFolder\image.png" – MilleB Feb 22 '15 at 18:50
  • but what executable are you trying to kill. You must be using an executable to show the image – faljbour Feb 22 '15 at 18:52
  • Yes, but if you don't have to set anything. It use the default viewer by the file type as I understand it. You find more information here http://stackoverflow.com/questions/6808029/open-image-in-windows-photo-viewer – MilleB Feb 22 '15 at 18:58
  • I would call the method WaitForExit() and see if it returns before you call process.kill, you can set it to wait for few seconds – faljbour Feb 22 '15 at 19:07
  • I just thought about this topic. The process.kill() is trying to kill the windows process that invoked the image viewer, that process invoked the viewer and terminated. To control the start and termination of the image viewer, I would recommend to call the exe of the image viewer. Let me know if you would like an example of how to invoke a viewer and have the image as a command line arugment. – faljbour Feb 23 '15 at 03:37

1 Answers1

6

The problem here is that you are not really starting a process, but rather passing a file path to the Windows Shell (explorer.exe) to handle. The shell figures out how to open the file and it starts the process.

When this happens your code doesn't get the process id back, so it doesn't know which process to kill.

What you should do, is find the default application for the file and then start that application explicitly (rather than letting the shell figure it out).

The most compact way I can think of to find the default application for a file is to use the Win32 API FindExecutable().


Things are complicated a little when the default application is contained within a dll. This is the case with the default Windows photo viewer (C:\Program Files (x86)\Windows Photo Viewer\PhotoViewer.dll). Since it is not a exe you cannot start it directly, however the application can be started using rundll32.


This should work for you:

[DllImport("shell32.dll")]
static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult);

public static async void OpenImage(string imagePath, int time)
{
    var exePathReturnValue = new StringBuilder();
    FindExecutable(Path.GetFileName(imagePath), Path.GetDirectoryName(imagePath), exePathReturnValue);
    var exePath = exePathReturnValue.ToString();
    var arguments = "\"" + imagePath + "\"";

    // Handle cases where the default application is photoviewer.dll.
    if (Path.GetFileName(exePath).Equals("photoviewer.dll", StringComparison.InvariantCultureIgnoreCase))
    {
        arguments = "\"" + exePath + "\", ImageView_Fullscreen " + imagePath;
        exePath = "rundll32";
    }

    var process = new Process();
    process.StartInfo.FileName = exePath;
    process.StartInfo.Arguments = arguments;

    process.Start();

    await Task.Delay(time);

    process.Kill();
    process.Close();
}

This code demonstrates the concept, but if you want to cater for more default applications with unusual argument formats (as shown by photoviewer.dll), you should search the registry yourself or use a third party library to find the correct command line to use.

For example,

Community
  • 1
  • 1
Chris O'Neill
  • 1,742
  • 12
  • 14
  • When I try this, I get a System.InvalidOperationException: 'Cannot start process because a file name has not been provided.', because exePath is empty – SideSky Nov 28 '22 at 11:14