我今天在这儿看了很长时间的关于WNetOpenEnum这一系列的函数,主要是想知道怎样获取局域网内的所有计算机及它们的IP。我总结了一下,写了三个函数,封装在一个单元内。基本能通过,可是......

liushikui 2001-09-25 08:42:24
找到所有工作组没什么问题,但搜寻某一工作组内的所有计算机时却很不稳定,有时成功,有时失败。
因为我是刚接触这些动动,实在是找不到原因,还望各位高手多多指教。
下面是单元的全部代码:

===================================
unit LanPcList;

interface

uses
windows, classes;

//获取局域网内工作组列表。
//参数:var list : TStringList
//返回值:如果成功取得工作组列表,返回true;
// 如果失败,返回false;
function GetGroupList(var list:TStringList) : boolean;

//获取某一工作组内计算机列表。
//参数:const groupName : String 工作组名
// var list : TStringList
//返回值:如果成功取得计算机列表,返回true;
// 如果失败,返回false
function GetPcList(const groupName:string; var list:TStringList) : boolean;

//根据计算机名得到IP地址
function GetIP(const pcName:String):string;

implementation

uses
winsock, sysUtils;

type
TNetResourcePtr = ^TNetResource;

function GetGroupList(var list:TStringList) : boolean;
var
buf : pointer;
bufSize : dword;
i : integer;
hRes : Thandle;
p : TNetResourcePtr;
ret : dword;
count : dword;
begin
//取得网络根节点
ret := WnetOpenEnum(RESOURCE_GLOBALNET,RESOURCETYPE_ANY,RESOURCEUSAGE_CONTAINER,NIL,hRes);
if ret<>NO_ERROR then
begin
GetGroupList := false;
exit; //失败,返回false
end;

count := $ffffff;
bufSize := 4096;
GetMem(buf,bufSize);
ret := WNetEnumResource(hRes,count,buf,bufSize);
if (ret<>NO_ERROR) or (count<1) then
begin //失败或者0个项目
GetGroupList := false;
freeMem(buf);
WnetCloseEnum(hRes);
exit;
end;

//得到网络根节点的 ^TNetResource
p := TNetResourcePtr(buf);

//关闭列举
wNetCloseEnum(hRes);

//打开新的列举
ret := WNetOpenEnum(RESOURCE_GLOBALNET,RESOURCETYPE_ANY,RESOURCEUSAGE_CONTAINER,@(p^),hRes);
if ret<>NO_ERROR then
begin
GetGroupList := false;
freeMem(buf);
exit;
end;

//获取工作组列表
count := $ffffffff;
bufSize := 4096;
GetMem(buf,bufSize);

ret := wNetEnumResource(hRes,count,buf,bufSize);
if (ret<>NO_ERROR) or (count<1) then
begin //失败或者0个项目
GetGroupList := false;
wNetCloseEnum(hRes);
freeMem(buf);
exit;
end;

p := TNetResourcePtr(buf);
list.clear;

for i:=0 to count-1 do
begin
list.add(p^.lpRemoteName);
inc(p);
end;

freeMem(buf);
wNetCloseEnum(hRes);

GetGroupList := true;

end;

function GetPcList(const groupName:string; var list:TStringList) : boolean;
var
buf : pointer;
bufSize : dword;
i : integer;
hRes : Thandle;
p : TNetResourcePtr;
ret : dword;
count : dword;
pcName : string;
begin
//检查是否给出工作组名字
if length(groupName)<1 then
begin
getPcList := false;
exit;
end;

//设置 p
new(p);
p^.dwScope := RESOURCE_GLOBALNET;
p^.dwType := RESOURCETYPE_ANY;
p^.dwUsage := RESOURCEUSAGE_CONTAINER;
p^.lpRemoteName := pchar(groupName);

//打开列举
ret := WNetOpenEnum(RESOURCE_GLOBALNET,RESOURCETYPE_ANY,RESOURCEUSAGE_CONTAINER,@(p^),hRes);
if ret<>NO_ERROR then
begin
getPcList := false;
dispose(p);
exit;
end;

