Как использовать WMI с Delphi без существенного увеличения размера файла приложения?
Я использую Delphi 2010, и когда я создал консольное приложение, которое печатает "Hello World", оно занимает 111 kb. Если я хочу запросить WMI с Delphi, я добавлю в проект проект WBEMScripting_TLB, ActiveX и Variants. Если я выполню простой запрос WMI, мой исполняемый размер сканируется до 810 кб. I
Есть ли в любом случае запрос WMI без такого большого дополнения к размеру файла? Простите мое невежество, но почему у меня нет этой проблемы с С++?
Вот мой код:
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:
Когда я компилирую следующий образец из MSDN с Microsoft Visual С++ 2008 (консольное приложение), он составляет 76 кб.
Ответы
Ответ 1
@Mick, вы можете получить доступ к WMI без импорта WBEMScripting из Delphi, используя IBindCtx и IMoniker.
Проверьте этот простой код (протестирован в 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.
Ответ 2
ActiveX и/или варианты добавят максимум 36 КБ.
Он WBEMScripting_TLB, который добавляет к 650 КБ к вашему проекту.
Он не имеет большого количества строк в коде, но более чем объявляет довольно много классов, интерфейсов и констант, он включает OleServer в своих целях.
И THAT приносит весь Controls
блок с тяжелым багажом.
Ответ 3
когда Delphi создает исполняемый файл, он статически связывается в библиотеках времени выполнения delphi. это приводит к более крупному исполняемому файлу, однако, поскольку rtl статически связана, развертывание проще, и есть элемент будущей проверки.
вы можете настроить delphi для использования пакетов времени выполнения, включив Build with runtime packages
в Project
/Options
. однако вы должны будете убедиться, что пакеты delphi rtl доступны, и вы можете столкнуться с проблемами с отладкой.
это статическое и связанное с реализацией время работы объясняет различия, которые вы видите между delphi и С++.
Ответ 4
Разница, которую вы видите, в любом случае, связана с тем, что по умолчанию VС++ использует динамически связанные библиотеки времени исполнения; библиотеки времени выполнения загружаются из DLL, когда приложение запускается, и поэтому код не присутствует в исполняемом файле.
Delphi, OTOH, по умолчанию ссылки во всем коде библиотеки времени выполнения, если вы не создаете с включенными пакетами времени исполнения. Эта разница в конфигурациях по умолчанию будет учитывать большинство различий в размерах между исполняемыми файлами.
Ответ 5
Ну, я не знаю о WBEMScripting_TLB, но ActiveX.pas - довольно огромная единица. Это почти 7000 строк на моей установке D2010. Если вам нужно внести значительную сумму в свой код, вы можете ожидать, что он добавит несколько сотен K к вашему размеру EXE.
Насколько велика TLB, между прочим?