EnumProcesses

EnumProcessesで、プロセスIDを列挙する。

EnumProcesses function (psapi.h) - Win32 apps | Microsoft Docs
C++でプロセス名からプロセスIDを取得する - 備忘録

psapi.libをリンク
psapi.libをリンク

psapi.libをリンク。

cbNeededで得られるのは必要な配列の全体サイズなので、要素数となるとDWORDのサイズで割るのがちょっとめんどくさい。

sizeof(dwProcessIds) = 4096
cbNeeded = 236
dwNum = 59
dwProcessIds[0] = 0
dwProcessIds[1] = 4
dwProcessIds[2] = 236
dwProcessIds[3] = 308
dwProcessIds[4] = 356
dwProcessIds[5] = 364
dwProcessIds[6] = 392
dwProcessIds[7] = 452
dwProcessIds[8] = 460
dwProcessIds[9] = 468
dwProcessIds[10] = 556
dwProcessIds[11] = 632
dwProcessIds[12] = 720
dwProcessIds[13] = 764
dwProcessIds[14] = 796
dwProcessIds[15] = 836
dwProcessIds[16] = 280
dwProcessIds[17] = 1076
dwProcessIds[18] = 1108
dwProcessIds[19] = 1184
dwProcessIds[20] = 1232
dwProcessIds[21] = 1372
dwProcessIds[22] = 1396
dwProcessIds[23] = 1468
dwProcessIds[24] = 1540
dwProcessIds[25] = 1604
dwProcessIds[26] = 304
dwProcessIds[27] = 2032
dwProcessIds[28] = 2060
dwProcessIds[29] = 2440
dwProcessIds[30] = 2460
dwProcessIds[31] = 2492
dwProcessIds[32] = 2524
dwProcessIds[33] = 2644
dwProcessIds[34] = 2796
dwProcessIds[35] = 2340
dwProcessIds[36] = 2856
dwProcessIds[37] = 2676
dwProcessIds[38] = 3544
dwProcessIds[39] = 4056
dwProcessIds[40] = 3956
dwProcessIds[41] = 4068
dwProcessIds[42] = 2436
dwProcessIds[43] = 3536
dwProcessIds[44] = 3600
dwProcessIds[45] = 3580
dwProcessIds[46] = 1964
dwProcessIds[47] = 4216
dwProcessIds[48] = 4452
dwProcessIds[49] = 4568
dwProcessIds[50] = 5156
dwProcessIds[51] = 1180
dwProcessIds[52] = 5588
dwProcessIds[53] = 5284
dwProcessIds[54] = 4108
dwProcessIds[55] = 5720
dwProcessIds[56] = 3904
dwProcessIds[57] = 1532
dwProcessIds[58] = 5960
続行するには何かキーを押してください . . .

とりあえずプロセスIDは列挙できた。

Sample/winapi/EnumProcesses/EnumProcesses/src/EnumProcesses at master · bg1bgst333/Sample · GitHub

ControlService

サービスの停止は、StopService・・・とおもったら、そういうものはなく、ControlServiceで、SERVICE_CONTROL_STOPを指定する。

ControlService function (winsvc.h) - Win32 apps | Microsoft Docs
Win32 Windowsサービスを制御する ControlService - s-kita’s blog

実行中の状態
実行中の状態

実行中の状態。

SERVICE_CONTROL_STOPで停止。

デバッグなしで開始
デバッグなしで開始

デバッグなしで開始。

UACが反応
UACが反応

UACが反応

停止成功
停止成功

停止成功。

停止してる
停止してる

停止してる。

Sample/winapi/ControlService/ControlService/src/ControlService at master · bg1bgst333/Sample · GitHub

StartService

StartServiceで、サービスを開始する。

StartServiceA function (winsvc.h) - Win32 apps | Microsoft Docs
Win32 Windowsサービスを開始する StartService - s-kita’s blog

"Irmon"をいったんサービス停止する
"Irmon"をいったんサービス停止する

"Irmon"をいったんサービス停止する。

停止状態
停止状態

停止状態。


デバッガなし起動
デバッガなし起動

デバッガなし起動。

UACが反応
UACが反応

UACが反応。

