EternalWindows
アカウント管理 / グループの列挙

ユーザーが属することのできるグループは、 ローカルグループとグローバルグループに大別されます。 ローカルグループは1台のコンピュータ上でのみ有効なグループであり、 グローバルグループはドメインコントローラ上で存在し、 ドメイン全体で有効なグループです。 今回は、ローカルグループを列挙するNetLocalGroupEnumについて説明します。

NET_API_STATUS NetLocalGroupEnum(
  LPCWSTR servername,
  DWORD level,
  LPBYTE *bufptr,
  DWORD prefmaxlen,
  LPDWORD entriesread,
  LPDWORD totalentries,
  PDWORD_PTR resumehandle
);

servernameは、この関数を実行するサーバーの名前を指定します。 NULLを指定した場合は、ローカルコンピュータで実行されます。 levelは、取得するデータのレベルを指定します。 bufptrは、バッファへのアドレスを受け取る変数のアドレスを指定します。 このバッファに、列挙されたグループ情報が格納されます。 prefmaxlenは、取得したいデータのサイズを指定します。 全てのデータを取得したい場合は、MAX_PREFERRED_LENGTHを指定します。 entriesreadは、列挙されたエントリの数を受け取る変数のアドレスを指定します。 totalentriesは、全てのエントリの数を受け取る変数のアドレスを指定します。 resume_handleは、レジュームハンドルを受け取る変数のアドレスを指定します。 通常は必要がないため、NULLを指定します。

特定のグループのメンバとなっているユーザーは、 NetLocalGroupGetMembersで列挙することができます。

NET_API_STATUS NetLocalGroupGetMembers(
  LPCWSTR servername,
  LPCWSTR localgroupname,
  DWORD level,
  LPBYTE *bufptr,
  DWORD prefmaxlen,
  LPDWORD entriesread,
  LPDWORD totalentries,
  PDWORD_PTR resumehandle
);

servernameは、この関数を実行するサーバーの名前を指定します。 NULLを指定した場合は、ローカルコンピュータで実行されます。 levelは、取得するデータのレベルを指定します。 bufptrは、バッファへのアドレスを受け取る変数のアドレスを指定します。 このバッファに、列挙されたメンバ情報が格納されます。 prefmaxlenは、取得したいデータのサイズを指定します。 全てのデータを取得したい場合は、MAX_PREFERRED_LENGTHを指定します。 entriesreadは、列挙されたエントリの数を受け取る変数のアドレスを指定します。 totalentriesは、全てのエントリの数を受け取る変数のアドレスを指定します。 resume_handleは、レジュームハンドルを受け取る変数のアドレスを指定します。 通常は必要がないため、NULLを指定します。

今回のプログラムは、システムに存在するグループを左のリストボックスに列挙します。 グループが選択された場合は、そのグループのメンバとなっているユーザーが左のリストボックスに列挙されます。

#include <windows.h>
#include <lm.h>

