EternalWindows
LSP / インストールサンプル

今回は、実際にLSPをインストールするプログラムを作成します。 まず、実行結果を確認します。

リストビューにはシステムに存在する全てのエントリが列挙され、 チェックされたエントリがインストールまたはアンインストールの対象になります。 上記の例では、MSAFD Tcpip [TCP/IP]を選択しており、 ここでメニューの「コマンド」から「インストール」を選択してDLL(LSP)を決定した場合、 MSAFD Tcpip [TCP/IP]の上に独自のエントリがインストールされることになります。

見て分かるように、sample over MSAFD Tcpip [TCP/IP]というエントリがMSAFD Tcpip [TCP/IP]より、オーダー上先行しています。 これにより、MSAFD Tcpip [TCP/IP]よりも先にTCP/IP要求を検出できるようになります。 また、上図では確認できませんが、オーダーの最後尾にはダミーエントリが存在しています。 アンインストール時には、sample over MSAFD Tcpip [TCP/IP]を選択してメニューの「コマンド」から「アンインストール」を選択します。 そうすると、sample over MSAFD Tcpip [TCP/IP]とダミーエントリがアンインストールされることになります。 ちなみに、WSCInstallProviderAndChainsによってインストールを実行した場合は、 RSVP TCP サービスプロバイダの上にも独自のエントリがインストールされ、 合計2つのエントリが存在することになります。 アンインストール時には、この両方のエントリをチェックするようにします。

今回のプログラムは、実際にLSPをインストールする処理とアンインストールする処理を含んでいます。 WSCEnumProtocolsなどのWinsock SPIを呼び出すには、ws2spi.hのインクルードが必要になります。 また、WSCWriteProviderOrderの呼び出しには、sporder.hのインクルードとsporder.libへのリンクが必要になります。

#include <ws2spi.h>
#include <sporder.h>
#include <commctrl.h>

#pragma comment(lib, "ws2_32.lib")
#pragma comment (lib, "sporder.lib")
#pragma comment (lib, "comctl32.lib")

#define ID_COMMAND   10
#define ID_INSTALL   20
#define ID_UNINSTALL 30

typedef void (WINAPI *LPFNGETLSPGUID)(LPGUID);
typedef int (WSPAPI *LPFNWSCINSTALLPROVIDERANDCHAINS)(const LPGUID, const LPWSTR, const LPWSTR, DWORD, const LPWSAPROTOCOL_INFOW, DWORD, LPDWORD, LPINT);

