在WINDOWS95&WINDOWS98下如何关闭网络连接(100分)

  • 主题发起人 主题发起人 飘叶
  • 开始时间 开始时间

飘叶

Unregistered / Unconfirmed
GUEST, unregistred user!
各位高手,谁能把下面的源程序帮我用DELPHI来完成
================================================
在WINDOWS95&WINDOWS98下如何关闭网络连接

黄 飞 <98/5/20>

一.问题提出:

每当你通过WINDOWS95或WINDOWS98访问"网上邻居"时,系统自动的建立了两
台机器之间的网络连接关系,但是在访问结束后,并不自动的断开网络连接,
所以有时我们关闭WINDOWS系统时,会弹出一个对话框,询问是否关闭网络连
接,在回答"YES"后,才真正开始关闭计算机.
程序员编制系统关闭程序时,就需要考虑这种情况,虽然SDK提供了关机的API:
ExitWindowsEx()和ExitWindows(),但实际应用中我发现,在指定FORCE关机时
在特定情况下会出问题.所以,必须想办法首先断开网络连接.

二.编程接口:

WINDOWS95及WINDOWS98提供的这方面的网络编程接口在SVRAPI.DLL中,利用它
我们可以列举出当前网络连接状态,控制或删除网络连接.WINDOWS附件中的
NETWATCH.EXE工具就是这样实现的.
也许您会问,NetAPI的详细说明在开发工具的SDK文档中很详细了,没有必要在
此演示.但是,在查寻了很多资料后,我不得不说:MSDN中有关NetAPI的部分说
明是错误的,至少是不完整而且含混不清的,可以说,依靠这些文档,你不能实
现全部的功能!下面的代码是本人自己分析得来,使用后,您会发现正确的应用
和文档说明有多么大的差距.

三.API声明:

关闭网络连接的实现方法分两步: 枚举出当前所有的网络连接状况; 依次
断开枚举出的网络连接.

1.枚举出当前所有的网络连接状况:
依照开发帮助文档,这个API是这样的:
NET_API_STATUS NetSessionEnum(
LPWSTR servername,
LPWSTR UncClientName,
LPWSTR username,
DWORD level,
LPBYTE *bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);

但是,实际情况是,在WINDOWS95和WINDOWS98平台下,
这样调用根本就无法连接上库文件.真正的API声明应该是:
DWORD NetSessionEnum( LPSTR,
DWORD,
LPBYTE,
DWORD,
LPDWORD,
LPDWORD )
参数1: NULL表示枚举本机的网络连接
参数2: 不详.在枚举中是常量0x32.
参数3: 存放信息的缓冲区指针
参数4: 缓冲区长度
参数5: 指向返回连接个数
参数6: 指向总共连接个数
可见,参数个数完全不同,另外参数意义也发生了变化.

2.依次断开枚举出的网络连接:
还算幸运的是,断开网络连接的API声明是正确的:
NET_API_STATUS NetSessionDel(
LPWSTR servername,
LPWSTR UncClientName,
LPWSTR username );
不过要注意的是,第2个和第3个参数的内容需要
从枚举得到的缓冲区中去取.具体方法参见程序.

四.源代码:

以下是实现断开网络连接的子程序,你可以方便的把它们加入到自己的项目中
去,而不用和我一样浪费时间去研究到底怎样实现网络枚举了.

注:由于本程序只实际用到了一个SVRAPI.DLL中的函数声明,简便期间,我没有
用原有的头文件,自己定义一下就可以了.

///////////////////////////////////////////////////////////////////
// File: NetClose.H
// Version: 1.01

#define NETBUFF_SIZE 0x208

#define NetSessionEnum_PROFILE ( DWORD (__stdcall *) ( LPSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD ) )
#define NetSessionDel_PROFILE ( DWORD (__stdcall *) ( LPSTR, LPSTR, DWORD ) )
///////////////////////////////////////////////////////////////////
// File: NetClose.CPP
// Version: 1.01
///////////////////////////////////////////////////////////////////
// Define: BOOL NetCloseAll( VOID )
// Parameters: None
// Return: TRUE or FALSE
//
// Author: Mr.Huang fei
// Time: 5/7/1998
// Note: Can only be used on Windows95 & Windows98
// Remark: Close all network connections
///////////////////////////////////////////////////////////////////
BOOL NetCloseAll( VOID )
{
BYTE byBuff[NETBUFF_SIZE];
DWORD dwNetRet = 0;;
DWORD i = 0;
DWORD dwEntries = 0;
DWORD dwTotalEntries = 0;
LPSTR szClient = NULL;
DWORD dwUserName = 0;
BOOL bRet = FALSE;
LPBYTE lpbyBuff = (LPBYTE)byBuff;

DWORD (__stdcall * hookNetSessionEnum)( LPSTR, DWORD, LPBYTE, DWORD, LPDWORD, LPDWORD );
DWORD (__stdcall * hookNetSessionDel)( LPSTR, LPSTR, DWORD );

HINSTANCE hMod = LoadLibrary( "SVRAPI.DLL" );
if( hMod != NULL )
{
// Get the address of function
hookNetSessionEnum = NetSessionEnum_PROFILE
GetProcAddress
( hMod, TEXT("NetSessionEnum") );
hookNetSessionDel = NetSessionDel_PROFILE
GetProcAddress
( hMod, TEXT("NetSessionDel") );

if( ( hookNetSessionDel != NULL ) &&
( hookNetSessionEnum != NULL ) )
{
dwNetRet = hookNetSessionEnum( NULL,
0x32, byBuff,
NETBUFF_SIZE, &dwEntries,
&dwTotalEntries );
if( dwNetRet == 0 )
{
bRet = TRUE;
for( i=0; i < dwTotalEntries; i++ )
{
szClient = (LPSTR)(((DWORD *)
lpbyBuff)[0]);
dwUserName = ((DWORD *)lpbyBuff)[2];
dwNetRet = hookNetSessionDel( NULL,
szClient, dwUserName );
if( dwNetRet != 0 )
{
bRet = FALSE;
break;
}
lpbyBuff += 26;
}
} // NetSessionEnum(...)
else
bRet = FALSE;
} // GetProcAddress(...)
else
bRet = FALSE;

FreeLibrary( hMod );
} // LoadLibrary(...)
return bRet;
}