StartService成功
StartService成功

StartService成功。

終了
終了

終了。

実行中になっている
実行中になっている

実行中になっている。

Sample/winapi/StartService/StartService/src/StartService at master · bg1bgst333/Sample · GitHub

OpenService

OpenServiceで、既存のサービスをオープンし、ハンドルを取得する。

OpenServiceA function (winsvc.h) - Win32 apps | Microsoft Docs
Win32 Windowsサービスを開始する StartService - s-kita’s blog

今回は、赤外線通信を管理するサービス"Irmon"、

赤外線通信を管理する"Irmon"
赤外線通信を管理する"Irmon"

こちらをオープンする。

一応、メニューからサービスを停止
一応、メニューからサービスを停止

一応、メニューからサービスを停止。

停止状態になっている
停止状態になっている

停止状態になっている。
コンソールアプリケーションの空プロジェクトで、

// ヘッダファイルのインクルード
#include <windows.h>	// 標準WindowsAPI
#include <tchar.h>		// TCHAR型
#include <stdio.h>		// 標準入出力

// _tmain関数の定義
int _tmain(int argc, TCHAR *argv[]){	// main関数のTCHAR版.

	// 変数の宣言と初期化.
	SC_HANDLE hSCM = NULL;	// SC_HANDLE型hSCMをNULLで初期化.
	SC_HANDLE hService = NULL;	// SC_HANDLE型hServiceをNULLで初期化.
	LPCTSTR lpctszService = _T("Irmon");	// サービス名lpctszServiceを"Irmon"で初期化.

	// SCManagerのオープン
	hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);	// OpenSCManagerでSCManagerを開き, ハンドルをhSCMに格納.
	if (hSCM != NULL){	// NULLでない時.

		// hSCMの出力.
		_tprintf(_T("hSCM = 0x%08x\n"), (unsigned long)hSCM);	// hSCMの値を出力.

		// Serviceのオープン
		hService = OpenService(hSCM, lpctszService, SERVICE_START);	// OpenServiceで"Irmon"を開く.
		if (hService != NULL){	// NULLでない時.

			// hServiceの出力.
			_tprintf(_T("hService = 0x%08x\n"), (unsigned long)hService);	// hServiceの値を出力.
			CloseServiceHandle(hService);	// CloseServiceHandleでhServiceを閉じる.

		}
		else{	// NULLの時.
			_tprintf(_T("OpenService failed!\n"));	// "OpenService failed!"と出力.
		}

		// hSCMを閉じる.
		CloseServiceHandle(hSCM);	// CloseServiceHandleでhSCMを閉じる.

	}
	else{	// NULLの時.
		_tprintf(_T("OpenSCManager failed!\n"));	// "OpenSCManager failed!"と出力.
	}

	// プログラムの終了
	return 0;	// 0を返して正常終了.

}

SERVICE_STARTで、開始権限を取得しようとしたが、

hSCM = 0x002d4c18
OpenService failed!
続行するには何かキーを押してください .

失敗した。

アプリケーション実行時に常にAdministratorとして実行する

VSからデバッガなし起動で管理者権限になっていないからダメなのかも。

app.manifestをrequireAdministratorに変更
app.manifestをrequireAdministratorに変更

app.manifestをrequireAdministratorに変更。

VSからデバッガなし起動でUACが反応するので管理者権限になれそう
VSからデバッガなし起動でUACが反応するので管理者権限になれそう

VSからデバッガなし起動でUACが反応するので管理者権限になれそう。

あれ?何も出ない。
あれ?何も出ない。

あれ?何も出ない。
ただ、一瞬何か見えたので、別コンソールになってるかもしれない。

hServiceを出力の後、Sleepで5秒待つ。

UACが出る
UACが出る

UACが出る。

やっぱり別コンソールで出力されてた
やっぱり別コンソールで出力されてた

やっぱり別コンソールで出力されてた。

Sample/winapi/OpenService/OpenService/src/OpenService at master · bg1bgst333/Sample · GitHub

OpenSCManager

サービスを制御するには、まずOpenSCManagerで、SCManagerをオープンして、ハンドルを取得する。

