Repository: microsoft/terminal
File: src/winconpty/winconpty.cpp (C++)

Code before:
// Function Description:
// - Tell the ConPTY about the state of the hosting window. This should be used
//   to keep ConPTY's internal HWND state in sync with the state of whatever the
//   hosting window is.
// - For more information, refer to GH#12515.
extern "C" HRESULT WINAPI ConptyShowHidePseudoConsole(_In_ HPCON hPC, bool show)
{
    // _ShowHidePseudoConsole will return E_INVALIDARG for us if the hPC is nullptr.
    return _ShowHidePseudoConsole((PseudoConsole*)hPC, show);
}

// - Sends a message to the pseudoconsole informing it that it should use the
//   given window handle as the owner for the conpty's pseudo window. This
//   allows the response given to GetConsoleWindow() to be a HWND that's owned
//   by the actual hosting terminal's HWND.
// - Used to support GH#2988
extern "C" HRESULT WINAPI ConptyReparentPseudoConsole(_In_ HPCON hPC, HWND newParent)
{
    return _ReparentPseudoConsole((PseudoConsole*)hPC, newParent);
}

// - Sends a message to the pseudoconsole informing it that it should
//   exit as soon as all console clients have disconnected.
extern "C" HRESULT WINAPI ConptySetPseudoConsoleAutoExit(_In_ HPCON hPC)
{
    return _SetPseudoConsoleAutoExit((PseudoConsole*)hPC);
}

// Function Description:
// Closes the conpty and all associated state.
// Client applications attached to the conpty will also behave as though the
//      console window they were running in was closed.
// This can fail if the conhost hosting the pseudoconsole failed to be
//      terminated, or if the pseudoconsole was already terminated.
// Waits for conhost/OpenConsole to exit first.
extern "C" VOID WINAPI ConptyClosePseudoConsole(_In_ HPCON hPC)
{
    _ClosePseudoConsole((PseudoConsole*)hPC, INFINITE);
}

// Function Description:
// Closes the conpty and all associated state.
// Client applications attached to the conpty will also behave as though the
//      console window they were running in was closed.
// This can fail if the conhost hosting the pseudoconsole failed to be
//      terminated, or if the pseudoconsole was already terminated.
// Doesn't wait for conhost/OpenConsole to exit.
extern "C" VOID WINAPI ConptyClosePseudoConsoleTimeout(_In_ HPCON hPC, _In_ DWORD dwMilliseconds)
{
    _ClosePseudoConsole((PseudoConsole*)hPC, dwMilliseconds);
}

Review comment (suggestion):
#4564 makes a good point about:
> On POSIX systems the master end will receive an EOF when all processes that use the slave have terminated or closed the connection.

...should we maybe make auto-exit the default? It might however make a session reconnect feature a bit more difficult in the future (since you might not want OpenConsole to exit in that case).

BTW this is a good point to talk about why I made this new API the way it is: An alternative approach would've been to allow a user to specify an event handle, which OpenConsole could signal whenever all clients have disconnected. A ConPTY user could then choose to call `ClosePseudoConsole`. But I'm very confident in saying that this is probably not what most people want from ConPTY. Instead the above POSIX behavior seems way simpler to use: Just read from your pipes until the pipes are EOF. Boom, done. In fact this is even sufficient for WT, since we don't have a session reconnect feature yet either.

Code after:
//   by the actual hosting terminal's HWND.
// - Used to support GH#2988
extern "C" HRESULT WINAPI ConptyReparentPseudoConsole(_In_ HPCON hPC, HWND newParent)
{
    return _ReparentPseudoConsole((PseudoConsole*)hPC, newParent);
}

// The \Reference handle ensures that conhost keeps running by keeping the ConDrv server pipe open.
// After you've finished setting up your PTY via PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, this method may be called
// to release that handle, allowing conhost to shut down automatically once the last client has disconnected.
// You'll know when this happens, because a ReadFile() on the output pipe will return ERROR_BROKEN_PIPE.
extern "C" HRESULT WINAPI ConptyReleasePseudoConsole(_In_ HPCON hPC)
{
    const auto pPty = (PseudoConsole*)hPC;
    if (pPty == nullptr)
    {
        return E_INVALIDARG;
    }

    if (_HandleIsValid(pPty->hPtyReference))
    {
        CloseHandle(pPty->hPtyReference);
        pPty->hPtyReference = nullptr;
    }

    return S_OK;
}

// Function Description:
// Closes the conpty and all associated state.
// Client applications attached to the conpty will also behave as though the
//      console window they were running in was closed.
// This can fail if the conhost hosting the pseudoconsole failed to be
//      terminated, or if the pseudoconsole was already terminated.
// Waits for conhost/OpenConsole to exit first.
extern "C" VOID WINAPI ConptyClosePseudoConsole(_In_ HPCON hPC)
{
    _ClosePseudoConsole((PseudoConsole*)hPC, INFINITE);
}

// Function Description:
// Closes the conpty and all associated state.
// Client applications attached to the conpty will also behave as though the
//      console window they were running in was closed.
// This can fail if the conhost hosting the pseudoconsole failed to be
//      terminated, or if the pseudoconsole was already terminated.
// Doesn't wait for conhost/OpenConsole to exit.
extern "C" VOID WINAPI ConptyClosePseudoConsoleTimeout(_In_ HPCON hPC, _In_ DWORD dwMilliseconds)
{
    _ClosePseudoConsole((PseudoConsole*)hPC, dwMilliseconds);
}