//开始列举计算机名字
count := $ffffffff;
bufSize := 4096;
getMem(buf,bufSize);
ret := WNetEnumResource(hRes,count,buf,bufSize);
if (ret<>NO_ERROR) or (count<1) then
begin
freeMem(buf);
WNetCloseEnum(hRes);
dispose(p);
getPcList := false;
exit;
end;

//获取计算机列表
p := TNetResourcePtr(buf);
list.Clear;
for i:=0 to count-1 do
begin
pcName := p^.lpRemoteName;
list.add(copy(pcName,3,length(pcName)-2));
inc(p);
end;

freeMem(buf);
WnetCloseEnum(hRes);
//dispose(p); 这里出问题,所以注释掉了 :(
getPcList := true;

end;

function GetIP(const pcName:string) : string;
var
WSAData: TWSAData;
HostEnt: PHostEnt;
begin
HostEnt := nil;
WSAStartup(2, WSAData);
HostEnt := gethostbyname(PChar(pcName));
if HostEnt <> nil then
begin
with HostEnt^ do
GetIP:= Format('%d.%d.%d.%d', [Byte(h_addr^[0]), Byte(h_addr^[1]), Byte(h_addr^[2]),Byte(h_addr^[3])]);
end
else
GetIP := '';
WSACleanup;
end;

end.

==========================================
...全文
534 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
liushikui 2001-09-29
  • 打赏
  • 举报
回复
to hellion(恶人) :
你说的是,其实这里应该用递归的,直到WNetEnumResource返回ERROR_NO_MORE_ITEMS为止。
依我的用法,局域网规模小尚可,太大了就只能取得前几条了。

我是delphi初学者,才三个星期,无pascal基础,希望跟各位爱好delphi的朋友多学习学习。
qq:55186917,附加信息“delphi”就行了。
hellion 2001-09-26
  • 打赏
  • 举报
回复
我大概看了看,觉得应该有以下问题:
GetGroupList中以下一段去掉
//获取工作组列表
count := $ffffffff;
bufSize := 4096;
GetMem(buf,bufSize);

GetPcList:
dispose(p); // add

//获取计算机列表
p := TNetResourcePtr(buf);

wNetEnumResource中传入的buff是否有不够的可能,应该对返回的buffsize加以判断
kevin_gao 2001-09-26
  • 打赏
  • 举报
回复
好东东!
alec_ma 2001-09-26
  • 打赏
  • 举报
回复
gz
genedna 2001-09-26
  • 打赏
  • 举报
回复
如何在程序中动态取得Win95/98的网络邻居中的工作组及计算机名

[本文不能保证绝对正确, 仅供参考]

如何在程序中动态取得Win95/98的网络邻居中的工作组及计算机名?可参考下面代码,或许有所帮助:

procedure GetDomainList(TV:TTreeView);
var
a : Integer;
ErrCode : Integer;
NetRes : Array[0..1023] of TNetResource;
EnumHandle : THandle;
EnumEntries : DWord;
BufferSize : DWord;
s : string;
itm : TTreeNode;
begin
{ Start here }
try
With NetRes[0] do begin
dwScope :=RESOURCE_GLOBALNET;
dwType :=RESOURCETYPE_ANY;
dwDisplayType :=RESOURCEDISPLAYTYPE_DOMAIN;
dwUsage :=RESOURCEUSAGE_CONTAINER;
lpLocalName :=NIL;
lpRemoteName :=NIL;
lpComment :=NIL;
lpProvider :=NIL;
end;
{ get net root }
ErrCode:=WNetOpenEnum(
RESOURCE_GLOBALNET,
RESOURCETYPE_ANY,
RESOURCEUSAGE_CONTAINER,
@NetRes[0],
EnumHandle
);
If ErrCode=NO_ERROR then begin
EnumEntries:=1;
BufferSize:=SizeOf(NetRes);
ErrCode:=WNetEnumResource(
EnumHandle,
EnumEntries,
@NetRes[0],
BufferSize
);
WNetCloseEnum(EnumHandle);
ErrCode:=WNetOpenEnum(
RESOURCE_GLOBALNET,
RESOURCETYPE_ANY,
RESOURCEUSAGE_CONTAINER,
@NetRes[0],
EnumHandle
);
EnumEntries:=1024;
BufferSize:=SizeOf(NetRes);
ErrCode:=WNetEnumResource(
EnumHandle,
EnumEntries,
@NetRes[0],
BufferSize
);
IF ErrCode=No_Error then with TV do try
a:=0;
Items.BeginUpDate;
Items.Clear;
Itm:=Items.Add(TV.Selected,string(NetRes[0].lpProvider));
Itm.ImageIndex:=0;
Itm.SelectedIndex:=0;