BOOL InstallLsp(LPWSTR lpszFilePath, LPWSTR lpszProtocolName, LPDWORD lpdwEntryArray, int nEntryCount);
BOOL InstallLspVistaLater(GUID guidProvider, LPWSTR lpszProviderPath, LPWSTR lpszProtocolName, LPWSAPROTOCOL_INFOW lpProtocolInfo, int nEntryCount, LPINT lpnError);
BOOL InstallLspLegacy(GUID guidProvider, LPWSTR lpszProviderPath, LPWSTR lpszProtocolName, LPWSAPROTOCOL_INFOW lpProtocolInfo, int nEntryCount, LPINT lpnError);
BOOL UninstallLsp(LPDWORD lpdwEntryArray, int nEntryCount);
BOOL SelectDllFile(HWND hwnd, LPWSTR lpszFilePath);
void UpdateListview(HWND hwndListView);
void InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId, HMENU hmenuSub);
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 hwndListView = NULL;

	switch (uMsg) {

	case WM_CREATE: {
		int                  i;
		int                  nColumnCount = 3;
		LVCOLUMN             column;
		INITCOMMONCONTROLSEX ic;
		DWORD                dwExStyle;
		LPTSTR               lpszColumn[] = {TEXT("プロバイダ名"), TEXT("エントリID"), TEXT("プロトコルチェーン")};
		HMENU                hmenu;
		HMENU                hmenuPopup;

		hmenu  = CreateMenu();
		hmenuPopup = CreatePopupMenu();

		InitializeMenuItem(hmenuPopup, TEXT("インストール(&I)"), ID_INSTALL, NULL);
		InitializeMenuItem(hmenuPopup, TEXT("アンインストール(&U)"), ID_UNINSTALL, NULL);
		InitializeMenuItem(hmenu, TEXT("コマンド(&C)"), ID_COMMAND, hmenuPopup);
		
		SetMenu(hwnd, hmenu);

		ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
		ic.dwICC  = ICC_LISTVIEW_CLASSES;
		InitCommonControlsEx(&ic);
		
		hwndListView = CreateWindowEx(0, WC_LISTVIEW, TEXT(""), WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
		dwExStyle = ListView_GetExtendedListViewStyle(hwndListView);
		ListView_SetExtendedListViewStyle(hwndListView, dwExStyle | LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);

		for (i = 0; i < nColumnCount; i++) {
			column.mask    = LVCF_WIDTH | LVCF_TEXT;
			column.cx      = 300;
			column.pszText = lpszColumn[i];
			ListView_InsertColumn(hwndListView, i, &column);
		}

		UpdateListview(hwndListView);

		return 0;
	}
	
	case WM_COMMAND: {
		int     nId = LOWORD(wParam);
		int     i, j;
		int     nItemCount;
		int     nEntryCount = 0;
		BOOL    bResult = FALSE;
		LPDWORD lpdwEntryArray;
		LVITEM  item;
		WCHAR   szFilePath[256];

		nItemCount = ListView_GetItemCount(hwndListView);
		for (i = 0; i < nItemCount; i++) {
			if (ListView_GetCheckState(hwndListView, i) != 0)
				nEntryCount++;
		}

		if (nEntryCount == 0) {
			MessageBox(NULL, TEXT("エントリがチェックされていません。"), NULL, MB_ICONWARNING);
			return 0;
		}
		
		lpdwEntryArray = (LPDWORD)HeapAlloc(GetProcessHeap(), 0, nEntryCount * sizeof(DWORD));

		for (i = 0, j = 0; i < nItemCount; i++) {
			if (ListView_GetCheckState(hwndListView, i) != 0) {
				item.mask     = LVIF_PARAM;
				item.iItem    = i;
				item.iSubItem = 1;
				ListView_GetItem(hwndListView, &item);
				lpdwEntryArray[j++] = (DWORD)item.lParam;
			}
		}

		if (nId == ID_INSTALL) {
			if (SelectDllFile(hwnd, szFilePath))
				bResult = InstallLsp(szFilePath, L"sample", lpdwEntryArray, nEntryCount);
		}
		else
			bResult = UninstallLsp(lpdwEntryArray, nEntryCount);

		if (bResult)
			UpdateListview(hwndListView);
		
		HeapFree(GetProcessHeap(), 0, lpdwEntryArray);
		
		return 0;
	}
	
	case WM_SIZE:
		MoveWindow(hwndListView, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

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

BOOL InstallLsp(LPWSTR lpszFilePath, LPWSTR lpszProtocolName, LPDWORD lpdwEntryArray, int nEntryCount)
{
	int                 i, j;
	int                 nError;
	int                 nTotalEntryCount;
	BOOL                bResult;
	DWORD               dwSize;
	OSVERSIONINFO       versionInfo;
	GUID                guidProvider;
	HMODULE             hmod;
	LPFNGETLSPGUID      lpfnGetLspGuid;
	LPWSAPROTOCOL_INFOW lpEntryList;
	LPWSAPROTOCOL_INFOW lpBaseEntryList;
	
	hmod = LoadLibraryW(lpszFilePath);
	if (hmod == NULL)
		return FALSE;

	lpfnGetLspGuid = (LPFNGETLSPGUID)GetProcAddress(hmod, "GetLspGuid");
	if (lpfnGetLspGuid == NULL) {
		FreeLibrary(hmod);
		return FALSE;
	}
	
	lpfnGetLspGuid(&guidProvider);
	FreeLibrary(hmod);
	
	WSCEnumProtocols(NULL, NULL, &dwSize, &nError);
	lpEntryList = (LPWSAPROTOCOL_INFOW)HeapAlloc(GetProcessHeap(), 0, dwSize);
	nTotalEntryCount = WSCEnumProtocols(NULL, lpEntryList, &dwSize, &nError);

	for (i = 0; i < nTotalEntryCount; i++) {
		if (lstrcmpW(lpEntryList[i].szProtocol, lpszProtocolName) == 0) {
			MessageBox(NULL, TEXT("同一プロトコル名のエントリが既に存在します。"), NULL, MB_ICONWARNING);
			HeapFree(GetProcessHeap(), 0, lpEntryList);
			return FALSE;
		}
	}

	lpBaseEntryList = (LPWSAPROTOCOL_INFOW)HeapAlloc(GetProcessHeap(), 0, sizeof(WSAPROTOCOL_INFOW) * nEntryCount);

	for (i = 0; i < nEntryCount; i++) {
		for (j = 0; j < nTotalEntryCount; j++) {
			if (lpEntryList[j].dwCatalogEntryId == lpdwEntryArray[i]) {
				if (lpEntryList[j].ProtocolChain.ChainLen == 0) {
					MessageBox(NULL, TEXT("ダミーエントリが選択されています。"), NULL, MB_ICONWARNING);
					HeapFree(GetProcessHeap(), 0, lpBaseEntryList);
					HeapFree(GetProcessHeap(), 0, lpEntryList);
					return FALSE;
				}
				CopyMemory(&lpBaseEntryList[i], &lpEntryList[j], sizeof(WSAPROTOCOL_INFOW));
				break;
			}
		}
	}
	
	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&versionInfo);

	if (versionInfo.dwMajorVersion >= 6)
		bResult = InstallLspVistaLater(guidProvider, lpszFilePath, lpszProtocolName, lpBaseEntryList, nEntryCount, &nError);
	else
		bResult = InstallLspLegacy(guidProvider, lpszFilePath, lpszProtocolName, lpBaseEntryList, nEntryCount, &nError);

	if (bResult)
		MessageBox(NULL, TEXT("LSPのインストールに成功しました。"), TEXT("OK"), MB_OK);
	else {
		MessageBox(NULL, TEXT("LSPのインストールに失敗しました。"), NULL, MB_ICONWARNING);
		if (nError == WSANO_RECOVERY)
			MessageBox(NULL, TEXT("管理者として実行してください。"), NULL, MB_ICONWARNING);
	}
	
	HeapFree(GetProcessHeap(), 0, lpBaseEntryList);
	HeapFree(GetProcessHeap(), 0, lpEntryList);

	return bResult;
}

BOOL InstallLspVistaLater(GUID guidProvider, LPWSTR lpszProviderPath, LPWSTR lpszProtocolName, LPWSAPROTOCOL_INFOW lpBaseEntryList, int nEntryCount, LPINT lpnError)
{
	HMODULE                         hmod;
	LPFNWSCINSTALLPROVIDERANDCHAINS lpfnWSCInstallProviderAndChains;

	hmod = LoadLibrary(TEXT("ws2_32.dll"));
	if (hmod == NULL)
		return FALSE;
	
	lpfnWSCInstallProviderAndChains = (LPFNWSCINSTALLPROVIDERANDCHAINS)GetProcAddress(hmod, "WSCInstallProviderAndChains");
	if (lpfnWSCInstallProviderAndChains == NULL) {
		FreeLibrary(hmod);
		return FALSE;
	}

	if (lpfnWSCInstallProviderAndChains(&guidProvider, lpszProviderPath, lpszProtocolName, XP1_IFS_HANDLES, lpBaseEntryList, nEntryCount, NULL, lpnError) == SOCKET_ERROR) {
		FreeLibrary(hmod);
		return FALSE;
	}

	FreeLibrary(hmod);

	return TRUE;
}

BOOL InstallLspLegacy(GUID guidProvider, LPWSTR lpszProviderPath, LPWSTR lpszProtocolName, LPWSAPROTOCOL_INFOW lpBaseEntryList, int nEntryCount, LPINT lpnError)
{
	int                 i, j;
	int                 nTotalEntryCount;
	int                 nOrderCount;
	int                 nError;
	DWORD               dwSize;
	DWORD               dwDummyEntryId = 0;
	LPDWORD             lpdwEntryIdOrder;
	WSAPROTOCOL_INFOW   dummyEntry;
	LPWSAPROTOCOL_INFOW lpEntryList;
	LPWSAPROTOCOL_INFOW lpNewEntryList;
	WCHAR               szOverProtocolName[WSAPROTOCOL_LEN];
	
	CopyMemory(&dummyEntry, &lpBaseEntryList[0], sizeof(WSAPROTOCOL_INFOW));

	dummyEntry.iSocketType            = 0;
	dummyEntry.iProtocol              = 0;
	dummyEntry.dwProviderFlags        |= PFL_HIDDEN;
	dummyEntry.dwProviderFlags        &= (~PFL_MATCHES_PROTOCOL_ZERO);
	dummyEntry.ProtocolChain.ChainLen = 0;
	lstrcpyW(dummyEntry.szProtocol, lpszProtocolName);

	if (WSCInstallProvider(&guidProvider, lpszProviderPath, &dummyEntry, 1, lpnError) == SOCKET_ERROR)
		return FALSE;

	WSCEnumProtocols(NULL, NULL, &dwSize, &nError);
	lpEntryList = (LPWSAPROTOCOL_INFOW)HeapAlloc(GetProcessHeap(), 0, dwSize);
	nTotalEntryCount = WSCEnumProtocols(NULL, lpEntryList, &dwSize, &nError);

	for (i = 0; i < nTotalEntryCount; i++) {
		if (IsEqualGUID(lpEntryList[i].ProviderId, guidProvider)) {
			dwDummyEntryId = lpEntryList[i].dwCatalogEntryId;
			break;
		}
	}

	lpNewEntryList = (LPWSAPROTOCOL_INFOW)HeapAlloc(GetProcessHeap(), 0, sizeof(WSAPROTOCOL_INFOW) * nEntryCount);

	for (i = 0; i < nEntryCount; i++) {
		CopyMemory(&lpNewEntryList[i], &lpBaseEntryList[i], sizeof(WSAPROTOCOL_INFOW));

		for (j = lpNewEntryList[i].ProtocolChain.ChainLen; j > 0; j--)
			lpNewEntryList[i].ProtocolChain.ChainEntries[j] = lpNewEntryList[i].ProtocolChain.ChainEntries[j - 1];

		lpNewEntryList[i].ProtocolChain.ChainEntries[0] = dwDummyEntryId;
		lpNewEntryList[i].ProtocolChain.ChainEntries[1] = lpBaseEntryList[i].dwCatalogEntryId;
		lpNewEntryList[i].ProtocolChain.ChainLen++;
		
		wsprintfW(szOverProtocolName, L"%s over [%s]", lpszProtocolName, lpBaseEntryList[i].szProtocol);
		lstrcpyW(lpNewEntryList[i].szProtocol, szOverProtocolName);
		
		CoCreateGuid(&lpNewEntryList[i].ProviderId);
		
		if (WSCInstallProvider(&lpNewEntryList[i].ProviderId, lpszProviderPath, &lpNewEntryList[i], 1, lpnError) == SOCKET_ERROR) {
			WSCDeinstallProvider(&guidProvider, &nError);
			HeapFree(GetProcessHeap(), 0, lpNewEntryList);
			HeapFree(GetProcessHeap(), 0, lpEntryList);
			return FALSE;
		}
	}

	HeapFree(GetProcessHeap(), 0, lpEntryList);
	WSCEnumProtocols(NULL, NULL, &dwSize, &nError);
	lpEntryList = (LPWSAPROTOCOL_INFOW)HeapAlloc(GetProcessHeap(), 0, dwSize);
	nTotalEntryCount = WSCEnumProtocols(NULL, lpEntryList, &dwSize, &nError);

	lpdwEntryIdOrder = (LPDWORD)HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) * nTotalEntryCount);

	nOrderCount = 0;
	for (i = 0; i < nTotalEntryCount; i++) {
		if (lpEntryList[i].ProtocolChain.ChainLen > 0 && lpEntryList[i].ProtocolChain.ChainEntries[0] == dwDummyEntryId)
			lpdwEntryIdOrder[nOrderCount++] = lpEntryList[i].dwCatalogEntryId;
	}

	for (i = 0; i < nTotalEntryCount; i++) {
		if (lpEntryList[i].ProtocolChain.ChainLen == 0 || lpEntryList[i].ProtocolChain.ChainEntries[0] != dwDummyEntryId)
			lpdwEntryIdOrder[nOrderCount++] = lpEntryList[i].dwCatalogEntryId;
	}

	nError = WSCWriteProviderOrder(lpdwEntryIdOrder, nTotalEntryCount);

	HeapFree(GetProcessHeap(), 0, lpdwEntryIdOrder);
	HeapFree(GetProcessHeap(), 0, lpNewEntryList);
	HeapFree(GetProcessHeap(), 0, lpEntryList);

	return nError == ERROR_SUCCESS;
}

