Add capturing of stdout/stderr output in exec API
This commit is contained in:
parent
af7ae2ae2a
commit
b1eab3abdf
@ -173,7 +173,7 @@ DQN_API Dqn_Str8 Dqn_CPPBuild_ToCommandLineStr8(Dqn_CPPBuildContext build_contex
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_CPPBuildAsyncResult Dqn_CPPBuild_Async(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode)
|
||||
DQN_API Dqn_CPPBuildAsyncResult Dqn_CPPBuild_Async(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMode mode, Dqn_ErrorSink *error)
|
||||
{
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Slice<Dqn_Str8> cmd_line = Dqn_CPPBuild_ToCommandLine(build_context, mode, scratch.arena);
|
||||
@ -183,10 +183,11 @@ DQN_API Dqn_CPPBuildAsyncResult Dqn_CPPBuild_Async(Dqn_CPPBuildContext build_con
|
||||
|
||||
if (!Dqn_OS_MakeDir(build_context.build_dir)) {
|
||||
result.status = Dqn_CPPBuildStatus_BuildDirectoryFailedToBeMade;
|
||||
Dqn_ErrorSink_MakeF(error, result.status, "Failed to make build directory '%.*s'", DQN_STR_FMT(build_context.build_dir));
|
||||
return result;
|
||||
}
|
||||
|
||||
result.async_handle = Dqn_OS_ExecAsync(cmd_line, build_context.build_dir);
|
||||
result.async_handle = Dqn_OS_ExecAsync(cmd_line, build_context.build_dir, Dqn_OSExecFlag_Nil, error);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -198,6 +199,6 @@ void Dqn_CPPBuild_ExecOrAbort(Dqn_CPPBuildContext build_context, Dqn_CPPBuildMod
|
||||
}
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Slice<Dqn_Str8> cmd_line = Dqn_CPPBuild_ToCommandLine(build_context, mode, scratch.arena);
|
||||
Dqn_OS_ExecOrAbort(cmd_line, build_context.build_dir);
|
||||
Dqn_OS_ExecOrAbort(cmd_line, build_context.build_dir, Dqn_OSExecFlag_Nil, scratch.arena);
|
||||
}
|
||||
#endif // DQN_CPP_BUILD_IMPLEMENTATION
|
||||
|
44
dqn_os.cpp
44
dqn_os.cpp
@ -440,29 +440,39 @@ DQN_API Dqn_Str8 Dqn_OS_PathBuildWithSeparator(Dqn_Arena *arena, Dqn_OSPath cons
|
||||
|
||||
|
||||
// NOTE: [$EXEC] Dqn_OSExec ////////////////////////////////////////////////////////////////////////
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_Exec(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir)
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_Exec(Dqn_Slice<Dqn_Str8> cmd_line,
|
||||
Dqn_Str8 working_dir,
|
||||
uint8_t exec_flag,
|
||||
Dqn_Arena *arena,
|
||||
Dqn_ErrorSink *error)
|
||||
{
|
||||
Dqn_OSExecAsyncHandle async_handle = Dqn_OS_ExecAsync(cmd_line, working_dir);
|
||||
Dqn_OSExecResult result = Dqn_OS_ExecWait(async_handle);
|
||||
Dqn_OSExecAsyncHandle async_handle = Dqn_OS_ExecAsync(cmd_line, working_dir, exec_flag, error);
|
||||
Dqn_OSExecResult result = Dqn_OS_ExecWait(async_handle, arena, error);
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API void Dqn_OS_ExecOrAbort(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir)
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena)
|
||||
{
|
||||
Dqn_OSExecResult result = Dqn_OS_Exec(cmd_line, working_dir);
|
||||
if (result.os_error_code || result.exit_code) {
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(nullptr);
|
||||
Dqn_Str8 cmd_combined = Dqn_Slice_Str8Render(scratch.arena, cmd_line, DQN_STR8(" ") /*separator*/);
|
||||
if (result.os_error_code) {
|
||||
Dqn_Log_ErrorF("OS failed to execute the requested command returning the error code %u. The command was\n\n%.*s", result.os_error_code, DQN_STR_FMT(cmd_combined));
|
||||
Dqn_OS_Exit(result.os_error_code);
|
||||
}
|
||||
|
||||
if (result.exit_code) {
|
||||
Dqn_Log_ErrorF("OS executed command and returned a non-zero status: %u. The command was\n\n%.*s", result.exit_code, DQN_STR_FMT(cmd_combined));
|
||||
Dqn_OS_Exit(result.exit_code);
|
||||
}
|
||||
Dqn_ErrorSink *error = Dqn_ErrorSink_Begin(Dqn_ErrorSinkMode_Nil);
|
||||
Dqn_OSExecResult result = Dqn_OS_Exec(cmd_line, working_dir, exec_flag, arena, error);
|
||||
if (result.os_error_code) {
|
||||
Dqn_ErrorSink_EndAndExitIfErrorF(
|
||||
error,
|
||||
result.os_error_code,
|
||||
"OS failed to execute the requested command returning the error code %u",
|
||||
result.os_error_code);
|
||||
}
|
||||
|
||||
if (result.exit_code) {
|
||||
Dqn_ErrorSink_EndAndExitIfErrorF(
|
||||
error,
|
||||
result.exit_code,
|
||||
"OS executed command and returned non-zero exit code %u",
|
||||
result.exit_code);
|
||||
}
|
||||
|
||||
Dqn_ErrorSink_EndAndIgnore(error);
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: [$HTTP] Dqn_OSHttp ////////////////////////////////////////////////////////////////////////
|
||||
|
26
dqn_os.h
26
dqn_os.h
@ -169,15 +169,33 @@ struct Dqn_OSPath
|
||||
};
|
||||
|
||||
// NOTE: [$EXEC] Dqn_OSExec ////////////////////////////////////////////////////////////////////////
|
||||
enum Dqn_OSExecFlag
|
||||
{
|
||||
Dqn_OSExecFlag_Nil = 0,
|
||||
Dqn_OSExecFlag_SaveStdout = 1 << 0,
|
||||
Dqn_OSExecFlag_SaveStderr = 1 << 1,
|
||||
Dqn_OSExecFlag_SaveOutput = Dqn_OSExecFlag_SaveStdout | Dqn_OSExecFlag_SaveStderr,
|
||||
Dqn_OSExecFlag_MergeStderrToStdout = 1 << 2 | Dqn_OSExecFlag_SaveOutput,
|
||||
};
|
||||
|
||||
struct Dqn_OSExecAsyncHandle
|
||||
{
|
||||
uint8_t exec_flags;
|
||||
uint32_t os_error_code;
|
||||
uint32_t exit_code;
|
||||
void *process;
|
||||
#if defined(DQN_OS_WIN32)
|
||||
void *stdout_read;
|
||||
void *stdout_write;
|
||||
void *stderr_read;
|
||||
void *stderr_write;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Dqn_OSExecResult
|
||||
{
|
||||
Dqn_Str8 stdout_text;
|
||||
Dqn_Str8 stderr_text;
|
||||
uint32_t os_error_code;
|
||||
uint32_t exit_code;
|
||||
};
|
||||
@ -345,10 +363,10 @@ DQN_API Dqn_Str8 Dqn_OS_PathConvertF (Dqn_Arena *arena
|
||||
|
||||
// NOTE: [$EXEC] Dqn_OSExec ////////////////////////////////////////////////////////////////////////
|
||||
DQN_API void Dqn_OS_Exit (int32_t exit_code);
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait (Dqn_OSExecAsyncHandle handle);
|
||||
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir);
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir);
|
||||
DQN_API void Dqn_OS_ExecOrAbort(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir);
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait (Dqn_OSExecAsyncHandle handle, Dqn_Arena *arena, Dqn_ErrorSink *error);
|
||||
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync (Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_ErrorSink *error);
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_Exec (Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena, Dqn_ErrorSink *error);
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_ExecOrAbort(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t exec_flag, Dqn_Arena *arena);
|
||||
|
||||
// NOTE: [$SEMA] Dqn_OSSemaphore ///////////////////////////////////////////////////////////////////
|
||||
#if !defined(DQN_NO_SEMAPHORE)
|
||||
|
197
dqn_os_win32.cpp
197
dqn_os_win32.cpp
@ -550,38 +550,92 @@ DQN_API void Dqn_OS_Exit(int32_t exit_code)
|
||||
ExitProcess(DQN_CAST(UINT)exit_code);
|
||||
}
|
||||
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle)
|
||||
DQN_API Dqn_OSExecResult Dqn_OS_ExecWait(Dqn_OSExecAsyncHandle handle, Dqn_Arena *arena, Dqn_ErrorSink *error)
|
||||
{
|
||||
Dqn_OSExecResult result = {};
|
||||
if (!handle.process || handle.os_error_code) {
|
||||
result.os_error_code = handle.os_error_code;
|
||||
if (!handle.process || handle.os_error_code || handle.exit_code) {
|
||||
if (handle.os_error_code)
|
||||
result.os_error_code = handle.os_error_code;
|
||||
else
|
||||
result.exit_code = handle.exit_code;
|
||||
|
||||
DQN_ASSERT(!handle.stdout_read);
|
||||
DQN_ASSERT(!handle.stdout_write);
|
||||
DQN_ASSERT(!handle.stderr_read);
|
||||
DQN_ASSERT(!handle.stderr_write);
|
||||
DQN_ASSERT(!handle.process);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (handle.exit_code) {
|
||||
result.exit_code = handle.exit_code;
|
||||
return result;
|
||||
}
|
||||
Dqn_Scratch scratch = Dqn_Scratch_Get(arena);
|
||||
DWORD exec_result = WaitForSingleObject(handle.process, INFINITE);
|
||||
CloseHandle(handle.stdout_write);
|
||||
CloseHandle(handle.stderr_write);
|
||||
|
||||
DWORD exec_result = WaitForSingleObject(handle.process, INFINITE);
|
||||
if (exec_result == WAIT_FAILED) {
|
||||
result.os_error_code = GetLastError();
|
||||
return result;
|
||||
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
Dqn_ErrorSink_MakeF(error, result.os_error_code, "Executed command failed to terminate: %.*s", DQN_STR_FMT(win_error.msg));
|
||||
CloseHandle(handle.process);
|
||||
} else {
|
||||
// NOTE: Get exit code /////////////////////////////////////////////////////////////////////
|
||||
DWORD exit_status;
|
||||
if (GetExitCodeProcess(handle.process, &exit_status)) {
|
||||
result.exit_code = exit_status;
|
||||
} else {
|
||||
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
Dqn_ErrorSink_MakeF(error,
|
||||
result.os_error_code,
|
||||
"Failed to retrieve command exit code: %.*s",
|
||||
DQN_STR_FMT(win_error.msg));
|
||||
}
|
||||
|
||||
CloseHandle(handle.process);
|
||||
|
||||
// NOTE: Read stdout from process //////////////////////////////////////////////////////////
|
||||
if (arena && handle.stdout_write) {
|
||||
char stdout_buffer[4096];
|
||||
Dqn_Str8Builder builder = {};
|
||||
builder.arena = scratch.arena;
|
||||
for (;;) {
|
||||
DWORD bytes_read = 0;
|
||||
BOOL success = ReadFile(handle.stdout_read, stdout_buffer, sizeof(stdout_buffer), &bytes_read, NULL);
|
||||
if (!success || bytes_read == 0)
|
||||
break;
|
||||
|
||||
Dqn_Str8Builder_AppendF(&builder, "%.*s", bytes_read, stdout_buffer);
|
||||
}
|
||||
|
||||
result.stdout_text = Dqn_Str8Builder_Build(&builder, arena);
|
||||
}
|
||||
|
||||
// NOTE: Read stderr from process //////////////////////////////////////////////////////////
|
||||
if (arena && handle.stderr_read) {
|
||||
char stderr_buffer[4096];
|
||||
Dqn_Str8Builder builder = {};
|
||||
builder.arena = scratch.arena;
|
||||
for (;;) {
|
||||
DWORD bytes_read = 0;
|
||||
BOOL success = ReadFile(handle.stderr_read, stderr_buffer, sizeof(stderr_buffer), &bytes_read, NULL);
|
||||
if (!success || bytes_read == 0)
|
||||
break;
|
||||
|
||||
Dqn_Str8Builder_AppendF(&builder, "%.*s", bytes_read, stderr_buffer);
|
||||
}
|
||||
|
||||
result.stderr_text = Dqn_Str8Builder_Build(&builder, arena);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD exit_status;
|
||||
if (!GetExitCodeProcess(handle.process, &exit_status)) {
|
||||
result.os_error_code = GetLastError();
|
||||
return result;
|
||||
}
|
||||
|
||||
result.exit_code = exit_status;
|
||||
CloseHandle(handle.process);
|
||||
CloseHandle(handle.stdout_read);
|
||||
CloseHandle(handle.stderr_read);
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir)
|
||||
DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn_Str8 working_dir, uint8_t flags, Dqn_ErrorSink *error)
|
||||
{
|
||||
// NOTE: Pre-amble /////////////////////////////////////////////////////////////////////////////
|
||||
Dqn_OSExecAsyncHandle result = {};
|
||||
if (cmd_line.size == 0)
|
||||
return result;
|
||||
@ -591,21 +645,118 @@ DQN_API Dqn_OSExecAsyncHandle Dqn_OS_ExecAsync(Dqn_Slice<Dqn_Str8> cmd_line, Dqn
|
||||
Dqn_Str16 cmd16 = Dqn_Win_Str8ToStr16(scratch.arena, cmd_rendered);
|
||||
Dqn_Str16 working_dir16 = Dqn_Win_Str8ToStr16(scratch.arena, working_dir);
|
||||
|
||||
// NOTE: Stdout/err security attributes ////////////////////////////////////////////////////////
|
||||
SECURITY_ATTRIBUTES save_std_security_attribs = {};
|
||||
save_std_security_attribs.nLength = sizeof(save_std_security_attribs);
|
||||
save_std_security_attribs.bInheritHandle = true;
|
||||
|
||||
// NOTE: Redirect stdout ///////////////////////////////////////////////////////////////////////
|
||||
HANDLE stdout_read = {};
|
||||
HANDLE stdout_write = {};
|
||||
if (flags & Dqn_OSExecFlag_SaveStdout) {
|
||||
if (!CreatePipe(&stdout_read, &stdout_write, &save_std_security_attribs, /*nSize*/ 0)) {
|
||||
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
Dqn_ErrorSink_MakeF(
|
||||
error,
|
||||
result.os_error_code,
|
||||
"Failed to create stdout pipe to redirect the output of the command '%.*s': %.*s",
|
||||
DQN_STR_FMT(cmd_rendered),
|
||||
DQN_STR_FMT(win_error.msg));
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_DEFER {
|
||||
if (result.os_error_code) {
|
||||
CloseHandle(stdout_read);
|
||||
CloseHandle(stdout_write);
|
||||
}
|
||||
};
|
||||
|
||||
if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) {
|
||||
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
Dqn_ErrorSink_MakeF(error,
|
||||
result.os_error_code,
|
||||
"Failed to make stdout 'read' pipe non-inheritable when trying to "
|
||||
"execute command '%.*s': %.*s",
|
||||
DQN_STR_FMT(cmd_rendered),
|
||||
DQN_STR_FMT(win_error.msg));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Redirect stderr ///////////////////////////////////////////////////////////////////////
|
||||
HANDLE stderr_read = {};
|
||||
HANDLE stderr_write = {};
|
||||
if (flags & Dqn_OSExecFlag_SaveStderr) {
|
||||
if (flags & Dqn_OSExecFlag_MergeStderrToStdout) {
|
||||
stderr_read = stdout_read;
|
||||
stderr_write = stdout_write;
|
||||
} else {
|
||||
if (!CreatePipe(&stderr_read, &stderr_write, &save_std_security_attribs, /*nSize*/ 0)) {
|
||||
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
Dqn_ErrorSink_MakeF(
|
||||
error,
|
||||
result.os_error_code,
|
||||
"Failed to create stderr pipe to redirect the output of the command '%.*s': %.*s",
|
||||
DQN_STR_FMT(cmd_rendered),
|
||||
DQN_STR_FMT(win_error.msg));
|
||||
return result;
|
||||
}
|
||||
|
||||
DQN_DEFER {
|
||||
if (result.os_error_code) {
|
||||
CloseHandle(stderr_read);
|
||||
CloseHandle(stderr_write);
|
||||
}
|
||||
};
|
||||
|
||||
if (!SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0)) {
|
||||
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
Dqn_ErrorSink_MakeF(error,
|
||||
result.os_error_code,
|
||||
"Failed to make stderr 'read' pipe non-inheritable when trying to "
|
||||
"execute command '%.*s': %.*s",
|
||||
DQN_STR_FMT(cmd_rendered),
|
||||
DQN_STR_FMT(win_error.msg));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Execute command ///////////////////////////////////////////////////////////////////////
|
||||
PROCESS_INFORMATION proc_info = {};
|
||||
STARTUPINFOW startup_info = {};
|
||||
startup_info.cb = sizeof(STARTUPINFOW);
|
||||
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||
startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
startup_info.hStdError = stderr_write ? stderr_write : GetStdHandle(STD_ERROR_HANDLE);
|
||||
startup_info.hStdOutput = stdout_write ? stdout_write : GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
||||
BOOL create_result = CreateProcessW(nullptr, cmd16.data, nullptr, nullptr, true, 0, nullptr, working_dir16.data, &startup_info, &proc_info);
|
||||
if (!create_result) {
|
||||
result.os_error_code = GetLastError();
|
||||
Dqn_WinError win_error = Dqn_Win_LastError(scratch.arena);
|
||||
result.os_error_code = win_error.code;
|
||||
Dqn_ErrorSink_MakeF(error,
|
||||
result.os_error_code,
|
||||
"Failed to execute command '%.*s': %.*s",
|
||||
DQN_STR_FMT(cmd_rendered),
|
||||
DQN_STR_FMT(win_error.msg));
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: Post-amble ////////////////////////////////////////////////////////////////////////////
|
||||
CloseHandle(proc_info.hThread);
|
||||
result.process = proc_info.hProcess;
|
||||
result.process = proc_info.hProcess;
|
||||
result.stdout_read = stdout_read;
|
||||
result.stdout_write = stdout_write;
|
||||
if ((flags & Dqn_OSExecFlag_MergeStderrToStdout) == 0) {
|
||||
result.stderr_read = stderr_read;
|
||||
result.stderr_write = stderr_write;
|
||||
}
|
||||
result.exec_flags = flags;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
16
dqn_win32.h
16
dqn_win32.h
@ -417,7 +417,6 @@
|
||||
|
||||
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
|
||||
|
||||
// NOTE: um/winbase.h //////////////////////////////////////////////////////////////////////////
|
||||
#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
|
||||
#define WAIT_OBJECT_0 ((STATUS_WAIT_0 ) + 0 )
|
||||
|
||||
@ -427,6 +426,9 @@
|
||||
#define STD_OUTPUT_HANDLE ((DWORD)-11)
|
||||
#define STD_ERROR_HANDLE ((DWORD)-12)
|
||||
|
||||
#define HANDLE_FLAG_INHERIT 0x00000001
|
||||
#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002
|
||||
|
||||
// NOTE: MoveFile
|
||||
#define MOVEFILE_REPLACE_EXISTING 0x00000001
|
||||
#define MOVEFILE_COPY_ALLOWED 0x00000002
|
||||
@ -1080,5 +1082,17 @@
|
||||
__declspec(dllimport) BOOL __stdcall IsDebuggerPresent();
|
||||
}
|
||||
|
||||
// NOTE: um/namedpipeapi.h /////////////////////////////////////////////////////////////////////
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport) BOOL __stdcall CreatePipe (HANDLE *hReadPipe, HANDLE *hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize);
|
||||
}
|
||||
|
||||
// NOTE: um/handleapi.h /////////////////////////////////////////////////////////////////////
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport) BOOL __stdcall SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags);
|
||||
}
|
||||
|
||||
DQN_MSVC_WARNING_POP
|
||||
#endif // !defined(_INC_WINDOWS)
|
||||
|
Loading…
Reference in New Issue
Block a user