VC下获取远程主机共享信息的一些方法
工程需要,要求就是在拥有了远程主机的IP地址、用户名和密码后列出远程主机上所有的共享资源。综合网上的资料和MSDN中的相关内容后,发现大概有WNet、NetAPI和WMI这么几种方式,感觉WMI是最强大的。下面就把各种方法大概说一下。
利用WMI获取远程主机的共享信息
1、 初始化操作
这部分我之前说过,参照以前WMI连接远程主机的文章就可以了,必须要能够正确得到IWbemServices对象,并为其设置了访问权限。
2、 枚举远程主机上的共享资源
共享资源对应的WMI类名是Win32_Share,我们只要用IWbemServices对象的CreateInstanceEnum()方法就可以得到所有的共享资源了。
HRESULT hr = S_OK;
IEnumWbemClassObject* pEnumObj = NULL;
Hr = pIWbemServices->CreateInstanceEnum(L"Win32_Share", 0, NULL, &pEnumObj);
Hr = CoSetProxyBlanket(
pEnumObj, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
pCID, // 这个需要设置用户信息,见之前WMI连接远程主机的文章
EOAC_NONE // proxy capabilities
);
ULONG uReturned = 1;
while(uReturned == 1)
{
IWbemClassObject *pStorageDev = NULL;
hr = pEnumObj->Next(
2000, // timeout in two seconds
1, // return just one storage device
&pStorageDev, // pointer to storage device
&uReturned); // number obtained: one or zero
if (SUCCEEDED(hr) && (uReturned == 1))
{
VARIANT pVal;
VariantInit(&pVal);
hr = pStorageDev->Get(L"__RELPATH", 0L, &pVal, NULL, NULL);
GetShareInfo(pIWbemServices, pVal.bstrVal);//得到共享信息,pVal就是类标识
VariantClear(&pVal);
pStorageDev->Release();
}
}
CHECK_AND_RELEASE(pEnumAdapters);
这里需要注意下,我们得到了枚举对象后,如果不是操作本机,而是要得到远程主机的共享资源是必须要为枚举对象设置访问权限的,也就是CoSetProxyBlanket()是不能少的。
3、 得到共享信息
这里说下GetShareInfo()方法的实现,我们通过枚举得到了每个共享对象Win32_Share的类的字符标识,这样我们就可以使用IWbemServices对象的GetObject()方法得到具体的Win32_Share对象,其中bstrPathName就是之前得到的pVal.bstrVal。
HRESULT hr = -1;
SAFEARRAY *psaNames = NULL;
IWbemClassObject* pClass = NULL;
long lLower, lUpper;
pIWbemServices->GetObject(bstrPathName, 0, NULL, &pClass, NULL);
if((hr = pClass->GetNames(NULL, WBEM_FLAG_ALWAYS|WBEM_FLAG_NONSYSTEM_ONLY, NULL, &psaNames)) == S_OK)
{
if((hr = SafeArrayGetLBound(psaNames, 1, &lLower)) != S_OK)
{
SafeArrayDestroy(psaNames);
CHECK_AND_RELEASE(pClass);
return;
}
if((hr = SafeArrayGetUBound(psaNames, 1, &lUpper)) != S_OK)
{
SafeArrayDestroy(psaNames);
CHECK_AND_RELEASE(pClass);
return;
}
for (long lCount=lLower; lCount<=lUpper; lCount++)
{
BSTR PropName = NULL;
VARIANT varString;
VariantInit(&varString);
if(SafeArrayGetElement(psaNames, &lCount, &PropName)==S_OK
&& pClass->Get(PropName, 0L, &varString, NULL, NULL)==S_OK)
{
if ((wcsicmp(PropName,L"Type")==0) && varString.vt!=VT_NULL)
{
UINT tmp_type = varString.uintVal;//0表示是共享文件夹
}
else if ((wcsicmp(PropName,L"Name")==0) && varString.vt!=VT_NULL)
{
CString tmp_name = varString.bstrVal;//共享名称
}
else if ((wcsicmp(PropName,L"Path")==0) && varString.vt!=VT_NULL)
{
CString tmp_path = varString.bstrVal;//共享在主机上的路径
}
}
VariantClear(&varString);
if (PropName != NULL)
{
SysFreeString(PropName);
}
if (bRes)
{
break;
}
}
SafeArrayDestroy(psaNames);
}
CHECK_AND_RELEASE(pClass);
好了,到此WMI就已经得到所有的共享资源了。
利用WNet获取远程主机的共享信息
1、 连接远程主机
NETRESOURCE nr;
memset(&nr, 0, sizeof(nr));
nr.dwScope=RESOURCE_CONNECTED;
nr.dwType=RESOURCETYPE_DISK;
nr.dwDisplayType=RESOURCEDISPLAYTYPE_GENERIC;
nr.dwUsage=RESOURCEUSAGE_CONNECTABLE;
nr.lpRemoteName = (LPTSTR)lpRemoteName;//远程主机名或IP如://192.168.1.11
WNetAddConnection2(&nr, lpPw/*密码*/, lpUser/*用户名*/, CONNECT_UPDATE_PROFILE);
2、 利用WNetOpenEnum枚举共享信息
DWORD dwResult, dwResultEnum;
HANDLE hEnum;
BYTE buf[16384];
DWORD cbBuffer = 16384; // 16K is a good size
LPNETRESOURCE lpnrLocal = (LPNETRESOURCE)buf;
DWORD cEntries = -1;
dwResult = WNetOpenEnum(RESOURCE_GLOBALNET, // all network resources
RESOURCETYPE_DISK, //只枚举共享文件夹
0, // enumerate all resources
&nr, // NULL first time the function is called
&hEnum); // handle to the resource
if (dwResult != NO_ERROR)
{
return;
}
do
{
cbBuffer = 16384;
memset(lpnrLocal, 0, 16384);
dwResultEnum = WNetEnumResource(hEnum, // resource handle
&cEntries, // defined locally as -1
lpnrLocal, // LPNETRESOURCE
&cbBuffer); // buffer size
if (dwResultEnum == NO_ERROR)
{
for (DWORD i=0; i<cEntries; i++)
{
CString str_remote = lpnrLocal[i].lpRemoteName;//得到共享名称
}
}
else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
{
break;
}
}
while (dwResultEnum != ERROR_NO_MORE_ITEMS);
WNetCloseEnum(hEnum);
WNet方式枚举共享资源的时候好像无法的共享名以$结尾的隐藏共享。
Wnet需要导入的头文件是:Winnetwk.h.
库文件是:#pragma comment(lib, "Mpr.lib")
利用NetAPI获取远程主机的共享信息
1、 连接远程主机
这和WNet方式完全一样
2、 枚举共享资源
PSHARE_INFO_1 BufPtr, pInfo;
NET_API_STATUS res;
DWORD er=0,tr=0,resume=0, i;
do
{
res = NetShareEnum ((LPTSTR)lpRemoteName, 1, (LPBYTE *) &BufPtr, -1, &er, &tr, &resume);
if(res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
{
pInfo = BufPtr;
for(i=1;i<=er;i++)
{
if (pInfo->shi1_type == STYPE_DISKTREE/*取文件夹共享*/
|| pInfo->shi1_type == STYPE_SPECIAL)
{
//pInfo->shi1_netname就是共享名称
}
pInfo++;
}
NetApiBufferFree(BufPtr);
}
}
while (res==ERROR_MORE_DATA);
NetAPI需要导入的头文件和库文件
#include <lm.h>
#pragma comment(lib, "Netapi32.lib")