BOOL UninstallLsp(LPDWORD lpdwEntryArray, int nEntryCount)
{
	int                 i, j, k;
	int                 nError;
	int                 nTotalEntryCount;
	int                 nRelativeDummyEntryCount;
	int                 nDummyEntryIndex;
	DWORD               dwDummyEntryId;
	DWORD               dwSize;
	LPWSAPROTOCOL_INFOW lpEntryList;
	
	WSCEnumProtocols(NULL, NULL, &dwSize, &nError);
	lpEntryList = (LPWSAPROTOCOL_INFOW)HeapAlloc(GetProcessHeap(), 0, dwSize);
	nTotalEntryCount = WSCEnumProtocols(NULL, lpEntryList, &dwSize, &nError);

	for (i = 0; i < nEntryCount; i++) {
		for (j = 0; j < nTotalEntryCount; j++) {
			if (lpdwEntryArray[i] == lpEntryList[j].dwCatalogEntryId) {
				if (lpEntryList[j].ProtocolChain.ChainLen == 0) {
					MessageBox(NULL, TEXT("ダミーエントリが選択されています。"), NULL, MB_ICONWARNING);
					HeapFree(GetProcessHeap(), 0, lpEntryList);
					return FALSE;
				}
				else if (lpEntryList[j].ProtocolChain.ChainLen == 1) {
					MessageBox(NULL, TEXT("ベースプロトコルが選択されています。"), NULL, MB_ICONWARNING);
					HeapFree(GetProcessHeap(), 0, lpEntryList);
					return FALSE;
				}
				else
					;
			}
		}
	}

	for (i = 0; i < nEntryCount; i++) {
		for (j = 0; j < nTotalEntryCount; j++) {
			if (lpEntryList[j].ProtocolChain.ChainLen > 1 && lpdwEntryArray[i] == lpEntryList[j].dwCatalogEntryId) {
				if (WSCDeinstallProvider(&lpEntryList[j].ProviderId, &nError) == SOCKET_ERROR)
					break;
				
				dwDummyEntryId = lpEntryList[j].ProtocolChain.ChainEntries[0];
				lpEntryList[j].ProtocolChain.ChainEntries[0] = 0;
				nDummyEntryIndex = 0;
				nRelativeDummyEntryCount = 0;

				for (k = 0; k < nTotalEntryCount; k++) {
					if (dwDummyEntryId == lpEntryList[k].dwCatalogEntryId)
						nDummyEntryIndex = k;
					else if (lpEntryList[k].ProtocolChain.ChainLen > 0 && dwDummyEntryId == lpEntryList[k].ProtocolChain.ChainEntries[0])
						nRelativeDummyEntryCount++;
				}

				if (nRelativeDummyEntryCount == 0)
					WSCDeinstallProvider(&lpEntryList[nDummyEntryIndex].ProviderId, &nError);

				break;
			}
		}

		if (nError != NO_ERROR) {
			MessageBox(NULL, TEXT("LSPのアンインストールに失敗しました。"), NULL, MB_ICONWARNING);
			if (nError == WSAEACCES)
				MessageBox(NULL, TEXT("管理者として実行してください。"), NULL, MB_ICONWARNING);
			HeapFree(GetProcessHeap(), 0, lpEntryList);
			return FALSE;
		}
	}
	
	MessageBox(NULL, TEXT("LSPのアンインストールに成功しました。"), TEXT("OK"), MB_OK);
	
	HeapFree(GetProcessHeap(), 0, lpEntryList);

	return TRUE;
}

