aminal/platform/winproc.go

240 lines
7.3 KiB
Go

// +build windows,cgo
package platform
// #include "windows.h"
//
// /* Until we can specify the platform SDK and target version for Windows.h *
// * without breaking our ability to gracefully display an error message, these *
// * definitions will be copied from the platform SDK headers and made to work. *
// */
//
// typedef BOOL (* InitializeProcThreadAttributeListProcType)(LPPROC_THREAD_ATTRIBUTE_LIST, DWORD, DWORD, PSIZE_T);
// typedef BOOL (* UpdateProcThreadAttributeProcType)(
// LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
// DWORD dwFlags,
// DWORD_PTR Attribute,
// PVOID lpValue,
// SIZE_T cbSize,
// PVOID lpPreviousValue,
// PSIZE_T lpReturnSize
// );
// typedef BOOL (* SetProcessDpiAwarenessContextType)(handle_t);
//
// InitializeProcThreadAttributeListProcType pfnInitializeProcThreadAttributeList = NULL;
// UpdateProcThreadAttributeProcType pfnUpdateProcThreadAttribute = NULL;
// SetProcessDpiAwarenessContextType pfnSetProcessDpiAwarenessContext = NULL;
//
// #define ProcThreadAttributePseudoConsole 22
//
// #define PROC_THREAD_ATTRIBUTE_NUMBER 0x0000FFFF
// #define PROC_THREAD_ATTRIBUTE_THREAD 0x00010000 // Attribute may be used with thread creation
// #define PROC_THREAD_ATTRIBUTE_INPUT 0x00020000 // Attribute is input only
// #define PROC_THREAD_ATTRIBUTE_ADDITIVE 0x00040000 // Attribute may be "accumulated," e.g. bitmasks, counters, etc.
//
// #define ProcThreadAttributeValue(Number, Thread, Input, Additive) \
// (((Number) & PROC_THREAD_ATTRIBUTE_NUMBER) | \
// ((Thread != FALSE) ? PROC_THREAD_ATTRIBUTE_THREAD : 0) | \
// ((Input != FALSE) ? PROC_THREAD_ATTRIBUTE_INPUT : 0) | \
// ((Additive != FALSE) ? PROC_THREAD_ATTRIBUTE_ADDITIVE : 0))
//
// #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE ProcThreadAttributeValue (ProcThreadAttributePseudoConsole, FALSE, TRUE, FALSE)
//
// typedef struct _STARTUPINFOEXW {
// STARTUPINFOW StartupInfo;
// LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
// } STARTUPINFOEXW, *LPSTARTUPINFOEXW;
//
// #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
// #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((handle_t)-4)
// #endif
//
// HMODULE hLibKernel32_Proc = NULL;
//
// DWORD initProcKernFuncs()
// {
// hLibKernel32_Proc = LoadLibrary( "kernel32.dll" );
// if( hLibKernel32_Proc == NULL )
// {
// return -1;
// }
//
// pfnInitializeProcThreadAttributeList = (InitializeProcThreadAttributeListProcType) GetProcAddress(hLibKernel32_Proc, "InitializeProcThreadAttributeList" );
// if( pfnInitializeProcThreadAttributeList == NULL )
// {
// return -1;
// }
//
// pfnUpdateProcThreadAttribute = (UpdateProcThreadAttributeProcType) GetProcAddress(hLibKernel32_Proc, "UpdateProcThreadAttribute" );
// if( pfnUpdateProcThreadAttribute == NULL )
// {
// return -1;
// }
//
// return 0;
// }
//
// DWORD enableHiDpiSupport() {
// HMODULE hLibUser32_Proc = LoadLibrary( "User32.dll" );
// if( hLibUser32_Proc == NULL )
// {
// return -1;
// }
//
// pfnSetProcessDpiAwarenessContext = (SetProcessDpiAwarenessContextType) GetProcAddress(hLibUser32_Proc, "SetProcessDpiAwarenessContext" );
// if( pfnInitializeProcThreadAttributeList == NULL )
// {
// return -1;
// }
// (*pfnSetProcessDpiAwarenessContext)( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 );
// return 0;
// }
//
// DWORD createGuestProcHelper( uintptr_t hpc, LPCWSTR imagePath, uintptr_t * hProcess, DWORD * dwProcessID )
// {
// STARTUPINFOEXW si;
// ZeroMemory( &si, sizeof(si) );
// si.StartupInfo.cb = sizeof(si);
//
// SIZE_T bytesRequired;
// (*pfnInitializeProcThreadAttributeList)( NULL, 1, 0, &bytesRequired );
//
// si.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
// if( !si.lpAttributeList )
// {
// return E_OUTOFMEMORY;
// }
//
// if (!(*pfnInitializeProcThreadAttributeList)(si.lpAttributeList, 1, 0, &bytesRequired))
// {
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
// return HRESULT_FROM_WIN32(GetLastError());
// }
//
// if (!(*pfnUpdateProcThreadAttribute)(si.lpAttributeList,
// 0,
// PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
// (PVOID) hpc,
// sizeof(hpc),
// NULL,
// NULL))
// {
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
// return HRESULT_FROM_WIN32(GetLastError());
// }
//
// bytesRequired = (wcslen(imagePath) + 1) * sizeof(wchar_t); // +1 null terminator
// PWSTR cmdLineMutable = (PWSTR)HeapAlloc(GetProcessHeap(), 0, bytesRequired);
//
// if (!cmdLineMutable)
// {
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
// return E_OUTOFMEMORY;
// }
//
// wcscpy_s(cmdLineMutable, bytesRequired, imagePath);
//
// PROCESS_INFORMATION pi;
// ZeroMemory(&pi, sizeof(pi));
//
// if (!CreateProcessW(NULL,
// cmdLineMutable,
// NULL,
// NULL,
// FALSE,
// EXTENDED_STARTUPINFO_PRESENT,
// NULL,
// NULL,
// &si.StartupInfo,
// &pi))
// {
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
// HeapFree(GetProcessHeap(), 0, cmdLineMutable);
// return HRESULT_FROM_WIN32(GetLastError());
// }
//
// *hProcess = (uintptr_t) pi.hProcess;
// *dwProcessID = pi.dwProcessId;
//
// HeapFree(GetProcessHeap(), 0, si.lpAttributeList);
// HeapFree(GetProcessHeap(), 0, cmdLineMutable);
// return S_OK;
// }
//
// int hr_succeeded( DWORD hResult );
import "C"
import (
"errors"
"os"
"syscall"
"unicode/utf16"
)
var procsInitSucceeded = false
func init() {
ret := int(C.initProcKernFuncs())
if ret == 0 {
ret = int(C.enableHiDpiSupport())
}
procsInitSucceeded = (ret == 0)
}
type winProcess struct {
hproc uintptr
processID uint32
goProcess *os.Process
}
func createPtyChildProcess(imagePath string, hcon uintptr) (*winProcess, error) {
path16 := utf16.Encode([]rune(imagePath))
cpath16 := C.calloc(C.size_t(len(path16)+1), 2)
pp := (*[0xffff]uint16)(cpath16)
copy(pp[:], path16)
hproc := C.uintptr_t(0)
dwProcessID := C.DWORD(0)
hr := C.createGuestProcHelper(C.uintptr_t(hcon), (C.LPCWSTR)(cpath16), &hproc, &dwProcessID)
C.free(cpath16)
if int(C.hr_succeeded(hr)) == 0 {
return nil, errors.New("Failed to create process: " + imagePath)
}
goProcess, err := os.FindProcess(int(dwProcessID))
if err != nil {
return nil, err
}
return &winProcess{
hproc: uintptr(hproc),
processID: uint32(dwProcessID),
goProcess: goProcess,
}, nil
}
func (process *winProcess) Wait() error {
_, err := process.goProcess.Wait()
if err != nil {
return err
}
return nil
}
func (process *winProcess) Close() error {
err := process.goProcess.Kill()
if err != nil {
return err
}
syscall.CloseHandle(syscall.Handle(process.hproc))
return nil
}