我正在使用Delphi 2010,当我创建一个打印“Hello World”的控制台应用程序时,需要111 kb。如果我想用Delphi查询WMI,我将WBEMScripting_TLB,ActiveX和Variants单元添加到我的项目中。如果我执行简单的WMI查询,我的可执行文件大小会跳到810 kb。我
无论如何在没有对文件大小的大量添加的情况下查询WMI?请原谅我的无知,但为什么我没有C ++的这个问题?
这是我的代码:
program WMITest;
{$APPTYPE CONSOLE}
uses
SysUtils,
WBEMScripting_TLB,
ActiveX,
Variants;
function GetWMIstring(wmiHost, root, wmiClass, wmiProperty: string): string;
var
Services: ISWbemServices;
SObject: ISWbemObject;
ObjSet: ISWbemObjectSet;
SProp: ISWbemProperty;
Enum: IEnumVariant;
Value: Cardinal;
TempObj: OLEVariant;
loc: TSWbemLocator;
SN: string;
i: integer;
begin
Result := '';
i := 0;
try
loc := TSWbemLocator.Create(nil);
Services := Loc.ConnectServer(wmiHost, root {'root\cimv2'}, '', '', '', '',
0, nil);
ObjSet := Services.ExecQuery('SELECT * FROM ' + wmiClass, 'WQL',
wbemFlagReturnImmediately and wbemFlagForwardOnly, nil);
Enum := (ObjSet._NewEnum) as IEnumVariant;
if not VarIsNull(Enum) then
try
while Enum.Next(1, TempObj, Value) = S_OK do
begin
try
SObject := IUnknown(TempObj) as ISWBemObject;
except SObject := nil;
end;
TempObj := Unassigned;
if SObject <> nil then
begin
SProp := SObject.Properties_.Item(wmiProperty, 0);
SN := SProp.Get_Value;
if not VarIsNull(SN) then
begin
if varisarray(SN) then
begin
for i := vararraylowbound(SN, 1) to vararrayhighbound(SN, 1) do
result := vartostr(SN[i]);
end
else
Result := SN;
Break;
end;
end;
end;
SProp := nil;
except
Result := '';
end
else
Result := '';
Enum := nil;
Services := nil;
ObjSet := nil;
except
on E: Exception do
Result := e.message;
end;
end;
begin
try
WriteLn('hello world');
WriteLn(GetWMIstring('.', 'root\CIMV2', 'Win32_OperatingSystem',
'Caption'));
WriteLn('done');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
更新 当我使用Microsoft Visual C ++ 2008(控制台应用程序)编译following sample from MSDN时,它是76 kb。
答案 0 :(得分:26)
@Mick,您可以使用IBindCtx和IMoniker接口从Delphi导入WBEMScripting来访问WMI。
检查这个简单的代码(在Delphi 2010和Windows 7中测试),exe文件大小为174 kb。
program WmiTest;
{$APPTYPE CONSOLE}
uses
SysUtils
,ActiveX
,ComObj
,Variants;
function GetWMIstring(wmiHost, root, wmiClass, wmiProperty: string): string;
var
objWMIService : OLEVariant;
colItems : OLEVariant;
colItem : OLEVariant;
oEnum : IEnumvariant;
iValue : LongWord;
function GetWMIObject(const objectName: String): IDispatch;
var
chEaten: Integer;
BindCtx: IBindCtx;//for access to a bind context
Moniker: IMoniker;//Enables you to use a moniker object
begin
OleCheck(CreateBindCtx(0, bindCtx));
OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));//Converts a string into a moniker that identifies the object named by the string
OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));//Binds to the specified object
end;
begin
objWMIService := GetWMIObject(Format('winmgmts:\\%s\%s',[wmiHost,root]));
colItems := objWMIService.ExecQuery(Format('SELECT * FROM %s',[wmiClass]),'WQL',0);
oEnum := IUnknown(colItems._NewEnum) as IEnumVariant;
while oEnum.Next(1, colItem, iValue) = 0 do
begin
Result:=colItem.Properties_.Item(wmiProperty, 0); //you can improve this code ;) , storing the results in an TString.
end;
end;
begin
try
CoInitialize(nil);
try
WriteLn(GetWMIstring('.', 'root\CIMV2', 'Win32_OperatingSystem','Caption'));
Readln;
finally
CoUninitialize;
end;
except
on E:Exception do
Begin
Writeln(E.Classname, ': ', E.Message);
Readln;
End;
end;
end.
答案 1 :(得分:6)
ActiveX和/或变体最多可添加36KB
WBEMScripting_TLB 添加关于 650KB 到您的项目。
它在代码行中并不是很大,但不仅仅是声明了很多类,接口和常量,而是包括OleServer 。
并且 这会带来整个 Controls
单元 及其 沉重的行李
答案 2 :(得分:2)
当delphi构建可执行文件时,它会在delphi运行时库中静态链接。这会导致更大的可执行文件,但是由于rtl是静态链接的,因此部署更容易,而且还有未来验证的元素。
您可以通过在Build with runtime packages
/ Project
中启用Options
来配置delphi以使用运行时包。但是你必须确保delphi rtl包可用,并且你可能会遇到调试问题。
这种静态与运行时链接行为可能解释了您在delphi和c ++之间看到的差异。
答案 3 :(得分:1)
无论如何,你所看到的差异是因为VC ++默认使用动态链接的运行时库;运行应用程序时,运行时库是从DLL加载的,因此代码不存在于可执行文件中。
Delphi,OTOH默认链接所有运行时库代码,除非您使用启用的运行时包进行构建。默认配置的这种差异将占可执行文件之间大小差异的大部分。
答案 4 :(得分:0)
好吧,我不知道WBEMScripting_TLB,但ActiveX.pas是一个非常庞大的单位。我的D2010安装上差不多有7000行。如果您必须将大量的内容添加到您的代码中,那么您可以预期它会为您的EXE大小增加几百K.
顺便说一句,TLB有多大?