1

In my MainWindow I have a button that can be used to open a Process (native OpenProcess call) and perform some checks on it's memory, but the method called on Click is asynchronous:

<Button Content="Attach" Click="OnClickAttach"/>

private async void OnClickAttach(Object sender, RoutedEventArgs e)
{
    AttachmentResult result = await m_ViewModel.Attach();

    switch (result)
        // Different MessageBox depending on the result.
}

Now, let's see the ViewModel portion of code...

// MemoryProcess class is just a wrapper for Process' handle and memory regions.
private MemoryProcess m_MemoryProcess;

public async Task<AttachmentResult> Attach()
{
    AttachmentResult result = AttachmentResult.Success;
    MemoryProcess memoryProcess = NativeMethods.OpenProcess(m_SelectedBrowserInstance.Process);

    if (memoryProcess == null)
        result = AttachmentResult.FailProcessNotOpened;
    else
    {
        Boolean check1 = false;
        Boolean check2 = false;

        foreach (MemoryRegion region in memoryProcess)
        {
            // I perform checks on Process' memory regions and I eventually change the value of check1 or check2...
            await Task.Delay(1);
        }

        if (!check1 && !check2)
        {
            NativeMethods.CloseHandle(memoryProcess.Handle);
            result = AttachmentResult.FailProcessNotValid;
        }
        else
        {
            // I keep the Process opened for further use. I save it to a private variable.
            m_MemoryProcess = memoryProcess;
            m_MemoryProcess.Check1 = check1;
            m_MemoryProcess.Check2 = check2;
        }
    }

    return result;
}

Now... here comes the problem. When the user closes the application, if a Process is opened, I must properly close its handle. So in my MainWindow I have the following code:

protected override void OnClosing(CancelEventArgs e)
{
    m_ViewModel.Detach();
    base.OnClosing(e);
}

And in my ViewModel I have the following code:

public void Detach()
{
    if (m_MemoryProcess != null)
    {
        if (m_MemoryProcess.Check1)
            // Do something...

        if (m_MemoryProcess.Check2)
            // Do something...

        NativeMethods.CloseHandle(m_MemoryProcess.Handle);
        m_MemoryProcess = null;
    }
}

The Attach() method can take very long time, more than 2 minutes sometimes. I need to find a solution for the following issues:

  • If the user closes the application while Attach() method is running and before memoryProcess is saved to the private variable, the Process handle will not be closed.
  • If I save the MemoryProcess instance to the private variable just at the beginning of the Attach() method, there is a risk for the user to get a NullReferenceException if he closes the application while the Attach() method is processing its foreach loop.
  • I absolutely don't want to make the user wait for Attach() method to complete before letting him close the application. That's horrible.

How can I do this?

Tommaso Belluzzo
  • 23,232
  • 8
  • 74
  • 98
  • How about when they close the application, if the asyc call didn't finish... just hide the window until its finished, then close the actual application when its done – Steve's a D May 14 '13 at 20:08
  • That's also odd because the method is quite CPU intensive and if the application is going to be closed when it finishes... well, what's the point?! The best would be stopping it completely... that's what I'm trying to do. – Tommaso Belluzzo May 14 '13 at 20:12
  • You should be using SafeWin32Handle instead of IntPtr so that you can dispose of the handler instead of closing it (i.e. the GC will dispose of it if you forget. For example: `public static extern SafeWin32Handle OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);` – Peter Ritchie May 14 '13 at 20:21
  • Yes but the problem doesn't change. I always have to close or dispose the handle when it's needed and I have to keep it opened until the user closes the application. – Tommaso Belluzzo May 14 '13 at 20:36
  • It is unclear what you are worrying about. Windows automatically cleans up any handles that were not closed by the app. – Hans Passant May 14 '13 at 21:48
  • @Hans Passant I wasn't thinking about this. What's your opinion about using a TaskCancellationSource instead? – Tommaso Belluzzo May 15 '13 at 00:27

1 Answers1

1

IMO, if you do not explicitly and specifically target to create separate detached/independent processes like, for example, through:

  • using PInvoke.CreateProcess
  • using

    (new System.Management.ManagementClass("Win32_ProcessStartup"))
    .Properties["CreateFlags"].Value = 8;
    
  • or maintaining child process alive upon app closing by launching them through separate shell scripts or other processes remaining to run after app closing;

  • creating a new thread in another independent process using CreateRemoteThread
  • etc.

or finding already run independently processes, you don't need to and probably should not "close" or dispose spawned by app processes. Windows (operting system) will close any unclosed spawned by app processes.

Also, I believe that it is impossible to execute any code in an application once it has started exiting or being closed.

PS (off-topic comment):
I do not even see that you close (really one should kill) or dispose your processes in your code...

Community
  • 1
  • 1