A question about emulating openpty with the new CreatePseudoConsole API #455

Closed
opened 2026-01-30 21:52:45 +00:00 by claunia · 8 comments
Owner

Originally created by @sad75 on GitHub (Nov 25, 2018).

Hello,

I wanted to use the new CreatePseudoConsole() API to implement Pythonos.openpty() in order to ease the use of Visual Studio Python environment.
In Python, the call just returns the master and slave file descriptors.
However I'm not able to find out a way to map the HANDLEs to the master/slave file descriptors.
My understanding is that the new API uses unidirectional pipe HANDLE and that the file descriptors are bidirectional.

Do you have already an example of an emulation of Linux openpty() on Windows using the new API?

Thank You

Originally created by @sad75 on GitHub (Nov 25, 2018). Hello, I wanted to use the new` CreatePseudoConsole()` API to implement Python`os.openpty()` in order to ease the use of Visual Studio Python environment. In Python, the call just returns the master and slave file descriptors. However I'm not able to find out a way to map the HANDLEs to the master/slave file descriptors. My understanding is that the new API uses unidirectional pipe HANDLE and that the file descriptors are bidirectional. Do you have already an example of an emulation of Linux `openpty()` on Windows using the new API? Thank You
claunia added the Issue-QuestionResolution-AnsweredArea-ServerProduct-Conpty labels 2026-01-30 21:52:45 +00:00
Author
Owner

@Ivan171 commented on GitHub (Nov 26, 2018):

Have you tried _open_osfhandle to a get file descriptor from the HANDLE?

@Ivan171 commented on GitHub (Nov 26, 2018): Have you tried [_open_osfhandle](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/open-osfhandle?view=vs-2017l) to a get file descriptor from the HANDLE?
Author
Owner

@sad75 commented on GitHub (Nov 26, 2018):

Yes, this is what I planned to do.

However in the example below, the API is associate to 4 PIPE HANDLEs, 2 for the slave part and 2 for the MASTER part.

HRESULT SetUpPseudoConsole(COORD size)
{
    HRESULT hr = S_OK;

    // Create communication channels

    // - Close these after CreateProcess of child application with pseudoconsole object.
    HANDLE inputReadSide, outputWriteSide; 

    // - Hold onto these and use them for communication with the child through the pseudoconsole. 
    HANDLE outputReadSide, inputWriteSide; 

    if (!CreatePipe(&inputReadSide, &inputWriteSide, NULL, 0))
    {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    if (!CreatePipe(&outputReadSide, &outputWriteSide, NULL, 0))
    {
        return HRESULT_FROM_WIN32(GetLastError())
    }

    hr = CreatePseudoConsole(size, inputReadSide, outputWriteSide, 0, &hPC);
    if (FAILED(hr))
    {
        return hr;
    }

    // ... 

}

The openpty API returns only 2 file descriptors, but they are read/write (bidirectional).

@sad75 commented on GitHub (Nov 26, 2018): Yes, this is what I planned to do. However in the example below, the API is associate to 4 PIPE HANDLEs, 2 for the slave part and 2 for the MASTER part. ``` HRESULT SetUpPseudoConsole(COORD size) { HRESULT hr = S_OK; // Create communication channels // - Close these after CreateProcess of child application with pseudoconsole object. HANDLE inputReadSide, outputWriteSide; // - Hold onto these and use them for communication with the child through the pseudoconsole. HANDLE outputReadSide, inputWriteSide; if (!CreatePipe(&inputReadSide, &inputWriteSide, NULL, 0)) { return HRESULT_FROM_WIN32(GetLastError()); } if (!CreatePipe(&outputReadSide, &outputWriteSide, NULL, 0)) { return HRESULT_FROM_WIN32(GetLastError()) } hr = CreatePseudoConsole(size, inputReadSide, outputWriteSide, 0, &hPC); if (FAILED(hr)) { return hr; } // ... } ``` The `openpty `API returns only 2 file descriptors, but they are read/write (bidirectional).
Author
Owner

@zadjii-msft commented on GitHub (Nov 26, 2018):

@sad75 I'd take a look at this sample code:

https://github.com/Microsoft/console/blob/master/samples/ConPTY/EchoCon/EchoCon/EchoCon.cpp#L91-L122

That function is going to:

  1. Create a pair of anonymous pipes for use with the pseudoconsole
  2. Get the size of the console window the app is currently running in. That sample is a console app, so it's already running in the console, but for your use case you can probably omit this, and pass the size you're expecting the pseudoconsole to be into that function.
  3. It then creates the conpty using the pipes from before.
  4. It then closes our handles to the master side of the conpty. The Pseudoconsole has already duped those handles into it's process space, so we need to make sure to close them in our process to correctly refcount the pipes. We won't need them anymore.

When the function returns, the parameters will be filled with the values you need:

  1. the HPCON can be used with other Pseudoconsole functions to manipulate it. You'll need that to:
  • attach child processes (see this sample)
  • resize the pseudoconsole
  • close the pseudoconsole when you're done with it.
  1. phPipeIn and phPipeOut can be used for reading the output from and writing input to the conpty. It's true that the HANDLEs returned by this API are not bi-directional, though managing a pair of unidirectional pipes is trivially harder than a single bidirectional pipe.

I agree that having a sample openconpty (and forkconpty) function might be helpful, especially for people who are solely familiar with linux. Obviously the signatures wouldn't be exactly the same, but if anyone wants to throw a sample together, I'd happily review the PR :)

