esp-idf/tools/windows/tool_setup/cmdlinerunner/cmdlinerunner.c

195 lines
5.4 KiB
C

// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at",
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License
#define CMDLINERUNNER_EXPORTS
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include "cmdlinerunner.h"
#define LINESIZE 1024
#ifdef WITH_DEBUG
#include <stdio.h>
#define DEBUGV(...) do { fprintf(stderr, __VA_ARG__); } while(0)
#else
#define DEBUGV(...)
#endif
struct proc_instance_s {
PROCESS_INFORMATION child_process;
HANDLE pipe_server_handle;
HANDLE pipe_client_handle;
};
#ifdef WITH_DEBUG
static void print_last_error(void)
{
DWORD dw;
TCHAR errmsg[LINESIZE];
dw = GetLastError();
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
errmsg, sizeof(errmsg) - 1, NULL );
DEBUGV("error %d: %s\n", dw, errmsg);
}
#define PRINT_LAST_ERROR() print_last_error()
#else
#define PRINT_LAST_ERROR()
#endif
static proc_instance_t *proc_instance_allocate(void)
{
return (proc_instance_t*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(proc_instance_t));
}
static void proc_instance_free(proc_instance_t *instance)
{
if (instance->pipe_server_handle) {
CloseHandle(instance->pipe_server_handle);
}
if (instance->pipe_client_handle) {
CloseHandle(instance->pipe_client_handle);
}
if (instance->child_process.hProcess) {
TerminateProcess(instance->child_process.hProcess, 1);
CloseHandle(instance->child_process.hProcess);
CloseHandle(instance->child_process.hThread);
}
HeapFree(GetProcessHeap(), 0, instance);
}
void proc_end(proc_instance_t *inst)
{
if (inst == NULL) {
return;
}
proc_instance_free(inst);
}
CMDLINERUNNER_API proc_instance_t * proc_start(LPCTSTR cmdline, LPCTSTR workdir)
{
proc_instance_t *inst = proc_instance_allocate();
if (inst == NULL) {
return NULL;
}
SECURITY_ATTRIBUTES sec_attr = {
.nLength = sizeof(SECURITY_ATTRIBUTES),
.bInheritHandle = TRUE,
.lpSecurityDescriptor = NULL
};
LPCTSTR pipename = TEXT("\\\\.\\pipe\\cmdlinerunner_pipe");
inst->pipe_server_handle = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_WAIT, 1, 1024 * 16, 1024 * 16,
NMPWAIT_WAIT_FOREVER, &sec_attr);
if (inst->pipe_server_handle == INVALID_HANDLE_VALUE) {
DEBUGV("inst->pipe_server_handle == INVALID_HANDLE_VALUE\n");
goto error;
}
inst->pipe_client_handle = CreateFile(pipename, GENERIC_WRITE | GENERIC_READ,
0, &sec_attr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (inst->pipe_client_handle == INVALID_HANDLE_VALUE) {
DEBUGV("inst->pipe_client_handle == INVALID_HANDLE_VALUE\n");
goto error;
}
DWORD new_mode = PIPE_READMODE_BYTE | PIPE_NOWAIT;
if (!SetNamedPipeHandleState(inst->pipe_server_handle, &new_mode, NULL,
NULL)) {
DEBUGV("SetNamedPipeHandleState failed\n");
goto error;
}
if (!SetHandleInformation(inst->pipe_server_handle, HANDLE_FLAG_INHERIT, 0)) {
DEBUGV("SetHandleInformation failed\n");
goto error;
}
if (!SetHandleInformation(inst->pipe_client_handle, HANDLE_FLAG_INHERIT,
HANDLE_FLAG_INHERIT)) {
DEBUGV("SetHandleInformation failed\n");
goto error;
}
STARTUPINFO siStartInfo = {
.cb = sizeof(STARTUPINFO),
.hStdError = inst->pipe_client_handle,
.hStdOutput = inst->pipe_client_handle,
.hStdInput = inst->pipe_client_handle,
.dwFlags = STARTF_USESTDHANDLES
};
size_t workdir_len = 0;
StringCbLength(workdir, STRSAFE_MAX_CCH * sizeof(TCHAR), &workdir_len);
if (workdir_len == 0) {
workdir = NULL;
}
TCHAR cmdline_tmp[LINESIZE];
StringCbCopy(cmdline_tmp, sizeof(cmdline_tmp), cmdline);
if (!CreateProcess(NULL, cmdline_tmp,
NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, workdir, &siStartInfo,
&inst->child_process)) {
DEBUGV("CreateProcess failed\n");
goto error;
}
return inst;
error:
PRINT_LAST_ERROR();
proc_instance_free(inst);
return NULL;
}
int proc_get_exit_code(proc_instance_t *inst)
{
DWORD result;
if (!GetExitCodeProcess(inst->child_process.hProcess, &result)) {
return -2;
}
if (result == STILL_ACTIVE) {
return -1;
}
return (int) result;
}
DWORD proc_get_output(proc_instance_t *inst, LPSTR dest, DWORD sz)
{
DWORD read_bytes;
BOOL res = ReadFile(inst->pipe_server_handle, dest,
sz - 1, &read_bytes, NULL);
if (!res) {
if (GetLastError() == ERROR_NO_DATA) {
return 0;
} else {
PRINT_LAST_ERROR();
return 0;
}
}
dest[read_bytes] = 0;
return read_bytes;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved )
{
return TRUE;
}