-
-
Save petrsmid/d96446beac825c8c0cf5a35240f444a8 to your computer and use it in GitHub Desktop.
fork() for Windows with fixed Console
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* fork.c | |
* Experimental fork() on Windows. Requires NT 6 subsystem or | |
* newer. | |
* | |
* Improved version with fixed Console | |
* | |
* Copyright (c) 2023 Petr Smid | |
* Copyright (c) 2012 William Pitcock <[email protected]> | |
* | |
* Permission to use, copy, modify, and/or distribute this software for any | |
* purpose with or without fee is hereby granted, provided that the above | |
* copyright notice and this permission notice appear in all copies. | |
* | |
* This software is provided 'as is' and without any warranty, express or | |
* implied. In no event shall the authors be liable for any damages arising | |
* from the use of this software. | |
*/ | |
#define _WIN32_WINNT 0x0600 | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#include <winnt.h> | |
#include <winternl.h> | |
#include <stdio.h> | |
#include <errno.h> | |
#include <assert.h> | |
#include <process.h> | |
#include <processthreadsapi.h> | |
#include <iostream> | |
#include <Windows.h> | |
/* | |
typedef struct _CLIENT_ID { | |
PVOID UniqueProcess; | |
PVOID UniqueThread; | |
} CLIENT_ID, * PCLIENT_ID; | |
*/ | |
typedef struct _SECTION_IMAGE_INFORMATION { | |
PVOID EntryPoint; | |
ULONG StackZeroBits; | |
ULONG StackReserved; | |
ULONG StackCommit; | |
ULONG ImageSubsystem; | |
WORD SubSystemVersionLow; | |
WORD SubSystemVersionHigh; | |
ULONG Unknown1; | |
ULONG ImageCharacteristics; | |
ULONG ImageMachineType; | |
ULONG Unknown2[3]; | |
} SECTION_IMAGE_INFORMATION, * PSECTION_IMAGE_INFORMATION; | |
typedef struct _RTL_USER_PROCESS_INFORMATION { | |
ULONG Size; | |
HANDLE Process; | |
HANDLE Thread; | |
CLIENT_ID ClientId; | |
SECTION_IMAGE_INFORMATION ImageInformation; | |
} RTL_USER_PROCESS_INFORMATION, * PRTL_USER_PROCESS_INFORMATION; | |
#define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED 0x00000001 | |
#define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES 0x00000002 | |
#define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE 0x00000004 | |
#define RTL_CLONE_PARENT 0 | |
#define RTL_CLONE_CHILD 297 | |
typedef DWORD pid_t; | |
typedef NTSTATUS(*RtlCloneUserProcess_f)(ULONG ProcessFlags, | |
PSECURITY_DESCRIPTOR ProcessSecurityDescriptor /* optional */, | |
PSECURITY_DESCRIPTOR ThreadSecurityDescriptor /* optional */, | |
HANDLE DebugPort /* optional */, | |
PRTL_USER_PROCESS_INFORMATION ProcessInformation); | |
int fork() | |
{ | |
DWORD parent_pid = GetCurrentProcessId(); | |
HMODULE mod; | |
RtlCloneUserProcess_f clone_p; | |
RTL_USER_PROCESS_INFORMATION process_info; | |
NTSTATUS result; | |
mod = GetModuleHandle("ntdll.dll"); | |
if (!mod) | |
return -ENOSYS; | |
clone_p = (RtlCloneUserProcess_f)GetProcAddress(mod, "RtlCloneUserProcess"); | |
if (clone_p == NULL) | |
return -ENOSYS; | |
/* lets do this */ | |
result = clone_p(RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED | RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES, NULL, NULL, NULL, &process_info); | |
if (result == RTL_CLONE_PARENT) | |
{ | |
HANDLE me = 0, hp = 0, ht = 0, hcp = 0; | |
DWORD pi, ti, mi; | |
me = GetCurrentProcess(); | |
pi = (DWORD)process_info.ClientId.UniqueProcess; | |
ti = (DWORD)process_info.ClientId.UniqueThread; | |
assert(hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi)); | |
assert(ht = OpenThread(THREAD_ALL_ACCESS, FALSE, ti)); | |
ResumeThread(ht); | |
CloseHandle(ht); | |
CloseHandle(hp); | |
return (int)pi; | |
} | |
else if (result == RTL_CLONE_CHILD) | |
{ | |
/* fix stdio */ | |
FreeConsole(); | |
AttachConsole(parent_pid); | |
return 0; | |
} | |
else | |
return -1; | |
/* NOTREACHED */ | |
return -1; | |
} | |
int main(int argc, const char* argv[]) | |
{ | |
pid_t pid; | |
pid = fork(); | |
switch (pid) { | |
case 0: //child | |
{ | |
printf("I am child.\n"); | |
break; | |
} | |
default: //parent | |
printf("I am parent. Child process PID: %d\n", pid); | |
break; | |
} | |
Sleep(1000); | |
exit(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I met the same problem. Windows 10 & GCC 8.1.0
The difference is, if I use compile and run in the IDE, it works well. But if I use the exe file, it will perform like that.
Could you please tell me if you have solved the problem? If so, could you kindly share with me how you resolved it?
Thanks a lot.