使用 NetShareEnum 遍历本地共享目录需要注意的问题

时间:2022-09-23 12:40:41

1 简介

Windows提供了NetShareEnum函数用于实现遍历服务器的共享目录,但在实现该功能时发现一个有关UNICODE和ANSI字符串的问题。


2. 函数原型简介

该函数原型如下:

NET_API_STATUS NetShareEnum(
  LPWSTR servername,
  DWORD level,
  LPBYTE* bufptr,
  DWORD prefmaxlen,
  LPDWORD entriesread,
  LPDWORD totalentries,
  LPDWORD resume_handle
);
通过第二个参数 level 用来选择使用哪种级别的信息提取,可取值分别为0,1,2,50,502,。不同的level决定了bufptr所指向的结构体不同。以502 Level为例,bufptr需要指向SHARE_INFO_502的结构体。其定义如下所示:

typedef struct _SHARE_INFO_502 {
  LPWSTR shi502_netname;
  DWORD shi502_type;
  LPWSTR shi502_remark;
  DWORD shi502_permissions;
  DWORD shi502_max_uses;
  DWORD shi502_current_uses;
  LPWSTR shi502_path;
  LPWSTR shi502_passwd;
  DWORD shi502_reserved;
  PSECURITY_DESCRIPTOR shi502_security_descriptor;
} SHARE_INFO_502, 
*PSHARE_INFO_502, 
*LPSHARE_INFO_502;

3. 实现方式


//定义一个简单的结构体,用于存放一个共享目录的目录名和所在的路径。
struct SHARE_FOLDER
{
	SHARE_FOLDER(): wsNetName(L""), wsPath(L""){}

	std::wstring wsNetName;
	std::wstring wsPath;
};


//遍历本地共享文件目录,结果存放至resShareFolders容器中
bool  EnumLocalShareFolders(std::vector<SHARE_FOLDER>& resShareFolders)
{
	resShareFolders.clear();
	PSHARE_INFO_502 pBuf=NULL;
	NET_API_STATUS  res;
	DWORD er=0, tr=0, resume=0;

	do
	{
		res = NetShareEnum(NULL, 502, (LPBYTE*) &pBuf,  MAX_PREFERRED_LENGTH,&er, &tr, &resume);
		if( NULL == pBuf)
		{
			return false;
		}

		if( ERROR_SUCCESS == res || ERROR_MORE_DATA == res )
		{
			PSHARE_INFO_502  pPos = pBuf;

			for(DWORD i=1; i<=er; ++i)
			{
				SHARE_FOLDER folder;
				folder.wsNetName = (wchar_t*)(pPos->shi502_netname);  //[1]
				folder.wsPath = (wchar_t*)(pPos->shi502_path);	      //[2]		
			
				resShareFolders.push_back(folder);

				++pPos;
			}
			NetApiBufferFree(pBuf);
		}
		
	}
	while(ERROR_MORE_DATA==res);


	return true;
}

 
 

4. 存在问题

由MSDN提供的函数原型可以看出,用于存储返回信息的结构体 SHARE_INFO_502的字符串类型的成员变量都是宽字符类型 LPWSTR, 例如shi502_netname和shi502_path。事实上,通过系统的调用所提取出的字符串信息也是UNICODE字符串。但是在编译器的头文件中,该类型的字符串被定义成了LPSTR,也就是ANSI字符串,这就导致了两者的不一致。因此需要进行强制的类型转换,如上例代码中[1] [2]标记的的部分。如果不进行转换而直接将路径值和共享文件名赋值给std::wstring编译器报错。如果直接将

shi502_netname和shi502_path赋值给std::string类型,则只会赋值第一个字母。

例如,假设提取出的信息 shi502_netname 值为"ADMIN$",实际上,该值是以UNICODE编码, std::string name = shi502_netname 的赋值结果是,name=="A"。因为由于对字母高位补0,因此将后面的字符串截断。


5. 疑问

不知道是我个人理解问题,还是微软在这方面的实现有问题,笔者使用的平台是 Win7+vs2005 。 还没有在其它平台和IDE上验证。希望各位能够给出点意见和建议。