简体   繁体   English

我如何实现IServiceProvider?

[英]How can I implement IServiceProvider?

How can I implement IServiceProvider in the class which I inherit other interfaces from so their methods actually get called? 如何在继承其他接口的类中实现IServiceProvider ,以便实际调用它们的方法? Right now I always get E_NOINTERFACE back from QueryInterface . 现在我总是从QueryInterface返回E_NOINTERFACE

    TPassthrough = class(TComObject, IInternetProtocolRoot, IInternetProtocolSink, IInternetProtocol, IServiceProvider)
    private
      FDefaultSink: IInternetProtocol;
      FProtSink: IInternetProtocolSink;
      FBindInfo: IInternetBindInfo;
    public
    { IServiceProvider }
    function QueryService(const rsid, iid: TGuid; out Obj): HResult; stdcall;

    { IInternetProtocolSink }
    function Switch(const ProtocolData: TProtocolData): HResult; stdcall;
    function ReportProgress(ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult; stdcall;
    function ReportData(grfBSCF: DWORD; ulProgress, ulProgressMax: ULONG): HResult; stdcall;
    function ReportResult(hrResult: HResult; dwError: DWORD; szResult: LPCWSTR): HResult; stdcall;

    { IInternetProtocolRoot }
    function Start(szUrl: LPCWSTR; OIProtSink: IInternetProtocolSink; OIBindInfo: IInternetBindInfo; grfPI, dwReserved: DWORD): HResult; stdcall;
    function Continue(const ProtocolData: TProtocolData): HResult; overload; stdcall;
    function Abort(hrReason: HResult; dwOptions: DWORD): HResult; stdcall;
    function Terminate(dwOptions: DWORD): HResult; stdcall;
    function Suspend: HResult; stdcall;
    function Resume: HResult; stdcall;

    { IInternetProtocol }
    function Read(pv: Pointer; cb: ULONG; out cbRead: ULONG): HResult; stdcall;
    function Seek(dlibMove: LARGE_INTEGER; dwOrigin: DWORD; out libNewPosition: ULARGE_INTEGER): HResult; stdcall;
    function LockRequest(dwOptions: DWORD): HResult; stdcall;
    function UnlockRequest: HResult; stdcall;
    end;

...

function TPassthrough.Start(szUrl: LPCWSTR; OIProtSink: IInternetProtocolSink; OIBindInfo: IInternetBindInfo; grfPI, dwReserved: DWORD): HResult; stdcall;
begin
  if (FDefaultSink = nil) then
  OleCheck(CoCreateInstance(CLSID_HttpProtocol, nil, CLSCTX_INPROC_SERVER, IUnknown, FDefaultSink));

  FBindInfo := OIBindInfo;
  FProtSink := OIProtSink;

  if (Assigned(FDefaultSink)) then
    Result := (FDefaultSink as IInternetProtocolRoot).Start(szUrl, Self, Self, grfPI, dwReserved)
  else
    Result := E_NOTIMPL;
end; 

function TPassthrough.QueryService(const rsid, iid: TGuid; out Obj): HResult; stdcall;
begin
  Result := E_NOINTERFACE;
  Pointer(Obj) := nil;

  if Succeeded(QueryInterface(rsid, Obj)) and
    Assigned(Pointer(Obj))
  then
    Result := S_OK;
end; 

The purpose of QueryService is different from the purpose of QueryInterface . QueryService的目的与QueryInterface的目的不同。

QueryService should return a pointer to the object itself if it provides the requested service (through rsid ), otherwise it should delegate to some other object, typically a container and with another QueryService call. QueryService提供所请求的服务(通过rsid ), QueryService应返回指向对象本身的指针,否则它应该委托给其他对象,通常是容器和另一个QueryService调用。

If no such service is found, it should return E_NOTIMPL . 如果未找到此类服务,则应返回E_NOTIMPL

The returned interface pointer will be of the requested type (through iid ), so if the service is found, the object that implements the service is finally QueryInterface d. 返回的接口指针将是所请求的类型(通过iid ),因此如果找到该服务,则实现该服务的对象最终是QueryInterface d。

If no such interface is implemented by the object, it should return E_NOINTERFACE . 如果对象没有实现这样的接口,它应该返回E_NOINTERFACE

It so happens that many service IDs (SID) are the same GUID as the typically implemented interface ID (IID), for instance, SID_SInternetSecurityManager and IID_IInternetSecurityManager . 碰巧许多服务ID(SID)与通常实现的接口ID(IID)是相同的GUID,例如, SID_SInternetSecurityManagerIID_IInternetSecurityManager Although this is a widely used convention, it is not a rule. 虽然这是一种广泛使用的惯例,但它不是一个规则。 For instance, you can ask for the SID_SWebBrowserApp service as a IID_IWebBrowser2 interface pointer . 例如, 您可以将SID_SWebBrowserApp服务作为IID_IWebBrowser2接口指针

So, analysing your original code : 所以,分析你的原始代码

function TPassthrough.QueryService(const rsid, iid: TGuid; out Obj): HResult; stdcall;
begin
  Result := E_NOINTERFACE;
  Pointer(Obj) := nil;

  if Succeeded(QueryInterface(rsid, Obj)) and
    Assigned(Pointer(Obj))
  then
    Result := S_OK;
end;

You're kind of just transforming QueryService into QueryInterface using a service ID ( rsid ), which is similar but not necessarily related to interface IDs ( iid ). 您只是使用服务ID( rsid )将QueryService转换为QueryInterface ,这类似于但不一定与接口ID( iid )相关。 As such, if the two differ, the caller may get an incompatible interface pointer. 因此,如果两者不同,则调用者可能会获得不兼容的接口指针。

Then, the changed code : 然后, 更改的代码

function TMonitor.QueryService(const rsid, iid: TGuid; out Obj): HResult; stdcall;
begin
  Result := E_NOINTERFACE;
  Pointer(Obj) := nil;

  if Succeeded(QueryInterface(iid, Obj)) and
    Assigned(Pointer(Obj))
  then
    Result := S_OK;
end;

This is saying that the object implements every imaginable service, so it merely delegates to QueryInterface , but at least correctly with iid . 这就是说该对象实现了所有可以想象的服务,因此它只是委托给QueryInterface ,但至少正确地使用了iid

This is what you should do: 这是你应该做的:

function TMonitor.QueryService(const rsid, iid: TGuid; out Obj): HResult; stdcall;
begin
  if Not Assigned(@Obj) then
  begin
    Result := E_POINTER;
    Exit;
  end;

  Pointer(Obj) := nil;
  Result := E_NOTIMPL;

  if Assigned(FServiceProvider) then
    Result := FServiceProvider.QueryService(rsid, iid, Obj);
end;

Should you want to provide your own services, you can optionally use the following code: 如果您想提供自己的服务,可以选择使用以下代码:

function TMonitor.QueryService(const rsid, iid: TGuid; out Obj): HResult; stdcall;
begin
  if Not Assigned(@Obj) then
  begin
    Result := E_POINTER;
    Exit;
  end;

  Pointer(Obj) := nil;
  Result := E_NOTIMPL;

  if IsEqualGUID(rsid, SID_SOverrideService1) or
     IsEqualGUID(rsid, SID_SOverrideService2)
  then
    Result := QueryInterface(iid, Obj);

  if Result = E_NOTIMPL and
     Assigned(FServiceProvider)
  then
    Result := FServiceProvider.QueryService(rsid, iid, Obj);

  if Result = E_NOTIMPL and
     (IsEqualGUID(rsid, SID_SFallbackService1) or
      IsEqualGUID(rsid, SID_SFallbackService2))
  then
    Result := QueryInterface(iid, Obj);
end;

Where SID_OverrideServiceN are the service IDs you want to override and SID_FallbackServiceN are the service IDs you want to fallback to. 其中SID_OverrideServiceN是您要覆盖的服务ID, SID_FallbackServiceN是您要回退的服务ID。 Note that I changed Succeeded(Result) to Result <> E_NOTIMPL , because I don't want to keep looking for services if one was actually found but some other error happened, eg the requested interface was not implemented ( E_NOINTERFACE ). 请注意,我将Succeeded(Result)更改为Result <> E_NOTIMPL ,因为我不想继续查找服务(如果实际找到了一个但发生了其他错误,例如请求的接口未实现( E_NOINTERFACE ))。

您正在查询服务ID(rsid),而不是接口ID(iid)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Delphi中实现线程安全的列表包装? - How can I implement a thread-safe list wrapper in Delphi? 如何使用Delphi实现突出显示的工具栏图标? - How Can I Implement Highlighted Toolbar Icons With Delphi? 如何在TDataSet中实现“可写计算”字段? - How can I implement “writable calculated” fields in a TDataSet? 如何在Delphi中实现一组标准的超链接检测规则 - How Can I Implement A Standard Set of Hyperlink Detection Rules in Delphi 我需要有关如何实现可在对象检查器中显示的类的帮助 - I need help on how to implement class that can be shown in object Inspector 如何在 delphi 控制台应用程序中实现 IsKeyPressed function? - How i can implement a IsKeyPressed function in a delphi console application? 我卡住了,如何在 datasnap rest Delphi 中实现 2 种不同的服务器方法 - I'm stuck, how can I implement 2 different server methods in datasnap rest Delphi 如何为特定类型的所有实例实现自己的自定义属性编辑器? - How can I implement my own custom property editor for all instances of a certain type? 如何在应用程序繁忙时通过delphi和Avoid Hung outlook实现OutlookApp.Onquit事件 - How can I implement OutlookApp.Onquit Event with redemption on delphi and Avoid Hung outlook when app is busy 我可以使用TVirtualMethodInterceptor实现实例计数监控吗? - Can I implement instance count monitoring using TVirtualMethodInterceptor?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM