Windows系统为服务提供者维护了一个目录,这些信息保存在注册表中,要更改/安装服务提供者,就必须对此目录信息进行维护。系统提供了一些函数简化对此信息的访问,他们都是以WSC开头。
对于基础服务提供者的安装相当简单,只要准备一个WSAPROTOCOL_INFOW结构,用来代表基础服务提供者信息,正确填充合适的值,然后调用WSCInstallProvider函数就可以完成基础服务提供者的安装。但是这种方法只对新增加的基础服务提供者来讲是很方便的,但是我们往往要利用系统的基础服务提供者来实现基本的协议,比如说TCP协议的实现,所以在这种情况下,方便的方法是不通过WSCInstallProvider函数,而是我们自己修改目录条目信息,对于基础提供者,只要把基础提供者的动态库路径信息改成我们自己虚拟的基础服务提供者路径就可以了。这样安装的后续工作必须是把所有调用传给原来的基础服务提供者,所以在我们虚拟的服务提供者程序中,必须能够检索到原来的服务提供者路径信息。记住,安装之前千万要备份原来的目录信息。否则,一旦发生错误会引起网络无法访问。
基础服务提供者安装代码实例如下所示:
void CBSPinstallDlg::OnBtnInstall()
{
// Update m_strFileName which is our mimic Base Provider filename
UpdateData(TRUE);
if(0==BackupBSP()) InstallBSP();
}
int CBSPinstallDlg::EnumRegisterKey(HKEY hKey,TCHAR* pszKeyName,TCHAR** ppBuf,DWORD* pdwBufSize)
{
HKEY hSubKey=NULL;
if(RegOpenKeyEx(hKey,pszKeyName,0,KEY_ALL_ACCESS,&hSubKey)!=ERROR_SUCCESS)
return -1;
TCHAR szKey[20]={ '/0' };
if(hKey==HKEY_CURRENT_CONFIG) strcpy(szKey,"HKEY_LOCAL_MACHINE"; else
if(hKey==HKEY_CURRENT_USER) strcpy(szKey,"HKEY_CURRENT_USER"; else
if(hKey==HKEY_LOCAL_MACHINE) strcpy(szKey,"HKEY_LOCAL_MACHINE"; else
if(hKey==HKEY_USERS) strcpy(szKey,"HKEY_USERS"; else
if(hKey==HKEY_PERFORMANCE_DATA) strcpy(szKey,"HKEY_PERFORMANCE_DATA"; else
if(hKey==HKEY_DYN_DATA) strcpy(szKey,"HKEY_DYN_DATA"; else
return -1;
int len=strlen(szKey)+strlen(pszKeyName)+5;
TCHAR* pszItem=new TCHAR[len+1];
memset(pszItem,0,len+1);
sprintf(pszItem,"[%s//%s]/r/n",szKey,pszKeyName);
TCHAR* pBuf=*ppBuf;
DWORD dwBufSize=*pdwBufSize;
TCHAR* pTmp=new TCHAR[dwBufSize+len];
memset(pTmp,0,dwBufSize+len);
memmove(pTmp,pBuf,dwBufSize);
memmove(pTmp+dwBufSize,pszItem,len);
delete[] pszItem; pszItem=NULL;
delete[] pBuf; pBuf=NULL;
dwBufSize+=len;
*ppBuf=pTmp;
*pdwBufSize=dwBufSize;
// "Num_Catalog_Entries"=dword:00000013
// "Next_Catalog_Entry_ID"=dword:0000043e
// "Serial_Access_Num"=dword:00000014
DWORD cbClass=0;
DWORD cSubKeys=0;
DWORD cbMaxSubKeyLen=0;
DWORD cbMaxClassLen=0;
DWORD cValues=0;
DWORD cbMaxValueNameLen=0;
DWORD cbMaxValueLen=0;
int nRet=RegQueryInfoKey(hSubKey,
NULL,
&cbClass,
NULL,
&cSubKeys,
&cbMaxSubKeyLen,
&cbMaxClassLen,
&cValues,
&cbMaxValueNameLen,
&cbMaxValueLen,
NULL,
NULL);
if(nRet!=ERROR_SUCCESS)
return -1;
for(DWORD dwIndex=0;dwIndex<cValues;dwIndex++)
{
DWORD dwItemNameSize=cbMaxValueNameLen+1;
TCHAR* pszItemName=new TCHAR[dwItemNameSize];
memset(pszItemName,0,dwItemNameSize);
DWORD dwDataSize=cbMaxValueLen+1;
BYTE* pbyData=new BYTE[dwDataSize];
memset(pbyData,0,dwDataSize);
DWORD dwType=0;
nRet=RegEnumValue(hSubKey,dwIndex,pszItemName,&dwItemNameSize,NULL,&dwType,pbyData,&dwDataSize);
if(nRet!=ERROR_SUCCESS)
{
delete[] pszItemName; pszItemName=NULL;
delete[] pbyData; pbyData=NULL;
return -1;
}
TCHAR* pBuf=*ppBuf;
DWORD dwBufSize=*pdwBufSize;
if(dwDataSize>0)
{
TCHAR* szTmp=new TCHAR[dwDataSize*4+266];
memset(szTmp,0,dwDataSize*4+266);
szTmp[0]='"';
int nPos=1;
memmove(szTmp+nPos,pszItemName,strlen(pszItemName));
nPos+=strlen(pszItemName);
szTmp[nPos]='"';nPos++;
szTmp[nPos]='=';nPos++;
switch(dwType)
{
case REG_SZ:
szTmp[nPos]='"';nPos++;
memmove(szTmp,pbyData,dwDataSize);
nPos+=dwDataSize;
szTmp[nPos]='"';nPos++;
szTmp[nPos]='/r';nPos++;
szTmp[nPos]='/n';nPos++;
break;
case REG_DWORD:
{
char sz[20]="dword:/0";
sprintf(sz,"%s%08x",sz,*(DWORD*)pbyData);
memmove(szTmp+nPos,sz,strlen(sz));
nPos+=strlen(sz);
}
break;
case REG_BINARY:
{
char sz[20]="hex:/0";
memmove(szTmp+nPos,sz,strlen(sz));
nPos+=strlen(sz);
int j=0;
for(UINT i=0;i<dwDataSize;i++)
{
if(( (j==0 && nPos%78==0) || /
( j>0 && (nPos-81-(j-1)*80)%77==0) /
&& i<dwDataSize-1)
{
j++;
szTmp[nPos]='//';nPos++;
szTmp[nPos]='/r';nPos++;
szTmp[nPos]='/n';nPos++;
if(j>0)
{
szTmp[nPos]=' ';nPos++;
szTmp[nPos]=' ';nPos++;
}
}
if(i<dwDataSize-1)
{
TCHAR szAppend[20]={ '/0' };
sprintf(szAppend,"%02x,",pbyData[i]);
strcat(szTmp,szAppend);
nPos+=3;
}
else
{
TCHAR szAppend[20]={ '/0' };
sprintf(szAppend,"%02x",pbyData[i]);
strcat(szTmp,szAppend);
nPos+=2;
}
}
}
default:
break;
}
delete[] pszItemName; pszItemName=NULL;
delete[] pbyData; pbyData=NULL;
szTmp[nPos]='/r';nPos++;
szTmp[nPos]='/n';nPos++;
TCHAR* pTmp=new TCHAR[dwBufSize+nPos];
memset(pTmp,0,dwBufSize+nPos);
memmove(pTmp,pBuf,dwBufSize);
memmove(pTmp+dwBufSize,szTmp,nPos);
delete[] szTmp;szTmp=NULL;
delete[] pBuf;pBuf=NULL;
dwBufSize+=nPos;
*ppBuf=pTmp;
*pdwBufSize=dwBufSize;
}
if(pszItemName) delete[] pszItemName; pszItemName=NULL;
if(pbyData) delete[] pbyData; pbyData=NULL;
}
{
TCHAR* pBuf=*ppBuf;
DWORD dwBufSize=*pdwBufSize;
TCHAR* pTmp=new TCHAR[dwBufSize+2];
memset(pTmp,0,dwBufSize+2);
memmove(pTmp,pBuf,dwBufSize);
pTmp[dwBufSize]='/r';
pTmp[dwBufSize+1]='/n';
*ppBuf=pTmp;
*pdwBufSize=dwBufSize+2;
delete[] pBuf; pBuf=NULL;
}
DWORD dwSubKeyLen=cbMaxSubKeyLen+1;
// [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/WinSock2/Parameters/Protocol_Catalog9/Catalog_Entries]
for(dwIndex=0;dwIndex<cSubKeys;dwIndex++)
{
TCHAR* szKeyName=new TCHAR[dwSubKeyLen];
memset(szKeyName,0,dwSubKeyLen);
int nRet=RegEnumKey(hSubKey,dwIndex,szKeyName,dwSubKeyLen);
if(nRet!=ERROR_SUCCESS)
{
delete[] szKeyName; szKeyName=NULL;
return -1;
}
TCHAR szKeyNameAnother[266]={ '/0' };
wsprintf(szKeyNameAnother,"%s//%s",pszKeyName,szKeyName);
delete[] szKeyName; szKeyName=NULL;
nRet=EnumRegisterKey(HKEY_LOCAL_MACHINE,szKeyNameAnother,ppBuf,pdwBufSize);
if(nRet==-1) return -1;
}
RegCloseKey(hSubKey);
return 0;
}
int CBSPinstallDlg::BackupBSP()
{
TCHAR szSysDir[266]={ '/0' };
GetWindowsDirectory(szSysDir,266);
TCHAR szBackupFile[266]={ '/0' };
sprintf(szBackupFile,"%s//MinBSP.reg",szSysDir);
CFileStatus status;
if(CFile::GetStatus(szBackupFile,status))
{
if(IDNO==::MessageBox(NULL,"你已经安装了基础服务提供者,是不是还要继续安装?","确认",MB_YESNO))
{
PostQuitMessage(0);
return -1;
}
}
if(m_strFileName.GetLength()==0)
{
AfxMessageBox("请指定基础服务提供者。";
m_edtFileName.SetFocus();
m_edtFileName.SetSel(0,-1);
return -1;
}
// 开始安装
// 首先备份原来的服务提供者目录条目信息
CFile f;
if(f.Open(szBackupFile,CFile::modeCreate|CFile::modeReadWrite))
{
TCHAR szTmp[266]="Windows Registry Editor Version 5.00/r/n/r/n/0";
DWORD dwBufSize=strlen(szTmp);
TCHAR* lpBuf=new TCHAR[dwBufSize];
memset(lpBuf,0,dwBufSize);
memmove(lpBuf,szTmp,dwBufSize);
TCHAR szKeyName[1024]="SYSTEM//CurrentControlSet//Services//WinSock2//Parameters//Protocol_Catalog9/0";
int nRet=EnumRegisterKey(HKEY_LOCAL_MACHINE,szKeyName,&lpBuf,&dwBufSize);
if(nRet==-1) { f.Close();delete[] lpBuf;lpBuf=NULL;return -1; }
nRet=dwBufSize*2+2;
WCHAR* pwszResult=new WCHAR[nRet];
memset(pwszResult,0,nRet);
nRet=MultiByteToWideChar(CP_ACP,0,lpBuf,dwBufSize,pwszResult,nRet);
BYTE by=0xFF;
f.Write(&by,1);
by=0xFE;
f.Write(&by,1);
f.Write(pwszResult,nRet*2);
f.Close();
delete[] pwszResult; pwszResult=NULL;
delete[] lpBuf;lpBuf=NULL;
}
return 0;
}
void CBSPinstallDlg::InstallBSP()
{
// 备份完成
// 接下来,更改系统原来的基础服务提供者目录条目信息为我的基础提供者信息
// 枚举协议
LPWSAPROTOCOL_INFOW lpProtocolInfo=NULL;
DWORD dwProtocolInfoSize=0;
int nErrorCode=0;
int nRet=WSCEnumProtocols(NULL,lpProtocolInfo,&dwProtocolInfoSize,&nErrorCode);
if(nRet==SOCKET_ERROR && nErrorCode!=WSAENOBUFS)
{
TRACE1("WSCEnumProtocols() returns error: %d/n",nErrorCode);
return;
}
lpProtocolInfo=(LPWSAPROTOCOL_INFOW) new BYTE[dwProtocolInfoSize];
memset(lpProtocolInfo,0,dwProtocolInfoSize);
__try
{
// 取得协议信息
int nTotalProtocols=WSCEnumProtocols(NULL,lpProtocolInfo,&dwProtocolInfoSize,&nErrorCode);
if(nTotalProtocols==SOCKET_ERROR) return;
// 查找TCP/IP协议信息
TCHAR szTCPIP[20]="[TCP/IP]/0";
TCHAR szTCP95[20]=".TCP/0";
TCHAR szProtocol[MAX_PATH]={ '/0' };
TCHAR szKeyName[]="SYSTEM//CurrentControlSet//Services//WinSock2//Parameters//Protocol_Catalog9//Catalog_Entries/0";
HKEY hSubKey=NULL;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,szKeyName,0,KEY_ALL_ACCESS,&hSubKey)!=ERROR_SUCCESS) return;
for(int i=0;i<nTotalProtocols;i++)
{
memset(szProtocol,0,MAX_PATH);
WCHAR* pwsz=(lpProtocolInfo+i)->szProtocol;
BSTR bstr=SysAllocString(pwsz);
WideCharToMultiByte(CP_ACP,0,bstr,-1,szProtocol,255,NULL,NULL);
SysFreeString(bstr);
// if(strstr(szProtocol,szTCPIP)!=NULL || strstr(szProtocol,szTCP95)!=NULL) break;
if((lpProtocolInfo+i)->ProtocolChain.ChainLen==1)
{
// 更改基础服务提供者信息
TCHAR szSubKeyName[MAX_PATH]={ '/0' };
int nRet=RegEnumKey(hSubKey,i,szSubKeyName,MAX_PATH);
if(nRet!=ERROR_SUCCESS) return;
HKEY hSubKeySub=NULL;
DWORD dwSubKeyLen=strlen(szKeyName);
TCHAR* pszKeyName=new TCHAR[dwSubKeyLen+strlen(szSubKeyName)+2];
memset(pszKeyName,0,dwSubKeyLen+strlen(szSubKeyName)+2);
wsprintf(pszKeyName,"%s//%s",szKeyName,szSubKeyName);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,pszKeyName,0,KEY_ALL_ACCESS,&hSubKeySub)!=ERROR_SUCCESS)
{
if(pszKeyName) delete[] pszKeyName; pszKeyName=NULL;
return;
}
DWORD cbClass=0;
DWORD cSubKeys=0;
DWORD cbMaxSubKeyLen=0;
DWORD cbMaxClassLen=0;
DWORD cValues=0;
DWORD cbMaxValueNameLen=0;
DWORD cbMaxValueLen=0;
nRet=RegQueryInfoKey(hSubKeySub,
NULL,
&cbClass,
NULL,
&cSubKeys,
&cbMaxSubKeyLen,
&cbMaxClassLen,
&cValues,
&cbMaxValueNameLen,
&cbMaxValueLen,
NULL,
NULL);
if(nRet!=ERROR_SUCCESS)
{
cbMaxValueNameLen=MAX_PATH;
cbMaxValueLen=MAX_PATH+sizeof(WSAPROTOCOL_INFOW)+2;
}
DWORD dwItemNameSize=cbMaxValueNameLen+1;
TCHAR* pszItemName=new TCHAR[dwItemNameSize];
memset(pszItemName,0,dwItemNameSize);
DWORD dwDataSize=cbMaxValueLen+1;
BYTE* pbyData=new BYTE[dwDataSize];
memset(pbyData,0,dwDataSize);
DWORD dwType=0;
nRet=RegEnumValue(hSubKeySub,0,pszItemName,&dwItemNameSize,NULL,&dwType,pbyData,&dwDataSize);
if(nRet!=ERROR_SUCCESS)
{
if(pszKeyName) delete[] pszKeyName; pszKeyName=NULL;
if(pszItemName) delete[] pszItemName; pszItemName=NULL;
if(pbyData) delete[] pbyData; pbyData=NULL;
return;
}
memset(pbyData,0,MAX_PATH);
TCHAR szDllPath[MAX_PATH+2];
wsprintf(szDllPath,"%%SystemRoot%%//System32//%s",m_strFileName);
int nLen=strlen(szDllPath);
memmove(pbyData,szDllPath,nLen);
nRet=RegSetValueEx(hSubKeySub,pszItemName,NULL,dwType,pbyData,dwDataSize);
if(nRet!=ERROR_SUCCESS)
{
if(pszKeyName) delete[] pszKeyName; pszKeyName=NULL;
if(pszItemName) delete[] pszItemName; pszItemName=NULL;
if(pbyData) delete[] pbyData; pbyData=NULL;
return;
}
if(pszKeyName) delete[] pszKeyName; pszKeyName=NULL;
if(pszItemName) delete[] pszItemName; pszItemName=NULL;
if(pbyData) delete[] pbyData; pbyData=NULL;
}
}
if(i<nTotalProtocols) TRACE1("TCP/IP 协议信息在目录条目中的第 %d 项。/n",i+1);
else TRACE("无法根据协议描述判断TCP/IP协议信息。/n";
}
__finally
{
if(lpProtocolInfo) delete[] lpProtocolInfo;
lpProtocolInfo=NULL;
}
}