五.总结:

以上是开发过程中的一点经验,希望对大家有所帮助,有不对的地方请谅解并
指出.另外,众所周知Microsoft的开发文档有相当一部分是未公开的,这些未
公开信息有时会给我们造成很大的困难,在此希望有类似体验的程序开发者
把自己的经验写出来,让后来者少走一些弯路.
 
如下(一部分原型是从 JEDI API Library 中拷过来的):
const
MaxNetArrayItems = 512;

type
TSessionInfo50 = packed record
sesi50_cname: PChar; //remote computer name (connection id in Netware)
sesi50_username: PChar;
sesi50_key: DWORD; // used to delete session (not used in Netware)
sesi50_num_conns: Word;
sesi50_num_opens: Word; //not available in Netware
sesi50_time: DWORD;
sesi50_idle_time: DWORD; //not available in Netware
sesi50_protocol: Char;
padl: Char;
end;
// *** NetSessionEnum
// *
// * API_FUNCTION NetSessionEnum( servername,
// * level,
// * buf,
// * buflen,
// * entriesread,
// * totalentries )
// * ENTRY
// *
// * servername; asciiz remote srv name, NULL if local
// * level; level of detail requested; (50 for Win95 peer servers)
// * buf; for returned entries
// * buflen; size of buffer on call;
// * entriesread; # of entries supplied on return
// * totalentries; total # of entries available

TNetSessionEnum = function (const pszServer: PChar; sLevel: SmallInt;
pbBuffer: Pointer; cbBuffer: Word; var pcEntriesRead: Word;
var pcTotalAvail: Word): DWORD; stdcall;

// *** NetSessionDel (Admin only)
// *
// *
// * API_FUNCTION NetSessionDel( servername, clientname, reserved )
// *
// * ENTRY
// *
// * servername; asciz remote srv name, NULL if local
// * clientname; asciz remote computer name (returned by NetSessionEnum)
// * of session being deleted
// * In the case of a Win95 NWSERVER, the clientname should be the
// * ascii connection number
// * reserved; session key returned by NetSessionEnum

TNetSessionDel = function (const pszServer: PChar; const pszClientName: PChar;
sReserved: SmallInt): DWORD; stdcall;

function NetCloseAll: boolean;
var
SessionInfo: array[0..MaxNetArrayItems] of TSessionInfo50;
EntriesRead, TotalAvail: Word;
I: Integer;
NetSessionEnum: TNetSessionEnum;
NetSessionDel: TNetSessionDel;
LibHandle: THandle;
begin
Result := False;
LibHandle := LoadLibrary('SVRAPI.DLL');
if LibHandle <> 0 then
begin
try
@NetSessionEnum := GetProcAddress(LibHandle, 'NetSessionEnum');
@NetSessionDel := GetProcAddress(LibHandle, 'NetSessionDel');
if (@NetSessionEnum <> nil) and (@NetSessionDel <> nil) then
if NetSessionEnum(nil, 50, @SessionInfo, Sizeof(SessionInfo), EntriesRead, TotalAvail) = 0 then
begin
Result := True;
for I := 0 to EntriesRead - 1 do
with SessionInfo do
if NetSessionDel(nil, sesi50_cname, sesi50_Key) <> 0 then
begin
Result := False;
break;
end;
end;
finally
FreeLibrary(LibHandle);
end;
end;

end;
 
借此机会
向大家郑重推荐Jedi这个组织
Jedi的JCL Lib很好,可以节省许多开发时间
 
还是不行
那里可找到JCL Lib?
 
visit @ url:
http://www.delphi-jedi.org/
 
怎么不行?编译应该可以通过的。
可能是 NetSessionDel(nil, sesi50_cname, sesi50_Key) 中的 sesi50_key 应改为
DWORD(sesi50_username),按你给出的 C 程序原来的含义是用后者作参数的,而我看了
JEDI API Library 中带的 demo 调用时却用的前者作参数,就自作主张帮你改过来了。
正好我的 Win98 有毛病,别的机器都看不到我共享的文件夹,就没具体测试了。
你改改再试试看。
JEDI 组织网站:www.delphi-jedi.org,
API Library 下载页:http://www.delphi-jedi.org/Jedi:APILIBRARY:23714
你要用的功能在 LanManager 那个zip中,svrapi.pas,具体使用看带的 NetWatch95
Demo。
 
我就是编译通不过,能把你的源程序打包寄给我吗?
piaoyes@163.net
谢谢
 
飘叶:
你好,我刚给你发过去了,一个空壳一般的程序,:) 请查收。
 
谢谢bbkxjy,我给你加分了
 

Similar threads

后退
顶部