EternalWindows
LSP / LSPのアンインストール

インストールしたLSPのエントリをアンインストールするには、WSCDeinstallProviderを呼び出します。

int WSPAPI WSCDeinstallProvider(
  LPGUID lpProviderId,
  LPINT lpErrno
);

lpProviderIdは、アンインストールしたいエントリのGUIDを指定します。 lpErrnoは、エラー情報を受け取る変数のアドレスを指定します。 戻り値は、関数が成功した場合に0が返り、失敗した場合にSOCKET_ERRORが返ります。

次に示すUninstallLspは、引数で指定されたIDを持つエントリをアンインストールします。 また、そのエントリに関連するダミーエントリをアンインストールする場合もあります。

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;
}

LSPのアンインストールで複雑となるのは、エントリ間の関係です。 LSPのインストールでは、ダミーエントリと実際のエントリの2つをインストールすることになりますから、 片方をアンインストールする場合は、もう片方のエントリもアンインストールする必要があります。 上記コードでは、実際のエントリのIDを先に考慮するようにし、 このエントリをアンインストールした後に、 ダミーエントリをアンインストールしてもよいかの判断を行っています。 主要な処理を順に見ていきます。

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
				;
		}
	}
}

このコードは、lpdwEntryArray[i]がダミーエントリ、またはベースプロトコルのエントリでないかを確認する部分です。 ダミーエントリは実際のエントリの後にアンインストールするべきものであり、 ベースプロトコルはLSPの下のエントリとして機能するものですから、 これらのエントリは直接アンインストールしないようにしいています。

for (j = 0; j < nTotalEntryCount; j++) {
	if (lpEntryList[j].ProtocolChain.ChainLen > 0 && 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;
	}
}

このコードは、実際のエントリとダミーエントリをアンインストールする部分です。 lpdwEntryArray[i]と一致したエントリのChainLenが1より大きい場合、 それはダミーエントリではない実際のエントリですから、 WSCDeinstallProviderでアンインストールすることになります。 また、実際のエントリには関連するダミーエントリが存在しているため、 それをアンインストールしてもよいかの判断を行う必要があります。 この基準となるのは、ダミーエントリのIDをChainEntries[0]として格納するエントリが存在するかどうかです。 具体的には、先ほどアンインストールした実際のエントリからダミーエントリのIDを取得し、 これを持つエントリを全エントリの中から検索します。 そして、一致数を表すnRelativeDummyEntryCountが0の場合は、 ダミーエントリをアンインストールすることになります。 この検索の際に、先ほどアンインストールした実際のエントリが考慮されてはいけませんから、 予めChainEntries[0]に0を格納しています。


戻る