在项目中使用LSP模块时碰到以下几个问题,在此总结下:
1、在64位系统中,针对32位程序和64位程序需要分别实现对应的LSP模块,即64位程序不会加载32位的lsp
2、lsp模块最后放到系统盘的system32(64位 syswow64)下,否则可能导致某些程序加载不到对应的模块
3、多个lsp同时安装时,按照google搜索的用例(中文主要是这篇http://blog.csdn.net/xxaqzy/article/details/4399271,和这篇文章 http://blog.csdn.net/karen_mo/article/details/26674249),会导致后面安装的lsp卸载其他lsp模块问题,主要原因在于 lsp实现的 WSPStartup 函数,在 LoadLibrary 加载下层LSP后,不能进行释放,否则会导致下层LSP失效
示例代码如下:
LSP实现(实现代码自行google,这里仅给出关键的WSPStartup函数)
//WSPStartup
int WSPAPI WSPStartup(
WORD wversionrequested,
LPWSPDATA lpwspdata,
LPWSAPROTOCOL_INFOW lppProtoInfo,
WSPUPCALLTABLE upcalltable,
LPWSPPROC_TABLE lpproctable)
{
int nRet = -1;
int i;
int nErrcode = 0;
int filterpathlen, wfilterpathlen;
int count;
string strErr;
DWORD layerid=0;
DWORD nextlayerid=0;
TCHAR *filterpath = NULL;
WCHAR *wfilterpath = NULL;
HINSTANCE hfilter = NULL;
LPWSPSTARTUP wspstartupfunc = NULL;
LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
do {
if (1 >= lppProtoInfo->ProtocolChain.ChainLen) {
//error
break;
}
if (NULL == (pProtoInfo = _get_lsp(count))) {
//error
break;
}
for (i = 0; i < count; ++i) {
if (0 == memcmp(&pProtoInfo[i].ProviderId,&filterguid,sizeof(GUID))) {
layerid = pProtoInfo[i].dwCatalogEntryId;
break;
}
}
if (i == count) {
//error
break;
}
for (i = 0; i < lppProtoInfo->ProtocolChain.ChainLen; ++i) {
if (lppProtoInfo->ProtocolChain.ChainEntries[i] == layerid) {
nextlayerid = lppProtoInfo->ProtocolChain.ChainEntries[i + 1];
break;
}
}
if (i == lppProtoInfo->ProtocolChain.ChainLen) {
//error
break;
}
filterpathlen = MAX_PATH*2;
wfilterpathlen = MAX_PATH;
if (NULL == (filterpath =(TCHAR*)GlobalAlloc(GPTR, filterpathlen))) {
//error
break;
}
if (NULL == (wfilterpath =(WCHAR*)GlobalAlloc(GPTR, wfilterpathlen))) {
//error
break;
}
for (i = 0; i < count; ++i) {
if (nextlayerid == pProtoInfo[i].dwCatalogEntryId) {
break;
}
}
if (i == count) {
//error
break;
}
if (SOCKET_ERROR == WSCGetProviderPath(&pProtoInfo[i].ProviderId, wfilterpath, &wfilterpathlen ,&nErrcode)) {
//error
break;
}
if (0 == WideCharToMultiByte(CP_OEMCP, NULL, wfilterpath, wfilterpathlen,
(char *)filterpath, filterpathlen, NULL, NULL))
{
//error
break;
}
TCHAR szPath[MAX_PATH];
memset(szPath, 0, sizeof(szPath)*sizeof(TCHAR));
if (0 == ExpandEnvironmentStrings(filterpath, szPath, MAX_PATH)) {
//error
break;
}
if (NULL == (hfilter = LoadLibrary(szPath))) {
nErrcode = GetLastError();
//error
break;
}
if (NULL == (wspstartupfunc = (LPWSPSTARTUP)GetProcAddress(hfilter, "WSPStartup"))) {
//error
break;
}
if (ERROR_SUCCESS != (nErrcode = wspstartupfunc(wversionrequested, lpwspdata, lppProtoInfo, upcalltable, lpproctable))) {
//error
break;
}
g_next_proc_table = *lpproctable;
lpproctable->lpWSPConnect = WSPConnect;
lpproctable->lpWSPSend = WSPSend; //TCP
lpproctable->lpWSPSendTo = WSPSendTo; //UDP
nRet = 0;
} while (0);
if (0 != nRet) {
//error
}
_free_lsp(&pProtoInfo);
if (NULL != filterpath) {
GlobalFree(filterpath);
filterpath = NULL;
}
if (NULL != wfilterpath) {
GlobalFree(wfilterpath);
wfilterpath = NULL;
}
/* 此处不能释放,否则会导致安装多个LSP时卸载下层的LSP
if (NULL != hfilter) {
FreeLibrary(hfilter);
hfilter = NULL;
}*/
return nRet;
}
LSP安装代码
int _install(
IN const TCHAR *pszPathName)
{
int nRet = -1;
string strErr;
WCHAR wszLSPName[] = L"mmclient.lsp";
LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
int i, nProtocols;
WSAPROTOCOL_INFOW OriginalProtocolInfo[3];
DWORD dwOrigCatalogId[3];
int nArrayCount = 0;
DWORD dwLayeredCatalogId; // 要安装的分层协议的目录ID号
int nErrcode = 0;
WCHAR *pwszPathName = NULL;
DWORD dwPathNameLen = strlen(pszPathName);
DWORD dwWPathNameLen = dwPathNameLen*3;
PDWORD dwIds = NULL;
do {
if (NULL == (pwszPathName = (WCHAR *)GlobalAlloc(GPTR, dwWPathNameLen))) {
//error
break;
}
if (0 == MultiByteToWideChar(CP_ACP, 0, (char *)pszPathName, dwPathNameLen, pwszPathName, dwWPathNameLen)) {
//error
break;
}
// 枚举所有服务程序提供者
if (NULL == (pProtoInfo = _get_provider(&nProtocols))) {
//error
break;
}
BOOL bFindUdp = FALSE;
BOOL bFindTcp = FALSE;
BOOL bFindRaw = FALSE;
for (i = 0; i < nProtocols; ++i) {
if (AF_INET == pProtoInfo[i].iAddressFamily) {
if (FALSE == bFindUdp && IPPROTO_UDP == pProtoInfo[i].iProtocol) {
memmove(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
bFindUdp = TRUE;
}
if (FALSE == bFindTcp && IPPROTO_TCP == pProtoInfo[i].iProtocol) {
memmove(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
bFindTcp = TRUE;
}
if (FALSE == bFindRaw && IPPROTO_IP == pProtoInfo[i].iProtocol && pProtoInfo[i].ProtocolChain.ChainLen != LAYERED_PROTOCOL) {
memmove(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 = OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
bFindRaw = TRUE;
}
}
}
// 安装我们的分层协议,获取一个dwLayeredCatalogId
// 随便找一个下层协议的结构复制过来即可
WSAPROTOCOL_INFOW LayeredProtocolInfo;
memmove(&LayeredProtocolInfo, &OriginalProtocolInfo[0], sizeof(WSAPROTOCOL_INFOW));
// 修改协议名称,类型,设置PFL_HIDDEN标志
wcscpy_s(LayeredProtocolInfo.szProtocol, wszLSPName);
LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // 0;
LayeredProtocolInfo.dwProviderFlags |= PFL_HIDDEN;
// 安装
if (SOCKET_ERROR == ::WSCInstallProvider(&ProviderGuid, pwszPathName, &LayeredProtocolInfo, 1, &nErrcode)) {
//error
break;
}
_free_provider(&pProtoInfo);
// 重新枚举协议,获取分层协议的目录ID号
if (NULL == (pProtoInfo = _get_provider(&nProtocols))) {
//error
break;
}
for (i = 0; i < nProtocols; ++i) {
if (memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0) {
dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
break;
}
}
if (i == nProtocols) {
//error
break;
}
// 安装协议链
// 修改协议名称,类型
WCHAR wszChainName[WSAPROTOCOL_LEN + 1];
for (i = 0; i < nArrayCount; ++i) {
swprintf_s(wszChainName, L"%ws over %ws", wszLSPName, OriginalProtocolInfo[i].szProtocol);
wcscpy_s(OriginalProtocolInfo[i].szProtocol, wszChainName);
if (OriginalProtocolInfo[i].ProtocolChain.ChainLen == 1) {
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[1] = dwOrigCatalogId[i];
} else {
for (int j = OriginalProtocolInfo[i].ProtocolChain.ChainLen; j > 0; --j) {
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j] = OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j-1];
}
}
OriginalProtocolInfo[i].ProtocolChain.ChainLen ++;
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[0] = dwLayeredCatalogId;
}
// 获取一个Guid,安装之
GUID ProviderChainGuid;
if (RPC_S_OK != ::UuidCreate(&ProviderChainGuid)) {
//error
break;
}
if (::WSCInstallProvider(&ProviderChainGuid, pwszPathName, OriginalProtocolInfo, nArrayCount, &nErrcode) == SOCKET_ERROR) {
//error
break;
}
_free_provider(&pProtoInfo);
// 重新排序Winsock目录,将我们的协议链提前
// 重新枚举安装的协议
if (NULL == (pProtoInfo = _get_provider(&nProtocols))) {
//error
break;
}
if (NULL == (dwIds = (PDWORD)malloc(sizeof(DWORD) * nProtocols))) {
//error
break;
}
int nIndex = 0;
// 添加我们的协议链
for (i = 0; i < nProtocols; ++i) {
if ((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&
(pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))
{
dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
}
}
// 添加其它协议
for (i = 0; i < nProtocols; ++i) {
if ((pProtoInfo[i].ProtocolChain.ChainLen <= 1) ||
(pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId))
{
dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
}
}
// 重新排序Winsock目录
if ((nErrcode = ::WSCWriteProviderOrder(dwIds, nIndex)) != ERROR_SUCCESS) {
//error
break;
}
nRet = 0;
} while(0);
_free_provider(&pProtoInfo);
if (NULL != pwszPathName) {
GlobalFree(pwszPathName);
pwszPathName = NULL;
}
if (NULL != dwIds) {
free(dwIds);
dwIds = NULL;
}
return nRet;
}
另,附上比较有价值的 通用LSP实现和安装示例
http://www.komodia.com/lsp/lsp-sample