【发布时间】:2021-10-16 06:40:28
【问题描述】:
我正在尝试使用 IPersistMoniker 从 URL 加载 HTML 以添加相对 URL 基本路径,例如 <img src="foo.jpg"> 从 mypath/images/(或任何其他路径)加载。根据我发现的过程是(基于this example):
- 实现
IMoniker实例,特别是GetDisplayName(提供相对链接的URL)和BindToStorage(加载内容) -
QueryInterface的 TWebBrowser 文档为IID_IPersistMoniker -
CreateBindCtx(不知道这是干什么用的) - 使用
IPersistMoniker的Load方法加载HTML,传递来自(1) 的IMoniker实例和来自(3) 的CreateBindCtx实例
GetDisplayName 在我的实例中确实被调用,但是我应该将IStream 传递给实际 HTML 的 BindToStorage 从未被调用,因此文档总是显示为空白,未加载。 HRESULT 是E_INVALIDARG,用于调用Load。我错过了什么?
IMoniker 实现(省略了一些内容):
// Simple IMoniker implementation
class TMoniker : public IMoniker
{
private: OleVariant baseUrl;
TMemoryStream* memStream;
LONG m_cRef;
public: TMoniker(const UnicodeString& fBaseUrl, const UnicodeString& fContent)
{
m_cRef = 1; // Set to 1 so that the AddRef() doesn't need to be called when initialized the first time
this->baseUrl = fBaseUrl;
memStream = new TMemoryStream;
memStream->LoadFromFile(fContent.SubString(8,fContent.Length()));
memStream->Position = 0;
}
//--------------------------------------------------------------
// IUnknown
//--------------------------------------------------------------
STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
//--------------------------------------------------------------
// IMoniker
//--------------------------------------------------------------
STDMETHODIMP GetDisplayName(IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
{
Application->MessageBox(L"GetDisplayName", L"Info", MB_OK); // Check if method is called
// UPDATE - should be *ppszDisplayName = this->baseUrl;
ppszDisplayName = this->baseUrl;
return S_OK;
}
STDMETHODIMP BindToStorage(IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riid, void **ppvObj)
{
Application->MessageBox(L"BindToStorage", L"Info", MB_OK); // Check if method is called
ppvObj = NULL;
if (IsEqualIID(riid, IID_IStream))
{
Application->MessageBox(L"IMoniker::BindToStorage", L"Info", MB_OK);
// DelphiInterface<IStream> sa(*(new TStreamAdapter(memStream.get(), soReference)));
// ppvObj = (IStream)sa;
}
return S_OK;
}
STDMETHODIMP BindToObject(IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riidResult, void **ppvResult) { return E_NOTIMPL; }
STDMETHODIMP Reduce(IBindCtx *pbc, DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced) { return E_NOTIMPL; }
STDMETHODIMP ComposeWith(IMoniker *pmkRight, BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite) { return E_NOTIMPL; }
STDMETHODIMP Enum(BOOL fForward, IEnumMoniker **ppenumMoniker) { return E_NOTIMPL; }
STDMETHODIMP IsEqual(IMoniker *pmkOtherMoniker) { return E_NOTIMPL; }
STDMETHODIMP Hash(DWORD *pdwHash) { return E_NOTIMPL; }
STDMETHODIMP IsRunning(IBindCtx *pbc, IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning) { return E_NOTIMPL; }
STDMETHODIMP GetTimeOfLastChange(IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime) { return E_NOTIMPL; }
STDMETHODIMP Inverse(IMoniker **ppmk) { return E_NOTIMPL; }
STDMETHODIMP CommonPrefixWith(IMoniker *pmkOther, IMoniker **ppmkPrefix) { return E_NOTIMPL; }
STDMETHODIMP RelativePathTo(IMoniker *pmkOther, IMoniker **ppmkRelPath) { return E_NOTIMPL; }
STDMETHODIMP ParseDisplayName(IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut) { return E_NOTIMPL; }
STDMETHODIMP IsSystemMoniker(DWORD *pdwMksys) { return E_NOTIMPL; }
//--------------------------------------------------------------
// IPersistStream
//--------------------------------------------------------------
STDMETHODIMP IsDirty() { return E_NOTIMPL; }
STDMETHODIMP Load(IStream *pStm) { return E_NOTIMPL; }
STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty) { return E_NOTIMPL; }
STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize) { return E_NOTIMPL; }
//--------------------------------------------------------------
// IPersist
//--------------------------------------------------------------
STDMETHODIMP GetClassID(CLSID *pClassID) { return E_NOTIMPL; }
};
//------------------------------------------------------------------------------
// IUnknown::QueryInterface
//------------------------------------------------------------------------------
STDMETHODIMP TMoniker::QueryInterface(REFIID riid, void** ppv)
{
if (!ppv) return E_POINTER;
if (IID_IUnknown == riid) *ppv = (IUnknown *) this;
else if (IID_IMoniker == riid) *ppv = (IMoniker *) this;
else if (IID_IPersistStream == riid) *ppv = (IPersistStream *)this;
else if (IID_IPersist == riid) *ppv = (IPersist *) this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
// AddRef It
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
//------------------------------------------------------------------------------
// IUnknown::AddRef
//------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) TMoniker::AddRef()
{
return ::InterlockedIncrement(&m_cRef);
}
//------------------------------------------------------------------------------
// IUnknown::Release
//------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) TMoniker::Release()
{
LONG cRef = ::InterlockedDecrement(&m_cRef);
if (0 == cRef) delete this;
return cRef;
}
加载内容:
TMoniker* pMnk = new TMoniker("about:blank", "file://c:\\temp\\file.html");
LPBC pbc=0;
DelphiInterface<IHTMLDocument2> diDoc2 = WB->Document;
if (diDoc2)
{
DelphiInterface<IPersistMoniker> diPM;
if (SUCCEEDED(diDoc2->QueryInterface(IID_IPersistMoniker, (void**)&diPM)))
{
if (SUCCEEDED(CreateBindCtx(0, &pbc)))
{
// !!! returns `E_INVALIDARG` here !!!
if (SUCCEEDED(diPM->Load(TRUE, pmk, pbc, STGM_READWRITE)))
{
}
}
}
}
if (pbc) pbc->Release();
pMnk->Release();
【问题讨论】:
-
多么愚蠢的错误,我使用
ppszDisplayName = this->baseUrl;而不是*ppszDisplayName = this->baseUrl;!! -
即使使用该 fix,您仍然会遇到错误,因为您没有返回
baseUrl持有的BSTR的 copy .调用者将释放返回的字符串,因此您不希望它直接释放baseUrl的内部BSTR,这就是您现在要返回的内容。
标签: c++builder twebbrowser moniker