SUCCEEDED

ここで、SUCCEEDEDマクロについて。
SUCCEEDEDは、引数のHRESULTがS_OKでもS_FALSEでも真を返す。
それ以外のエラーでは偽になる。

SUCCEEDED macro (winerror.h) - Win32 apps | Microsoft Docs

SUCCEEDED.cppで、

とすると、

SUCCEEDED!
CoInitialize success!
SUCCEEDED!
Already initialized!
続行するには何かキーを押してください . . .

S_OKでもS_FALSEでも真となる。

Sample/com/SUCCEEDED/SUCCEEDED/src/SUCCEEDED at master · bg1bgst333/Sample · GitHub

CoInitializeSecurity

CoInitializeSecurityで、セキュリティ設定を初期化する。

CoInitializeSecurity function (combaseapi.h) - Win32 apps | Microsoft Docs
例: ローカルコンピューターから WMI データを取得する - Win32 apps | Microsoft Docs

WMIのように、COMインターフェースによっては、これを設定しないと値を取得出来なかったりするので、設定する。

どう設定するかは難しいので、参考URLの通りにしておく。

CoInitializeEx success!
CoInitializeSecurity success!
続行するには何かキーを押してください . . .

セキュリティ初期化出来た模様。

Sample/com/CoInitializeSecurity/CoInitializeSecurity/src/CoInitializeSecurity at master · bg1bgst333/Sample · GitHub

CoInitializeEx

CoInitializeExも、COMの初期化を行う。

CoInitializeEx function (combaseapi.h) - Win32 apps | Microsoft Docs

こちらは、STA(シングルスレッドアパートメント)か、MTA(マルチスレッドアパートメント)か、どちらに属するかも設定する。
この話は難しいので、

ChalkTalk CLR – COMのすべて – kekyoの丼
COMのアパートメント (5) CoInitializeExは初期化ではない – kekyoの丼

を参照の事。
今回から、WMIを呼び出そうと思っているが、WMIのサンプル、

例: ローカルコンピューターから WMI データを取得する - Win32 apps | Microsoft Docs

こちらでは、CoInitializeExのCOINIT_MULTITHREADEDとしている。
(ただWMIは、CoInitializeでもCOINIT_APARTMENTTHREADEDでもいけるって話もある。)

CoInitializeと同様に初期化だけ。

CoInitializeEx success!
続行するには何かキーを押してください . . .

成功。

Sample/com/CoInitializeEx/CoInitializeEx/src/CoInitializeEx at master · bg1bgst333/Sample · GitHub

CoUninitialize

CoUninitializeで、COMの終了処理を行う。

CoUninitialize function (combaseapi.h) - Win32 apps | Microsoft Docs

CoInitializeで初期化して、COMインターフェースを使い終わったら、これで終了処理をする。
そして、この後にまたCOMインターフェースを使う場合は、CoInitializeで初期化が必要で、もちろんS_OKとなる。

こう書くと、

CoInitialize success!
CoInitialize success!
続行するには何かキーを押してください . . .

CoUninitializeをしてから、CoInitializeをしてるので、S_OKになる。

Sample/com/CoUninitialize/CoUninitialize/src/CoUninitialize at master · bg1bgst333/Sample · GitHub

CoInitialize

CoInitializeで、COMの初期化を行う。

CoInitialize function (objbase.h) - Win32 apps | Microsoft Docs

まずは、

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

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

	// COMの初期化.
	HRESULT hr = CoInitialize(NULL);	// CoInitializeでCOMを初期化し, 戻り値をhrに格納.
	if (hr == S_OK){	// S_OKなら初期化成功.
		_tprintf(_T("CoInitialize success!\n"));	// "CoInitialize success!"と出力.
	}

	// COMの終了処理.
	CoUninitialize();	// CoUninitializeで終了処理.

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

}

こう書いて、実行すると、

CoInitialize success!
続行するには何かキーを押してください . . .