BOOL SelectDllFile(HWND hwnd, LPWSTR lpszFilePath)
{
	OPENFILENAMEW ofn;

	lpszFilePath[0] = '\0';

	ZeroMemory(&ofn, sizeof(OPENFILENAME));
	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner   = hwnd;
	ofn.lpstrFilter = L"DLL File (*.dll)\0*.dll\0\0";
	ofn.lpstrFile   = lpszFilePath;
	ofn.nMaxFile    = MAX_PATH;
	ofn.lpstrTitle  = L"DLLファイル読み込み";
	ofn.Flags       = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;

	if (!GetOpenFileNameW(&ofn))
		return FALSE;

	return TRUE;
}

void UpdateListview(HWND hwndListView)
{
	int                 i, j;
	int                 nError;
	int                 nTotalEntryCount;
	int                 nColumnCount = 3;
	LVITEMW             item;
	LPWSAPROTOCOL_INFOW lpProtocolInfo;
	DWORD               dwSize;
	TCHAR               szBuf[256];
	WCHAR               szProtocol[256];

	WSCEnumProtocols(NULL, NULL, &dwSize, &nError);
	lpProtocolInfo = (LPWSAPROTOCOL_INFOW)HeapAlloc(GetProcessHeap(), 0, dwSize);
	nTotalEntryCount = WSCEnumProtocols(NULL, lpProtocolInfo, &dwSize, &nError);
	
	ListView_DeleteAllItems(hwndListView);

	for (i = 0; i < nTotalEntryCount; i++) {
		for (j = 0; j < nColumnCount; j++) {
			item.mask     = LVIF_TEXT;
			item.iItem    = i;
			item.iSubItem = j;

			if (j == 0) {
				item.mask    |= LVIF_PARAM;
				item.pszText = szProtocol;
				item.lParam  = lpProtocolInfo[i].dwCatalogEntryId;
				
				wsprintfW(szProtocol, L"%s", lpProtocolInfo[i].szProtocol);
				SendMessage(hwndListView, LVM_INSERTITEMW, 0, (LPARAM)&item);
			}
			else if (j == 1) {
				item.pszText = szBuf;
				wsprintf(szBuf, TEXT("%d"), lpProtocolInfo[i].dwCatalogEntryId);
				ListView_SetItem(hwndListView, &item);
			}
			else if (j == 2) {
				item.pszText = szBuf;
				wsprintf(szBuf, TEXT("%d"), lpProtocolInfo[i].ProtocolChain.ChainLen);
				ListView_SetItem(hwndListView, &item);
			}
			else
				;
		}
	}
}