#pragma comment (lib, "netapi32.lib")

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndListBoxLeft = NULL;
	static HWND hwndListBoxRight = NULL;

	switch (uMsg) {

	case WM_CREATE: {
		DWORD              i;
		DWORD              dwEntryCount;
		DWORD              dwTotalEntries;
		PLOCALGROUP_INFO_0 pGroupInfo;

		hwndListBoxLeft = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | LBS_NOTIFY, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		hwndListBoxRight = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | LBS_NOTIFY, 0, 0, 0, 0, hwnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		
		if (NetLocalGroupEnum(NULL, 0, (LPBYTE *)&pGroupInfo, MAX_PREFERRED_LENGTH, &dwEntryCount, &dwTotalEntries, NULL) != NERR_Success)
			return -1;

		for (i = 0; i < dwEntryCount; i++)
			SendMessageW(hwndListBoxLeft, LB_ADDSTRING, 0, (LPARAM)pGroupInfo[i].lgrpi0_name);
		
		NetApiBufferFree(pGroupInfo);

		return 0;
	}
	
	case WM_COMMAND: {
		WCHAR                      szBuf[256];
		DWORD                      i;
		DWORD                      dwEntryCount;
		DWORD                      dwTotalEntries;
		DWORD                      dwIndex;
		PLOCALGROUP_MEMBERS_INFO_1 pMemversInfo;
		
		if ((HWND)lParam == hwndListBoxRight || HIWORD(wParam) != LBN_SELCHANGE)
			return 0;
		
		SendMessage(hwndListBoxRight, LB_RESETCONTENT, 0, 0);

		dwIndex = (DWORD)SendMessage(hwndListBoxLeft, LB_GETCURSEL, 0, 0);
		SendMessage(hwndListBoxLeft, LB_GETTEXT, dwIndex, (LPARAM)szBuf);

		if (NetLocalGroupGetMembers(NULL, szBuf, 1, (LPBYTE *)&pMemversInfo, MAX_PREFERRED_LENGTH, &dwEntryCount, &dwTotalEntries, NULL) != NERR_Success)
			return -1;
		
		for (i = 0; i < dwEntryCount; i++)
			SendMessageW(hwndListBoxRight, LB_ADDSTRING, 0, (LPARAM)pMemversInfo[i].lgrmi1_name);

		NetApiBufferFree(pMemversInfo);

		return 0;
	}

	case WM_SIZE:
		MoveWindow(hwndListBoxLeft, 0, 0, LOWORD(lParam) / 2, HIWORD(lParam), TRUE);
		MoveWindow(hwndListBoxRight, LOWORD(lParam) / 2, 0, LOWORD(lParam) / 2, HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

WM_CREATEでは、NetLocalGroupEnumを呼び出して、システムに存在するグループを取得しています。 第2引数に0を指定しているため、第3引数に指定するのはLOCALGROUP_INFO_0構造体となり、 唯一のメンバであるlgrpi0_nameには、グループの名前が格納されています。 よって、これをリストボックスに追加しています。 WM_COMMANDでは、選択されたグループをNetLocalGroupGetMembersに指定し、 そのメンバであるユーザーを取得しています。 LOCALGROUP_MEMBERS_INFO_1構造体には、ユーザー名の他にSIDが含まれています。

NetUserGetLocalGroups

NetLocalGroupGetMembersを呼び出すことで、 特定のグループのメンバであるユーザーを列挙することができましたが、 それでは、特定のユーザーがメンバとなっているグループを列挙するにはどうすればよいのでしょうか。 これには、NetUserGetLocalGroupsを呼び出します。

#include <windows.h>
#include <lm.h>

#pragma comment (lib, "netapi32.lib")

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndListBoxLeft = NULL;
	static HWND hwndListBoxRight = NULL;

	switch (uMsg) {

	case WM_CREATE: {
		DWORD        i;
		DWORD        dwEntryCount;
		DWORD        dwTotalEntries;
		PUSER_INFO_0 pUserInfo;

		hwndListBoxLeft = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | LBS_NOTIFY, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		hwndListBoxRight = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | LBS_NOTIFY, 0, 0, 0, 0, hwnd, (HMENU)2, ((LPCREATESTRUCT)lParam)->hInstance, NULL);

		if (NetUserEnum(NULL, 0, 0, (LPBYTE *)&pUserInfo, MAX_PREFERRED_LENGTH, &dwEntryCount, &dwTotalEntries, NULL) != NERR_Success)
			return -1;

		for (i = 0; i < dwEntryCount; i++)
			SendMessageW(hwndListBoxLeft, LB_ADDSTRING, 0, (LPARAM)pUserInfo[i].usri0_name);

		NetApiBufferFree(pUserInfo);

		return 0;
	}

	case WM_COMMAND: {
		WCHAR                    szBuf[256];
		DWORD                    i;
		DWORD                    dwEntryCount;
		DWORD                    dwTotalEntries;
		DWORD                    dwIndex;
		PLOCALGROUP_USERS_INFO_0 pGroupUserInfo;
	
		if ((HWND)lParam == hwndListBoxRight || HIWORD(wParam) != LBN_SELCHANGE)
			return 0;
		
		SendMessage(hwndListBoxRight, LB_RESETCONTENT, 0, 0);

		dwIndex = (DWORD)SendMessage(hwndListBoxLeft, LB_GETCURSEL, 0, 0);
		SendMessage(hwndListBoxLeft, LB_GETTEXT, dwIndex, (LPARAM)szBuf);
		
		if (NetUserGetLocalGroups(NULL, szBuf, 0, 0, (LPBYTE *)&pGroupUserInfo, MAX_PREFERRED_LENGTH, &dwEntryCount, &dwTotalEntries) != NERR_Success)
			return -1;
		
		for (i = 0; i < dwEntryCount; i++)
			SendMessageW(hwndListBoxRight, LB_ADDSTRING, 0, (LPARAM)pGroupUserInfo[i].lgrui0_name);
			
		NetApiBufferFree(pGroupUserInfo);

		return 0;
	}

	case WM_SIZE:
		MoveWindow(hwndListBoxLeft, 0, 0, LOWORD(lParam) / 2, HIWORD(lParam), TRUE);
		MoveWindow(hwndListBoxRight, LOWORD(lParam) / 2, 0, LOWORD(lParam) / 2, HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

NetUserGetLocalGroupsの第2引数は、グループを取得したいユーザー名を指定します。 第3引数は情報レベルであり、0を指定しているため第5引数にはLOCALGROUP_USERS_INFO_0構造体を指定しています。 第4引数は、フラグを指定することができますが、0で問題ありません。



戻る