Регистрация для событий NLM (INetworkListManager, Advise, Sink и т. Д.)

В моем приложении Delphi я хотел бы получать информацию об изменениях в сети с помощью API диспетчера сетевых списков Microsoft Windows (NLM): http://msdn.microsoft.com/library/ee264321

Я посмотрел на связанный пример "Как зарегистрироваться для событий NLM" и перевел его на Delphi. Тем не менее, я понятия не имею, как продолжить это.

var
    pNLM: INetworkListManager;
    pCpc: IConnectionPointContainer;
    pConnectionPoint: IConnectionPoint;
    pSink: IUnknown;
    dwCookie: LongInt;
const
    IID_IConnectionPointContainer: TGUID = '{B196B284-BAB4-101A-B69C-00AA00341D07}';
    IID_IUnknown: TGUID = '{00000000-0000-0000-C000-000000000046}';
begin
    if Succeeded(CoCreateInstance(CLASS_NetworkListManager, nil, CLSCTX_ALL, IID_INetworkListManager, pNLM)) then
    begin
        if Succeeded(pNLM.QueryInterface(IID_IConnectionPointContainer, pCpc)) then
        begin
            if Succeeded(pCpc.FindConnectionPoint(IID_INetworkEvents, pConnectionPoint)) then
            begin
                if Succeeded(pCpc.QueryInterface(IID_IUnknown, pSink)) then
                begin
                    pConnectionPoint.Advise(pSink, dwCookie);
                end;
            end;
        end;
    end;
end;

В статье говорится:

"После создания объекта INetworkListManager, указанного выше, вы будете получать уведомления INetworkEvents с этой точки вперед. PSink реализует интерфейс INetworkEvent, включая такие методы обработки событий, как NetworkAdded, NetworkDeleted, NetworkConnectivityChanged и NetworkPropertyChanged".

К сожалению, я понятия не имею, как это сделать. Никаких дальнейших инструкций нет, и поэтому я надеюсь, что кто-то здесь сможет проинструктировать меня / предоставить пример того, что еще нужно сделать для вызова пользовательских процедур для этих событий. Благодарю.

1 ответ

Решение

Вы передаете не тот объект Advise(), Вы передаете IConnectionPointContainer объект. Вместо этого вам нужно написать свой собственный класс, который реализует INetworkEvents интерфейс, затем создайте экземпляр класса и передайте этот объект Advise(), Именно так NLM (или любой другой COM-объект, который использует точки подключения) может отправлять события в ваш код.

Обновление: вам нужно изменить NLMEvents блок для поддержания объекта NLM после StartNLMEventListener() выходы, тогда события будут работать правильно. Как у вас это закодировано, объект NLM является локальным для StartNLMEventListener() и, таким образом, освобождается, когда StartNLMEventListener() выходы, которые отменяют регистрацию вашего приемника событий.

Попробуйте это вместо этого:

unit NLMEvents;

interface

function StartNLMEventListener: HResult;
function StopNLMEventListener: HResult;

implementation

uses
  Windows, ActiveX, NETWORKLIST_TLB, SysUtils, Unit1;

type
  TMyNetworkEvents = class(TInterfacedObject, INetworkEvents, INetworkConnectionEvents, INetworkListManagerEvents)
  public
    function NetworkAdded(networkId: TGUID): HResult; stdcall;
    function NetworkConnectivityChanged(networkId: TGUID; NewConnectivity: NLM_CONNECTIVITY): HResult; stdcall;
    function NetworkDeleted(networkId: TGUID): HResult; stdcall;
    function NetworkPropertyChanged(networkId: TGUID; fFlags: NLM_NETWORK_PROPERTY_CHANGE): HResult; stdcall;
    function ConnectivityChanged(NewConnectivity: NLM_CONNECTIVITY): HResult; stdcall;
    function NetworkConnectionConnectivityChanged(networkId: TGUID; NewConnectivity: NLM_CONNECTIVITY): HResult; stdcall;
    function NetworkConnectionPropertyChanged(networkId: TGUID; fFlags: NLM_NETWORK_PROPERTY_CHANGE): HResult; stdcall;
  end;

var
  pNLM: INetworkListManager = nil;
  dwCookie1: LongInt = -1;
  dwCookie2: LongInt = -1;
  dwCookie3: LongInt = -1;

const
  IID_IConnectionPointContainer: TGUID = '{B196B284-BAB4-101A-B69C-00AA00341D07}';
  //IID_IUnknown: TGUID = '{00000000-0000-0000-C000-000000000046}';
  //CLSID_NetworkListManager: TGUID = '{DCB00C01-570F-4A9B-8D69-199FDBA5723B}';