void InitializeMenuItem(HMENU hmenu, LPTSTR lpszItemName, int nId, HMENU hmenuSub)
{
	MENUITEMINFO mii;
	
	mii.cbSize = sizeof(MENUITEMINFO);
	mii.fMask  = MIIM_ID | MIIM_TYPE;
	mii.wID    = nId;

	if (lpszItemName != NULL) {
		mii.fType      = MFT_STRING;
		mii.dwTypeData = lpszItemName;
	}
	else
		mii.fType = MFT_SEPARATOR;

	if (hmenuSub != NULL) {
		mii.fMask   |= MIIM_SUBMENU;
		mii.hSubMenu = hmenuSub;
	}

	InsertMenuItem(hmenu, nId, FALSE, &mii);
}

このプログラムでは、これまでの節で説明してきたInstallLsp、InstallLspVistaLater、InstallLspLegacy、 UninstallLspをそのまま使用しているため、内部処理については各節を参照してください。 WM_CREATEでは、インストールとアンインストールを選択できるためのメニューを作成し、 システムに存在するエントリを表示するためのリストビューを作成しています。 UpdateListviewを呼び出せば、リストビューにエントリが表示されることになります。

メニューから「インストール」または「アンインストール」が選択された場合は、 WM_COMMANDが送られることになります。 まず、チェックが入ったアイテムをカウントし、この数だけDWORD型の配列を確保します。 続いて、チェックが入ったエントリのIDを取得し、これを先ほど確保した配列に格納します。 その後、選択されたコマンドに応じて、 InstallLspまたはUninstallLspを呼び出すことになります。 InstallLspの第2引数はエントリ名のプロトコル名であり、これは自由に設定することができます。 インストールまたはアンインストール後にUpdateListviewを呼び出すことで、 処理内容が即座にリストビューに反映されることになります。

今回のプログラムのように、ユーザーにエントリを選択させる場合は、 いくつか難しい問題が発生することが予想されます。 たとえば、ダミーエントリというのは、ユーザーにとって非常に分かりにくいエントリですから、 できれば表示しないほうがよいともいえるはずです。 これを実現するには、ダミーエントリを意図的に省略するか、 WSAEnumProtocolsを呼び出して列挙を行う方法が考えられます。 また、プロトコルチェーンが1であるベースプロトコルは、 アンインストールするべきではありませんが、 何らかの問題で誤ってアンインストールしてしまった場合はどうすればよいのでしょうか。 この場合は、次に示すコマンドをコマンドプロンプト上で実行してださい。

netsh winsock reset catalog

このコマンドを実行した場合、エントリを格納するシステム構成データベースがリセットされ、 システムに既定で存在するエントリのみで構成されることになります。


戻る