node-pty 1.1.0-beta1 → 1.1.0-beta11

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.
@@ -11,6 +11,7 @@ import * as tty from 'tty';
11
11
  import * as fs from 'fs';
12
12
  import { constants } from 'os';
13
13
  import { pollUntil } from './testUtils.test';
14
+ import { pid } from 'process';
14
15
 
15
16
  const FIXTURES_PATH = path.normalize(path.join(__dirname, '..', 'fixtures', 'utf8-character.txt'));
16
17
 
@@ -262,6 +263,40 @@ if (process.platform !== 'win32') {
262
263
  term.on('exit', () => done());
263
264
  term.destroy();
264
265
  });
266
+ it('should return the name of the sub process', (done) => {
267
+ const data = `
268
+ var pty = require('./lib/index');
269
+ var ptyProcess = pty.spawn('zsh', ['-c', 'python3'], {
270
+ env: process.env
271
+ });
272
+ ptyProcess.on('data', function (data) {
273
+ if (ptyProcess.process === 'Python') {
274
+ console.log('title', ptyProcess.process);
275
+ }
276
+ });
277
+ setTimeout(() => null, 500);
278
+ console.log('ready', ptyProcess.pid);
279
+ `;
280
+ const p = cp.spawn('node', ['-e', data]);
281
+ let sub = '';
282
+ let pid = '';
283
+ p.stdout.on('data', (data) => {
284
+ if (!data.toString().indexOf('title')) {
285
+ sub = data.toString().split(' ')[1].slice(0, -1);
286
+ setTimeout(() => {
287
+ process.kill(parseInt(pid), 'SIGINT');
288
+ p.kill('SIGINT');
289
+ }, 200);
290
+ } else if (!data.toString().indexOf('ready')) {
291
+ pid = data.toString().split(' ')[1].slice(0, -1);
292
+ }
293
+ });
294
+ p.on('exit', () => {
295
+ assert.notStrictEqual(pid, '');
296
+ assert.strictEqual(sub, 'Python');
297
+ done();
298
+ });
299
+ });
265
300
  it('should close on exec', (done) => {
266
301
  const data = `
267
302
  var pty = require('./lib/index');
@@ -263,7 +263,8 @@ export class UnixTerminal extends Terminal {
263
263
  */
264
264
  public get process(): string {
265
265
  if (process.platform === 'darwin') {
266
- return pty.process(this._pid) || this._file;
266
+ const title = pty.process(this._fd);
267
+ return (title !== 'kernel_task' ) ? title : this._file;
267
268
  }
268
269
 
269
270
  return pty.process(this._fd, this._pty) || this._file;
package/src/win/conpty.cc CHANGED
@@ -8,24 +8,20 @@
8
8
  * with pseudo-terminal file descriptors.
9
9
  */
10
10
 
11
- // node versions lower than 10 define this as 0x502 which disables many of the definitions needed to compile
12
- #include <node_version.h>
13
- #if NODE_MODULE_VERSION <= 57
14
- #define _WIN32_WINNT 0x600
15
- #endif
11
+ #define _WIN32_WINNT 0x600
16
12
 
17
- #include <iostream>
18
- #include <nan.h>
13
+ #define NODE_ADDON_API_DISABLE_DEPRECATED
14
+ #include <napi.h>
15
+ #include <assert.h>
19
16
  #include <Shlwapi.h> // PathCombine, PathIsRelative
20
17
  #include <sstream>
21
18
  #include <string>
19
+ #include <thread>
22
20
  #include <vector>
23
21
  #include <Windows.h>
24
22
  #include <strsafe.h>
25
23
  #include "path_util.h"
26
24
 
27
- extern "C" void init(v8::Local<v8::Object>);
28
-
29
25
  // Taken from the RS5 Windows SDK, but redefined here in case we're targeting <= 17134
30
26
  #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
31
27
  #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE \
@@ -46,10 +42,6 @@ struct pty_baton {
46
42
  HPCON hpc;
47
43
 
48
44
  HANDLE hShell;
49
- HANDLE hWait;
50
- Nan::Callback cb;
51
- uv_async_t async;
52
- uv_thread_t tid;
53
45
 
54
46
  pty_baton(int _id, HANDLE _hIn, HANDLE _hOut, HPCON _hpc) : id(_id), hIn(_hIn), hOut(_hOut), hpc(_hpc) {};
55
47
  };
@@ -67,19 +59,78 @@ static pty_baton* get_pty_baton(int id) {
67
59
  return nullptr;
68
60
  }
69
61
 
70
- template <typename T>
71
- std::vector<T> vectorFromString(const std::basic_string<T> &str) {
72
- return std::vector<T>(str.begin(), str.end());
62
+ static bool remove_pty_baton(int id) {
63
+ for (size_t i = 0; i < ptyHandles.size(); ++i) {
64
+ pty_baton* ptyHandle = ptyHandles[i];
65
+ if (ptyHandle->id == id) {
66
+ ptyHandles.erase(ptyHandles.begin() + i);
67
+ ptyHandle = nullptr;
68
+ return true;
69
+ }
70
+ }
71
+ return false;
73
72
  }
74
73
 
75
- void throwNanError(const Nan::FunctionCallbackInfo<v8::Value>* info, const char* text, const bool getLastError) {
74
+ struct ExitEvent {
75
+ int exit_code = 0;
76
+ };
77
+
78
+ void SetupExitCallback(Napi::Env env, Napi::Function cb, pty_baton* baton) {
79
+ std::thread *th = new std::thread;
80
+ // Don't use Napi::AsyncWorker which is limited by UV_THREADPOOL_SIZE.
81
+ auto tsfn = Napi::ThreadSafeFunction::New(
82
+ env,
83
+ cb, // JavaScript function called asynchronously
84
+ "SetupExitCallback_resource", // Name
85
+ 0, // Unlimited queue
86
+ 1, // Only one thread will use this initially
87
+ [th](Napi::Env) { // Finalizer used to clean threads up
88
+ th->join();
89
+ delete th;
90
+ });
91
+ *th = std::thread([tsfn = std::move(tsfn), baton] {
92
+ auto callback = [](Napi::Env env, Napi::Function cb, ExitEvent *exit_event) {
93
+ cb.Call({Napi::Number::New(env, exit_event->exit_code)});
94
+ delete exit_event;
95
+ };
96
+
97
+ ExitEvent *exit_event = new ExitEvent;
98
+ // Wait for process to complete.
99
+ WaitForSingleObject(baton->hShell, INFINITE);
100
+ // Get process exit code.
101
+ GetExitCodeProcess(baton->hShell, (LPDWORD)(&exit_event->exit_code));
102
+ // Clean up handles
103
+ // Calling DisconnectNamedPipes here or in PtyKill results in a crash,
104
+ // ref https://github.com/microsoft/node-pty/issues/512,
105
+ // so we only call CloseHandle for now.
106
+ CloseHandle(baton->hIn);
107
+ CloseHandle(baton->hOut);
108
+
109
+ auto status = tsfn.BlockingCall(exit_event, callback); // In main thread
110
+ switch (status) {
111
+ case napi_closing:
112
+ break;
113
+
114
+ case napi_queue_full:
115
+ Napi::Error::Fatal("SetupExitCallback", "Queue was full");
116
+
117
+ case napi_ok:
118
+ if (tsfn.Release() != napi_ok) {
119
+ Napi::Error::Fatal("SetupExitCallback", "ThreadSafeFunction.Release() failed");
120
+ }
121
+ break;
122
+
123
+ default:
124
+ Napi::Error::Fatal("SetupExitCallback", "ThreadSafeFunction.BlockingCall() failed");
125
+ }
126
+ });
127
+ }
128
+
129
+ Napi::Error errorWithCode(const Napi::CallbackInfo& info, const char* text) {
76
130
  std::stringstream errorText;
77
131
  errorText << text;
78
- if (getLastError) {
79
- errorText << ", error code: " << GetLastError();
80
- }
81
- Nan::ThrowError(errorText.str().c_str());
82
- (*info).GetReturnValue().SetUndefined();
132
+ errorText << ", error code: " << GetLastError();
133
+ return Napi::Error::New(info.Env(), errorText.str());
83
134
  }
84
135
 
85
136
  // Returns a new server named pipe. It has not yet been connected.
@@ -158,32 +209,32 @@ HRESULT CreateNamedPipesAndPseudoConsole(COORD size,
158
209
  return HRESULT_FROM_WIN32(GetLastError());
159
210
  }
160
211
 
161
- static NAN_METHOD(PtyStartProcess) {
162
- Nan::HandleScope scope;
212
+ static Napi::Value PtyStartProcess(const Napi::CallbackInfo& info) {
213
+ Napi::Env env(info.Env());
214
+ Napi::HandleScope scope(env);
163
215
 
164
- v8::Local<v8::Object> marshal;
216
+ Napi::Object marshal;
165
217
  std::wstring inName, outName;
166
218
  BOOL fSuccess = FALSE;
167
219
  std::unique_ptr<wchar_t[]> mutableCommandline;
168
220
  PROCESS_INFORMATION _piClient{};
169
221
 
170
222
  if (info.Length() != 6 ||
171
- !info[0]->IsString() ||
172
- !info[1]->IsNumber() ||
173
- !info[2]->IsNumber() ||
174
- !info[3]->IsBoolean() ||
175
- !info[4]->IsString() ||
176
- !info[5]->IsBoolean()) {
177
- Nan::ThrowError("Usage: pty.startProcess(file, cols, rows, debug, pipeName, inheritCursor)");
178
- return;
223
+ !info[0].IsString() ||
224
+ !info[1].IsNumber() ||
225
+ !info[2].IsNumber() ||
226
+ !info[3].IsBoolean() ||
227
+ !info[4].IsString() ||
228
+ !info[5].IsBoolean()) {
229
+ throw Napi::Error::New(env, "Usage: pty.startProcess(file, cols, rows, debug, pipeName, inheritCursor)");
179
230
  }
180
231
 
181
- const std::wstring filename(path_util::to_wstring(Nan::Utf8String(info[0])));
182
- const SHORT cols = static_cast<SHORT>(info[1]->Uint32Value(Nan::GetCurrentContext()).FromJust());
183
- const SHORT rows = static_cast<SHORT>(info[2]->Uint32Value(Nan::GetCurrentContext()).FromJust());
184
- const bool debug = Nan::To<bool>(info[3]).FromJust();
185
- const std::wstring pipeName(path_util::to_wstring(Nan::Utf8String(info[4])));
186
- const bool inheritCursor = Nan::To<bool>(info[5]).FromJust();
232
+ const std::wstring filename(path_util::to_wstring(info[0].As<Napi::String>()));
233
+ const SHORT cols = static_cast<SHORT>(info[1].As<Napi::Number>().Uint32Value());
234
+ const SHORT rows = static_cast<SHORT>(info[2].As<Napi::Number>().Uint32Value());
235
+ const bool debug = info[3].As<Napi::Boolean>().Value();
236
+ const std::wstring pipeName(path_util::to_wstring(info[4].As<Napi::String>()));
237
+ const bool inheritCursor = info[5].As<Napi::Boolean>().Value();
187
238
 
188
239
  // use environment 'Path' variable to determine location of
189
240
  // the relative path that we have recieved (e.g cmd.exe)
@@ -195,10 +246,10 @@ static NAN_METHOD(PtyStartProcess) {
195
246
  }
196
247
 
197
248
  if (shellpath.empty() || !path_util::file_exists(shellpath)) {
198
- std::wstringstream why;
199
- why << "File not found: " << shellpath;
200
- Nan::ThrowError(path_util::from_wstring(why.str().c_str()));
201
- return;
249
+ std::string why;
250
+ why += "File not found: ";
251
+ why += path_util::wstring_to_string(shellpath);
252
+ throw Napi::Error::New(env, why);
202
253
  }
203
254
 
204
255
  HANDLE hIn, hOut;
@@ -209,67 +260,35 @@ static NAN_METHOD(PtyStartProcess) {
209
260
  SetConsoleCtrlHandler(NULL, FALSE);
210
261
 
211
262
  // Set return values
212
- marshal = Nan::New<v8::Object>();
263
+ marshal = Napi::Object::New(env);
213
264
 
214
265
  if (SUCCEEDED(hr)) {
215
266
  // We were able to instantiate a conpty
216
267
  const int ptyId = InterlockedIncrement(&ptyCounter);
217
- Nan::Set(marshal, Nan::New<v8::String>("pty").ToLocalChecked(), Nan::New<v8::Number>(ptyId));
268
+ marshal.Set("pty", Napi::Number::New(env, ptyId));
218
269
  ptyHandles.insert(ptyHandles.end(), new pty_baton(ptyId, hIn, hOut, hpc));
219
270
  } else {
220
- Nan::ThrowError("Cannot launch conpty");
221
- return;
271
+ throw Napi::Error::New(env, "Cannot launch conpty");
222
272
  }
223
273
 
224
- std::string inNameStr(path_util::from_wstring(inName.c_str()));
274
+ std::string inNameStr = path_util::wstring_to_string(inName);
225
275
  if (inNameStr.empty()) {
226
- Nan::ThrowError("Failed to initialize conpty conin");
227
- return;
276
+ throw Napi::Error::New(env, "Failed to initialize conpty conin");
228
277
  }
229
- std::string outNameStr(path_util::from_wstring(outName.c_str()));
278
+ std::string outNameStr = path_util::wstring_to_string(outName);
230
279
  if (outNameStr.empty()) {
231
- Nan::ThrowError("Failed to initialize conpty conout");
232
- return;
280
+ throw Napi::Error::New(env, "Failed to initialize conpty conout");
233
281
  }
234
282
 
235
- Nan::Set(marshal, Nan::New<v8::String>("fd").ToLocalChecked(), Nan::New<v8::Number>(-1));
236
- Nan::Set(marshal, Nan::New<v8::String>("conin").ToLocalChecked(), Nan::New<v8::String>(inNameStr).ToLocalChecked());
237
- Nan::Set(marshal, Nan::New<v8::String>("conout").ToLocalChecked(), Nan::New<v8::String>(outNameStr).ToLocalChecked());
238
- info.GetReturnValue().Set(marshal);
283
+ marshal.Set("fd", Napi::Number::New(env, -1));
284
+ marshal.Set("conin", Napi::String::New(env, inNameStr));
285
+ marshal.Set("conout", Napi::String::New(env, outNameStr));
286
+ return marshal;
239
287
  }
240
288
 
241
- VOID CALLBACK OnProcessExitWinEvent(
242
- _In_ PVOID context,
243
- _In_ BOOLEAN TimerOrWaitFired) {
244
- pty_baton *baton = static_cast<pty_baton*>(context);
245
-
246
- // Fire OnProcessExit
247
- uv_async_send(&baton->async);
248
- }
249
-
250
- static void OnProcessExit(uv_async_t *async) {
251
- Nan::HandleScope scope;
252
- pty_baton *baton = static_cast<pty_baton*>(async->data);
253
-
254
- UnregisterWait(baton->hWait);
255
-
256
- // Get exit code
257
- DWORD exitCode = 0;
258
- GetExitCodeProcess(baton->hShell, &exitCode);
259
-
260
- // Call function
261
- v8::Local<v8::Value> args[1] = {
262
- Nan::New<v8::Number>(exitCode)
263
- };
264
-
265
- Nan::AsyncResource asyncResource("node-pty.callback");
266
- baton->cb.Call(1, args, &asyncResource);
267
- // Clean up
268
- baton->cb.Reset();
269
- }
270
-
271
- static NAN_METHOD(PtyConnect) {
272
- Nan::HandleScope scope;
289
+ static Napi::Value PtyConnect(const Napi::CallbackInfo& info) {
290
+ Napi::Env env(info.Env());
291
+ Napi::HandleScope scope(env);
273
292
 
274
293
  // If we're working with conpty's we need to call ConnectNamedPipe here AFTER
275
294
  // the Socket has attempted to connect to the other end, then actually
@@ -279,26 +298,24 @@ static NAN_METHOD(PtyConnect) {
279
298
  BOOL fSuccess = FALSE;
280
299
 
281
300
  if (info.Length() != 5 ||
282
- !info[0]->IsNumber() ||
283
- !info[1]->IsString() ||
284
- !info[2]->IsString() ||
285
- !info[3]->IsArray() ||
286
- !info[4]->IsFunction()) {
287
- Nan::ThrowError("Usage: pty.connect(id, cmdline, cwd, env, exitCallback)");
288
- return;
301
+ !info[0].IsNumber() ||
302
+ !info[1].IsString() ||
303
+ !info[2].IsString() ||
304
+ !info[3].IsArray() ||
305
+ !info[4].IsFunction()) {
306
+ throw Napi::Error::New(env, "Usage: pty.connect(id, cmdline, cwd, env, exitCallback)");
289
307
  }
290
308
 
291
- const int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
292
- const std::wstring cmdline(path_util::to_wstring(Nan::Utf8String(info[1])));
293
- const std::wstring cwd(path_util::to_wstring(Nan::Utf8String(info[2])));
294
- const v8::Local<v8::Array> envValues = info[3].As<v8::Array>();
295
- const v8::Local<v8::Function> exitCallback = v8::Local<v8::Function>::Cast(info[4]);
309
+ const int id = info[0].As<Napi::Number>().Int32Value();
310
+ const std::wstring cmdline(path_util::to_wstring(info[1].As<Napi::String>()));
311
+ const std::wstring cwd(path_util::to_wstring(info[2].As<Napi::String>()));
312
+ const Napi::Array envValues = info[3].As<Napi::Array>();
313
+ Napi::Function exitCallback = info[4].As<Napi::Function>();
296
314
 
297
315
  // Fetch pty handle from ID and start process
298
316
  pty_baton* handle = get_pty_baton(id);
299
317
  if (!handle) {
300
- Nan::ThrowError("Invalid pty handle");
301
- return;
318
+ throw Napi::Error::New(env, "Invalid pty handle");
302
319
  }
303
320
 
304
321
  // Prepare command line
@@ -310,17 +327,17 @@ static NAN_METHOD(PtyConnect) {
310
327
  hr = StringCchCopyW(mutableCwd.get(), cwd.length() + 1, cwd.c_str());
311
328
 
312
329
  // Prepare environment
313
- std::wstring env;
330
+ std::wstring envStr;
314
331
  if (!envValues.IsEmpty()) {
315
- std::wstringstream envBlock;
316
- for(uint32_t i = 0; i < envValues->Length(); i++) {
317
- std::wstring envValue(path_util::to_wstring(Nan::Utf8String(Nan::Get(envValues, i).ToLocalChecked())));
318
- envBlock << envValue << L'\0';
332
+ std::wstring envBlock;
333
+ for(uint32_t i = 0; i < envValues.Length(); i++) {
334
+ envBlock += path_util::to_wstring(envValues.Get(i).As<Napi::String>());
335
+ envBlock += L'\0';
319
336
  }
320
- envBlock << L'\0';
321
- env = envBlock.str();
337
+ envBlock += L'\0';
338
+ envStr = std::move(envBlock);
322
339
  }
323
- auto envV = vectorFromString(env);
340
+ std::vector<wchar_t> envV(envStr.cbegin(), envStr.cend());
324
341
  LPWSTR envArg = envV.empty() ? nullptr : envV.data();
325
342
 
326
343
  ConnectNamedPipe(handle->hIn, nullptr);
@@ -341,7 +358,7 @@ static NAN_METHOD(PtyConnect) {
341
358
 
342
359
  fSuccess = InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &size);
343
360
  if (!fSuccess) {
344
- return throwNanError(&info, "InitializeProcThreadAttributeList failed", true);
361
+ throw errorWithCode(info, "InitializeProcThreadAttributeList failed");
345
362
  }
346
363
  fSuccess = UpdateProcThreadAttribute(siEx.lpAttributeList,
347
364
  0,
@@ -351,7 +368,7 @@ static NAN_METHOD(PtyConnect) {
351
368
  NULL,
352
369
  NULL);
353
370
  if (!fSuccess) {
354
- return throwNanError(&info, "UpdateProcThreadAttribute failed", true);
371
+ throw errorWithCode(info, "UpdateProcThreadAttribute failed");
355
372
  }
356
373
 
357
374
  PROCESS_INFORMATION piClient{};
@@ -368,40 +385,34 @@ static NAN_METHOD(PtyConnect) {
368
385
  &piClient // lpProcessInformation
369
386
  );
370
387
  if (!fSuccess) {
371
- return throwNanError(&info, "Cannot create process", true);
388
+ throw errorWithCode(info, "Cannot create process");
372
389
  }
373
390
 
374
391
  // Update handle
375
392
  handle->hShell = piClient.hProcess;
376
- handle->cb.Reset(exitCallback);
377
- handle->async.data = handle;
378
-
379
- // Setup OnProcessExit callback
380
- uv_async_init(uv_default_loop(), &handle->async, OnProcessExit);
381
393
 
382
- // Setup Windows wait for process exit event
383
- RegisterWaitForSingleObject(&handle->hWait, piClient.hProcess, OnProcessExitWinEvent, (PVOID)handle, INFINITE, WT_EXECUTEONLYONCE);
394
+ SetupExitCallback(env, exitCallback, handle);
384
395
 
385
396
  // Return
386
- v8::Local<v8::Object> marshal = Nan::New<v8::Object>();
387
- Nan::Set(marshal, Nan::New<v8::String>("pid").ToLocalChecked(), Nan::New<v8::Number>(piClient.dwProcessId));
388
- info.GetReturnValue().Set(marshal);
397
+ auto marshal = Napi::Object::New(env);
398
+ marshal.Set("pid", Napi::Number::New(env, piClient.dwProcessId));
399
+ return marshal;
389
400
  }
390
401
 
391
- static NAN_METHOD(PtyResize) {
392
- Nan::HandleScope scope;
402
+ static Napi::Value PtyResize(const Napi::CallbackInfo& info) {
403
+ Napi::Env env(info.Env());
404
+ Napi::HandleScope scope(env);
393
405
 
394
406
  if (info.Length() != 3 ||
395
- !info[0]->IsNumber() ||
396
- !info[1]->IsNumber() ||
397
- !info[2]->IsNumber()) {
398
- Nan::ThrowError("Usage: pty.resize(id, cols, rows)");
399
- return;
407
+ !info[0].IsNumber() ||
408
+ !info[1].IsNumber() ||
409
+ !info[2].IsNumber()) {
410
+ throw Napi::Error::New(env, "Usage: pty.resize(id, cols, rows)");
400
411
  }
401
412
 
402
- int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
403
- SHORT cols = static_cast<SHORT>(info[1]->Uint32Value(Nan::GetCurrentContext()).FromJust());
404
- SHORT rows = static_cast<SHORT>(info[2]->Uint32Value(Nan::GetCurrentContext()).FromJust());
413
+ int id = info[0].As<Napi::Number>().Int32Value();
414
+ SHORT cols = static_cast<SHORT>(info[1].As<Napi::Number>().Uint32Value());
415
+ SHORT rows = static_cast<SHORT>(info[2].As<Napi::Number>().Uint32Value());
405
416
 
406
417
  const pty_baton* handle = get_pty_baton(id);
407
418
 
@@ -419,48 +430,48 @@ static NAN_METHOD(PtyResize) {
419
430
  }
420
431
  }
421
432
 
422
- return info.GetReturnValue().SetUndefined();
433
+ return env.Undefined();
423
434
  }
424
435
 
425
- static NAN_METHOD(PtyClear) {
426
- Nan::HandleScope scope;
436
+ static Napi::Value PtyClear(const Napi::CallbackInfo& info) {
437
+ Napi::Env env(info.Env());
438
+ Napi::HandleScope scope(env);
427
439
 
428
440
  if (info.Length() != 1 ||
429
- !info[0]->IsNumber()) {
430
- Nan::ThrowError("Usage: pty.clear(id)");
431
- return;
441
+ !info[0].IsNumber()) {
442
+ throw Napi::Error::New(env, "Usage: pty.clear(id)");
432
443
  }
433
444
 
434
- int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
445
+ // int id = info[0].As<Napi::Number>().Int32Value();
435
446
 
436
- const pty_baton* handle = get_pty_baton(id);
447
+ // const pty_baton* handle = get_pty_baton(id);
437
448
 
438
- if (handle != nullptr) {
439
- HANDLE hLibrary = LoadLibraryExW(L"kernel32.dll", 0, 0);
440
- bool fLoadedDll = hLibrary != nullptr;
441
- if (fLoadedDll)
442
- {
443
- PFNCLEARPSEUDOCONSOLE const pfnClearPseudoConsole = (PFNCLEARPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "ClearPseudoConsole");
444
- if (pfnClearPseudoConsole)
445
- {
446
- pfnClearPseudoConsole(handle->hpc);
447
- }
448
- }
449
- }
449
+ // if (handle != nullptr) {
450
+ // HANDLE hLibrary = LoadLibraryExW(L"kernel32.dll", 0, 0);
451
+ // bool fLoadedDll = hLibrary != nullptr;
452
+ // if (fLoadedDll)
453
+ // {
454
+ // PFNCLEARPSEUDOCONSOLE const pfnClearPseudoConsole = (PFNCLEARPSEUDOCONSOLE)GetProcAddress((HMODULE)hLibrary, "ClearPseudoConsole");
455
+ // if (pfnClearPseudoConsole)
456
+ // {
457
+ // pfnClearPseudoConsole(handle->hpc);
458
+ // }
459
+ // }
460
+ // }
450
461
 
451
- return info.GetReturnValue().SetUndefined();
462
+ return env.Undefined();
452
463
  }
453
464
 
454
- static NAN_METHOD(PtyKill) {
455
- Nan::HandleScope scope;
465
+ static Napi::Value PtyKill(const Napi::CallbackInfo& info) {
466
+ Napi::Env env(info.Env());
467
+ Napi::HandleScope scope(env);
456
468
 
457
469
  if (info.Length() != 1 ||
458
- !info[0]->IsNumber()) {
459
- Nan::ThrowError("Usage: pty.kill(id)");
460
- return;
470
+ !info[0].IsNumber()) {
471
+ throw Napi::Error::New(env, "Usage: pty.kill(id)");
461
472
  }
462
473
 
463
- int id = info[0]->Int32Value(Nan::GetCurrentContext()).FromJust();
474
+ int id = info[0].As<Napi::Number>().Int32Value();
464
475
 
465
476
  const pty_baton* handle = get_pty_baton(id);
466
477
 
@@ -476,27 +487,24 @@ static NAN_METHOD(PtyKill) {
476
487
  }
477
488
  }
478
489
 
479
- DisconnectNamedPipe(handle->hIn);
480
- DisconnectNamedPipe(handle->hOut);
481
- CloseHandle(handle->hIn);
482
- CloseHandle(handle->hOut);
483
490
  CloseHandle(handle->hShell);
491
+ assert(remove_pty_baton(id));
484
492
  }
485
493
 
486
- return info.GetReturnValue().SetUndefined();
494
+ return env.Undefined();
487
495
  }
488
496
 
489
497
  /**
490
498
  * Init
491
499
  */
492
500
 
493
- extern "C" void init(v8::Local<v8::Object> target) {
494
- Nan::HandleScope scope;
495
- Nan::SetMethod(target, "startProcess", PtyStartProcess);
496
- Nan::SetMethod(target, "connect", PtyConnect);
497
- Nan::SetMethod(target, "resize", PtyResize);
498
- Nan::SetMethod(target, "clear", PtyClear);
499
- Nan::SetMethod(target, "kill", PtyKill);
501
+ Napi::Object init(Napi::Env env, Napi::Object exports) {
502
+ exports.Set("startProcess", Napi::Function::New(env, PtyStartProcess));
503
+ exports.Set("connect", Napi::Function::New(env, PtyConnect));
504
+ exports.Set("resize", Napi::Function::New(env, PtyResize));
505
+ exports.Set("clear", Napi::Function::New(env, PtyClear));
506
+ exports.Set("kill", Napi::Function::New(env, PtyKill));
507
+ return exports;
500
508
  };
501
509
 
502
- NODE_MODULE(pty, init);
510
+ NODE_API_MODULE(NODE_GYP_MODULE_NAME, init);
@@ -2,23 +2,24 @@
2
2
  * Copyright (c) 2019, Microsoft Corporation (MIT License).
3
3
  */
4
4
 
5
- #include <nan.h>
5
+ #define NODE_ADDON_API_DISABLE_DEPRECATED
6
+ #include <napi.h>
6
7
  #include <windows.h>
7
8
 
8
- static NAN_METHOD(ApiConsoleProcessList) {
9
+ static Napi::Value ApiConsoleProcessList(const Napi::CallbackInfo& info) {
10
+ Napi::Env env(info.Env());
9
11
  if (info.Length() != 1 ||
10
- !info[0]->IsNumber()) {
11
- Nan::ThrowError("Usage: getConsoleProcessList(shellPid)");
12
- return;
12
+ !info[0].IsNumber()) {
13
+ throw Napi::Error::New(env, "Usage: getConsoleProcessList(shellPid)");
13
14
  }
14
15
 
15
- const DWORD pid = info[0]->Uint32Value(Nan::GetCurrentContext()).FromJust();
16
+ const DWORD pid = info[0].As<Napi::Number>().Uint32Value();
16
17
 
17
18
  if (!FreeConsole()) {
18
- Nan::ThrowError("FreeConsole failed");
19
+ throw Napi::Error::New(env, "FreeConsole failed");
19
20
  }
20
21
  if (!AttachConsole(pid)) {
21
- Nan::ThrowError("AttachConsole failed");
22
+ throw Napi::Error::New(env, "AttachConsole failed");
22
23
  }
23
24
  auto processList = std::vector<DWORD>(64);
24
25
  auto processCount = GetConsoleProcessList(&processList[0], static_cast<DWORD>(processList.size()));
@@ -28,16 +29,16 @@ static NAN_METHOD(ApiConsoleProcessList) {
28
29
  }
29
30
  FreeConsole();
30
31
 
31
- v8::Local<v8::Array> result = Nan::New<v8::Array>();
32
+ Napi::Array result = Napi::Array::New(env);
32
33
  for (DWORD i = 0; i < processCount; i++) {
33
- Nan::Set(result, i, Nan::New<v8::Number>(processList[i]));
34
+ result.Set(i, Napi::Number::New(env, processList[i]));
34
35
  }
35
- info.GetReturnValue().Set(result);
36
+ return result;
36
37
  }
37
38
 
38
- extern "C" void init(v8::Local<v8::Object> target) {
39
- Nan::HandleScope scope;
40
- Nan::SetMethod(target, "getConsoleProcessList", ApiConsoleProcessList);
39
+ Napi::Object init(Napi::Env env, Napi::Object exports) {
40
+ exports.Set("getConsoleProcessList", Napi::Function::New(env, ApiConsoleProcessList));
41
+ return exports;
41
42
  };
42
43
 
43
- NODE_MODULE(pty, init);
44
+ NODE_API_MODULE(NODE_GYP_MODULE_NAME, init);