Windows NT使用技巧、編程原理及程序示例
[歡迎交流]
[本文最后更新:2000-09]
-
利用Net User命令和Cacls命令做用戶管理
-
利用At命令做日程管理
-
利用用戶登錄腳本實現開機提示
-
利用Net Session命令實現登錄用戶統計
-
Windows NT局域網管理API函數庫(NETAPI)簡介
-
怎樣添加、刪除、配置用戶?
-
怎樣修改用戶口令?
-
怎樣編程實現用戶的注銷和關機?
-
怎樣獲取所有登錄用戶列表?
-
怎樣向用戶或計算機發送消息?
-
怎樣實現遠程關閉計算機?
-
UNICODE字符串和普通ASCII字符串怎樣轉換?
-
如何獲取系統錯誤信息?
-
什么是Service(服務)程序?
-
如何使自己的應用程序成為Service?
-
如何編制Service程序?
利用Net命令和Cacls命令定制用戶管理
(
返回主題選擇
)[歡迎交流]
NT的“域用戶管理器”是用來管理域、成員服務器和工作站安全性的工具。使用“域用戶管理器”可以:選定要管理的域或計算機;創建和管理用戶帳號;
創建和管理組;管理安全性規則。通常網絡管理員是用“域用戶管理器”來完成。但是,“域用戶管理器”每次只能配置一個用戶,雖然NT利用組的概念實施用戶
管理,事實上對組內用戶的配置還是單獨進行的。
Net Group和Net User 命令行實用程序是NT下的兩個管理域用戶的重要程序。它可以完成NT域用戶管理器所能完成的所有功能,其區別僅在于不具備友好的界面。Net
Group命令行實用程序用于在Windows NT Server
域中添加、顯示或更改全局組。該命令僅在 Windows
NT Server 域中可用。Net User命令行實用程序用于添加或更改用戶帳號或顯示用戶帳號信息。靈活應用這兩個程序,可以完成許多“域用戶管理器”不能完成的功能,例如:建立批量用戶,詳細設置每個用戶目錄的權限等等。
通常在建立用戶組的時候,需要建立一個和組名相匹配的用戶目錄,并設置此目錄的安全性使得該目錄只能被管理員和該組成員訪問。現在建立一個名為“實驗組A”的用戶組,并為該組設立一個管理員,可以執行下面的批命令:
Net Group 實驗組A /Add /Comment:”建立用戶組實驗” //建立組
Net User Admin_LabA /Add /Comment:”實驗組A管理員” //建立組管理員
Net Group 實驗組A Admin_LabA /Add //將組管理員加入組
再為此組建立一個私有目錄,執行下面的命令:
Md \\ServerName\STUDENT\實驗組A
Cacls \\ServerName\STUDENT\實驗組A /r everyone /e /t
Cacls \\ServerName\STUDENT\實驗組A /g 實驗組A:r /e /t
Cacls \\ServerName\STUDENT\實驗組A /g Administrator:f /e /t
現在建立該組下的一般成員,運行下面的命令:
Net User User001 /Add /Comment:”實驗組A一般用戶”
Net Group 實驗組A User001 /Add
為該用戶建立自己的私有目錄(此目錄將只能由管理員、該組管理員和User001訪問)
Md \\ServerName\STUDENT\實驗組A\User001
Cacls \\ServerName\STUDENT\實驗組A /r 實驗組A:r /e /t
Cacls \\ServerName\STUDENT\實驗組A\User001 /g User001:f /e /t
利用At命令做日程管理
(
返回主題選擇
)[歡迎交流]
作為一個教學實驗室,需要由極少數的管理人員維護批量的計算機。鑒于教學實驗室的工作特性,經常需要管理人員定期地對實驗室中計算機進行硬盤清理、文件復
制的工作。重復性的勞動不僅降低了工作效率,更重要的是,經常由此引入操作失誤。將一些不要求交互輸入的系統維護程序安排到計算機的調度命令中,不僅可以
讓計算機協助完成工作,計算機執行調度命令的可靠性也決不會有任何錯誤和紕漏。故而,將計算機的日程管理條理化,是改變教學實驗室傳統人工管理、將教學實
驗室管理納入現代化的必然。以下將以具體實例說明公用實驗室管理措施在NT調度服務下的實現。
機房定時提示關機并定時強制關機的實現。為了實現自動關機提示并關機,首先要編制NT下的注銷程序和關閉系統程序。可以調用WindowsAPI中的
ExitWindows()和ExitWindowsEx()函數,需要立即強制注銷,只需要在程序中調用ExitWindows(0,0);需要立即強
制關機,只需要在程序中調用ExitWindowsEx(EWX_POWEROFF|
EWX_FORCE)即可(如果需要配置為重新啟動等其他要求,請查閱WindowsAPI中此二函數的具體參數)。假設已經做好注銷程序
ScheduleLogoff.exe和關機程序ScheduleShutdown.exe并將它們拷貝到c:\winnt。運行如下命令:
at \\MyStation 21:55 /every: M,T,W,Th,F,S,Su
c:\winnt\ScheduleLogoff.exe
at \\MyStation 22:00 /every: M,T,W,Th,F,S,Su
c:\winnt\ScheduleShutdown.exe
則在每天的晚9:55自動強制名為MyStation的計算機上的用戶注銷并在5分鐘后自動關閉該計算機。建議在強制用戶注銷之前幾分鐘,給用戶發送關機提示以便用戶有足夠的時間保存文件,可以用net
send命令行程序來完成這一功能。具體使用如下:
at \\MyStation 21:55 /every: M,T,W,Th,F,S,Su “cmd /c net send
請立即保存程序,5分鐘后系統將自動關閉!”
這樣,就可以完全的由計算機來控制整個實驗室所有計算機的自動關機時間,而機房管理人員則可以將主要精力用于實驗輔導而非系統管理。
教學實驗室還經常需要進行硬盤整理(如Scandisk.exe)和硬盤清理(如刪除用戶空間)。同樣也可以將所需執行的功能編制為應用程序并加入系統的
調度命令。如安排每周一早晨進行磁盤整理;每天關機前進行用戶磁盤空間的清理。合理地調度命令安排,將使機房的管理日程化,同時提高有盤工作站的安全系
數。在多媒體實驗室的實際應用中,將用戶管理和日程安排相結合,實現了NT有盤工作站的安全防拷貝。
利用用戶登錄腳本實現開機提示
(
返回主題選擇
)[歡迎交流]
用戶的登錄腳本(登錄腳本存放的路徑是:“%systemroot%\system32\REPL\IMPORT\SCRIPTS”)是在用戶登錄
時候運行的,在此程序中,可以根據需要加入有關的代碼,實現特殊的功能。如果將有關實驗室的介紹和試驗內容放置在網站上,則可以在登錄腳本中訪問這個網站
從而實現開機提示或聯機幫助系統。多媒體通信實驗室目前設置為在登錄腳本中打開Internet
Explorer并連接實驗室主頁,從而實現開機提示和聯機幫助。如果您使用VC來編寫這個登錄腳本,則簡單地調用ShellExecute()函數來打
開網站地址即可。例如:
ShellExecute(NULL,"open","http://192.168.1.20",NULL,NULL,SW_MAXIMIZE);
利用Net Session命令實現登錄用戶統計
(
返回主題選擇
)[歡迎交流]
Net Session是NT下的一個命令行程序。運行它可以列出或斷開本地計算機和與之連接的客戶端的會話。其基本的使用格式為:
net session [\\computername] [/delete]。
其命令參數為:
\\computername 標識要列出或斷開會話的計算機。
/delete 結束與 \\computername
計算機會話并關閉本次會話期間計算機的所有打開文件。如果省略
\\computername
參數,將取消與本地計算機的所有會話。
如果鍵入不帶參數的 net session
則可以顯示所有與本地計算機的會話的信息。
要顯示某個用戶的會話,請在命令中添加
\\computername
參數。單個用戶的顯示還包括用戶所連接到的共享資源列表。當客戶機用戶與服務成功連接時,將記錄該會話。當兩個系統在同一個網絡中,并且服務器接受用戶名
和密碼時,就出現成功會話。客戶機用戶必須先與服務器建立會話,才能使用服務器資源,而且客戶機用戶在建立與服務器的會話之前必須連接到網絡資源。客戶端
和服務器之間只能有一個會話,但可以有許多資源入口點和與資源的連接。要設置在自動斷開某個會話之前暫停的時間,請使用
net config server 命令的 /autodisconnect 選項設置
autodisconnect 特征。自動斷開連接對用戶是透明的,因為當用戶再次使用資源時,Windows
NT 自動重新連接會話。要結束與服務器的會話,使用
/delete 選項與 \\computername。
net session 命令也可以寫為 net sessions或net sess。使用
net session 命令顯示訪問服務器的計算機名和用戶名、它們是否打開文件及每個用戶會話的空閑時間。顯示結果類似于下面的內容:
計算機 用戶名 客戶類型 打開空閑時間
\\BASSETT CHRISDR NT 1 00:00:13
\\SHARONCA Administrator DOS LM 2.1 0 01:05:13
根據這個顯示結果,我們可以得到實時的再線用戶信息。利用重定向功能將顯示的結果送入一個臨時文本(net
session > tmp_sessions.txt),分析該文本格式并由NT計算機名用戶名長度要求可知:計算機名、用戶名和客戶類型均固定占用占用22個字符的長度。故可以從此文本中分離在線計算機和在線用戶的信息,從而實現在線用戶的統計和監控。
Windows NT局域網管理API函數庫(NETAPI)
(
返回主題選擇
)[歡迎交流]
在Windows NT
的系統目錄下,存放有關于局域網管理的動態鏈接庫NetAPI32.DLL。含有一組網絡管理的函數定義。這些函數被分成以下類型:
英文名稱 |
中文解釋 |
Alert functions |
網絡警告函數 |
ApiBuffer functions |
內存管理函數 |
Distributed File System (Dfs) functions |
分布文件系統管理函數 |
File functions |
文件管理函數 |
Group functions |
組管理函數 |
Local Group functions |
本地組管理函數 |
Message functions |
消息管理函數 |
Remote Utility functions |
遠程信息服務函數 |
Replicator functions |
復制服務管理函數 |
Schedule functions |
日程管理函數 |
Server functions |
服務器管理函數 |
Service functions |
服務管理函數 |
Session functions |
會話管理函數 |
Share functions |
共享資源管理函數 |
Statistics functions |
網絡統計函數 |
User functions |
用戶管理函數 |
Workstation and workstation user functions |
工作站及工作站用戶管理函數 |
所有表中列出的函數,囊括了Windows NT所有的網絡管理功能,合理地使用這些函數,可以編制功能強大的Windows
NT網絡管理軟件。例如現在比較流行的一些英文版Windows
NT工具如:RemoteShutdown(遠程關機)、svcmgr(遠程服務管理)、Devicelock(外設權限設置)等軟件全部都是在這些網絡管理函數基礎上實現的。
什么是Service(服務)程序?
(
返回主題選擇
)[歡迎交流]
Service程序和普通的應用程序有一個根本的區別:Service程序可以在無用戶登錄和用戶已經注銷的情況下運行,而應用程序在沒有用戶注銷
的時候是會被終止的。您可以通過控制面板的“服務”項來啟動、暫停和停止一個服務的運行,當然您也可以通過網絡來訪問其他裝有Windows
NT的計算機(當然可能需要安裝特定的程序例如:svcmgr)。
在Windows NT 下,各種Service都存在Service Control Manager Database中,因此我們可以通過對Service Control Manager Database進行操作來實現對Service的編
程。從而用自己的程序來啟動、停止、和暫停一個服務的運行
。(Delphi下的例子:Delphi-Service.pas)
如何使自己的應用程序成為Service?
(
返回主題選擇
)[歡迎交流]
[方法一] 利用工具軟件
(1)在nt的toolkit里有個應用軟件(srvinstw.exe)可以把普通程序設成service
(2)Rehan Nadeem的AppWizard
to Create MFC Based Windows NT Service Projects
[方法二] 直接修改注冊表(推薦)
(1)打開鍵:“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services”
(2)新建一個項名為“<你的服務的名字>”
(3)在它下面建立以下鍵
“DisplayName”,字符串類型,值為“<你希望在控制面板服務項打開的時候能夠看到的服務顯示的名稱>”;
“Description”,字符串類型,值為“<關于服務的簡要說明>”;
“ImagePath”,字符串類型,值為“<你的可執行文件的全路徑>”;
“ObjectName”,字符串類型,值為“<LocalSystem>”;
“ErrorControl”,DWORD類型,值為“0”
“Start”,DWORD類型,值為“0x00000003”
“Type”,DWORD類型,值為“0x00000110”
建議自己寫一個MyService.REG文件直接運行即可,內容如下:
REGEDIT4
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<你的服務的名字>]
"DisplayName"="<你希望在控制面板服務項打開的時候能夠看到的服務顯示的名稱>"
"Description"="<關于服務的簡要說明>"
"ImagePath"="<你的可執行文件的全路徑>"
"ObjectName”,字符串類型,值為“<LocalSystem>”;
"ErrorControl"=dword:00000000
"Start"=dword:00000003
"Type"=dword:00000110
如何編制Service程序?
(
返回主題選擇
)[歡迎交流]
[編制Service程序的例子]
(1)用Delphi制作。“New”一個“Service Application”即可
(2)用VC制作。這里提供兩個例子:ntservice_sample_project.zip(推薦)、cntservice_src.zip
[Windows98下使一個應用程序成為一個Service](只適用于Windows98)
在自己的應用程序的開始部分加入以下代碼:
HINSTANCE hDllInst = LoadLibrary("KERNEL32.DLL");
//Windows2000下的kernel.dll中沒有RegisterServiceProcess函數
if(hDllInst)
{
typedef DWORD (WINAPI *MYFUNC)(DWORD,DWORD);
MYFUNC RegisterServiceProcessAlias = NULL;
RegisterServiceProcessAlias = (MYFUNC)GetProcAddress(hDllInst,
"RegisterServiceProcess");
if(RegisterServiceProcessAlias)
{
RegisterServiceProcessAlias(GetCurrentProcessId(),1);
}
FreeLibrary(hDllInst);
}
用戶的注銷和關機實現
(
返回主題選擇
)[歡迎交流]
和Windows 9x下不同,如果編程實現關機和用戶注銷,必須先取得有關的權限。
需要利用LookupPrivilegeValue()函數和AdjustTokenPrivileges()函數來獲取關閉系統有關的權限“SE_SHUTDOWN_NAME”;然后再調用關閉系統函數ExitWindows()。上述函數使用示例請參照ShutDown.Cpp文件中格式。
如果您需要從網絡關閉系統,請參照怎樣實現遠程關閉計算機?。
如果在您選擇了ExitWindows()函數的參數以后仍然不能關閉計算機的電源,請參照怎樣使Windows NT4.0關閉系統的時候關閉電源?
所有登錄用戶列表獲取
(
返回主題選擇
)[歡迎交流]
獲取用戶列表過程為:獲取當前NT局域網上的所有工作站和服務器信息(利用函數NetServerEnum());獲取每一臺工作站和服務器上的用戶信息(利用函數NetWkstaUserEnum())并加入自己的列表。上述函數調用格式請參照KeeperDlg.cpp文件中的OnGetWksList()函數和GetWksLogonUser()函數。
該文件中還用了NETAPI函數組的內存分配函數(NetApiBufferAllocate()
和NetApiBufferFree()),本人在使用過程中發現釋放內存時調用NetApiBufferFree()函數經常出錯,如果您有什么建議請與本人聯系。
UNICODE字符串和普通ASCII字符串的轉換
(
返回主題選擇
)[歡迎交流]
在編寫Windows
NT應用程序的時候,經常會遇到一個問題:函數的參數是“LPWSTR”類型,即UNICODE字符串,而我們平常的字符串是ASCII字符串。所以編寫
一個通用的“LPWSTR”類型字符串和“LPSTR”類型字符串的轉換程序是非常必要的。可以參考KeeperDlg.cpp文件中的ASCIIToUnicode(LPSTR
SourceStr)函數和UnicodeToASCII(LPWSTR SourceStr)函數。
向用戶和計算機發送消息
(
返回主題選擇
)[歡迎交流]
利用NETAPI中的NetMessageNameAdd()函數、NetMessageBufferSend()函數和NetMessageNameDel()函數實現,具體調用格式請參照KeeperDlg.cpp文件中的NetSendMsg(LPSTR
WksName)函數。
遠程關機的實現
(
返回主題選擇
)[歡迎交流]
用ExitWindow()和exitWindowEx()函數只能實現本地計算機的用戶注銷與系統關閉(注意:此時需要獲取有關的操作權限,具體參照怎樣編程實現用戶的注銷和關機?),如果需要通過網絡遠程關機,則應該調用InitiateSystemShutdown()函數,具體調用格式如下:
InitiateSystemShutdown((LPTSTR)WksName,
"系統1分鐘將會自動關閉,請保存文件到服務器!",
60,
TRUE,
FALSE
);
用戶添加、刪除和配置
(
返回主題選擇
)[歡迎交流]
NETAPI函數庫中函數引用的數據類型在VC的相應頭文件中有定義。如:
USER_INFO_0 、USER_INFO_1 、USER_INFO_2
等是有關用戶管理函數所用到的部分結構體。詳細的信息可以閱讀Windows
API函數庫介紹。下面給出幾個簡單的用戶管理函數的應用。
1 添加新用戶的實現
USER_INFO_1 user_info;
DWORD parm_err = 0;
user_info.usri1_name = L"SampleUser";
user_info.usri1_password = L"123456";
user_info.usri1_priv = USER_PRIV_USER;
user_info.usri1_comment = L"Sample User";
user_info.usri1_flags = UF_SCRIPT;
result = NetUserAdd( NULL,1,(LPBYTE)&user_info, &parm_err
);
if(result != NERR_Success) ErrorMsg("建立用戶失敗!",result);
2 刪除用戶的實現
LPWSTR username = L"bb";
LPWSTR servername = L"mmc";
result = NetUserDel(servername,username);
if(result != NERR_Success) ErrorMsg("用戶刪除失敗!",result);
3 配置現有用戶
USER_INFO_1 user_info;
DWORD parm_err = 0;
user_info.usri1_name = L"SampleUser";
user_info.usri1_password = L"123456";
user_info.usri1_priv = USER_PRIV_USER;
user_info.usri1_comment = L"Sample User";
user_info.usri1_flags = UF_SCRIPT;
result = NetUserSetInfo(lpszPrimaryDC, lpszUser, 1,
(LPBYTE)&user_info, &parm_err );
if(result != NERR_Success) ErrorMsg("配置用戶失敗!",result);
修改用戶口令的實現
(
返回主題選擇
)[歡迎交流]
調用函數NetUserChangePassword(),具體格式參照以下內容:
OnChangePassword()
{
LPWSTR wUserName = L"aa";
LPWSTR wComputerName = L"mmc";
LPWSTR wOldPassword = L"aaabbb";
LPWSTR wNewPassword = L"123456";
NET_API_STATUS nas;
nas = NetGetDCName(NULL,
L"mmc_lab",
(LPBYTE *)&wComputerName
);
if(nas != NERR_Success) {
ErrorMsg("主控域查找失敗!",nas);
}
nas = NetUserChangePassword(
wComputerName,
wUserName,
wOldPassword,
wNewPassword
);
if(nas == NERR_InvalidComputer){
MessageBox(NULL, "Invalid Computer Error!", MB_OK);
}
if(nas == NERR_UserNotFound){
MessageBox(NULL, "User not found Error!", MB_OK);
}
if(nas == ERROR_ACCESS_DENIED){
MessageBox(NULL, "Access deny Error!", MB_OK);
}
if(nas == NERR_NotPrimary){
MessageBox(NULL, "NOT primary Error!", MB_OK);
}
if(nas == NERR_PasswordTooShort){
MessageBox(NULL, "PasswordTooShort Error!", MB_OK);
}
if(nas != NERR_Success) {
ErrorMsg("密碼更改失敗!",nas);
// DisplayErrorText( nas );
}
else{
MessageBox("OK!",NULL,MB_OK);
}
}
獲取系統錯誤信息
(
返回主題選擇
)[歡迎交流]
在函數執行完畢的時候,調用ErrorMsg("XX函數執行錯誤信息",GetLastError());
void ErrorMsg(CString Msg,DWORD dwLastError)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwLastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
MessageBox((LPCTSTR )lpMsgBuf, Msg, MB_OK);
LocalFree( lpMsgBuf );
}