Помогите найти утечку

garun
Дата: 21.10.2019 17:59:50
Добрый вечер! Прошу помочь понять в чем проблема. Нижеприведенная функция крутится в таймере с интервалом 1сек и достает текущий адрес папки из проводника. Если смотреть в диспетчере, то с каждой секундой потребляемая память увеличивается на 50-60Кб. Почему так происходит и как это предотвратить?

uses 
 Winapi.ActiveX, SHDocVw, System.Win.ComObj, ShLWAPI;

function ExtractDirAddress(Wnd: HWND): string;
var
  I: Integer;
  WndIface: IDispatch;
  ShellWindows: IShellWindows;
  WebBrowserApp: IWebBrowserApp;
  ResultSize: DWORD;
begin
  if Succeeded(CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_LOCAL_SERVER,  IID_IShellWindows, ShellWindows))
  then
  begin
    for I := 0 to ShellWindows.Count - 1 do
    begin
      if (Wnd <> HWND_TOPMOST)
      then WndIface:= ShellWindows.Item(VarAsType(I, VT_I4))
      else WndIface:= ShellWindows.Item(VarAsType(SWC_EXPLORER, VT_UI4));
      if Succeeded(WndIface.QueryInterface(IID_IWebBrowserApp, WebBrowserApp))
      then
      begin
        if (Wnd = HWND_TOPMOST) or (WebBrowserApp.HWnd = Wnd) then
        begin
         Result:=  WebBrowserApp.LocationURL;
          Break;
        end;
      end;
    end;
  end;
end;

procedure TForm1.tmr1Timer(Sender: TObject);
var
 S: string;
begin
  S:= ExtractDirAddress(GetForegroundWindow);
  if S > ''
  then mmo1.Text:= '[' + TimeToStr(Now) + ']: ' + S;
end;
ma1tus
Дата: 21.10.2019 19:11:15
garun
      if Succeeded(WndIface.QueryInterface(IID_IWebBrowserApp, WebBrowserApp))
      then
      begin
        if (Wnd = HWND_TOPMOST) or (WebBrowserApp.HWnd = Wnd) then
        begin
         Result:=  WebBrowserApp.LocationURL;
          Break;
        end;
      end;

Освобождай WebBrowserApp на каждой итерации.
garun
Дата: 21.10.2019 19:19:52
ma1tus
garun
      if Succeeded(WndIface.QueryInterface(IID_IWebBrowserApp, WebBrowserApp))
      then
      begin
        if (Wnd = HWND_TOPMOST) or (WebBrowserApp.HWnd = Wnd) then
        begin
         Result:=  WebBrowserApp.LocationURL;
          Break;
        end;
      end;

Освобождай WebBrowserApp на каждой итерации.


Проблема не в этом. Если убрать всё, оставив только вот эту конструкцию, то утечка всё равно продолжается:

if Succeeded(CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_LOCAL_SERVER,  IID_IShellWindows, ShellWindows))
then

 //do nothing

end;
rgreat
Дата: 21.10.2019 19:33:19
Как я понимаю ShellWindows:=nil не помогает?
Ghost Writer
Дата: 21.10.2019 19:51:33
garun
крутится в таймере с интервалом 1сек
обязательно создавать ежесекундно ? один раз создать и использовать - не вариант ?
garun
Дата: 21.10.2019 19:52:23
rgreat
Как я понимаю ShellWindows:=nil не помогает?


Неа :(
rgreat
Дата: 21.10.2019 19:55:47
Вызови .Release явно.
garun
Дата: 21.10.2019 19:56:39
Ghost Writer
garun
крутится в таймере с интервалом 1сек
обязательно создавать ежесекундно ? один раз создать и использовать - не вариант ?


Обязательно.

Кстати, если заменить это:
if Succeeded(CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_LOCAL_SERVER,  IID_IShellWindows, ShellWindows)) then

На это:
ShellWindows:= CoShellWindows.Create;

То код будет тоже работать, но утечка никуда не девается.

Отсюда вопрос - как освободить ShellWindows?
Ghost Writer
Дата: 21.10.2019 19:58:27
garun
Обязательно
и почему же ?
создать экземпляр и использовать.
только если вдруг будет завершен процесс explorer.exe, то придется отлавливать исключения.
rgreat
Дата: 21.10.2019 20:01:48
Кстати, может раз ShellWindows это список, то оно так криво реализовано что элементы надо поштучно освобождать?