@zadjii-msft commented on GitHub (Nov 26, 2018): @sad75 I'd take a look at this sample code: https://github.com/Microsoft/console/blob/master/samples/ConPTY/EchoCon/EchoCon/EchoCon.cpp#L91-L122 That function is going to: 1. Create a pair of anonymous pipes for use with the pseudoconsole 2. Get the size of the console window the app is currently running in. That sample is a console app, so it's already running in the console, but for your use case you can probably omit this, and pass the size you're expecting the pseudoconsole to be into that function. 3. It then creates the conpty using the pipes from before. 4. It then closes our handles to the master side of the conpty. The Pseudoconsole has already duped those handles into it's process space, so we need to make sure to close them in our process to correctly refcount the pipes. We won't need them anymore. When the function returns, the parameters will be filled with the values you need: 1. the HPCON can be used with other Pseudoconsole functions to manipulate it. You'll need that to: * attach child processes (see [this sample](https://github.com/Microsoft/console/blob/master/samples/ConPTY/EchoCon/EchoCon/EchoCon.cpp#L126-L165)) * resize the pseudoconsole * close the pseudoconsole when you're done with it. 2. `phPipeIn` and `phPipeOut` can be used for reading the output from and writing input to the conpty. It's true that the HANDLEs returned by this API are not bi-directional, though managing a pair of unidirectional pipes is trivially harder than a single bidirectional pipe. I agree that having a sample `openconpty` (and `forkconpty`) function might be helpful, especially for people who are solely familiar with linux. Obviously the signatures wouldn't be *exactly* the same, but if anyone wants to throw a sample together, I'd happily review the PR :)
Author
Owner

@miniksa commented on GitHub (May 18, 2019):

Looks like question answered to me. Closing.

@miniksa commented on GitHub (May 18, 2019): Looks like question answered to me. Closing.
Author
Owner

@marcomorain commented on GitHub (Aug 26, 2019):

@sad75 did you manage to get this to work in the end? I'm having the same problem trying to make the Windows PTY match the Linux API for a golang project. The existing code that I'm porting to Windows expects a single file handle where it can both read and write to the same file.

What did you see?

@marcomorain commented on GitHub (Aug 26, 2019): @sad75 did you manage to get this to work in the end? I'm having the same problem trying to make the Windows PTY match the Linux API for a `golang` project. The existing code that I'm porting to Windows expects a single file handle where it can both read and write to the same file. ![What did you see?](https://imgs.xkcd.com/comics/wisdom_of_the_ancients.png)
Author
Owner

@sad75 commented on GitHub (Oct 2, 2019):

@marcomorain
Sorry for my late answer. No, I haven't find a solution.

@sad75 commented on GitHub (Oct 2, 2019): @marcomorain Sorry for my late answer. No, I haven't find a solution.
Author
Owner

@Kreijstal commented on GitHub (Jul 26, 2024):

@marcomorain did you find a solution?

@Kreijstal commented on GitHub (Jul 26, 2024): @marcomorain did you find a solution?
Author
Owner

@fdmarc commented on GitHub (Jul 26, 2024):

No I never did, and I've since changed company, so I can no longer check how my previous company have solved this problem.

@fdmarc commented on GitHub (Jul 26, 2024): No I never did, and I've since changed company, so I can no longer check how my previous company have solved this problem.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#455