OpenSCManagerA function (winsvc.h) - Win32 apps | Microsoft Docs
Win32 Windowsサービスを開始する StartService - s-kita’s blog

コンソールアプリ
コンソールアプリ

コンソールアプリ。

空のプロジェクト
空のプロジェクト

空のプロジェクト。

OpenSCManagerで、SC_HANDLEのhSCMを取得する。
SC_MANAGER_CONNECTは、接続権限を持つハンドルといったところかな。

基本的にサービスは管理者権限が要りそうなのでマニフェストを用意しておく
基本的にサービスは管理者権限が要りそうなのでマニフェストを用意しておく

基本的にサービスは管理者権限が要りそうなのでマニフェストを用意しておく。
(ただし、ここではまだasInvokerにしてる。)

app.manifestを登録
app.manifestを登録

app.manifestを登録。

hSCM = 0x00544c98
続行するには何かキーを押してください . . .

hSCMを取得できた。

Sample/winapi/OpenSCManager/OpenSCManager/src/OpenSCManager at master · bg1bgst333/Sample · GitHub

PAINTSTRUCT

PAINTSTRUCTは、WM_PAINTの中で、BeginPaintで再描画情報を取得する時に使う。

PAINTSTRUCT (winuser.h) - Win32 apps | Microsoft Docs
【Win32】PAINTSTRUCT構造体 | 初心者のWindowsプログラミング日記

どこを再描画するかはPAINTSTRUCTのrcPaintに格納される。

再描画要求されるたびに、指定された再描画領域矩形をRectangleで塗る。
毎回色を変える。

最初は赤で全体を塗られる
最初は赤で全体を塗られる

最初は赤で全体を塗られる。

左側を画面外に移動
左側を画面外に移動

左側を画面外に移動。

戻すとこうなる
戻すとこうなる

戻すとこうなる。
再描画は1回ではなく、動かすたびに呼ばれるため、こう何度も色を塗ってこうなる。

左下に移動
左下に移動

左下に移動。

戻すのが速ければ、再描画の回数は少ない。
戻すのが速ければ、再描画の回数は少ない。

戻すのが速ければ、再描画の回数は少ない。

Sample/winapi/PAINTSTRUCT/PAINTSTRUCT/src/PAINTSTRUCT at master · bg1bgst333/Sample · GitHub

MSG

GetMessageなどで取得した、ウィンドウメッセージ情報を格納しているのがMSG。

MSG (winuser.h) - Win32 apps | Microsoft Docs

単純にはそうだが、メッセージループとなると、不思議な部分もある。

こういうMSG構造体のmessageの値を記録しておくログ関数を作っておいて、

メッセージループ付近にログを配置。

ウィンドウを表示するだけ。
ウィンドウを表示するだけ。

ウィンドウを表示するだけ。

win32apiのGetMessage関数について質問です。第二引数のハン... - Yahoo!知恵袋

GetMessageにNULLを指定していて、これは呼び出し側のスレッド(つまりこのメインウィンドウスレッド)のすべてのウィンドウメッセージと、PostThreadMessageでこちらに送られたものを指す。
それにしても、msg.logを見てみると、00000001(つまりWM_CREATE)が無い。
メッセージループの前にCreateWindowしているけど、そこの時点でWM_CREATE処理しているため、記録されない。

00000012はWM_QUIT
00000012はWM_QUIT

00000012はWM_QUIT。
それにしても不思議なのは、WM_QUITは最後なのであるとして、WM_CLOSEやWM_DESTROYが記録されないのは不思議。スレッドが違うのかな。

通常終了じゃなくて、デバッガ終了だと、

0000000fはWM_PAINT
0000000fはWM_PAINT

0000000fはWM_PAINT。
最初の描画があるので当然呼ばれる。

最大化などでWM_SYSCOMMAND
最大化などでWM_SYSCOMMAND

最大化などでWM_SYSCOMMAND。

00000112がWM_SYSCOMMAND
00000112がWM_SYSCOMMAND

00000112がWM_SYSCOMMAND。
でもグリグリとウィンドウを動かしてもWM_MOVEとかは記録が無かった。

Sample/winapi/MSG/MSG/src/MSG at master · bg1bgst333/Sample · GitHub