0

I want to display a tiff file using shell execute. I am assuming the default app is the photoviewer. My Problem is that when i want to kill the process with photoviewer.Kill() i get an System.InvalidOperationException. When setting a breakpoint after photoViewer.Start() i realised that photoviewer does not conatain an Id. I there a sufficent way to kill it? As it runs via dllhost.exe i do not want to retrun all processes named dllhost and kill them all since i do not know what else is run by dllhost.

Process photoViewer = new Process();
  private void StartProcessUsingShellExecute(string filePath)
        {
            photoViewer.StartInfo = new ProcessStartInfo(filePath);
            photoViewer.StartInfo.UseShellExecute = true;
            photoViewer.Start();
        }

I have another approach without shell execute but this approach seems to have dpi issues. Approach without shell execute

Little-God
  • 183
  • 1
  • 3
  • 16
  • 1
    Why don't you create a simple graphic interface and show the TIFF yourself? Otherwise, you can get the Window that's showing the Image after and close it (send `WM_CLOSE`). – Jimi Nov 11 '20 at 07:31
  • Already tried that in wpf using tiffBitmapDecoder. The files i display are 100 - 500 mb. I need to be able to zoom and scroll. Problem is that the performance and memory consumption is much worse using WPF/C#. And i thought to myself why not use what is already there. – Little-God Nov 11 '20 at 07:42

1 Answers1

0

Found a solution, may help anyone with a similar problem. When i looked into the task manager i found that the windows 10 photoviewer runs detached from the application via dllhost. So since i have 4 dllhost processes up and running and just want to close the window. I do:

        private void StartProcessAsShellExecute(string filePath)
    {
        photoViewer.StartInfo = new ProcessStartInfo(filePath);
        photoViewer.StartInfo.UseShellExecute = true;
        photoViewer.Start();

        Process[] processes = Process.GetProcessesByName("dllhost");

        foreach (Process p in processes)
        {
            IntPtr windowHandle = p.MainWindowHandle;
            CloseWindow(windowHandle);
            // do something with windowHandle
        }


        viewerOpen = true;
    }


    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    //I'd double check this constant, just in case
    static uint WM_CLOSE = 0x10;

    public void CloseWindow(IntPtr hWindow)
    {
        SendMessage(hWindow, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
    }

that closes all dllhost windows (of which i have just 1, the photoviewer)

Little-God
  • 183
  • 1
  • 3
  • 16
  • A couple of notes: if you do that in my PC, you actually start PhotoShop instead, it's the default viewer for TIFFs. You could start `rundll32.exe` with arguments `$"\"C:\\Program Files\\Windows Photo Viewer\\PhotoViewer.dll\", ImageView_Fullscreen {fileName}"`, where `fileName` is the full path Image to show. At this point, the Process object you started refers to the the `rundll32.exe` process that holds the PhotoViewer Window, so you can just `.Kill()` it and it will close the Window. Or be gentle and call `[Process].CloseMainWindow()` instead :) – Jimi Nov 11 '20 at 09:01
  • Of course you should use `Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);` to get the path of the `Program Files` folder in a machine. -- You could also parent the viewer Window with a Window or Form of your app and show it as a child Window. – Jimi Nov 11 '20 at 09:05
  • Thanks for your input. I tried that before this approach. The problem is with this the photoviwer runs on a low dpi Setting. I have high res scanner images ca. 15649 x 10975 px in 300dpi. It may look fine on a "24 Display in 1080p but i have to display it on a 4K 75" Screen. I couldnt figure out how to change the DPI Awareness context in c# for a certain process. – Little-God Nov 11 '20 at 09:14
  • If you mean showing the Image yourself or *hosting* PhotoViewer, in a GUI app, well, if you build a WPF app, that's not a problem, it's DpiAware by default. A WinForms app requires that you set the DpiAwareness yourself. You need `PerMonitorV2` DpiAwarenes in Windows 10 and target .Net Framework 4.7.2+. See the `app.config` settings in [High DPI support in Windows Forms](https://learn.microsoft.com/en-us/dotnet/desktop/winforms/high-dpi-support-in-windows-forms). – Jimi Nov 11 '20 at 09:26