代码之家  ›  专栏  ›  技术社区  ›  Coder12345

从IPersistMoniker加载需要很长时间才能加载无法解析的URL

  •  1
  • Coder12345  · 技术社区  · 3 年前

    我正在加载一个本地磁盘驱动器 _test.htm 归档 IPersistMoniker Load 方法据我所知,它应该将路径作为基本路径添加到相对URL中。问题是——它并没有这样做。相反,从互联网解析路径需要很长时间,直到它放弃(大约20-30秒)。我想要的是,一旦检测到无法解决的路径(因为它无论如何都是本地磁盘文件),就立即放弃。

    这是我正在加载的HTML示例:

    <html>
      <head>
        <script src="//test/test.js"></script>
      <head>
      <body>
        <img src="image.jpg">
        <img src="/image.jpg">
        <img src="//image.jpg">
      </body>
    </html>
    

    简化代码(C++Builder),无错误检查:

    WideString      URL = "file:///" + StringReplace(ExtractFilePath(Application->ExeName), "\\", "/", TReplaceFlags() << rfReplaceAll) + "_test.htm";
    TCppWebBrowser* WB  = CppWebBrowser1;
    
    DelphiInterface<IMoniker> pMoniker;
    OleCheck(CreateURLMonikerEx(NULL, URL.c_bstr(), &pMoniker, URL_MK_UNIFORM));
    
    DelphiInterface<IHTMLDocument2> diDoc2 = WB->Document;
    DelphiInterface<IPersistMoniker> pPrstMnkr;
    OleCheck(diDoc2->QueryInterface(IID_IPersistMoniker, (LPVOID*)&pPrstMnkr));
    
    DelphiInterface<IBindCtx> pBCtx;
    OleCheck(CreateBindCtx(0, &pBCtx));
    
    pPrstMnkr->Load(0, pMoniker, pBCtx, STGM_READWRITE);
    

    问题- image.jpg 负载很好,但是路径 //test/test.js /image.jpg //image.jpg 解析/加载需要很长时间。据我所知 CreateURLMonikerEx 应该使用 file:///path/to/executable/ 并将其自动预加到这些路径上,在这种情况下,它们会立即失败- file:///path/to/executable//test/test.js 例如但事实并非如此。

    我还试图搬家 形象jpg 添加到子文件夹,然后创建自定义 IMoniker GetDisplayName BindToStorage 从自定义路径加载图像的实现。但是,对于以 // / .即使我 file:///path/to/executable/ GetDisplayName 通过 *ppszDisplayName 参数

    我如何避免长时间加载这些不可用的链接(丢弃它们),或者像上面那样将它们重定向到本地路径?

    我找到了一个局部解决方案 about:blank *ppszDisplayName 但它不会加载带有有效路径的图像 形象jpg 当它加载它们时 about:image.jpg 这也是无效路径。

    此外,我还尝试添加 IDocHostUIHandler 与实现 Invoke 方法( DISPID_AMBIENT_DLCONTROL )和 pVarResult->lVal = DLCTL_NO_SCRIPTS | DLCTL_NO_JAVA | DLCTL_NO_RUNACTIVEXCTLS | DLCTL_NO_DLACTIVEXCTLS | DLCTL_NO_FRAMEDOWNLOAD | DLCTL_FORCEOFFLINE; -它完全阻止了图像的下载,但仍然会在20-30秒之间检查以 // / .

    0 回复  |  直到 3 年前
        1
  •  0
  •   Coder12345    3 年前

    更新-这不好用!

    下面的代码不太好用!问题是——它失去了 <BODY> 标记属性。装载后,车身标签完全变空。我 最后用 IHTMLDocument2.write 方法

    见: Assigning IHTMLDocument2 instance to a TWebBrowser instance

    在这里花了很多时间,没有任何指导之后,我相信当链接无效时,不可能避免这种等待20-30秒。我找到了另一个解决方案,如果有人想补充这个解决方案,请随意。

    相反,我要做的是创建一个 CLSID_HTMLDocument ( IHTMLDocument3 IHTMLDocument2 接口),然后将文档加载到该容器中,并在使用链接之前解析链接。以下是对这一点的描述:

    https://docs.microsoft.com/en-us/previous-versions/aa703592(v=vs.85)

    这也有助于:

    How to load html contents from stream and then how to create style sheet to display the html file in preview pane (like HTML preview handler)

    解析文档URL并修复无效URL后,可以将其保存/显示在实际应用程序中 TWebBrowser .

    粗略解决方案(C++Builder):

    try
        {
        DelphiInterface<IHTMLDocument2> diDoc2;
        OleCheck(CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IHTMLDocument2, (void**)&diDoc2));
    
        DelphiInterface<IPersistStreamInit> diPersist;
        OleCheck(diDoc2->QueryInterface(IID_IPersistStreamInit, (void**)&diPersist));
        OleCheck(diPersist->InitNew());
    
        DelphiInterface<IMarkupServices> diMS;
        OleCheck(diDoc2->QueryInterface(IID_IMarkupServices, (void**)&diMS));
    
        DelphiInterface<IMarkupPointer> diMkStart;
        DelphiInterface<IMarkupPointer> diMkFinish;
    
        OleCheck(diMS->CreateMarkupPointer(&diMkStart));
        OleCheck(diMS->CreateMarkupPointer(&diMkFinish));
    
        // ...Load from file or memory stream into your WideString here...
    
        DelphiInterface<IMarkupContainer> diMC;
        OleCheck(diMS->ParseString(WideString(MsgHTMLSrc).c_bstr(), 0, &diMC, diMkStart, diMkFinish));
    
        DelphiInterface<IHTMLDocument2> diDoc;
        OleCheck(diMC->QueryInterface(IID_PPV_ARGS(&diDoc)));
    
        DelphiInterface<IHTMLElementCollection> diCol;
        OleCheck(diDoc->get_all(&diCol));
    
        long ColLen = 0;
        OleCheck(diCol->get_length(&ColLen));
    
        for (int i = 0; i < ColLen; ++i)
            {
            DelphiInterface<IDispatch> diItem;
            diCol->item(OleVariant(i), OleVariant(i), &diItem);
    
            DelphiInterface<IHTMLElement> diElem;
            OleCheck(diItem->QueryInterface(IID_IHTMLElement, (void**)&diElem));
    
            WideString wTagName;
            OleCheck(diElem->get_tagName(&wTagName));
    
            if (StartsText("img", wTagName))
                {
                OleVariant vSrc;
                OleCheck(diElem->getAttribute(OleVariant("src"), 4, vSrc));
    
                // Make changes to vSrc here....
    
                // And save it back to src
                OleCheck(diElem->setAttribute(OleVariant("src"), vSrc, 0));
                }
            else if (StartsText("script", wTagName)) 
                {
                // More parsing here...
                }
            }
        }
    catch (EOleSysError& e)
        {
        // Process exception as needed
        }
    catch (Exception& e)
        {
        // Process exception as needed
        }
    

    在完全解析所有必需元素之后( img / src , script / src , base / href 等)保存并加载到 特威布朗瑟 .

    我现在只需要看看解析后的HTML IHTMLDocument2 可以直接分配给 特威布朗瑟 但这是另一个问题(参见- 将IHTMLDocument2实例分配给TWebBrowser实例 )

    推荐文章