Compare commits
21 Commits
master
...
nodejs_fix
Author | SHA1 | Date | |
---|---|---|---|
|
bbdc8b82ae | ||
|
4f38a876ec | ||
|
86690addf4 | ||
|
25e3186e9e | ||
|
d4b5cb8a33 | ||
|
1db59898e3 | ||
|
efc82affdf | ||
|
9325995ae4 | ||
|
587e5125a7 | ||
|
237c36b7db | ||
|
515dea18de | ||
|
b4fea62fb0 | ||
|
4bdd7b32b5 | ||
|
8aa7662093 | ||
|
1cb199b1f0 | ||
|
3f1bbcd9af | ||
|
7091af176a | ||
|
857ed8934b | ||
|
964f5a63f8 | ||
|
747a5401e8 | ||
|
5363fb6c21 |
@ -192,7 +192,7 @@ void Agent::handlePacket(ReadBuffer &packet)
|
||||
|
||||
int Agent::handleStartProcessPacket(ReadBuffer &packet)
|
||||
{
|
||||
BOOL success;
|
||||
BOOL success;
|
||||
ASSERT(m_childProcess == NULL);
|
||||
|
||||
std::wstring program = packet.getWString();
|
||||
@ -212,7 +212,11 @@ int Agent::handleStartProcessPacket(ReadBuffer &packet)
|
||||
cmdlineArg = &cmdlineCopy[0];
|
||||
}
|
||||
LPCWSTR cwdArg = cwd.empty() ? NULL : cwd.c_str();
|
||||
LPCWSTR envArg = env.empty() ? NULL : env.data();
|
||||
LPCWSTR envArg = env.empty() ? NULL : env.c_str();
|
||||
|
||||
if(envArg != NULL && wcscmp(envArg, L"")) {
|
||||
envArg = NULL;
|
||||
}
|
||||
|
||||
STARTUPINFO sui;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
class EventLoop;
|
||||
|
||||
|
@ -57,7 +57,7 @@ Terminal::Terminal(NamedPipe *output) :
|
||||
void Terminal::reset(bool sendClearFirst, int newLine)
|
||||
{
|
||||
if (sendClearFirst)
|
||||
m_output->write(CSI"1;1H"CSI"2J");
|
||||
m_output->write(CSI"1;1H" CSI"2J");
|
||||
m_remoteLine = newLine;
|
||||
m_cursorHidden = false;
|
||||
m_cursorPos = std::pair<int, int>(0, newLine);
|
||||
@ -162,7 +162,7 @@ void Terminal::finishOutput(const std::pair<int, int> &newCursorPos)
|
||||
if (m_cursorHidden) {
|
||||
moveTerminalToLine(newCursorPos.second);
|
||||
char buffer[32];
|
||||
sprintf(buffer, CSI"%dG"CSI"?25h", newCursorPos.first + 1);
|
||||
sprintf(buffer, CSI"%dG" CSI"?25h", newCursorPos.first + 1);
|
||||
m_output->write(buffer);
|
||||
m_cursorHidden = false;
|
||||
}
|
||||
@ -187,7 +187,7 @@ void Terminal::moveTerminalToLine(int line)
|
||||
if (line < m_remoteLine) {
|
||||
// CUrsor Up (CUU)
|
||||
char buffer[32];
|
||||
sprintf(buffer, "\r"CSI"%dA", m_remoteLine - line);
|
||||
sprintf(buffer, "\r" CSI"%dA", m_remoteLine - line);
|
||||
m_output->write(buffer);
|
||||
m_remoteLine = line;
|
||||
} else if (line > m_remoteLine) {
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define WINPTY_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -49,6 +50,16 @@ typedef struct winpty_s winpty_t;
|
||||
*/
|
||||
WINPTY_API winpty_t *winpty_open(int cols, int rows);
|
||||
|
||||
/**
|
||||
* Starts a new winpty instance with the given size.
|
||||
*
|
||||
* This function creates a new agent process and connects to it.
|
||||
* By using this method you are responsible for creating your own named
|
||||
* pipe server for communicating with the child process.
|
||||
*
|
||||
*/
|
||||
WINPTY_API winpty_t *winpty_open_use_own_datapipe(const wchar_t *dataPipe, int cols, int rows);
|
||||
|
||||
/*
|
||||
* Start a child process. Either (but not both) of appname and cmdline may
|
||||
* be NULL. cwd and env may be NULL. env is a pointer to an environment
|
||||
@ -88,7 +99,7 @@ WINPTY_API int winpty_set_size(winpty_t *pc, int cols, int rows);
|
||||
/*
|
||||
* Closes the winpty.
|
||||
*/
|
||||
WINPTY_API void winpty_close(winpty_t *pc);
|
||||
WINPTY_API void winpty_exit(winpty_t *pc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -27,9 +27,59 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
std::string to_utf8(const wchar_t* buffer, int len)
|
||||
{
|
||||
int nChars = ::WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
buffer,
|
||||
len,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
if (nChars == 0) return "";
|
||||
|
||||
std::string newbuffer;
|
||||
newbuffer.resize(nChars) ;
|
||||
::WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
buffer,
|
||||
len,
|
||||
const_cast< char* >(newbuffer.c_str()),
|
||||
nChars,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
return newbuffer;
|
||||
}
|
||||
|
||||
std::string to_utf8(const std::wstring& str)
|
||||
{
|
||||
return to_utf8(str.c_str(), (int)str.size());
|
||||
}
|
||||
|
||||
std::wstring to_wstring(const std::string& s)
|
||||
{
|
||||
int len;
|
||||
int slength = (int)s.length() + 1;
|
||||
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
|
||||
wchar_t* buf = new wchar_t[len];
|
||||
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
|
||||
std::wstring r(buf);
|
||||
delete[] buf;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "../shared/DebugClient.h"
|
||||
#include "../shared/AgentMsg.h"
|
||||
#include "../shared/Buffer.h"
|
||||
#include "../shared/c99_snprintf.h"
|
||||
|
||||
// TODO: Error handling, handle out-of-memory.
|
||||
|
||||
@ -86,7 +136,7 @@ static bool pathExists(const std::wstring &path)
|
||||
static std::wstring findAgentProgram()
|
||||
{
|
||||
std::wstring progDir = dirname(getModuleFileName(getCurrentModule()));
|
||||
std::wstring ret = progDir + L"\\"AGENT_EXE;
|
||||
std::wstring ret = progDir + (L"\\" AGENT_EXE);
|
||||
assert(pathExists(ret));
|
||||
return ret;
|
||||
}
|
||||
@ -117,10 +167,13 @@ static bool connectNamedPipe(HANDLE handle, bool overlapped)
|
||||
static void writePacket(winpty_t *pc, const WriteBuffer &packet)
|
||||
{
|
||||
std::string payload = packet.str();
|
||||
|
||||
int32_t payloadSize = payload.size();
|
||||
DWORD actual;
|
||||
BOOL success = WriteFile(pc->controlPipe, &payloadSize, sizeof(int32_t), &actual, NULL);
|
||||
|
||||
assert(success && actual == sizeof(int32_t));
|
||||
|
||||
success = WriteFile(pc->controlPipe, payload.c_str(), payloadSize, &actual, NULL);
|
||||
assert(success && (int32_t)actual == payloadSize);
|
||||
}
|
||||
@ -259,10 +312,13 @@ WINPTY_API winpty_t *winpty_open(int cols, int rows)
|
||||
|
||||
// Start pipes.
|
||||
std::wstringstream pipeName;
|
||||
pipeName << L"\\\\.\\pipe\\winpty-" << GetCurrentProcessId()
|
||||
<< L"-" << InterlockedIncrement(&consoleCounter);
|
||||
std::wstring controlPipeName = pipeName.str() + L"-control";
|
||||
std::wstring dataPipeName = pipeName.str() + L"-data";
|
||||
|
||||
// Allow custom pipe names.
|
||||
pipeName << L"\\\\.\\pipe\\winpty-" << GetCurrentProcessId()
|
||||
<< L"-" << InterlockedIncrement(&consoleCounter);
|
||||
std::wstring controlPipeName = pipeName.str() + L"-control";
|
||||
std::wstring dataPipeName = pipeName.str() + L"-data";
|
||||
|
||||
pc->controlPipe = createNamedPipe(controlPipeName, false);
|
||||
if (pc->controlPipe == INVALID_HANDLE_VALUE) {
|
||||
delete pc;
|
||||
@ -353,31 +409,67 @@ WINPTY_API winpty_t *winpty_open(int cols, int rows)
|
||||
return pc;
|
||||
}
|
||||
|
||||
WINPTY_API winpty_t *winpty_open_use_own_datapipe(const wchar_t *dataPipe, int cols, int rows)
|
||||
{
|
||||
|
||||
winpty_t *pc = new winpty_t;
|
||||
|
||||
// Setup pipes.
|
||||
std::wstringstream pipeName;
|
||||
pipeName << L"\\\\.\\pipe\\winpty-" << GetCurrentProcessId()
|
||||
<< L"-" << InterlockedIncrement(&consoleCounter);
|
||||
std::wstring controlPipeName = pipeName.str() + L"-control";
|
||||
|
||||
// The callee provides his own pipe implementation for handling sending/recieving
|
||||
// data between the started child process.
|
||||
std::wstring dataPipeName(to_wstring(to_utf8(dataPipe)));
|
||||
|
||||
// Create control pipe
|
||||
pc->controlPipe = createNamedPipe(controlPipeName, false);
|
||||
if (pc->controlPipe == INVALID_HANDLE_VALUE) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Setup a background desktop for the agent.
|
||||
BackgroundDesktop desktop = setupBackgroundDesktop();
|
||||
|
||||
// Start the agent.
|
||||
startAgentProcess(desktop, controlPipeName, dataPipeName, cols, rows);
|
||||
|
||||
// Test control pipe connection.
|
||||
if (!connectNamedPipe(pc->controlPipe, false)) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Restore desktop.
|
||||
restoreOriginalDesktop(desktop);
|
||||
|
||||
WriteBuffer packet;
|
||||
packet.putInt(AgentMsg::Ping);
|
||||
writePacket(pc, packet);
|
||||
if (readInt32(pc) != 0) {
|
||||
delete pc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pc;
|
||||
}
|
||||
|
||||
WINPTY_API int winpty_start_process(winpty_t *pc,
|
||||
const wchar_t *appname,
|
||||
const wchar_t *cmdline,
|
||||
const wchar_t *cwd,
|
||||
const wchar_t *env)
|
||||
{
|
||||
|
||||
WriteBuffer packet;
|
||||
packet.putInt(AgentMsg::StartProcess);
|
||||
packet.putWString(appname ? appname : L"");
|
||||
packet.putWString(cmdline ? cmdline : L"");
|
||||
packet.putWString(cwd ? cwd : L"");
|
||||
std::wstring envStr;
|
||||
if (env != NULL) {
|
||||
const wchar_t *p = env;
|
||||
while (*p != L'\0') {
|
||||
p += wcslen(p) + 1;
|
||||
}
|
||||
p++;
|
||||
envStr.assign(env, p);
|
||||
|
||||
// Can a Win32 environment be empty? If so, does it end with one NUL or
|
||||
// two? Add an extra NUL just in case it matters.
|
||||
envStr.push_back(L'\0');
|
||||
}
|
||||
packet.putWString(envStr);
|
||||
packet.putWString(env ? env : L"");
|
||||
packet.putWString(getDesktopFullName());
|
||||
writePacket(pc, packet);
|
||||
return readInt32(pc);
|
||||
@ -406,9 +498,10 @@ WINPTY_API int winpty_set_size(winpty_t *pc, int cols, int rows)
|
||||
return readInt32(pc);
|
||||
}
|
||||
|
||||
WINPTY_API void winpty_close(winpty_t *pc)
|
||||
WINPTY_API void winpty_exit(winpty_t *pc)
|
||||
{
|
||||
CloseHandle(pc->controlPipe);
|
||||
CloseHandle(pc->dataPipe);
|
||||
delete pc;
|
||||
CloseHandle(pc->controlPipe);
|
||||
if(pc->dataPipe > 0) {
|
||||
CloseHandle(pc->dataPipe);
|
||||
}
|
||||
}
|
||||
|
@ -99,4 +99,4 @@ void trace(const char *format, ...)
|
||||
fullMessage[sizeof(fullMessage) - 1] = '\0';
|
||||
|
||||
sendToDebugServer(fullMessage);
|
||||
}
|
||||
}
|
28
winpty.gyp
28
winpty.gyp
@ -6,37 +6,28 @@
|
||||
'include_dirs' : [
|
||||
'include',
|
||||
],
|
||||
'libraries' : [
|
||||
'user32.lib'
|
||||
],
|
||||
'defines' : [
|
||||
'UNICODE',
|
||||
'_UNICODE',
|
||||
'_WIN32_WINNT=0x0501',
|
||||
'NOMINMAX',
|
||||
],
|
||||
'msvs_disabled_warnings': [ 4267, 4244, 4530, 4267, 4800 ],
|
||||
'sources' : [
|
||||
'agent/Agent.h',
|
||||
'agent/Agent.cc',
|
||||
'agent/AgentAssert.h',
|
||||
'agent/AgentAssert.cc',
|
||||
'agent/ConsoleInput.cc',
|
||||
'agent/ConsoleInput.h',
|
||||
'agent/Coord.h',
|
||||
'agent/Coord.cc',
|
||||
'agent/DsrSender.h',
|
||||
'agent/EventLoop.cc',
|
||||
'agent/NamedPipe.h',
|
||||
'agent/NamedPipe.cc',
|
||||
'agent/SmallRect.h',
|
||||
'agent/SmallRect.cc',
|
||||
'agent/Terminal.h',
|
||||
'agent/Terminal.cc',
|
||||
'agent/Win32Console.cc',
|
||||
'agent/Win32Console.h',
|
||||
'agent/main.cc',
|
||||
'shared/AgentMsg.h',
|
||||
'shared/Buffer.h',
|
||||
'shared/DebugClient.h',
|
||||
'shared/DebugClient.cc',
|
||||
'shared/c99_snprintf.h',
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -45,6 +36,9 @@
|
||||
'include_dirs' : [
|
||||
'include',
|
||||
],
|
||||
'libraries' : [
|
||||
'user32.lib'
|
||||
],
|
||||
'defines' : [
|
||||
'UNICODE',
|
||||
'_UNICODE',
|
||||
@ -52,15 +46,11 @@
|
||||
'NOMINMAX',
|
||||
'WINPTY',
|
||||
],
|
||||
'msvs_disabled_warnings': [ 4267, 4800 ],
|
||||
'sources' : [
|
||||
'include/winpty.h',
|
||||
'libwinpty/winpty.cc',
|
||||
'shared/AgentMsg.h',
|
||||
'shared/Buffer.h',
|
||||
'shared/DebugClient.h',
|
||||
'shared/DebugClient.cc',
|
||||
'shared/c99_snprintf.h',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user