gpt4 book ai didi

delphi - 如何实现IServiceProvider?

转载 作者:行者123 更新时间:2023-12-02 02:40:54 26 4
gpt4 key购买 nike

如何在继承其他接口(interface)的类中实现 IServiceProvider ,以便实际调用它们的方法?现在我总是从 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;

最佳答案

QueryService的目的与QueryInterface的目的不同.

QueryService如果它提供了所请求的服务(通过 rsid ),则应该返回指向对象本身的指针,否则它应该委托(delegate)给其他一些对象,通常是一个容器和另一个 QueryService 。打电话。

如果没有找到这样的服务,它应该返回E_NOTIMPL .

返回的接口(interface)指针将是请求的类型(通过 iid ),因此如果找到服务,则实现该服务的对象最终是 QueryInterface d.

如果对象没有实现这样的接口(interface),它应该返回 E_NOINTERFACE .

很多服务 ID (SID) 与通常实现的接口(interface) ID (IID) 具有相同的 GUID,例如 SID_SInternetSecurityManagerIID_IInternetSecurityManager 。尽管这是一个广泛使用的约定,但这并不是一条规则。例如,you can ask for the SID_SWebBrowserApp service as a IID_IWebBrowser2 interface pointer .

因此,分析您的 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;

你只是在转变QueryService进入QueryInterface使用服务 ID ( rsid ),它与接口(interface) ID ( iid ) 类似但不一定相关。因此,如果两者不同,调用者可能会得到不兼容的接口(interface)指针。

然后,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;

这意味着该对象实现了所有可以想象到的服务,因此它仅仅委托(delegate)给 QueryInterface ,但至少正确地使用 iid .

这是你应该做的:

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;

如果您想提供自己的服务,您可以选择使用以下代码:

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;

哪里SID_OverrideServiceN是您要覆盖的服务 ID,SID_FallbackServiceN是您想要回退到的服务 ID。请注意,我更改了 Succeeded(Result)Result <> E_NOTIMPL ,因为如果确实找到了服务但发生了其他一些错误,例如,我不想继续寻找服务。请求的接口(interface)未实现( E_NOINTERFACE )。

关于delphi - 如何实现IServiceProvider?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28090884/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com