Delphi深度探索:活動目錄開發一
活動目錄是 Windows NT 4.0 和 Windows 2000 使用的目錄服務。要想使用活動目錄服務,需要調用 ADSI( 活動目錄服務接口 ) 。 ADSI 是一組以 COM 接口的形式提供目錄服務的,程序員可以通過 ADSI 存取四種網絡目錄結構: WinNT (Microsoft SAM 數據庫 ) 、 LDAP ( 輕量目錄存取協議 ) 、 NDS (NetWare 目錄服務 ) 和 NWCOMPAT (Novell NetWare 3.x) 。
ADSI 可以使 Windows NT 管理員的工作變得輕松。 ADSI 支持管理員執行一些一般的管理任務,比如添加新用戶、管理打印機、安全設定和控制 NT 域。因為 ADSI 使用 COM 接口,任何支持 COM 的編程語言像 Delphi 、 BCB 、 VB 、 VC 等都可以調用 ADSI 。
圖 1.111
活動目錄運行在 Windows NT 4.0 和 Windows 2000 上??蛻舳顺绦蚩梢赃\行在 Windows 95 、 Windows 98 、 Windows NT 4.0 和 Windows 2000 上。為了使用 ADSI ,必須安裝 ADSI COM 接口。 ADSI 2.5 SDK 可以從 Microsoft ADSI 網址 http://www.microsoft.com/adsi 下載 。 SDK 包括文檔、在線幫助和很多例子,不過不幸的是這些例子都是針對 VB 和 VC 的,這里我們將演示如何使用 Delphi 調用 ADSI 。
程序演示
圖 1.111 所示的程序演示了如何調用 WinNT provider 提供的功能。演示程序用來連接到一個域,一旦連接到域,程序將會列出在 PDC 上找到的 NT 的用戶和組以及域中的計算機。同時這個程序還演示了如何察看域中計算機上的服務和察看、添加、刪除 NT 組中的用戶。
使用 ADSI 控制 Windows NT/2000
ADSI 可以使我們控制用戶、組、計算機、文件共享、打印任務、打印隊列和服務等系統資源。要想在 Delphi 中調用 ADSI ,需要引入活動目錄類型庫,調用菜單 Project | Import Type Library 命令,選擇 ActiveDs (Version 1.0) 點確認, Delphi 會生成相應的封裝文件。
1.綁定 Win NT 目錄服務
連接 Win NT 目錄服務就是找到域控制器然后綁定到相應的對象上。綁定可以通過 ADsGetObject 或 ADsOpenObject 函數來實現。 ADsGetObject 函數聲明如下:
function ADsGetObject(lpszPathName: PWideChar; const riid: TIID; out obj): HResult; stdcall; external 'activeds.dll';
第一個參數是對象的路徑名,第二個參數是對象的接口標識符,第三個參數用于返回得到的被請求的接口指針。缺省條件下,函數根據當前用戶進行安全認證。
ADsOpenObject 函數在不同的安全認證機制下綁定 ADSI 對象,它主要是通過調用參數返回的用戶名和口令來認證的。函數聲明如下:
function ADsOpenObject(lpszPathName: PWideChar; lpszUserName: PWideChar; lpszPassword: PWideChar; dwReserved: LongInt; const riid: TIID; out obj): HResult; stdcall; external 'activeds.dll';
第一個參數意義同上,第二、三個參數是調用者提供的用戶名和口令,第四個參數是一個保留的 provider 標識,用來確定綁定的認證方法,第五個參數是請求接口的接口標識符,最后一個參數用來返回請求的接口指針。
第一個函數使用登錄用戶缺省的信任級別,而第二個函數允許開發者指定特殊的安全信任機制來綁定 ADSI 對象。下面代碼演示了兩種不同的綁定方式:
- procedure TMainFrm.actOpenWinNTExecute(Sender: TObject);
- var
- UnknownObject: IUnknown;
- DomainPath: WideString;
- Domain: IADsContainer;
- begin
// 指定域路徑
- DomainPath := 'WinNT://' + ADSIDomainName.Text;
// 如果使用用戶登錄了信息
- if cbUseLogin.Checked then
// 使用用戶登錄的信息創建域對象
- OleCheck(AdsOpenObject(PWideChar(DomainPath),
- PWideChar(ADSIUsername.Text),
- PWideChar(ADSIPassword.Text), 0, IID_IADsContainer,
- UnknownObject));
- else
- OleCheck(ADsGetObject(PWideChar(DomainPath),
- IID_IADsContainer, UnknownObject));
- // 設定域對象
- Domain := UnknownObject as IADsContainer;
- // 從域中獲得信息列表
- GetDomainInformation(Domain);
- end;
下面我們需要聲明三個變量 :
第一個是接口變量 , 用來綁定由指定的對象路徑返回的函數。
UnknownObject: IUnknown;
第二個參數是 WideString 類型的變量 , 用來在綁定函數中產生一個對象路徑。
DomainPath: WideString;
第三是一個 IADsContainer 接口類型變量 , 用來保存返回的接口變量。
Domain: IADsContainer;
IADsContainer 變量將被用來從指定的 ADSI 對象中獲得全部用戶、組和計算機。當然也可以使用 IADsDomain 類型的變量,但它不適合枚舉域中的子對象。
下面指定想要獲得的對象路徑 , 如果域名是 "PRISMA" , 要想獲得 ADSI 對象 , 就需要指定路徑為 "WinNT://PRISMA" :
// 設定域名路徑
DomainPath := 'WinNT://' + ADSIDomainName.Text;
下面代碼使用不同的安全認證方式:
// 如果使用登錄信息
if cbUseLogin.Checked then
// 使用登錄并創建域對象
- OleCheck(AdsOpenObject(PWideChar(DomainPath),
- PWideChar(ADSIUsername.Text),
- PWideChar(ADSIPassword.Text), 0, IID_IADsContainer,
- UnknownObject));
- else
- // 創建域對象
- OleCheck(ADsGetObject(PWideChar(DomainPath),
- IID_IADsContainer, UnknownObject));
- 然后我們獲取 IADsContainer 指針,以便查詢域中的子對象:
- // 獲取域對象
- Domain := UnknownObject as IADsContainer;
- 最后 , 把 IADsContainer 接口指針作為參數調用來獲得域中的子對象 :
- GetDomainInformation(Domain);
在域中查找
要想在域中查找子對象 , 可以使用 GetDomainInformation 過程 , 代碼如下 :
// 獲取域信息
- procedure TMainFrm.GetDomainInformation(
- Domain: IADsContainer);
- var
- Enum: IEnumVariant;
- ADsTempObj: OLEVariant;
- ADsObj: IADs;
- Value: LongWord;
- begin
- // 清空用戶、組和計算機列表
- UserListView.Items.Clear;
- GroupListView.Items.Clear;
- ComputerListView.Items.Clear;
- // 獲取枚舉對象
- Enum := (Domain._NewEnum) as IEnumVariant;
- // 利用枚舉對象查找
- while (Enum.Next(1, ADsTempObj, Value) = S_OK) do begin
- // 獲得臨時對象
- ADsObj := IUnknown(ADsTempObj) as IADs;
- // 如果是用戶對象
- if AdsObj.Class_ = 'User' then
- AddUserToList(ADsObj);
- // 如果是組對象
- if AdsObj.Class_ = 'Group' then
- AddGroupToList(ADsObj);
- // 如果是計算機對象
- if AdsObj.Class_ = 'Computer' then
- AddComputerToList(ADsObj);
- end;
- end;
下面是對程序流程的詳細說明,首先獲得枚舉對象,并賦值給 Enum 變量:
Enum := (Domain._NewEnum) as IEnumVariant;
然后利用枚舉變量進行查找并把每個子對象賦值給臨時的 OLEVariant 對象:
while (Enum.Next(1, ADsTempObj, Value) = S_OK) do begin
OLEVariant 變量賦值給 ADSI 對象
ADsObj := IUnknown(ADsTempObj) as IADs;
獲得 ADSI 對象后,開始檢查對象類,根據對象類別把 ADSI 分別處理,并把不同 ADSI 對象的屬性添加到各自的列表視圖中去:
// 如果是用戶對象
if AdsObj.Class_ = 'User' then
AddUserToList(ADsObj);
// 如果是組對象
if AdsObj.Class_ = 'Group' then
AddGroupToList(ADsObj);
// 如果是計算機對象
圖 1.112
if AdsObj.Class_ = 'Computer' then AddComputerToList(ADsObj);
運行結果如 圖 1.112 所示。
更多內容點擊Delphi深度探索:活動目錄開發二
【編輯推薦】