こうなる。
CoInitializeによる初期化が成功すると、S_OKが返ってくる。
次に、

// ヘッダファイルのインクルード
#include <windows.h>	// 標準WindowsAPI
#include <tchar.h>		// TCHAR対応

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

	// COMの初期化.
	HRESULT hr = CoInitialize(NULL);	// CoInitializeでCOMを初期化し, 戻り値をhrに格納.
	if (hr == S_OK){	// S_OKなら初期化成功.
		_tprintf(_T("CoInitialize success!\n"));	// "CoInitialize success!"と出力.
	}

	// 2回目のCOMの初期化.
	HRESULT hr2 = CoInitialize(NULL);	// CoInitializeでCOMを初期化し, 戻り値をhr2に格納.
	if (hr2 == S_FALSE){	// S_FALSEならすでに初期化されている.
		_tprintf(_T("Already initialized!\n"));	// "Already initialized!"と出力.
	}

	// COMの終了処理.
	CoUninitialize();	// CoUninitializeで終了処理.

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

}

2回呼び出すと、

CoInitialize success!
Already initialized!
続行するには何かキーを押してください . . .

S_FALSEが返ってくる。
これは失敗というより、すでに初期化されてるという意味。
最後に、

メインスレッドでCoInitialize初期化した後で、ワーカースレッドでCoInitialize初期化。

CoInitialize success!
Already initialized!
Thread Begin
ThreadProc: CoInitialize success!
Thread End
dwExitCode = 0
続行するには何かキーを押してください . . .

プログラムの最初で初期化というより、スレッドごとに初期化できるということ。

Sample/com/CoInitialize/CoInitialize/src/CoInitialize at master · bg1bgst333/Sample · GitHub

DEV_BROADCAST_VOLUME

dbch_devicetypeが、DBT_DEVTYP_VOLUMEなら、DEV_BROADCAST_HDRポインタをDEV_BROADCAST_VOLUMEポインタにキャストできる。

DEV_BROADCAST_VOLUME (dbt.h) - Win32 apps | Microsoft Docs
USBメモリーの挿入などを検出する(UsefullCode.net)

今度は、DEV_BROADCAST_VOLUME構造体としての各要素を見てみる。
DEV_BROADCAST_VOLUME.cppで、

このように各要素をMessageBoxで表示。

これが来たら、OKを押す。
これが来たら、OKを押す。

これが来たら、OKを押す。

ここでさらに、OKを押す。
ここでさらに、OKを押す。

ここでさらに、OKを押す。

で、さらに各要素がわかる。
で、さらに各要素がわかる。

で、さらに各要素がわかる。
DBT_DEVTYP_VOLUMEということは、ボリュームを持つデバイスであり、USBメモリやUSBポータブルHDDなどのリムーバブルディスクはこれ。
実は、dbcv_unitmaskがドライブレターを表しており、例えば、一番下のビットが立っていたら'A'、下から2番目のビットが立っていたら'B'という感じになっている。
ここでは16になっているが、2進数で0x10000だから、'E'ドライブということになる。

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

DEV_BROADCAST_HDR

DBT_DEVICEARRIVALや、DBT_DEVICEREMOVECOMPLETEの時、lParamにはDEV_BROADCAST_HDR構造体のポインタが渡される。

DEV_BROADCAST_HDR (dbt.h) - Win32 apps | Microsoft Docs

渡されたlParamをDEV_BROADCAST_HDR構造体ポインタにキャストして各要素を見てみる。
DEV_BROADCAST_HDR.cppで、

このように各要素をMessageBoxで表示。

DBT_DEVICEARRIVALでOKを押す
DBT_DEVICEARRIVALでOKを押す

DBT_DEVICEARRIVALでOKを押す。

するとこれが出る。dbch_devicetypeは2。
するとこれが出る。dbch_devicetypeは2。

するとこれが出る。dbch_devicetypeは2。
これは、DBT_DEVTYP_VOLUMEにあたる。

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