Dalamud.Injector
Entrypoint to the program.
A delegate used during initialization of the CLR from Dalamud.Injector.Boot.
Count of arguments.
char** string arguments.
Return value (HRESULT).
Start the Dalamud injector.
Count of arguments.
byte** string arguments.
Return value (HRESULT).
This routine appends the given argument to a command line such that
CommandLineToArgvW will return the argument string unchanged. Arguments
in a command line should be separated by spaces; this function does
not add these spaces.
Taken from https://stackoverflow.com/questions/5510343/escape-command-line-arguments-in-c-sharp
and https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/.
Supplies the argument to encode.
Supplies an indication of whether we should quote the argument even if it
does not contain any characters that would ordinarily require quoting.
Class representing an already held process handle.
Initializes a new instance of the class.
The existing held process handle.
Class responsible for starting the game and stripping ACL protections from processes.
Start a process without ACL protections.
The working directory.
The path to the executable file.
Arguments to pass to the executable file.
Don't actually fix the ACL.
Action to execute before the process is started.
Wait for the game window to be ready before proceeding.
The started process.
Thrown when a win32 error occurs.
Thrown when the process did not start correctly.
Copies ACL of current process to the target process.
Native handle to the target process.
Thrown when a win32 error occurs.
Claim a SE Debug Privilege.
Exception thrown when the process has exited before a window could be found.
Initializes a new instance of the class.
The message to pass on.
This class implements injecting into a remote process. It is a highly stripped down version of the
https://github.com/Reloaded-Project injector/assembler implementation due to issues with Lutris and
Wine.
Initializes a new instance of the class.
Process to inject.
Dispose given process on disposing self.
Finalizes an instance of the class.
Load a module by absolute file path.
Absolute file path.
Address to the module.
Get the address of an exported module function.
Module address.
Name of the exported method.
Address to the function.
Call a method in a remote process via CreateRemoteThread.
Method address.
Parameter address.
Thread exit code.
Initializes a new instance of the class.
The key to use.
Native user32 functions.
Native kernel32 functions.
MB_* from winuser.
The default value for any of the various subtypes.
The message box contains three push buttons: Abort, Retry, and Ignore.
The message box contains three push buttons: Cancel, Try Again, Continue. Use this message box type instead
of MB_ABORTRETRYIGNORE.
Adds a Help button to the message box. When the user clicks the Help button or presses F1, the system sends
a WM_HELP message to the owner.
The message box contains one push button: OK. This is the default.
The message box contains two push buttons: OK and Cancel.
The message box contains two push buttons: Retry and Cancel.
The message box contains two push buttons: Yes and No.
The message box contains three push buttons: Yes, No, and Cancel.
An exclamation-point icon appears in the message box.
An exclamation-point icon appears in the message box.
An icon consisting of a lowercase letter i in a circle appears in the message box.
An icon consisting of a lowercase letter i in a circle appears in the message box.
A question-mark icon appears in the message box.
The question-mark message icon is no longer recommended because it does not clearly represent a specific type
of message and because the phrasing of a message as a question could apply to any message type. In addition,
users can confuse the message symbol question mark with Help information. Therefore, do not use this question
mark message symbol in your message boxes. The system continues to support its inclusion only for backward
compatibility.
A stop-sign icon appears in the message box.
A stop-sign icon appears in the message box.
A stop-sign icon appears in the message box.
The first button is the default button.
MB_DEFBUTTON1 is the default unless MB_DEFBUTTON2, MB_DEFBUTTON3, or MB_DEFBUTTON4 is specified.
The second button is the default button.
The third button is the default button.
The fourth button is the default button.
The user must respond to the message box before continuing work in the window identified by the hWnd parameter.
However, the user can move to the windows of other threads and work in those windows. Depending on the hierarchy
of windows in the application, the user may be able to move to other windows within the thread. All child windows
of the parent of the message box are automatically disabled, but pop-up windows are not. MB_APPLMODAL is the
default if neither MB_SYSTEMMODAL nor MB_TASKMODAL is specified.
Same as MB_APPLMODAL except that the message box has the WS_EX_TOPMOST style.
Use system-modal message boxes to notify the user of serious, potentially damaging errors that require immediate
attention (for example, running out of memory). This flag has no effect on the user's ability to interact with
windows other than those associated with hWnd.
Same as MB_APPLMODAL except that all the top-level windows belonging to the current thread are disabled if the
hWnd parameter is NULL. Use this flag when the calling application or library does not have a window handle
available but still needs to prevent input to other windows in the calling thread without suspending other threads.
Same as desktop of the interactive window station. For more information, see Window Stations. If the current
input desktop is not the default desktop, MessageBox does not return until the user switches to the default
desktop.
The text is right-justified.
Displays message and caption text using right-to-left reading order on Hebrew and Arabic systems.
The message box becomes the foreground window. Internally, the system calls the SetForegroundWindow function
for the message box.
The message box is created with the WS_EX_TOPMOST window style.
The caller is a service notifying the user of an event. The function displays a message box on the current active
desktop, even if there is no user logged on to the computer.
Displays a modal dialog box that contains a system icon, a set of buttons, and a brief application-specific message,
such as status or error information. The message box returns an integer value that indicates which button the user
clicked.
A handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no
owner window.
The message to be displayed. If the string consists of more than one line, you can separate the lines using a carriage
return and/or linefeed character between each line.
The dialog box title. If this parameter is NULL, the default title is Error.
The contents and behavior of the dialog box. This parameter can be a combination of flags from the following groups
of flags.
If a message box has a Cancel button, the function returns the IDCANCEL value if either the ESC key is pressed or
the Cancel button is selected. If the message box has no Cancel button, pressing ESC will no effect - unless an
MB_OK button is present. If an MB_OK button is displayed and the user presses ESC, the return value will be IDOK.
If the function fails, the return value is zero.To get extended error information, call GetLastError. If the function
succeeds, the return value is one of the ID* enum values.
MEM_* from memoryapi.
To coalesce two adjacent placeholders, specify MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS. When you coalesce
placeholders, lpAddress and dwSize must exactly match those of the placeholder.
Frees an allocation back to a placeholder (after you've replaced a placeholder with a private allocation using
VirtualAlloc2 or Virtual2AllocFromApp). To split a placeholder into two placeholders, specify
MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER.
Allocates memory charges (from the overall size of memory and the paging files on disk) for the specified reserved
memory pages. The function also guarantees that when the caller later initially accesses the memory, the contents
will be zero. Actual physical pages are not allocated unless/until the virtual addresses are actually accessed.
To reserve and commit pages in one step, call VirtualAllocEx with MEM_COMMIT | MEM_RESERVE. Attempting to commit
a specific address range by specifying MEM_COMMIT without MEM_RESERVE and a non-NULL lpAddress fails unless the
entire range has already been reserved. The resulting error code is ERROR_INVALID_ADDRESS. An attempt to commit
a page that is already committed does not cause the function to fail. This means that you can commit pages without
first determining the current commitment state of each page. If lpAddress specifies an address within an enclave,
flAllocationType must be MEM_COMMIT.
Reserves a range of the process's virtual address space without allocating any actual physical storage in memory
or in the paging file on disk. You commit reserved pages by calling VirtualAllocEx again with MEM_COMMIT. To
reserve and commit pages in one step, call VirtualAllocEx with MEM_COMMIT | MEM_RESERVE. Other memory allocation
functions, such as malloc and LocalAlloc, cannot use reserved memory until it has been released.
Decommits the specified region of committed pages. After the operation, the pages are in the reserved state.
The function does not fail if you attempt to decommit an uncommitted page. This means that you can decommit
a range of pages without first determining the current commitment state. The MEM_DECOMMIT value is not supported
when the lpAddress parameter provides the base address for an enclave.
Releases the specified region of pages, or placeholder (for a placeholder, the address space is released and
available for other allocations). After this operation, the pages are in the free state. If you specify this
value, dwSize must be 0 (zero), and lpAddress must point to the base address returned by the VirtualAlloc function
when the region is reserved. The function fails if either of these conditions is not met. If any pages in the
region are committed currently, the function first decommits, and then releases them. The function does not
fail if you attempt to release pages that are in different states, some reserved and some committed. This means
that you can release a range of pages without first determining the current commitment state.
Indicates that data in the memory range specified by lpAddress and dwSize is no longer of interest. The pages
should not be read from or written to the paging file. However, the memory block will be used again later, so
it should not be decommitted. This value cannot be used with any other value. Using this value does not guarantee
that the range operated on with MEM_RESET will contain zeros. If you want the range to contain zeros, decommit
the memory and then recommit it. When you use MEM_RESET, the VirtualAllocEx function ignores the value of fProtect.
However, you must still set fProtect to a valid protection value, such as PAGE_NOACCESS. VirtualAllocEx returns
an error if you use MEM_RESET and the range of memory is mapped to a file. A shared view is only acceptable
if it is mapped to a paging file.
MEM_RESET_UNDO should only be called on an address range to which MEM_RESET was successfully applied earlier.
It indicates that the data in the specified memory range specified by lpAddress and dwSize is of interest to
the caller and attempts to reverse the effects of MEM_RESET. If the function succeeds, that means all data in
the specified address range is intact. If the function fails, at least some of the data in the address range
has been replaced with zeroes. This value cannot be used with any other value. If MEM_RESET_UNDO is called on
an address range which was not MEM_RESET earlier, the behavior is undefined. When you specify MEM_RESET, the
VirtualAllocEx function ignores the value of flProtect. However, you must still set flProtect to a valid
protection value, such as PAGE_NOACCESS.
Reserves an address range that can be used to map Address Windowing Extensions (AWE) pages. This value must
be used with MEM_RESERVE and no other values.
Allocates memory at the highest possible address. This can be slower than regular allocations, especially when
there are many allocations.
Causes the system to track pages that are written to in the allocated region. If you specify this value, you
must also specify MEM_RESERVE. To retrieve the addresses of the pages that have been written to since the region
was allocated or the write-tracking state was reset, call the GetWriteWatch function. To reset the write-tracking
state, call GetWriteWatch or ResetWriteWatch. The write-tracking feature remains enabled for the memory region
until the region is freed.
Allocates memory using large page support. The size and alignment must be a multiple of the large-page minimum.
To obtain this value, use the GetLargePageMinimum function. If you specify this value, you must also specify
MEM_RESERVE and MEM_COMMIT.
Unprefixed flags from CreateRemoteThread.
The thread runs immediately after creation.
The thread is created in a suspended state, and does not run until the ResumeThread function is called.
The dwStackSize parameter specifies the initial reserve size of the stack. If this flag is not specified, dwStackSize specifies the commit size.
DUPLICATE_* values for DuplicateHandle's dwDesiredAccess.
Closes the source handle. This occurs regardless of any error status returned.
Ignores the dwDesiredAccess parameter. The duplicate handle has the same access as the source handle.
PAGE_* from memoryapi.
Enables execute access to the committed region of pages. An attempt to write to the committed region results
in an access violation. This flag is not supported by the CreateFileMapping function.
Enables execute or read-only access to the committed region of pages. An attempt to write to the committed region
results in an access violation.
Enables execute, read-only, or read/write access to the committed region of pages.
Enables execute, read-only, or copy-on-write access to a mapped view of a file mapping object. An attempt to
write to a committed copy-on-write page results in a private copy of the page being made for the process. The
private page is marked as PAGE_EXECUTE_READWRITE, and the change is written to the new page. This flag is not
supported by the VirtualAlloc or VirtualAllocEx functions.
Disables all access to the committed region of pages. An attempt to read from, write to, or execute the committed
region results in an access violation. This flag is not supported by the CreateFileMapping function.
Enables read-only access to the committed region of pages. An attempt to write to the committed region results
in an access violation. If Data Execution Prevention is enabled, an attempt to execute code in the committed
region results in an access violation.
Enables read-only or read/write access to the committed region of pages. If Data Execution Prevention is enabled,
attempting to execute code in the committed region results in an access violation.
Enables read-only or copy-on-write access to a mapped view of a file mapping object. An attempt to write to
a committed copy-on-write page results in a private copy of the page being made for the process. The private
page is marked as PAGE_READWRITE, and the change is written to the new page. If Data Execution Prevention is
enabled, attempting to execute code in the committed region results in an access violation. This flag is not
supported by the VirtualAlloc or VirtualAllocEx functions.
Sets all locations in the pages as invalid targets for CFG. Used along with any execute page protection like
PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE and PAGE_EXECUTE_WRITECOPY. Any indirect call to locations
in those pages will fail CFG checks and the process will be terminated. The default behavior for executable
pages allocated is to be marked valid call targets for CFG. This flag is not supported by the VirtualProtect
or CreateFileMapping functions.
Pages in the region will not have their CFG information updated while the protection changes for VirtualProtect.
For example, if the pages in the region was allocated using PAGE_TARGETS_INVALID, then the invalid information
will be maintained while the page protection changes. This flag is only valid when the protection changes to
an executable type like PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE and PAGE_EXECUTE_WRITECOPY.
The default behavior for VirtualProtect protection change to executable is to mark all locations as valid call
targets for CFG.
Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a
STATUS_GUARD_PAGE_VIOLATION exception and turn off the guard page status. Guard pages thus act as a one-time
access alarm. For more information, see Creating Guard Pages. When an access attempt leads the system to turn
off guard page status, the underlying page protection takes over. If a guard page exception occurs during a
system service, the service typically returns a failure status indicator. This value cannot be used with
PAGE_NOACCESS. This flag is not supported by the CreateFileMapping function.
Sets all pages to be non-cachable. Applications should not use this attribute except when explicitly required
for a device. Using the interlocked functions with memory that is mapped with SEC_NOCACHE can result in an
EXCEPTION_ILLEGAL_INSTRUCTION exception. The PAGE_NOCACHE flag cannot be used with the PAGE_GUARD, PAGE_NOACCESS,
or PAGE_WRITECOMBINE flags. The PAGE_NOCACHE flag can be used only when allocating private memory with the
VirtualAlloc, VirtualAllocEx, or VirtualAllocExNuma functions. To enable non-cached memory access for shared
memory, specify the SEC_NOCACHE flag when calling the CreateFileMapping function.
Sets all pages to be write-combined. Applications should not use this attribute except when explicitly required
for a device. Using the interlocked functions with memory that is mapped as write-combined can result in an
EXCEPTION_ILLEGAL_INSTRUCTION exception. The PAGE_WRITECOMBINE flag cannot be specified with the PAGE_NOACCESS,
PAGE_GUARD, and PAGE_NOCACHE flags. The PAGE_WRITECOMBINE flag can be used only when allocating private memory
with the VirtualAlloc, VirtualAllocEx, or VirtualAllocExNuma functions. To enable write-combined memory access
for shared memory, specify the SEC_WRITECOMBINE flag when calling the CreateFileMapping function.
PROCESS_* from processthreadsapi.
All possible access rights for a process object.
Required to create a process.
Required to create a thread.
Required to duplicate a handle using DuplicateHandle.
Required to retrieve certain information about a process, such as its token, exit code,
and priority class (see OpenProcessToken).
Required to retrieve certain information about a process(see GetExitCodeProcess, GetPriorityClass, IsProcessInJob,
QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted
PROCESS_QUERY_LIMITED_INFORMATION.
Required to set certain information about a process, such as its priority class (see SetPriorityClass).
Required to set memory limits using SetProcessWorkingSetSize.
Required to suspend or resume a process.
Required to terminate a process using TerminateProcess.
Required to perform an operation on the address space of a process(see VirtualProtectEx and WriteProcessMemory).
Required to read memory in a process using ReadProcessMemory.
Required to write to memory in a process using WriteProcessMemory.
Required to wait for the process to terminate using the wait functions.
WAIT_* from synchapi.
The specified object is a mutex object that was not released by the thread that owned the mutex object
before the owning thread terminated.Ownership of the mutex object is granted to the calling thread and
the mutex state is set to nonsignaled. If the mutex was protecting persistent state information, you
should check it for consistency.
The state of the specified object is signaled.
The time-out interval elapsed, and the object's state is nonsignaled.
The function has failed. To get extended error information, call GetLastError.
Closes an open object handle.
A valid handle to an open object.
If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error
information, call GetLastError. If the application is running under a debugger, the function will throw an exception if it receives
either a handle value that is not valid or a pseudo-handle value. This can happen if you close a handle twice, or if you call
CloseHandle on a handle returned by the FindFirstFile function instead of calling the FindClose function.
Creates a thread that runs in the virtual address space of another process. Use the CreateRemoteThreadEx function
to create a thread that runs in the virtual address space of another process and optionally specify extended attributes.
A handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD,
PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights, and may fail without
these rights on certain platforms. For more information, see Process Security and Access Rights.
A pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new thread and determines whether
child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor
and the handle cannot be inherited. The access control lists (ACL) in the default security descriptor for a thread come from
the primary token of the creator.
The initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is 0 (zero), the
new thread uses the default size for the executable. For more information, see Thread Stack Size.
A pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and represents the
starting address of the thread in the remote process. The function must exist in the remote process. For more information,
see ThreadProc.
A pointer to a variable to be passed to the thread function.
The flags that control the creation of the thread.
A pointer to a variable that receives the thread identifier. If this parameter is NULL, the thread identifier is not returned.
If the function succeeds, the return value is a handle to the new thread. If the function fails, the return value is
NULL.To get extended error information, call GetLastError. Note that CreateRemoteThread may succeed even if lpStartAddress
points to data, code, or is not accessible. If the start address is invalid when the thread runs, an exception occurs, and
the thread terminates. Thread termination due to a invalid start address is handled as an error exit for the thread's process.
This behavior is similar to the asynchronous nature of CreateProcess, where the process is created even if it refers to
invalid or missing dynamic-link libraries (DLL).
Retrieves the termination status of the specified thread.
A handle to the thread. The handle must have the THREAD_QUERY_INFORMATION or THREAD_QUERY_LIMITED_INFORMATION
access right.For more information, see Thread Security and Access Rights.
A pointer to a variable to receive the thread termination status.
If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get
extended error information, call GetLastError.
Opens an existing local process object.
The access to the process object. This access right is checked against the security descriptor for the process. This parameter can be one or
more of the process access rights. If the caller has enabled the SeDebugPrivilege privilege, the requested access is granted regardless of the
contents of the security descriptor.
If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.
The identifier of the local process to be opened. If the specified process is the System Idle Process(0x00000000), the function fails and the
last error code is ERROR_INVALID_PARAMETER.If the specified process is the System process or one of the Client Server Run-Time Subsystem(CSRSS)
processes, this function fails and the last error code is ERROR_ACCESS_DENIED because their access restrictions prevent user-level code from
opening them. If you are using GetCurrentProcessId as an argument to this function, consider using GetCurrentProcess instead of OpenProcess, for
improved performance.
If the function succeeds, the return value is an open handle to the specified process.
If the function fails, the return value is NULL.To get extended error information, call GetLastError.
See https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex.
Reserves, commits, or changes the state of a region of memory within the virtual address space of a specified process.
The function initializes the memory it allocates to zero. To specify the NUMA node for the physical memory, see
VirtualAllocExNuma.
The handle to a process. The function allocates memory within the virtual address space of this process. The handle
must have the PROCESS_VM_OPERATION access right. For more information, see Process Security and Access Rights.
The pointer that specifies a desired starting address for the region of pages that you want to allocate. If you
are reserving memory, the function rounds this address down to the nearest multiple of the allocation granularity.
If you are committing memory that is already reserved, the function rounds this address down to the nearest page
boundary. To determine the size of a page and the allocation granularity on the host computer, use the GetSystemInfo
function. If lpAddress is NULL, the function determines where to allocate the region. If this address is within
an enclave that you have not initialized by calling InitializeEnclave, VirtualAllocEx allocates a page of zeros
for the enclave at that address. The page must be previously uncommitted, and will not be measured with the EEXTEND
instruction of the Intel Software Guard Extensions programming model. If the address in within an enclave that you
initialized, then the allocation operation fails with the ERROR_INVALID_ADDRESS error.
The size of the region of memory to allocate, in bytes. If lpAddress is NULL, the function rounds dwSize up to the
next page boundary. If lpAddress is not NULL, the function allocates all pages that contain one or more bytes in
the range from lpAddress to lpAddress+dwSize. This means, for example, that a 2-byte range that straddles a page
boundary causes the function to allocate both pages.
The type of memory allocation. This parameter must contain one of the MEM_* enum values.
The memory protection for the region of pages to be allocated. If the pages are being committed, you can specify
any one of the memory protection constants.
If the function succeeds, the return value is the base address of the allocated region of pages. If the function
fails, the return value is NULL.To get extended error information, call GetLastError.
See https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfreeex.
Releases, decommits, or releases and decommits a region of memory within the virtual address space of a specified
process.
A handle to a process. The function frees memory within the virtual address space of the process. The handle must
have the PROCESS_VM_OPERATION access right.For more information, see Process Security and Access Rights.
A pointer to the starting address of the region of memory to be freed. If the dwFreeType parameter is MEM_RELEASE,
lpAddress must be the base address returned by the VirtualAllocEx function when the region is reserved.
The size of the region of memory to free, in bytes. If the dwFreeType parameter is MEM_RELEASE, dwSize must be 0
(zero). The function frees the entire region that is reserved in the initial allocation call to VirtualAllocEx.
If dwFreeType is MEM_DECOMMIT, the function decommits all memory pages that contain one or more bytes in the range
from the lpAddress parameter to (lpAddress+dwSize). This means, for example, that a 2-byte region of memory that
straddles a page boundary causes both pages to be decommitted. If lpAddress is the base address returned by
VirtualAllocEx and dwSize is 0 (zero), the function decommits the entire region that is allocated by VirtualAllocEx.
After that, the entire region is in the reserved state.
The type of free operation. This parameter must be one of the MEM_* enum values.
If the function succeeds, the return value is a nonzero value. If the function fails, the return value is 0 (zero).
To get extended error information, call GetLastError.
Waits until the specified object is in the signaled state or the time-out interval elapses. To enter an alertable wait
state, use the WaitForSingleObjectEx function.To wait for multiple objects, use WaitForMultipleObjects.
A handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.
If this handle is closed while the wait is still pending, the function's behavior is undefined. The handle must have the
SYNCHRONIZE access right. For more information, see Standard Access Rights.
The time-out interval, in milliseconds. If a nonzero value is specified, the function waits until the object is signaled
or the interval elapses. If dwMilliseconds is zero, the function does not enter a wait state if the object is not signaled;
it always returns immediately. If dwMilliseconds is INFINITE, the function will return only when the object is signaled.
If the function succeeds, the return value indicates the event that caused the function to return.
It can be one of the WaitResult values.
Writes data to an area of memory in a specified process. The entire area to be written to must be accessible or
the operation fails.
A handle to the process memory to be modified. The handle must have PROCESS_VM_WRITE and PROCESS_VM_OPERATION access
to the process.
A pointer to the base address in the specified process to which data is written. Before data transfer occurs, the
system verifies that all data in the base address and memory of the specified size is accessible for write access,
and if it is not accessible, the function fails.
A pointer to the buffer that contains data to be written in the address space of the specified process.
The number of bytes to be written to the specified process.
A pointer to a variable that receives the number of bytes transferred into the specified process. This parameter
is optional. If lpNumberOfBytesWritten is NULL, the parameter is ignored.
If the function succeeds, the return value is nonzero. If the function fails, the return value is 0 (zero). To get
extended error information, call GetLastError.The function fails if the requested write operation crosses into an
area of the process that is inaccessible.
Duplicates an object handle.
A handle to the process with the handle to be duplicated.
The handle must have the PROCESS_DUP_HANDLE access right.
The handle to be duplicated. This is an open object handle that is valid in the context of the source process.
For a list of objects whose handles can be duplicated, see the following Remarks section.
A handle to the process that is to receive the duplicated handle.
The handle must have the PROCESS_DUP_HANDLE access right.
A pointer to a variable that receives the duplicate handle. This handle value is valid in the context of the target process.
If hSourceHandle is a pseudo handle returned by GetCurrentProcess or GetCurrentThread, DuplicateHandle converts it to a real handle to a process or thread, respectively.
If lpTargetHandle is NULL, the function duplicates the handle, but does not return the duplicate handle value to the caller. This behavior exists only for backward compatibility with previous versions of this function. You should not use this feature, as you will lose system resources until the target process terminates.
This parameter is ignored if hTargetProcessHandle is NULL.
The access requested for the new handle. For the flags that can be specified for each object type, see the following Remarks section.
This parameter is ignored if the dwOptions parameter specifies the DUPLICATE_SAME_ACCESS flag. Otherwise, the flags that can be specified depend on the type of object whose handle is to be duplicated.
This parameter is ignored if hTargetProcessHandle is NULL.
A variable that indicates whether the handle is inheritable. If TRUE, the duplicate handle can be inherited by new processes created by the target process. If FALSE, the new handle cannot be inherited.
This parameter is ignored if hTargetProcessHandle is NULL.
Optional actions.
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError.
See https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle.