node-pty 1.1.0-beta8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/binding.gyp +7 -4
- package/deps/winpty/src/agent/Agent.cc +11 -3
- package/deps/winpty/src/winpty.gyp +29 -1
- package/lib/conpty_console_list_agent.js +3 -7
- package/lib/conpty_console_list_agent.js.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/terminal.js.map +1 -1
- package/lib/terminal.test.js.map +1 -1
- package/lib/unixTerminal.js +78 -37
- package/lib/unixTerminal.js.map +1 -1
- package/lib/unixTerminal.test.js +3 -5
- package/lib/unixTerminal.test.js.map +1 -1
- package/lib/utils.js +23 -1
- package/lib/utils.js.map +1 -1
- package/lib/windowsConoutConnection.js +6 -3
- package/lib/windowsConoutConnection.js.map +1 -1
- package/lib/windowsPtyAgent.js +45 -48
- package/lib/windowsPtyAgent.js.map +1 -1
- package/lib/windowsTerminal.js +19 -21
- package/lib/windowsTerminal.js.map +1 -1
- package/lib/windowsTerminal.test.js +40 -26
- package/lib/windowsTerminal.test.js.map +1 -1
- package/lib/worker/conoutSocketWorker.js.map +1 -1
- package/package.json +6 -2
- package/prebuilds/darwin-arm64/pty.node +0 -0
- package/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/prebuilds/darwin-x64/pty.node +0 -0
- package/prebuilds/darwin-x64/spawn-helper +0 -0
- package/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/prebuilds/win32-arm64/conpty.node +0 -0
- package/prebuilds/win32-arm64/conpty.pdb +0 -0
- package/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
- package/prebuilds/win32-arm64/pty.node +0 -0
- package/prebuilds/win32-arm64/pty.pdb +0 -0
- package/prebuilds/win32-arm64/winpty-agent.exe +0 -0
- package/prebuilds/win32-arm64/winpty-agent.pdb +0 -0
- package/prebuilds/win32-arm64/winpty.dll +0 -0
- package/prebuilds/win32-arm64/winpty.pdb +0 -0
- package/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/prebuilds/win32-x64/conpty.node +0 -0
- package/prebuilds/win32-x64/conpty.pdb +0 -0
- package/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
- package/prebuilds/win32-x64/pty.node +0 -0
- package/prebuilds/win32-x64/pty.pdb +0 -0
- package/prebuilds/win32-x64/winpty-agent.exe +0 -0
- package/prebuilds/win32-x64/winpty-agent.pdb +0 -0
- package/prebuilds/win32-x64/winpty.dll +0 -0
- package/prebuilds/win32-x64/winpty.pdb +0 -0
- package/scripts/gen-compile-commands.js +8 -0
- package/scripts/{publish.js → increment-version.js} +7 -15
- package/scripts/post-install.js +48 -10
- package/scripts/prebuild.js +34 -0
- package/src/conpty_console_list_agent.ts +2 -6
- package/src/index.ts +2 -1
- package/src/interfaces.ts +2 -1
- package/src/native.d.ts +5 -5
- package/src/terminal.test.ts +1 -1
- package/src/terminal.ts +2 -2
- package/src/unix/pty.cc +27 -10
- package/src/unixTerminal.test.ts +3 -6
- package/src/unixTerminal.ts +101 -34
- package/src/utils.ts +20 -0
- package/src/win/conpty.cc +141 -55
- package/src/win/conpty.h +41 -0
- package/src/win/path_util.cc +23 -24
- package/src/windowsConoutConnection.ts +6 -3
- package/src/windowsPtyAgent.ts +42 -43
- package/src/windowsTerminal.test.ts +46 -33
- package/src/windowsTerminal.ts +24 -29
- package/src/worker/conoutSocketWorker.ts +2 -2
- package/third_party/conpty/1.23.251008001/win10-arm64/OpenConsole.exe +0 -0
- package/third_party/conpty/1.23.251008001/win10-arm64/conpty.dll +0 -0
- package/third_party/conpty/1.23.251008001/win10-x64/OpenConsole.exe +0 -0
- package/third_party/conpty/1.23.251008001/win10-x64/conpty.dll +0 -0
- package/typings/node-pty.d.ts +9 -1
package/src/win/conpty.cc
CHANGED
|
@@ -11,16 +11,18 @@
|
|
|
11
11
|
#define _WIN32_WINNT 0x600
|
|
12
12
|
|
|
13
13
|
#define NODE_ADDON_API_DISABLE_DEPRECATED
|
|
14
|
-
#include <
|
|
14
|
+
#include <node_api.h>
|
|
15
15
|
#include <assert.h>
|
|
16
16
|
#include <Shlwapi.h> // PathCombine, PathIsRelative
|
|
17
17
|
#include <sstream>
|
|
18
|
+
#include <iostream>
|
|
18
19
|
#include <string>
|
|
19
20
|
#include <thread>
|
|
20
21
|
#include <vector>
|
|
21
22
|
#include <Windows.h>
|
|
22
23
|
#include <strsafe.h>
|
|
23
24
|
#include "path_util.h"
|
|
25
|
+
#include "conpty.h"
|
|
24
26
|
|
|
25
27
|
// Taken from the RS5 Windows SDK, but redefined here in case we're targeting <= 17134
|
|
26
28
|
#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
|
|
@@ -32,6 +34,7 @@ typedef HRESULT (__stdcall *PFNCREATEPSEUDOCONSOLE)(COORD c, HANDLE hIn, HANDLE
|
|
|
32
34
|
typedef HRESULT (__stdcall *PFNRESIZEPSEUDOCONSOLE)(HPCON hpc, COORD newSize);
|
|
33
35
|
typedef HRESULT (__stdcall *PFNCLEARPSEUDOCONSOLE)(HPCON hpc);
|
|
34
36
|
typedef void (__stdcall *PFNCLOSEPSEUDOCONSOLE)(HPCON hpc);
|
|
37
|
+
typedef void (__stdcall *PFNRELEASEPSEUDOCONSOLE)(HPCON hpc);
|
|
35
38
|
|
|
36
39
|
#endif
|
|
37
40
|
|
|
@@ -46,27 +49,26 @@ struct pty_baton {
|
|
|
46
49
|
pty_baton(int _id, HANDLE _hIn, HANDLE _hOut, HPCON _hpc) : id(_id), hIn(_hIn), hOut(_hOut), hpc(_hpc) {};
|
|
47
50
|
};
|
|
48
51
|
|
|
49
|
-
static std::vector<pty_baton
|
|
52
|
+
static std::vector<std::unique_ptr<pty_baton>> ptyHandles;
|
|
50
53
|
static volatile LONG ptyCounter;
|
|
51
54
|
|
|
52
55
|
static pty_baton* get_pty_baton(int id) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
auto it = std::find_if(ptyHandles.begin(), ptyHandles.end(), [id](const auto& ptyHandle) {
|
|
57
|
+
return ptyHandle->id == id;
|
|
58
|
+
});
|
|
59
|
+
if (it != ptyHandles.end()) {
|
|
60
|
+
return it->get();
|
|
58
61
|
}
|
|
59
62
|
return nullptr;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
static bool remove_pty_baton(int id) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
66
|
+
auto it = std::remove_if(ptyHandles.begin(), ptyHandles.end(), [id](const auto& ptyHandle) {
|
|
67
|
+
return ptyHandle->id == id;
|
|
68
|
+
});
|
|
69
|
+
if (it != ptyHandles.end()) {
|
|
70
|
+
ptyHandles.erase(it);
|
|
71
|
+
return true;
|
|
70
72
|
}
|
|
71
73
|
return false;
|
|
72
74
|
}
|
|
@@ -100,16 +102,26 @@ void SetupExitCallback(Napi::Env env, Napi::Function cb, pty_baton* baton) {
|
|
|
100
102
|
// Get process exit code.
|
|
101
103
|
GetExitCodeProcess(baton->hShell, (LPDWORD)(&exit_event->exit_code));
|
|
102
104
|
// Clean up handles
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// so we only call CloseHandle for now.
|
|
106
|
-
CloseHandle(baton->hIn);
|
|
107
|
-
CloseHandle(baton->hOut);
|
|
105
|
+
CloseHandle(baton->hShell);
|
|
106
|
+
assert(remove_pty_baton(baton->id));
|
|
108
107
|
|
|
109
108
|
auto status = tsfn.BlockingCall(exit_event, callback); // In main thread
|
|
110
|
-
|
|
109
|
+
switch (status) {
|
|
110
|
+
case napi_closing:
|
|
111
|
+
break;
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
case napi_queue_full:
|
|
114
|
+
Napi::Error::Fatal("SetupExitCallback", "Queue was full");
|
|
115
|
+
|
|
116
|
+
case napi_ok:
|
|
117
|
+
if (tsfn.Release() != napi_ok) {
|
|
118
|
+
Napi::Error::Fatal("SetupExitCallback", "ThreadSafeFunction.Release() failed");
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
|
|
122
|
+
default:
|
|
123
|
+
Napi::Error::Fatal("SetupExitCallback", "ThreadSafeFunction.BlockingCall() failed");
|
|
124
|
+
}
|
|
113
125
|
});
|
|
114
126
|
}
|
|
115
127
|
|
|
@@ -141,28 +153,60 @@ bool createDataServerPipe(bool write,
|
|
|
141
153
|
/*dwOpenMode=*/winOpenMode,
|
|
142
154
|
/*dwPipeMode=*/PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
|
143
155
|
/*nMaxInstances=*/1,
|
|
144
|
-
/*nOutBufferSize=*/
|
|
145
|
-
/*nInBufferSize=*/
|
|
156
|
+
/*nOutBufferSize=*/128 * 1024,
|
|
157
|
+
/*nInBufferSize=*/128 * 1024,
|
|
146
158
|
/*nDefaultTimeOut=*/30000,
|
|
147
159
|
&sa);
|
|
148
160
|
|
|
149
161
|
return *hServer != INVALID_HANDLE_VALUE;
|
|
150
162
|
}
|
|
151
163
|
|
|
152
|
-
|
|
164
|
+
HANDLE LoadConptyDll(const Napi::CallbackInfo& info,
|
|
165
|
+
const bool useConptyDll)
|
|
166
|
+
{
|
|
167
|
+
if (!useConptyDll) {
|
|
168
|
+
return LoadLibraryExW(L"kernel32.dll", 0, 0);
|
|
169
|
+
}
|
|
170
|
+
wchar_t currentDir[MAX_PATH];
|
|
171
|
+
HMODULE hModule = GetModuleHandleA("conpty.node");
|
|
172
|
+
if (hModule == NULL) {
|
|
173
|
+
throw errorWithCode(info, "Failed to get conpty.node module handle");
|
|
174
|
+
}
|
|
175
|
+
DWORD result = GetModuleFileNameW(hModule, currentDir, MAX_PATH);
|
|
176
|
+
if (result == 0) {
|
|
177
|
+
throw errorWithCode(info, "Failed to get conpty.node module file name");
|
|
178
|
+
}
|
|
179
|
+
PathRemoveFileSpecW(currentDir);
|
|
180
|
+
wchar_t conptyDllPath[MAX_PATH];
|
|
181
|
+
PathCombineW(conptyDllPath, currentDir, L"conpty\\conpty.dll");
|
|
182
|
+
if (!path_util::file_exists(conptyDllPath)) {
|
|
183
|
+
std::wstring errorMessage = L"Cannot find conpty.dll at " + std::wstring(conptyDllPath);
|
|
184
|
+
std::string errorMessageStr = path_util::wstring_to_string(errorMessage);
|
|
185
|
+
throw errorWithCode(info, errorMessageStr.c_str());
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return LoadLibraryW(conptyDllPath);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
HRESULT CreateNamedPipesAndPseudoConsole(const Napi::CallbackInfo& info,
|
|
192
|
+
COORD size,
|
|
153
193
|
DWORD dwFlags,
|
|
154
194
|
HANDLE *phInput,
|
|
155
195
|
HANDLE *phOutput,
|
|
156
196
|
HPCON* phPC,
|
|
157
197
|
std::wstring& inName,
|
|
158
198
|
std::wstring& outName,
|
|
159
|
-
const std::wstring& pipeName
|
|
199
|
+
const std::wstring& pipeName,
|
|
200
|
+
const bool useConptyDll)
|
|
160
201
|
{
|
|
161
|
-
HANDLE hLibrary =
|
|
202
|
+
HANDLE hLibrary = LoadConptyDll(info, useConptyDll);
|
|
203
|
+
DWORD error = GetLastError();
|
|
162
204
|
bool fLoadedDll = hLibrary != nullptr;
|
|
163
205
|
if (fLoadedDll)
|
|
164
206
|
{
|
|
165
|
-
PFNCREATEPSEUDOCONSOLE const pfnCreate = (PFNCREATEPSEUDOCONSOLE)GetProcAddress(
|
|
207
|
+
PFNCREATEPSEUDOCONSOLE const pfnCreate = (PFNCREATEPSEUDOCONSOLE)GetProcAddress(
|
|
208
|
+
(HMODULE)hLibrary,
|
|
209
|
+
useConptyDll ? "ConptyCreatePseudoConsole" : "CreatePseudoConsole");
|
|
166
210
|
if (pfnCreate)
|
|
167
211
|
{
|
|
168
212
|
if (phPC == NULL || phInput == NULL || phOutput == NULL)
|
|
@@ -189,6 +233,8 @@ HRESULT CreateNamedPipesAndPseudoConsole(COORD size,
|
|
|
189
233
|
// We should fall back to winpty in this case.
|
|
190
234
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
191
235
|
}
|
|
236
|
+
} else {
|
|
237
|
+
throw errorWithCode(info, "Failed to load conpty.dll");
|
|
192
238
|
}
|
|
193
239
|
|
|
194
240
|
// Failed to find kernel32. This is realy unlikely - honestly no idea how
|
|
@@ -206,14 +252,15 @@ static Napi::Value PtyStartProcess(const Napi::CallbackInfo& info) {
|
|
|
206
252
|
std::unique_ptr<wchar_t[]> mutableCommandline;
|
|
207
253
|
PROCESS_INFORMATION _piClient{};
|
|
208
254
|
|
|
209
|
-
if (info.Length() !=
|
|
255
|
+
if (info.Length() != 7 ||
|
|
210
256
|
!info[0].IsString() ||
|
|
211
257
|
!info[1].IsNumber() ||
|
|
212
258
|
!info[2].IsNumber() ||
|
|
213
259
|
!info[3].IsBoolean() ||
|
|
214
260
|
!info[4].IsString() ||
|
|
215
|
-
!info[5].IsBoolean()
|
|
216
|
-
|
|
261
|
+
!info[5].IsBoolean() ||
|
|
262
|
+
!info[6].IsBoolean()) {
|
|
263
|
+
throw Napi::Error::New(env, "Usage: pty.startProcess(file, cols, rows, debug, pipeName, inheritCursor, useConptyDll)");
|
|
217
264
|
}
|
|
218
265
|
|
|
219
266
|
const std::wstring filename(path_util::to_wstring(info[0].As<Napi::String>()));
|
|
@@ -222,6 +269,7 @@ static Napi::Value PtyStartProcess(const Napi::CallbackInfo& info) {
|
|
|
222
269
|
const bool debug = info[3].As<Napi::Boolean>().Value();
|
|
223
270
|
const std::wstring pipeName(path_util::to_wstring(info[4].As<Napi::String>()));
|
|
224
271
|
const bool inheritCursor = info[5].As<Napi::Boolean>().Value();
|
|
272
|
+
const bool useConptyDll = info[6].As<Napi::Boolean>().Value();
|
|
225
273
|
|
|
226
274
|
// use environment 'Path' variable to determine location of
|
|
227
275
|
// the relative path that we have recieved (e.g cmd.exe)
|
|
@@ -241,7 +289,7 @@ static Napi::Value PtyStartProcess(const Napi::CallbackInfo& info) {
|
|
|
241
289
|
|
|
242
290
|
HANDLE hIn, hOut;
|
|
243
291
|
HPCON hpc;
|
|
244
|
-
HRESULT hr = CreateNamedPipesAndPseudoConsole({cols, rows}, inheritCursor ? 1/*PSEUDOCONSOLE_INHERIT_CURSOR*/ : 0, &hIn, &hOut, &hpc, inName, outName, pipeName);
|
|
292
|
+
HRESULT hr = CreateNamedPipesAndPseudoConsole(info, {cols, rows}, inheritCursor ? 1/*PSEUDOCONSOLE_INHERIT_CURSOR*/ : 0, &hIn, &hOut, &hpc, inName, outName, pipeName, useConptyDll);
|
|
245
293
|
|
|
246
294
|
// Restore default handling of ctrl+c
|
|
247
295
|
SetConsoleCtrlHandler(NULL, FALSE);
|
|
@@ -252,8 +300,9 @@ static Napi::Value PtyStartProcess(const Napi::CallbackInfo& info) {
|
|
|
252
300
|
if (SUCCEEDED(hr)) {
|
|
253
301
|
// We were able to instantiate a conpty
|
|
254
302
|
const int ptyId = InterlockedIncrement(&ptyCounter);
|
|
255
|
-
marshal.Set("pty", Napi::Number::New(env, ptyId));
|
|
256
|
-
ptyHandles.
|
|
303
|
+
marshal.Set("pty", Napi::Number::New(env, ptyId));
|
|
304
|
+
ptyHandles.emplace_back(
|
|
305
|
+
std::make_unique<pty_baton>(ptyId, hIn, hOut, hpc));
|
|
257
306
|
} else {
|
|
258
307
|
throw Napi::Error::New(env, "Cannot launch conpty");
|
|
259
308
|
}
|
|
@@ -284,20 +333,22 @@ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
|
|
|
284
333
|
std::stringstream errorText;
|
|
285
334
|
BOOL fSuccess = FALSE;
|
|
286
335
|
|
|
287
|
-
if (info.Length() !=
|
|
336
|
+
if (info.Length() != 6 ||
|
|
288
337
|
!info[0].IsNumber() ||
|
|
289
338
|
!info[1].IsString() ||
|
|
290
339
|
!info[2].IsString() ||
|
|
291
340
|
!info[3].IsArray() ||
|
|
292
|
-
!info[4].
|
|
293
|
-
|
|
341
|
+
!info[4].IsBoolean() ||
|
|
342
|
+
!info[5].IsFunction()) {
|
|
343
|
+
throw Napi::Error::New(env, "Usage: pty.connect(id, cmdline, cwd, env, useConptyDll, exitCallback)");
|
|
294
344
|
}
|
|
295
345
|
|
|
296
346
|
const int id = info[0].As<Napi::Number>().Int32Value();
|
|
297
347
|
const std::wstring cmdline(path_util::to_wstring(info[1].As<Napi::String>()));
|
|
298
348
|
const std::wstring cwd(path_util::to_wstring(info[2].As<Napi::String>()));
|
|
299
349
|
const Napi::Array envValues = info[3].As<Napi::Array>();
|
|
300
|
-
|
|
350
|
+
const bool useConptyDll = info[4].As<Napi::Boolean>().Value();
|
|
351
|
+
Napi::Function exitCallback = info[5].As<Napi::Function>();
|
|
301
352
|
|
|
302
353
|
// Fetch pty handle from ID and start process
|
|
303
354
|
pty_baton* handle = get_pty_baton(id);
|
|
@@ -375,9 +426,27 @@ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
|
|
|
375
426
|
throw errorWithCode(info, "Cannot create process");
|
|
376
427
|
}
|
|
377
428
|
|
|
429
|
+
HANDLE hLibrary = LoadConptyDll(info, useConptyDll);
|
|
430
|
+
bool fLoadedDll = hLibrary != nullptr;
|
|
431
|
+
if (useConptyDll && fLoadedDll)
|
|
432
|
+
{
|
|
433
|
+
PFNRELEASEPSEUDOCONSOLE const pfnReleasePseudoConsole = (PFNRELEASEPSEUDOCONSOLE)GetProcAddress(
|
|
434
|
+
(HMODULE)hLibrary, "ConptyReleasePseudoConsole");
|
|
435
|
+
if (pfnReleasePseudoConsole)
|
|
436
|
+
{
|
|
437
|
+
pfnReleasePseudoConsole(handle->hpc);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
378
441
|
// Update handle
|
|
379
442
|
handle->hShell = piClient.hProcess;
|
|
380
443
|
|
|
444
|
+
// Close the thread handle to avoid resource leak
|
|
445
|
+
CloseHandle(piClient.hThread);
|
|
446
|
+
// Close the input read and output write handle of the pseudoconsole
|
|
447
|
+
CloseHandle(handle->hIn);
|
|
448
|
+
CloseHandle(handle->hOut);
|
|
449
|
+
|
|
381
450
|
SetupExitCallback(env, exitCallback, handle);
|
|
382
451
|
|
|
383
452
|
// Return
|
|
@@ -390,25 +459,29 @@ static Napi::Value PtyResize(const Napi::CallbackInfo& info) {
|
|
|
390
459
|
Napi::Env env(info.Env());
|
|
391
460
|
Napi::HandleScope scope(env);
|
|
392
461
|
|
|
393
|
-
if (info.Length() !=
|
|
462
|
+
if (info.Length() != 4 ||
|
|
394
463
|
!info[0].IsNumber() ||
|
|
395
464
|
!info[1].IsNumber() ||
|
|
396
|
-
!info[2].IsNumber()
|
|
397
|
-
|
|
465
|
+
!info[2].IsNumber() ||
|
|
466
|
+
!info[3].IsBoolean()) {
|
|
467
|
+
throw Napi::Error::New(env, "Usage: pty.resize(id, cols, rows, useConptyDll)");
|
|
398
468
|
}
|
|
399
469
|
|
|
400
470
|
int id = info[0].As<Napi::Number>().Int32Value();
|
|
401
471
|
SHORT cols = static_cast<SHORT>(info[1].As<Napi::Number>().Uint32Value());
|
|
402
472
|
SHORT rows = static_cast<SHORT>(info[2].As<Napi::Number>().Uint32Value());
|
|
473
|
+
const bool useConptyDll = info[3].As<Napi::Boolean>().Value();
|
|
403
474
|
|
|
404
475
|
const pty_baton* handle = get_pty_baton(id);
|
|
405
476
|
|
|
406
477
|
if (handle != nullptr) {
|
|
407
|
-
HANDLE hLibrary =
|
|
478
|
+
HANDLE hLibrary = LoadConptyDll(info, useConptyDll);
|
|
408
479
|
bool fLoadedDll = hLibrary != nullptr;
|
|
409
480
|
if (fLoadedDll)
|
|
410
481
|
{
|
|
411
|
-
PFNRESIZEPSEUDOCONSOLE const pfnResizePseudoConsole = (PFNRESIZEPSEUDOCONSOLE)GetProcAddress(
|
|
482
|
+
PFNRESIZEPSEUDOCONSOLE const pfnResizePseudoConsole = (PFNRESIZEPSEUDOCONSOLE)GetProcAddress(
|
|
483
|
+
(HMODULE)hLibrary,
|
|
484
|
+
useConptyDll ? "ConptyResizePseudoConsole" : "ResizePseudoConsole");
|
|
412
485
|
if (pfnResizePseudoConsole)
|
|
413
486
|
{
|
|
414
487
|
COORD size = {cols, rows};
|
|
@@ -424,21 +497,30 @@ static Napi::Value PtyClear(const Napi::CallbackInfo& info) {
|
|
|
424
497
|
Napi::Env env(info.Env());
|
|
425
498
|
Napi::HandleScope scope(env);
|
|
426
499
|
|
|
427
|
-
if (info.Length() !=
|
|
428
|
-
!info[0].IsNumber()
|
|
429
|
-
|
|
500
|
+
if (info.Length() != 2 ||
|
|
501
|
+
!info[0].IsNumber() ||
|
|
502
|
+
!info[1].IsBoolean()) {
|
|
503
|
+
throw Napi::Error::New(env, "Usage: pty.clear(id, useConptyDll)");
|
|
430
504
|
}
|
|
431
505
|
|
|
432
506
|
int id = info[0].As<Napi::Number>().Int32Value();
|
|
507
|
+
const bool useConptyDll = info[1].As<Napi::Boolean>().Value();
|
|
508
|
+
|
|
509
|
+
// This API is only supported for conpty.dll as it was introduced in a later version of Windows.
|
|
510
|
+
// We could hook it up to point at >= a version of Windows only, but the future is conpty.dll
|
|
511
|
+
// anyway.
|
|
512
|
+
if (!useConptyDll) {
|
|
513
|
+
return env.Undefined();
|
|
514
|
+
}
|
|
433
515
|
|
|
434
516
|
const pty_baton* handle = get_pty_baton(id);
|
|
435
517
|
|
|
436
518
|
if (handle != nullptr) {
|
|
437
|
-
HANDLE hLibrary =
|
|
519
|
+
HANDLE hLibrary = LoadConptyDll(info, useConptyDll);
|
|
438
520
|
bool fLoadedDll = hLibrary != nullptr;
|
|
439
521
|
if (fLoadedDll)
|
|
440
522
|
{
|
|
441
|
-
PFNCLEARPSEUDOCONSOLE const pfnClearPseudoConsole = (PFNCLEARPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "
|
|
523
|
+
PFNCLEARPSEUDOCONSOLE const pfnClearPseudoConsole = (PFNCLEARPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "ConptyClearPseudoConsole");
|
|
442
524
|
if (pfnClearPseudoConsole)
|
|
443
525
|
{
|
|
444
526
|
pfnClearPseudoConsole(handle->hpc);
|
|
@@ -453,29 +535,33 @@ static Napi::Value PtyKill(const Napi::CallbackInfo& info) {
|
|
|
453
535
|
Napi::Env env(info.Env());
|
|
454
536
|
Napi::HandleScope scope(env);
|
|
455
537
|
|
|
456
|
-
if (info.Length() !=
|
|
457
|
-
!info[0].IsNumber()
|
|
458
|
-
|
|
538
|
+
if (info.Length() != 2 ||
|
|
539
|
+
!info[0].IsNumber() ||
|
|
540
|
+
!info[1].IsBoolean()) {
|
|
541
|
+
throw Napi::Error::New(env, "Usage: pty.kill(id, useConptyDll)");
|
|
459
542
|
}
|
|
460
543
|
|
|
461
544
|
int id = info[0].As<Napi::Number>().Int32Value();
|
|
545
|
+
const bool useConptyDll = info[1].As<Napi::Boolean>().Value();
|
|
462
546
|
|
|
463
547
|
const pty_baton* handle = get_pty_baton(id);
|
|
464
548
|
|
|
465
549
|
if (handle != nullptr) {
|
|
466
|
-
HANDLE hLibrary =
|
|
550
|
+
HANDLE hLibrary = LoadConptyDll(info, useConptyDll);
|
|
467
551
|
bool fLoadedDll = hLibrary != nullptr;
|
|
468
552
|
if (fLoadedDll)
|
|
469
553
|
{
|
|
470
|
-
PFNCLOSEPSEUDOCONSOLE const pfnClosePseudoConsole = (PFNCLOSEPSEUDOCONSOLE)GetProcAddress(
|
|
554
|
+
PFNCLOSEPSEUDOCONSOLE const pfnClosePseudoConsole = (PFNCLOSEPSEUDOCONSOLE)GetProcAddress(
|
|
555
|
+
(HMODULE)hLibrary,
|
|
556
|
+
useConptyDll ? "ConptyClosePseudoConsole" : "ClosePseudoConsole");
|
|
471
557
|
if (pfnClosePseudoConsole)
|
|
472
558
|
{
|
|
473
559
|
pfnClosePseudoConsole(handle->hpc);
|
|
474
560
|
}
|
|
475
561
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
562
|
+
if (useConptyDll) {
|
|
563
|
+
TerminateProcess(handle->hShell, 1);
|
|
564
|
+
}
|
|
479
565
|
}
|
|
480
566
|
|
|
481
567
|
return env.Undefined();
|
package/src/win/conpty.h
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT license.
|
|
3
|
+
|
|
4
|
+
// This header prototypes the Pseudoconsole symbols from conpty.lib with their original names.
|
|
5
|
+
// This is required because we cannot import __imp_CreatePseudoConsole from a static library
|
|
6
|
+
// as it doesn't produce an import lib.
|
|
7
|
+
// We can't use an /ALTERNATENAME trick because it seems that that name is only resolved when the
|
|
8
|
+
// linker cannot otherwise find the symbol.
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
|
|
12
|
+
#include <consoleapi.h>
|
|
13
|
+
|
|
14
|
+
#ifndef CONPTY_IMPEXP
|
|
15
|
+
#define CONPTY_IMPEXP __declspec(dllimport)
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#ifndef CONPTY_EXPORT
|
|
19
|
+
#ifdef __cplusplus
|
|
20
|
+
#define CONPTY_EXPORT extern "C" CONPTY_IMPEXP
|
|
21
|
+
#else
|
|
22
|
+
#define CONPTY_EXPORT extern CONPTY_IMPEXP
|
|
23
|
+
#endif
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
#define PSEUDOCONSOLE_RESIZE_QUIRK (2u)
|
|
27
|
+
#define PSEUDOCONSOLE_PASSTHROUGH_MODE (8u)
|
|
28
|
+
|
|
29
|
+
CONPTY_EXPORT HRESULT WINAPI ConptyCreatePseudoConsole(COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
|
|
30
|
+
CONPTY_EXPORT HRESULT WINAPI ConptyCreatePseudoConsoleAsUser(HANDLE hToken, COORD size, HANDLE hInput, HANDLE hOutput, DWORD dwFlags, HPCON* phPC);
|
|
31
|
+
|
|
32
|
+
CONPTY_EXPORT HRESULT WINAPI ConptyResizePseudoConsole(HPCON hPC, COORD size);
|
|
33
|
+
CONPTY_EXPORT HRESULT WINAPI ConptyClearPseudoConsole(HPCON hPC);
|
|
34
|
+
CONPTY_EXPORT HRESULT WINAPI ConptyShowHidePseudoConsole(HPCON hPC, bool show);
|
|
35
|
+
CONPTY_EXPORT HRESULT WINAPI ConptyReparentPseudoConsole(HPCON hPC, HWND newParent);
|
|
36
|
+
CONPTY_EXPORT HRESULT WINAPI ConptyReleasePseudoConsole(HPCON hPC);
|
|
37
|
+
|
|
38
|
+
CONPTY_EXPORT VOID WINAPI ConptyClosePseudoConsole(HPCON hPC);
|
|
39
|
+
CONPTY_EXPORT VOID WINAPI ConptyClosePseudoConsoleTimeout(HPCON hPC, DWORD dwMilliseconds);
|
|
40
|
+
|
|
41
|
+
CONPTY_EXPORT HRESULT WINAPI ConptyPackPseudoConsole(HANDLE hServerProcess, HANDLE hRef, HANDLE hSignal, HPCON* phPC);
|
package/src/win/path_util.cc
CHANGED
|
@@ -58,38 +58,37 @@ std::wstring get_shell_path(std::wstring filename) {
|
|
|
58
58
|
return shellpath;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
wchar_t buffer_[MAX_ENV];
|
|
61
|
+
wchar_t* buffer_ = new wchar_t[MAX_ENV];
|
|
62
62
|
int read = ::GetEnvironmentVariableW(L"Path", buffer_, MAX_ENV);
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
paths.push_back(buffer.substr(0, pos));
|
|
73
|
-
buffer.erase(0, pos + delimiter.length());
|
|
74
|
-
}
|
|
63
|
+
if (read) {
|
|
64
|
+
std::wstring delimiter = L";";
|
|
65
|
+
size_t pos = 0;
|
|
66
|
+
std::vector<std::wstring> paths;
|
|
67
|
+
std::wstring buffer(buffer_);
|
|
68
|
+
while ((pos = buffer.find(delimiter)) != std::wstring::npos) {
|
|
69
|
+
paths.push_back(buffer.substr(0, pos));
|
|
70
|
+
buffer.erase(0, pos + delimiter.length());
|
|
71
|
+
}
|
|
75
72
|
|
|
76
|
-
|
|
73
|
+
const wchar_t *filename_ = filename.c_str();
|
|
77
74
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
for (size_t i = 0; i < paths.size(); ++i) {
|
|
76
|
+
std::wstring path = paths[i];
|
|
77
|
+
wchar_t searchPath[MAX_PATH];
|
|
78
|
+
::PathCombineW(searchPath, const_cast<wchar_t*>(path.c_str()), filename_);
|
|
82
79
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
if (searchPath == NULL) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
if (file_exists(searchPath)) {
|
|
85
|
+
shellpath = searchPath;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
90
|
|
|
91
|
+
delete[] buffer_;
|
|
93
92
|
return shellpath;
|
|
94
93
|
}
|
|
95
94
|
|
|
@@ -37,9 +37,12 @@ export class ConoutConnection implements IDisposable {
|
|
|
37
37
|
public get onReady(): IEvent<void> { return this._onReady.event; }
|
|
38
38
|
|
|
39
39
|
constructor(
|
|
40
|
-
private _conoutPipeName: string
|
|
40
|
+
private _conoutPipeName: string,
|
|
41
|
+
private _useConptyDll: boolean
|
|
41
42
|
) {
|
|
42
|
-
const workerData: IWorkerData = {
|
|
43
|
+
const workerData: IWorkerData = {
|
|
44
|
+
conoutPipeName: _conoutPipeName
|
|
45
|
+
};
|
|
43
46
|
const scriptPath = __dirname.replace('node_modules.asar', 'node_modules.asar.unpacked');
|
|
44
47
|
this._worker = new Worker(join(scriptPath, 'worker/conoutSocketWorker.js'), { workerData });
|
|
45
48
|
this._worker.on('message', (message: ConoutWorkerMessage) => {
|
|
@@ -54,7 +57,7 @@ export class ConoutConnection implements IDisposable {
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
dispose(): void {
|
|
57
|
-
if (this._isDisposed) {
|
|
60
|
+
if (!this._useConptyDll && this._isDisposed) {
|
|
58
61
|
return;
|
|
59
62
|
}
|
|
60
63
|
this._isDisposed = true;
|