我想在使用Delphi(7及更高版本)开发的应用程序中查询Active Directory,但不希望在“uses”子句中包含“ActiveDs_TLB”以保持EXE大小不变。查询WMI时,可以使用IBindCtx和IMoniker接口来避免在类型库中进行链接(请参阅How do I use WMI with Delphi without drastically increasing the application's file size?获取解决方案)。
执行AD查询时是否可以这样做?我的情况我想要检索“IADsUser”和“IADsComputer”。我知道我可以通过手动将所需的定义从“ActiveDs_TLB”复制到我的程序或使用LDAP查询来减少EXE大小,但我更喜欢类似于为WMI描述的解决方案。
答案 0 :(得分:3)
我不是Active Directory专家,但我刚创建了两个D7控制台应用程序,一个使用ActiveDS_TLB.Pas类型库访问WnNTSystemInfo对象,另一个使用后期绑定做同样的事情,即从AD获取ComputerName
首先,后期绑定一个:
program ActiveDSLBConsole;
{$APPTYPE CONSOLE}
uses
SysUtils, ActiveX, ComObj;
var
SI : OleVariant;
S : String;
begin
CoInitialize(Nil);
SI := CreateOleObject('WinNTSystemInfo');
S := SI.ComputerName;
writeln(S);
readln;
end.
(上面写了上面最长的是检查注册表的名称 要创建的对象)
无论如何,我希望这表明,是的,您可以通过后期绑定查询AD,并且这个最小的示例将让您开始以这种方式查询AD。
使用ActiveDS_Tlb的等效AD控制台应用程序是
program ActiveDSConsole;
{$APPTYPE CONSOLE}
uses
SysUtils, ActiveX, ActiveDS_Tlb;
var
SI : IADsWinNTSystemInfo;
S : String;
begin
CoInitialize(Nil);
SI := CoWinNTSystemInfo.Create;
S := SI.ComputerName;
writeln(S);
readln;
end.
这些.Exe大小为
ActiveDSConsole : 390144 bytes
ActiveDSLBConsole : 87552 bytes (late bound)
因此显然有相当多的代码可以支持使用 tlb对象,但都不是很大。
FWIW,上面重写为极简主义VCL应用程序的Button1Click处理程序,提供了Exe大小 的
using ActiveDS_TLB : 396288 bytes
late bound : 392704 bytes
这两者之间的差异对我来说似乎相当微不足道,但有一个明确的 在最小的D7控制台应用程序中后期绑定的大小优势。你的旅费可能会改变, 如果你赦免混合的比喻,那么最好“吮吸它并看到”。
顺便说一下,后期绑定的优点是你不必总是为接口方法中的每个参数提供参数。您可以使用这种特殊语法调用方法,以便编译器得到增强,以允许(在D2中添加自动化支持时)它知道包含后期绑定自动化对象的变体:
(来自MS Word后期绑定示例)
Table := MSWord.ActiveDocument.Tables.Add(Range:= MSWord.Selection.Range, NumRows:= Rows, NumColumns:= Columns, DefaultTableBehavior:= wdWord9TableBehavior, AutoFitBehavior:= wdAutoFitFixed);
答案 1 :(得分:1)
program GetUserObjectPath;
{$APPTYPE CONSOLE}
uses SysUtils, ActiveX, ComObj;
function GetObject (const Name: WideString) : IDispatch;
var
Moniker : IMoniker;
Eaten : Integer;
BindContext : IBindCtx;
begin
OleCheck (CreateBindCtx (0, BindContext));
OleCheck (MkParseDisplayName (BindContext, PWideChar (Name), Eaten,
Moniker));
OleCheck (Moniker.BindToObject (BindContext, NIL, IDispatch, Result));
end; { GetObject }
procedure Query_AD (const sQuery: String);
var
vUser : OleVariant;
begin
vUser := GetObject (sQuery); // = IADsUser
WriteLn ('Name = ' + vUser.FullName);
end; { Query_AD }
var
sQuery, sDomain, sUserName : String;
begin
sDomain := GetEnvironmentVariable ('USERDNSDOMAIN');
sUserName := GetEnvironmentVariable ('USERNAME');
sQuery := Format ('WinNT://%s/%s,user', [sDomain, sUserName]);
CoInitialize (NIL);
try
Query_AD (sQuery);
finally
// Causes Access Violation if AD query does not happen in subroutine
CoUninitialize;
end; { try / finally }
WriteLn;
Write ('Press [Enter] to continue ...');
ReadLn;
end.
实际的AD查询应该在子例程(此处为“Query_AD”)中进行,否则调用“CoUninitialize”将导致访问冲突(请参阅Why does CoUninitialize cause an error on exit?获取解释)。