{ get domains }


下面的一个单元定义了一个组件. TNetworkBrowser, 可以枚举hierachical树上所有
的网络资源. 实际上浏览是要花费很长时间的,这您可以通过在WINDOWS资源管理器
中打开"整个网络" 来比较一下. 如果你设置SCOPE属性 为nsContext , 你就可以看到
和网络邻居中一样的机器列表.

unit NetBrwsr;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
TNetScope = (nsConnected, nsGlobal, nsRemembered, nsContext);
TNetResourceType = (nrAny, nrDisk, nrPrint);
TNetDisplay = (ndDomain, ndGeneric, ndServer, ndShare, ndFile, ndGroup,
ndNetwork, ndRoot, ndShareAdmin, ndDirectory, ndTree, ndNDSContainer);
TNetUsage = set of (nuConnectable, nuContainer);

TNetworkItems = class;

TNetworkItem = class
private
FScope: TNetScope;
FResourceType: TNetResourceType;
FDisplay: TNetDisplay;
FUsage: TNetUsage;
FLocalName: string;
FRemoteName: string;
FComment: string;
FProvider: string;
FSubItems: TNetworkItems;
public
constructor Create;
destructor Destroy; override;
property Scope: TNetScope read FScope;
property ResourceType: TNetResourceType read FResourceType;
property Display: TNetDisplay read FDisplay;
property Usage: TNetUsage read FUsage;
property LocalName: string read FLocalName;
property RemoteName: string read FRemoteName;
property Comment: string read FComment;
property Provider: string read FProvider;
property SubItems: TNetworkItems read FSubItems;
end;

TNetworkItems = class
private
FList: TList;
procedure SetItem(Index: Integer; Value: TNetworkItem);
function GetItem(Index: Integer): TNetworkItem;
function GetCount: Integer;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure Add(Item: TNetworkItem);
procedure Delete(Index: Integer);
property Items[Index: Integer]: TNetworkItem read GetItem write
SetItem; default;
property Count: Integer read GetCount;
end;

TNetworkBrowser = class(TComponent)
private
FItems: TNetworkItems;
FScope: TNetScope;
FResourceType: TNetResourceType;
FUsage: TNetUsage;
FActive: Boolean;
procedure Refresh;
procedure SetActive(Value: Boolean);
procedure SetScope(Value: TNetScope);
procedure SetResourceType(Value: TNetResourceType);
procedure SetUsage(Value: TNetUsage);
procedure EnumerateNet(NetItems: TNetworkItems; lpnr: PNetResource);
protected
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Open;
procedure Close;
property Items: TNetworkItems read FItems;
published
property Scope: TNetScope read FScope write SetScope default nsGlobal;
property ResourceType: TNetResourceType read FResourceType
write SetResourceType default nrAny;
property Usage: TNetUsage read FUsage write SetUsage default [];
property Active: Boolean read FActive write SetActive default False;
end;

implementation

type
PNetResourceArray = ^TNetResourceArray;
TNetResourceArray = array[0..0] of TNetResource;

{ TNetworkItem }

