Обратный вызов события Delphi WPD — получение имени файла

Я пытаюсь отследить, когда файл создается на WPD-совместимом устройстве, таком как цифровая камера или телефон Android. Я регистрируюсь для получения событий с помощью Advice, и мой обратный вызов вызывается правильно, но я не могу правильно получить имя файла (возможно, OBJECT_NAME). Вот что у меня есть:

TPortableDeviceEventsCallback = class(TInterfacedObject, IPortableDeviceEventCallback)
 public
  function OnEvent(const pEventParameters: IPortableDeviceValues): HResult; dynamic; stdcall;
 end;
.
.
.
function TPortableDeviceEventsCallback.OnEvent(const pEventParameters: IPortableDeviceValues): HResult;
var
ObjName: PWideChar;
begin
  pEventParameters.GetStringValue(WPD_EVENT_PARAMETER_OBJECT_NAME, ObjName);
  Log(string(ObjName));
end;

Я получаю только мусор вместо имени добавленного/удаленного объекта. Что мне здесь не хватает?


person Delphi.Boy    schedule 08.03.2016    source источник


Ответы (1)


Во-первых, OnEvent() не следует объявлять как dynamic. Это уже virtual в IPortableDeviceEventCallback.

Во-вторых, вы не обрабатываете ошибки IPortableDeviceValues.GetStringValue() и не освобождаете память, которую он возвращает. Это должно выглядеть примерно так:

function TPortableDeviceEventsCallback.OnEvent(const pEventParameters: IPortableDeviceValues): HResult;
var
  Hr: HResult;
  ObjName: PWideChar;
begin
  Hr := pEventParameters.GetStringValue(WPD_EVENT_PARAMETER_OBJECT_NAME, ObjName);
  case Hr of
    S_OK: begin
      try
        Log('Object Name: ' + String(ObjName));
      finally
        CoTaskMemFree(ObjName);
      end;
    end;
    DISP_E_TYPEMISMATCH: begin
      Log('Object Name is not a string!');
    end;
    $80070490: // HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
    begin
      Log('Object Name is not found!');
    end;
  else
    // some other error
    Log('Error getting Object Name: $' + IntToHex(Hr, 8));
  end;
  Result := S_OK;
end;

В-третьих, вы не смотрите на значение параметра WPD_EVENT_PARAMETER_EVENT_ID (это единственный обязательный параметр), чтобы узнать, какое событие вы получаете, чтобы узнать, какие параметры доступны для него. Разные события имеют разные значения параметров.

Попробуйте перечислить доступные значения, чтобы увидеть, что вы на самом деле получаете в каждом событии:

function TPortableDeviceEventsCallback.OnEvent(const pEventParameters: IPortableDeviceValues): HResult;
var
  Hr: HResult;
  Count, I: DWORD;
  Key: PROPERTYKEY;
  Value: PROPVARIANT;
begin
  Log('Event received');

  Hr := pEventParameters.GetCount(Count);
  if FAILED(Hr) or (Count = 0) then Exit;

  Log('Param count: ' + IntToStr(Count));

  for I := 0 to Count-1 do
  begin
    Hr := pEventParameters.GetAt(I, Key, Value);
    if FAILED(Hr) then
    begin
      Log('Cant get parameter at index ' + IntToStr(I));
      Continue;
    end;
    try
      Log('Param Key: ' + GuidToString(Key.fmtid) + ', Value type: $' + IntToHex(Value.vt, 4));
      // log content of Value based on its particular data type as needed...
    finally
      PropVariantClear(Value);
    end;
  end;
  Result := S_OK;
end;
person Remy Lebeau    schedule 09.03.2016
comment
Большое большое спасибо. Я применю все эти изменения к своему коду. Но вопрос в том, если предположить, что я получил событие WPD_EVENT_OBJECT_ADDED, является ли это правильным способом получения имени добавляемого файла? И почему я получаю мусор? - person Delphi.Boy; 09.03.2016
comment
Хорошо! Я понял, что использовал неправильную константу. Теперь я могу получить правильное имя файла, используя WPD_OBJECT_ORIGINAL_FILE_NAME. - person Delphi.Boy; 09.03.2016