Win32APIを用いたプロセス操作

# プロセスの作成
`CreateProcess`関数を用いて新しいプロセスとプライマリスレッドを作成します。
なお、作成されるプロセスのウインドウに関する指定する情報は`STARTUPINFO`構造体に設定します。
また、新しいプロセスは呼び出し元プロセスのセキュリティ コンテキストで実行されます。

:::note info
Windowsはプロセスを作成するとスレッドが必ず1つ作成されます。
このスレッドは`プライマリスレッド`と呼ばれます。
:::

関数が成功すると、戻り値は0以外になります。関数が失敗した場合は、0を返します。
また、起動したプロセスに関する情報は`PROCESS_INFORMATION`構造体に格納されます。


```c: CreateProcess関数
BOOL CreateProcessA(
    [in, optional]      LPCSTR                lpApplicationName,
    [in, out, optional] LPSTR                 lpCommandLine,
    [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
    [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
    [in]                BOOL                  bInheritHandles,
    [in]                DWORD                 dwCreationFlags,
    [in, optional]      LPVOID                lpEnvironment,
    [in, optional]      LPCSTR                lpCurrentDirectory,
    [in]                LPSTARTUPINFOA        lpStartupInfo,
    [out]               LPPROCESS_INFORMATION lpProcessInformation
);
```

```c: STARTUPINFO構造体
typedef struct _STARTUPINFOA {
    DWORD  cb;
    LPSTR  lpReserved;
    LPSTR  lpDesktop;
    LPSTR  lpTitle;
    DWORD  dwX;
    DWORD  dwY;
    DWORD  dwXSize;
    DWORD  dwYSize;
    DWORD  dwXCountChars;
    DWORD  dwYCountChars;
    DWORD  dwFillAttribute;
    DWORD  dwFlags;
    WORD   wShowWindow;
    WORD   cbReserved2;
    LPBYTE lpReserved2;
    HANDLE hStdInput;
    HANDLE hStdOutput;
    HANDLE hStdError;
} STARTUPINFOA, *LPSTARTUPINFOA;
```

```c: PROCESS_INFORMATION構造体
typedef struct _PROCESS_INFORMATION {
  HANDLE hProcess;
  HANDLE hThread;
  DWORD  dwProcessId;
  DWORD  dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
```

なおプロセス作成後、プロセスへアクセス不要になった時点でハンドルをクローズする必要があります。

```c
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
```

> * [CreateProcess関数](https://learn.microsoft.com/ja-jp/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa)
> * [プロセスとスレッドの概要](https://learn.microsoft.com/ja-jp/windows/win32/procthread/about-processes-and-threads)
> * [PROCESS_INFORMATION 構造体](https://learn.microsoft.com/ja-jp/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_information)
> * [プロセスを作成する](https://learn.microsoft.com/ja-jp/windows/win32/procthread/creating-processes)

## サンプルプログラム
```c: sample_CreateProcess.c
#include <windows.h>
#include <stdio.h>

int WINAPI main() {
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	// 構造体の確保したメモリ領域を0で埋める（＝初期化）
	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));

	// STARTUPINFO構造体のサイズを設定する
	si.cb = sizeof(si);

	// 起動したいプロセス名
	char pName[] = "notepad.exe";

	/* PROCESS_INFORMATION
		CreateProcessで作成されたプロセスとそのプライマリスレッドに関する情報が保存される

		HANDLE hProcess		作成されたプロセスのハンドル
		HANDLE hThread		作成されたプライマリスレッドのハンドル
		DWORD dwProcessId	作成されたプロセスのID
		DWORD dwThreadId	作成されたプライマリスレッドのID
	*/

	/* CreateProcess
		CreateProcessの第1引数と第2引数で指定する差分
		　第1引数：フルパスで実行したいファイルを指定しなければならない
		　第2引数：キーワード（notepad, calc.exe）で実行することが可能
	*/

	if (CreateProcess(NULL, pName, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0) {
		printf("Failed to create process\n");
		return 1;
	}

	// 情報の表示
	printf("Process ID\t%d\n", pi.dwProcessId);
	printf("Thread ID\t%d\n", pi.dwThreadId);

	if (CloseHandle(pi.hProcess) == 0 || CloseHandle(pi.hThread) == 0) {
		printf("Failed to close handle\n");

		return 1;
	}

	return 0;
}
```

# プロセスを開く
`OpenProcess`関数を用いて既に起動しているローカルのプロセスオブジェクトを開きます。  
関数が成功した場合、戻り値は指定されたプロセスに対する開いているハンドルです。関数が失敗した場合は、返される値はNULLです。

```c: OpenProcess関数
HANDLE OpenProcess(
    [in] DWORD dwDesiredAccess,
    [in] BOOL  bInheritHandle,
    [in] DWORD dwProcessId
);
```

> * [OpenProcess関数](https://learn.microsoft.com/ja-jp/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess)

# プロセスの強制終了
`TerminalteProcess`関数を用いて、指定したプロセスとそのすべてのスレッドを`強制終了`します。なお、ハンドルは`PROCESS_TERMINATE`のアクセス権限を有している必要があります。  
関数が成功すると、戻り値は0以外になります。関数が失敗した場合は、0を返します。

```c: TerminateProcess関数
BOOL TerminateProcess(
    [in] HANDLE hProcess,
    [in] UINT   uExitCode
);
```

> * [TerminateProcess関数](https://learn.microsoft.com/ja-jp/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess)

## サンプルプログラム
プログラムの流れとしては以下のとおりである。なお、プログラム起動時には第1引数として終了させたいプロセスのPIDを指定する。
```shell
# 1756はユーザー権限で動作しているnotepad.exe
>example_TerminateProcess.exe 1756
Exit Code：259
Success to terminate process
```

1. 終了させるプロセスのハンドルを取得する
2. GetExitCodeProcess関数を使用して終了コードを取得する
3. TerminateProcess関数で終了する

```c: sample_TerminateProcess.c
#include <windows.h>
#include <stdio.h>

int WINAPI main(int argc, char* argv[]) {
	DWORD pid = atoi(argv[1]);


	// 1.対象プロセスのハンドルを取得
	//	GetExitCodeProcess関数を実行するためには、アクセス権限「PROCESS_QUERY_LIMITED_INFORMATION」を有していなければならない
	//	TerminateProcess関数を実行するためには、アクセス権限「PROCESS_TERMINATE」を有していなければならない
	HANDLE hProcess = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);

	if (hProcess == NULL) {
		printf("OpenProcess failed\n");
		return 1;
	}

	// 2.終了コードの取得
	DWORD ExitCode = 0;
	if (GetExitCodeProcess(hProcess, &ExitCode) == 0) {
		printf("GetExitCodeProcess failed\n");

		CloseHandle(hProcess);
		return 1;
	}
	printf("Exit Code：%d\n", ExitCode);

	// 3.プロセスの強制終了
	if (TerminateProcess(hProcess, ExitCode) == 0) {
		printf("TerminateProcess failed\n");

		CloseHandle(hProcess);
		return 1;
	}
	else {
		WaitForSingleObject(hProcess, INFINITE);
		printf("Success to terminate process\n");
	}

	CloseHandle(hProcess);
	return 0;
}
```