constructor TNetworkItem.Create;
begin
inherited;
FSubItems := TNetworkItems.Create;
end;

destructor TNetworkItem.Destroy;
begin
if FSubItems <> nil then
FSubItems.Free;
inherited;
end;

{ TNetworkItems }

constructor TNetworkItems.Create;
begin
inherited;
FList := TList.Create;
end;

destructor TNetworkItems.Destroy;
begin
Clear;
if FList <> nil then
FList.Free;
inherited;
end;

procedure TNetworkItems.SetItem(Index: Integer; Value: TNetworkItem);
begin
if (FList.Items[Index] <> nil) and (FList.Items[Index] <> Value) then
TNetworkItem(FList.Items[Index]).Free;
FList.Items[Index] := Value;
end;

function TNetworkItems.GetItem(Index: Integer): TNetworkItem;
begin
Result := TNetworkItem(FList.Items[Index]);
end;

procedure TNetworkItems.Clear;
begin
while Count > 0 do
Delete(0);
end;

procedure TNetworkItems.Add(Item: TNetworkItem);
begin
FList.Add(Item);
end;

procedure TNetworkItems.Delete(Index: Integer);
begin
if FList.Items[Index] <> nil then
TNetworkItem(FList.Items[Index]).Free;
FList.Delete(Index);
end;

function TNetworkItems.GetCount: Integer;
begin
if FList <> nil then
Result := FList.Count
else
Result := 0;
end;

{ TNetworkBrowser }

constructor TNetworkBrowser.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FItems := TNetworkItems.Create;
FScope := nsGlobal;
FResourceType := nrAny;
FUsage := [];
end;

destructor TNetworkBrowser.Destroy;
begin
if FItems <> nil then
FItems.Free;
inherited;
end;

procedure TNetworkBrowser.EnumerateNet(NetItems: TNetworkItems; lpnr:
PNetResource);
var
dwResult, dwResultEnum: Integer;
hEnum: THandle;
cbBuffer, cEntries, i: Integer;
nrArray: PNetResourceArray;
NewItem: TNetworkItem;
dwScope, dwType, dwUsage: Integer;
begin
cbBuffer := 16384;
cEntries := $FFFFFFFF;

case FScope of
nsConnected: dwScope := RESOURCE_CONNECTED;
nsGlobal: dwScope := RESOURCE_GLOBALNET;
nsRemembered: dwScope := RESOURCE_REMEMBERED;
nsContext: dwScope := RESOURCE_CONTEXT;
else
dwScope := RESOURCE_GLOBALNET;
end;
case FResourceType of
nrAny: dwType := RESOURCETYPE_ANY;
nrDisk: dwType := RESOURCETYPE_DISK;
nrPrint: dwType := RESOURCETYPE_PRINT;
else
dwType := RESOURCETYPE_ANY;
end;
dwUsage := 0;
if nuConnectable in FUsage then
dwUsage := dwUsage or RESOURCEUSAGE_CONNECTABLE;
if nuContainer in FUsage then
dwUsage := dwUsage or RESOURCEUSAGE_CONTAINER;

dwResult := WNetOpenEnum(dwScope, dwType, dwUsage, lpnr, hEnum);
if dwResult <> NO_ERROR then Exit;

