Joh*_*wis 2 delphi com bho urlmon delphi-xe7
如何IServiceProvider在我继承其他接口的类中实现,以便实际调用它们的方法?现在我总是E_NOINTERFACE回来QueryInterface.
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;
Run Code Online (Sandbox Code Playgroud)
目的QueryService不同于目的QueryInterface.
QueryService如果它提供所请求的服务(通过rsid),则应该返回指向对象本身的指针,否则它应该委托给其他对象,通常是容器和另一个QueryService调用.
如果没有找到这样的服务,它应该返回E_NOTIMPL.
返回的接口指针将是所请求的类型(直通iid),因此如果找到该服务,则最终实现该服务的对象为QueryInterfaced.
如果对象没有实现这样的接口,它应该返回E_NOINTERFACE.
事实上,有许多的服务ID(SID)是相同的GUID作为通常实现接口ID(IID),例如,SID_SInternetSecurityManager和IID_IInternetSecurityManager.虽然这是一种广泛使用的惯例,但它不是一个规则.例如,您可以将SID_SWebBrowserApp服务作为IID_IWebBrowser2接口指针.
所以,分析你的原始代码:
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;
Run Code Online (Sandbox Code Playgroud)
您只是转变QueryService为QueryInterface使用服务ID(rsid),它与接口ID(iid)类似但不一定相关.因此,如果两者不同,则调用者可能会获得不兼容的接口指针.
然后,更改的代码:
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;
Run Code Online (Sandbox Code Playgroud)
这就是说该对象实现了所有可以想象的服务,因此它只是委托给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;
Run Code Online (Sandbox Code Playgroud)
如果您想提供自己的服务,可以选择使用以下代码:
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;
Run Code Online (Sandbox Code Playgroud)
SID_OverrideServiceN您要覆盖的服务ID 在哪里,并且SID_FallbackServiceN是您要回退的服务ID.请注意,我换Succeeded(Result)到Result <> E_NOTIMPL了,因为我不想继续寻找服务,如果一个竟是找到,但其他一些错误发生,例如请求的接口没有实现(E_NOINTERFACE).
| 归档时间: |
|
| 查看次数: |
665 次 |
| 最近记录: |