而对于分层服务提供者而言,安装要复杂一点。他需要建立两个WSAPROTOCOL_INFOW结构,一个代表分层提供者(ChainLen==0),另一个代表协议链(ChainLen>1),利用该协议链把分层服务提供者和基础服务提供者连接起来。
分层服务提供者安装的具体的步骤,概括起来大致分为五步:
第一,初始化两个协议信息结构,初始化可以借助于WSCEnumProtocols函数取回的信息来完成;
第二,用WSCInstallProvider调用来安装你的分层服务提供者;
第三,在第二步成功的基础上,列举所有的目录条目,获得新安装的分层提供者的目录编号。并利用这个目录信息来设置一个协议链的目录信息,通过这个协议链,将你的分层提供者和基础服务提供者(或者是它下一层的分层协议提供者)连接起来。
第四,调用WSCInstallProvider安装这个协议链。
第五,分层服务提供者安装成功后,Windows会在服务提供者目录的最后加入这个新的条目。但是我们为了让我们的分层服务提供者成为系统默认的TCP服务提供者的话,就必须对目录进行重新排列,让新安装的协议链目录条目放在最上面。这些排序过程通过调用WSCWriteProviderOrder完成,该函数将所有的服务提供者重新排序。需要包含 <sporder.h>头文件和sporder.lib库。
以下是单纯针对TCP协议(其他协议处理方法雷同)的分层服务提供者示例:
int CLSPinstallDlg::EnumProtocols(LPWSAPROTOCOL_INFOW* lppInfo,DWORD& dwProtocolInfoSize,int& nTotalProtocols)
{
LPWSAPROTOCOL_INFOW lpProtocolInfo=*lppInfo;
if(lpProtocolInfo!=NULL) delete[] lpProtocolInfo; lpProtocolInfo=NULL;
int nErrorCode=0;
int nRet=WSCEnumProtocols(NULL,lpProtocolInfo,&dwProtocolInfoSize,&nErrorCode);
if(nRet==SOCKET_ERROR&&nErrorCode!=WSAENOBUFS) return nErrorCode;
lpProtocolInfo = (LPWSAPROTOCOL_INFOW)new BYTE[dwProtocolInfoSize];
ASSERT(lpProtocolInfo!=NULL);
nTotalProtocols = WSCEnumProtocols(NULL,lpProtocolInfo,&dwProtocolInfoSize,&nErrorCode);
if(nTotalProtocols== SOCKET_ERROR) return -1;
*lppInfo=lpProtocolInfo;
return 0;
}
void CLSPinstallDlg::InstallLSP()
{
LPWSAPROTOCOL_INFOW lpProtocolInfo=NULL;
DWORD dwProtocolInfoSize=0;
int nTotalProtocols=0;
_try
{
// 第一步,初始化两个协议信息结构,初始化可以借助于WSCEnumProtocols函数取回的信息来完成;
int nRet=EnumProtocols(&lpProtocolInfo,dwProtocolInfoSize,nTotalProtocols);
if(nRet!=0)
{
TRACE1("WSCEnumProtocols() returns error: %d/n",nRet);
return;
}
DWORD dwLayeredCatalogId,dwTcpCatalogId;
WSAPROTOCOL_INFOW stuLayeredInfo,stuTcpChainInfo;
for(int i=0;i<nTotalProtocols;i++)
{
if(lpProtocolInfo[i].iAddressFamily == AF_INET && lpProtocolInfo[i].iProtocol == IPPROTO_TCP)
{
dwTcpCatalogId = lpProtocolInfo[i].dwCatalogEntryId;
memmove(&stuTcpChainInfo, &lpProtocolInfo[i], sizeof(WSAPROTOCOL_INFOW));
memmove(&stuLayeredInfo, &lpProtocolInfo[i], sizeof(WSAPROTOCOL_INFOW));
stuTcpChainInfo.dwServiceFlags1 = lpProtocolInfo[i].dwServiceFlags1 & ~XP1_IFS_HANDLES;
break;
}
}
// 第二步,用WSCInstallProvider调用来安装你的分层服务提供者;
wcscpy(stuLayeredInfo.szProtocol, L"Mini Layered Provider";
stuLayeredInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL;
WCHAR wszDllPath[MAX_PATH*2+2]={ '/0' };
swprintf(wszDllPath,L"%%SystemRoot%%//System32//%s",m_strFileName);
int nErrorCode=0;
nRet=WSCInstallProvider(&guidMiniProvider,wszDllPath,&stuLayeredInfo,1,&nErrorCode);
if(nRet==SOCKET_ERROR)
{
printf("WSCInstallProvider failed %d/n", nErrorCode);
return;
}
// 第三步,在第二步成功的基础上,列举所有的目录条目,获得新安装的分层提供者的目录编号。
// 并利用这个目录信息来设置一个协议链的目录信息,通过这个协议链,将分层提供者和基础服务提供者
// (或者是它下一层的分层协议提供者)连接起来。
nRet=EnumProtocols(&lpProtocolInfo,dwProtocolInfoSize,nTotalProtocols);
if(nRet!=0)
{
TRACE1("WSCEnumProtocols() returns error: %d/n",nRet);
return;
}
for (i=0;i<nTotalProtocols;i++)
{
if(memcmp(&lpProtocolInfo[i].ProviderId, &guidMiniProvider,sizeof (GUID))==0)
{
dwLayeredCatalogId = lpProtocolInfo[i].dwCatalogEntryId;
break;
}
}
WCHAR wszChainName[MAX_PATH*2+2]={ '/0' };
swprintf(wszChainName, L"Mini Layered TCP [%s]", stuTcpChainInfo.szProtocol);
wcscpy(stuTcpChainInfo.szProtocol,wszChainName);
if (stuTcpChainInfo.ProtocolChain.ChainLen==BASE_PROTOCOL)
{
stuTcpChainInfo.ProtocolChain.ChainEntries[1] = dwTcpCatalogId;
}
else
{
for (i=stuTcpChainInfo.ProtocolChain.ChainLen;i>0;i--)
{
stuTcpChainInfo.ProtocolChain.ChainEntries[i+1] = stuTcpChainInfo.ProtocolChain.ChainEntries[i];
}
}
stuTcpChainInfo.ProtocolChain.ChainLen++;
stuTcpChainInfo.ProtocolChain.ChainEntries[0] = dwLayeredCatalogId;
// 第四步,调用WSCInstallProvider安装这个协议链
nRet=WSCInstallProvider(&guidMiniProviderChain,wszDllPath,&stuTcpChainInfo,1,&nErrorCode);
if(nRet==SOCKET_ERROR)
{
printf("WSCInstallProvider for protocol chain failed %d/n", nErrorCode);
return;
}
// 第五步,安装成功后将所有的服务提供者重新排序。
LPDWORD lpCatalogEntries=(LPDWORD)new BYTE[nTotalProtocols*sizeof(DWORD)];
ASSERT(lpCatalogEntries!=NULL);
memset(lpCatalogEntries,0,nTotalProtocols*sizeof(DWORD));
DWORD dwIndex=0;
for (i=0;i<nTotalProtocols;i++)
{
if(memcmp(&lpProtocolInfo[i].ProviderId, &guidMiniProvider, sizeof (GUID))==0 || /
memcmp (&lpProtocolInfo[i].ProviderId, &guidMiniProviderChain, sizeof (GUID))==0)
lpCatalogEntries[dwIndex++] = lpProtocolInfo[i].dwCatalogEntryId;
}
for (i=0;i<nTotalProtocols;i++)
{
if(memcmp (&lpProtocolInfo[i].ProviderId, &guidMiniProvider, sizeof (GUID))!=0 && /
memcmp (&lpProtocolInfo[i].ProviderId, &guidMiniProviderChain, sizeof (GUID))!=0)
lpCatalogEntries[dwIndex++]=lpProtocolInfo[i].dwCatalogEntryId;
}
nRet=WSCWriteProviderOrder(lpCatalogEntries,nTotalProtocols);
delete[] lpCatalogEntries; lpCatalogEntries=NULL;
if(nRet!=ERROR_SUCCESS)
{
printf("WSCWriteProviderOrder failed %d/n", nErrorCode);
return;
}
}
__finally
{
if(lpProtocolInfo) delete[] lpProtocolInfo; lpProtocolInfo=NULL;
}
}
好了,到目前,我们安装了基础服务提供者和分层服务提供者,到了该卸载他们的时候了,对于基础服务提供者,简单地恢复原来的目录信息就可以了,对于分层服务提供者,调用WSCDeinstallProvider卸载函数可以简单的卸载,但是对于分层服务提供者,一定要维护好协议链,把所有和你的分层服务提供者的协议链相关的信息都清除掉,恢复安装之前的协议链状态,免得发生协议链断开的现象发生,如果断开了,就会影响网络的功能。Windows SPI在这方面存在缺陷,如果很多人装了很多个分层服务提供者,那怎么办呢?会很麻烦的。