GetMem(nrArray, cbBuffer);
repeat
dwResultEnum := WNetEnumResource(hEnum, cEntries, nrArray, cbBuffer);
if dwResultEnum = NO_ERROR then
for i := 0 to cEntries-1 do
begin
NewItem := TNetworkItem.Create;
case nrArray[i].dwScope of
RESOURCE_CONNECTED: NewItem.FScope := nsConnected;
RESOURCE_GLOBALNET: NewItem.FScope := nsGlobal;
RESOURCE_REMEMBERED: NewItem.FScope := nsRemembered;
RESOURCE_CONTEXT: NewItem.FScope := nsContext;
else
NewItem.FScope := nsGlobal;
end;
case nrArray[i].dwType of
RESOURCETYPE_ANY: NewItem.FResourceType := nrAny;
RESOURCETYPE_DISK: NewItem.FResourceType := nrDisk;
RESOURCETYPE_PRINT: NewItem.FResourceType := nrPrint;
else
NewItem.FResourceType := nrAny;
end;
case nrArray[i].dwDisplayType of
RESOURCEDISPLAYTYPE_GENERIC: NewItem.FDisplay := ndGeneric;
RESOURCEDISPLAYTYPE_DOMAIN: NewItem.FDisplay := ndDomain;
RESOURCEDISPLAYTYPE_SERVER: NewItem.FDisplay := ndServer;
RESOURCEDISPLAYTYPE_SHARE: NewItem.FDisplay := ndShare;
RESOURCEDISPLAYTYPE_FILE: NewItem.FDisplay := ndFile;
RESOURCEDISPLAYTYPE_GROUP: NewItem.FDisplay := ndGroup;
RESOURCEDISPLAYTYPE_NETWORK: NewItem.FDisplay := ndNetwork;
RESOURCEDISPLAYTYPE_ROOT: NewItem.FDisplay := ndRoot;
RESOURCEDISPLAYTYPE_SHAREADMIN: NewItem.FDisplay :=
ndShareAdmin;
RESOURCEDISPLAYTYPE_DIRECTORY: NewItem.FDisplay :=
ndDirectory;
RESOURCEDISPLAYTYPE_TREE: NewItem.FDisplay := ndTree;
RESOURCEDISPLAYTYPE_NDSCONTAINER: NewItem.FDisplay :=
ndNDSContainer;
else
NewItem.FDisplay := ndGeneric;
end;
NewItem.FUsage := [];
if nrArray[i].dwUsage and RESOURCEUSAGE_CONNECTABLE <> 0 then
Include(NewItem.FUsage, nuConnectable);
if nrArray[i].dwUsage and RESOURCEUSAGE_CONTAINER <> 0 then
Include(NewItem.FUsage, nuContainer);
NewItem.FLocalName := StrPas(nrArray[i].lpLocalName);
NewItem.FRemoteName := StrPas(nrArray[i].lpRemoteName);
NewItem.FComment := StrPas(nrArray[i].lpComment);
NewItem.FProvider := StrPas(nrArray[i].lpProvider);
NetItems.Add(NewItem);
// if container, call recursively
if (nuContainer in NewItem.FUsage) and (FScope <> nsContext) then
EnumerateNet(NewItem.FSubItems, @nrArray[i])
end;
until dwResultEnum = ERROR_NO_MORE_ITEMS;

FreeMem(nrArray);
WNetCloseEnum(hEnum);
end;

procedure TNetworkBrowser.Refresh;
begin
FItems.Clear;
if FActive then
EnumerateNet(FItems, nil);
end;

procedure TNetworkBrowser.SetActive(Value: Boolean);
begin
if Value <> FActive then
begin
FActive := Value;
Refresh;
end;
end;

procedure TNetworkBrowser.SetScope(Value: TNetScope);
begin
if Value <> FScope then
begin
FScope := Value;
Refresh;
end;
end;

procedure TNetworkBrowser.SetResourceType(Value: TNetResourceType);
begin
if Value <> FResourceType then
begin
FResourceType := Value;
Refresh;
end;
end;

procedure TNetworkBrowser.SetUsage(Value: TNetUsage);
begin
if Value <> FUsage then
begin
FUsage := Value;
Refresh;
end;
end;

procedure TNetworkBrowser.Open;
begin
Active := True;
end;

procedure TNetworkBrowser.Close;
begin
Active := False;
end;

end.



movingboy 2001-09-26
  • 打赏
  • 举报
回复
In my project, I set buf's size to 8*SizeOf(TNetResource)
liushikui 2001-09-25
  • 打赏
  • 举报
回复
各位都来发言呀,不要太保守哦,呵呵~~

5,402

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