function TMyNetworkEvents.ConnectivityChanged(NewConnectivity: NLM_CONNECTIVITY): HResult; stdcall;
begin
  Form2.Memo1.Lines.Add('ConnectivityChanged');
  Result := S_OK;
end;

function TMyNetworkEvents.NetworkConnectionConnectivityChanged(networkId: TGUID; NewConnectivity: NLM_CONNECTIVITY): HResult; stdcall;
begin
  Form2.Memo1.Lines.Add('NetworkConnectionConnectivityChanged');
  Result := S_OK;
end;

function TMyNetworkEvents.NetworkConnectionPropertyChanged(networkId: TGUID; fFlags: NLM_NETWORK_PROPERTY_CHANGE): HResult; stdcall;
begin
  Form2.Memo1.Lines.Add('NetworkConnectionPropertyChange');
  Result := S_OK;
end;

function TMyNetworkEvents.NetworkAdded(networkId: TGUID): HResult; stdcall;
begin
  Form2.Memo1.Lines.Add('NetworkAdded');
  Result := S_OK;
end;

function TMyNetworkEvents.NetworkConnectivityChanged(networkId: TGUID; NewConnectivity: NLM_CONNECTIVITY): HResult; stdcall;
begin
  Form2.Memo1.Lines.Add('NetworkConnectivityChanged');
  Result := S_OK;
end;

function TMyNetworkEvents.NetworkDeleted(networkId: TGUID): HResult; stdcall;
begin
  Form2.Memo1.Lines.Add('NetworkDeleted');
  Result := S_OK;
end;

function TMyNetworkEvents.NetworkPropertyChanged(networkId: TGUID; fFlags: NLM_NETWORK_PROPERTY_CHANGE): HResult; stdcall;
begin
  Form2.Memo1.Lines.Add('NetworkPropertyChanged');
  Result := S_OK;
end;

function StartNLMEventListener: HResult;
var
  pCpc: IConnectionPointContainer;
  pConnectionPoint: IConnectionPoint;
  pSink: INetworkEvents;
begin
  if pNLM = nil then
  begin
    Result := CoCreateInstance(CLASS_NetworkListManager, nil, CLSCTX_ALL, IID_INetworkListManager, pNLM);
    if Failed(Result) then
      Exit;
  end else
  begin
    Result := S_OK;
  end;

  if Succeeded(pNLM.QueryInterface(IID_IConnectionPointContainer, pCpc)) then
  begin
    pSink := TMyNetworkEvents.Create as INetworkEvents;

    if dwCookie1 = -1 then
    begin
      if Succeeded(pCpc.FindConnectionPoint(IID_INetworkEvents, pConnectionPoint)) then
      begin
        pConnectionPoint.Advise(pSink, dwCookie1);
        pConnectionPoint := nil;
      end;
    end;

    if dwCookie2 = -1 then
    begin
      if Succeeded(pCpc.FindConnectionPoint(IID_INetworkConnectionEvents, pConnectionPoint)) then
      begin
        pConnectionPoint.Advise(pSink, dwCookie2);
        pConnectionPoint := nil;
      end;
    end;

    if dwCookie3 = -1 then
    begin
      if Succeeded(pCpc.FindConnectionPoint(IID_INetworkListManagerEvents, pConnectionPoint)) then
      begin
        pConnectionPoint.Advise(pSink, dwCookie3);
        pConnectionPoint := nil;
      end;
    end;
  end;
end;

function StopNLMEventListener: HResult;
var
  pCpc: IConnectionPointContainer;
  pConnectionPoint: IConnectionPoint;
begin
  if pNLM <> nil then
  begin
    if Succeeded(pNLM.QueryInterface(IID_IConnectionPointContainer, pCpc)) then
    begin
      if dwCookie1 <> -1 then
      begin
        if Succeeded(pCpc.FindConnectionPoint(IID_INetworkEvents, pConnectionPoint)) then
        begin
          pConnectionPoint.Unadvise(dwCookie1);
          pConnectionPoint := nil;
        end;
      end;

      if dwCookie2 <> -1 then
      begin
        if Succeeded(pCpc.FindConnectionPoint(IID_INetworkConnectionEvents, pConnectionPoint)) then
        begin
          pConnectionPoint.Unadvise(dwCookie2);
          pConnectionPoint := nil;
        end;
      end;

      if dwCookie3 <> -1 then
      begin
        if Succeeded(pCpc.FindConnectionPoint(IID_INetworkListManagerEvents, pConnectionPoint)) then
        begin
          pConnectionPoint.Unadvise(dwCookie3);
          pConnectionPoint := nil;
        end;
      end;
    end;

    pNLM := nil;
  end;

  dwCookie1 := -1;
  dwCookie2 := -1;
  dwCookie3 := -1;

  Result := S_OK;
end;

end.
Другие вопросы по тегам