Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Delphi: Система, Windows API > Как заменить SetLength?


Автор: navodri 17.07.18, 15:28
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    function TRestoreViewer.GetRestorePoints: TRestorePoints;
    var
      ObjWMIService           : OLEVariant;
      ColItems                : OLEVariant;
      ColItem                 : OLEVariant;
      OEnum                   : IEnumvariant;
    //  IValue                  : PLongint;
      CountOfRestorePoint     : Integer;
      I: Integer;
      RestorePoint            : TRestorePoint;
    begin
      ObjWMIService := GetWMIObject('winmgmts:\\localhost\root\default');
      ColItems      := objWMIService.ExecQuery('SELECT * FROM SystemRestore','WQL',0);
      OEnum         := IUnknown(colItems._NewEnum) as IEnumVariant;
     
     if not VarIsNull(ColItems.Count) then
       CountOfRestorePoint := StrToInt(VarToStr(ColItems.Count))
     else
       CountOfRestorePoint := 0;
     if (CountOfRestorePoint = 0) then Exit;
     
    //   SetLength(Result, CountOfRestorePoint);
     
      I := 0;
     
      while OEnum.Next(1, colItem, nil {IValue}) = 0 do
      begin
        RestorePoint.Description := ColItem.Description;
        RestorePoint.EventType := EventTypeToStr(ColItem.EventType);
        RestorePoint.SequenceNumber := ColItem.SequenceNumber;
        RestorePoint.CreationTime := WMITimeToStr(ColItem.CreationTime);
        RestorePoint.RestorePointType := RestorePointTypeToStr(ColItem.RestorePointType);
     
        Result[i] := RestorePoint;
        Inc(i);
      end;
    end;

Автор: MBo 17.07.18, 15:58
SetLength нельзя заменить ничем, если оно применяется к переменным соответствующих типов.

А про тип мы не знаем, т.к. не телепаты.

Автор: navodri 17.07.18, 17:36
Сорри. Вот тип:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    type
      TRestorePoint = record
        Description:string;
        EventType:string;
        SequenceNumber:string;
        CreationTime:string;
        RestorePointType:string;
      end;
     TRestorePoints = array [0..255]of TRestorePoint;

Автор: Gonarh 17.07.18, 18:24
getmem/freemem

Автор: navodri 17.07.18, 19:53
В моем случае Result не Pointer. Так не компилится: Incompatible types

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    GetMem(Result, sizeOf(CountOfRestorePoint));

Автор: MBo 18.07.18, 02:11
Массив статический, так что задавать длину ему не нужно, память под результат уже выделена компилятором.
При этом неизвестно, сколько реально элементов заполнено

SetLength требуется для динамических массивов

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
        TRestorePoints = array of TRestorePoint;

Автор: navodri 18.07.18, 06:24
Это не помогает. ListView1 заполняется множеством пустых пунктов. Может, в заполнении ошибка:


<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure TForm1.Button1Click(Sender: TObject);
    var
     MyRestoreViewer:TRestoreViewer;
     AllRestorePoint:TRestorePoints;
     I: Integer;
    begin
     ListView1.Items.Clear;
     
     MyRestoreViewer := TRestoreViewer.Create;
     AllRestorePoint := MyRestoreViewer.GetRestorePoints;
     
     for I := 0 to High(AllRestorePoint) do
      with ListView1.Items.Add do
      begin
        Caption := AllRestorePoint[i].Description;
        SubItems.Add(AllRestorePoint[i].EventType);
        SubItems.Add(AllRestorePoint[i].SequenceNumber);
        SubItems.Add(AllRestorePoint[i].RestorePointType);
        SubItems.Add(AllRestorePoint[i].CreationTime);
      end;
     
     MyRestoreViewer.Free;
     
    end;

Автор: MBo 18.07.18, 06:33
А длина динамического массива установлена в соответствии с реальным содержанием? Если используется код из первого поста, то i после цикла содержит счётчик записей.

Автор: Fr0sT 18.07.18, 06:58
1) Поставь точку останова после заполнения массива и посмотри в отладчике, что туда записалось
2) (а) Возвращай кол-во заполненных элементов либо (б) выставляй флаг внутри записи, что она содержит данные, чтобы не рассматривать незаполненные элементы
3) Если выберешь вариант (б), обнуляй массив перед каждым заполнением.

Автор: navodri 18.07.18, 08:04
Сенкс! Нашел ошибку. Закрывайте тему.

Автор: Fr0sT 19.07.18, 08:40
Сам и закрывай)

Автор: Jin X 19.07.18, 15:23
navodri, используй динамический массив (см. выше строку кода от MBo) и используй с ним SetLength, High и пр.
Это гораздо лучше, чем забивать стек массивом и потом копировать его с одного места на другое.
К тому же, SetLength обнуляет выделенные элементы массива – ещё один плюс.
А если ты создаёшь динамический массив как локальную переменную в вызывающей процедуре:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure Example;
    var RestorePoints: TRestorePoints;
    begin
      . . .
      RestorePoints := TRestoreViewer.GetRestorePoints;
      . . .
    end;
то потом этот массив уничтожается автоматически при выходе из процедуры (т.е. не надо будет писать SetLength(RestorePoints, 0)).

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)