I am using Delphi 2010, and when I created a console application that prints "Hello World", it takes 111 kb. If I want to query WMI with Delphi, I add WBEMScripting_TLB, ActiveX, and Variants units to my project. If I perform a simple WMI query, my executable size jumps to 810 kb. I
Is there anyway to query WMI without such a large addition to the size of the file? Forgive my ignorance, but why do I not have this issue with C++?
Here is my code:
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.
UPDATE: When I compile the following sample from MSDN with Microsoft Visual C++ 2008 (console application), it is 76 kb.
@Mick, you can access the WMI without import the WBEMScripting from Delphi, using the IBindCtx and IMoniker interfaces.
Check this simple code (Tested in Delphi 2010 and Windows 7), the exe file size is 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.