VBGood网站全文搜索 Google

搜索VBGood全站网页(全文搜索)

VB爱好者乐园(VBGood)

 找回密码
 立即注册
搜索
查看: 21469|回复: 74

[求助] 怎么在WebBrowser里面显示内存中的图片?

  [复制链接]
 楼主| 发表于 2010-2-15 23:44:21 | 显示全部楼层 |阅读模式
如题,我在编山寨MSDN浏览器中遇到这个问题,由于要支持浏览本地数据库中的文档功能,所以我用先在WebBrowser中打开about:blank,然后从数据库中读出HTML代码,再用document.write方法写到WebBrowser中去……现在初步试验结果良好,但是MSDN中有些页面带图片,图片可以存到数据库中去,但是不知道怎样在WebBrowser中显示出内存中的图片……经百度+我自己YY想出以下几种方案,但是不是不好,就是比较麻烦:

1、把图片释放到临时文件夹。这个方法太丑陋了,我极其不愿意采用……
2、先document.body.contentEditable = True,再用document.images获取所有图片,选择相应图片后用Range.execCommand "Paste"把内存中的图片粘贴上去……经实验,不知什么原因只能粘贴文本,粘贴图片失败,没有效果……
3、本地建一个http服务器。这个方法太麻烦了吧……

不知道大家还有没有别的什么好的方法……

附:网上资料:

1、WebBrowser显示内存中的HTML,如何显示其包含的图片?图片也在内存中,不使用临时文件 http://topic.csdn.net/u/20071026 ... 8-be9b7adff89d.html

如题

#1楼  你的html和图片是怎么存放在内存中的?

#2楼  都是解压后后(文件)内存流

#3楼  打开HTML时应该有一个请求图片数据的事件或接口吧~我查一下MSDN,GOOGLE,无所获! (注:我看了一下,似乎没这个事件)

#4楼  自己写一个http服务器来提供URL转图片的服务差不多

#5楼  up

#6楼  倒,太麻烦了吧 以前马健写的Myreader是用的服务器的方法,没别的什么方法了吗?!

#7楼  主要是图片不好处理,写一个http服务器应该是最简单的办法了。 简单的http服务器网上到处都有,delphi的也可以拿直接来用...


2、把验证码图片复制过来的代码,我受到这个代码启发想到把图片粘贴到网页里面去的WS方法:http://blog.csdn.net/fish_8510/archive/2009/11/12/4802132.aspx
  1. //页面有框架
  2. HTMLDocument html = (HTMLDocument)this.webBrowser1.Document.Window.Frames["login_iframe"].Document.DomDocument;
  3.             HTMLDocument doc = (HTMLDocument)webBrowser1.Document.DomDocument;
  4.             HTMLBody body = (HTMLBody)doc.body;
  5.             IHTMLControlElement img = (IHTMLControlElement)webBrowser1.Document.Window.Frames["login_iframe"].Document.Images["imgVerify"].DomElement;
  6.             IHTMLControlRange range = (IHTMLControlRange)((HTMLBody)html.body).createControlRange();
  7.             range.add(img);
  8.             range.execCommand("Copy", false, null);
  9.             img = null;
  10.             range = null;
  11.             html = null;

  12.             if (Clipboard.ContainsImage())
  13.             {
  14.                 this.pictureBox1.Image = Clipboard.GetImage();
  15.             }
  16.             else
  17.             {
  18.                 MessageBox.Show("执行不成功");
  19.             }

  20.             Clipboard.Clear();
复制代码
 楼主| 发表于 2010-2-16 00:14:15 | 显示全部楼层
本帖最后由 acme_pjz 于 2010-2-16 00:31 编辑

又百度到方法4:自己实现一个协议(如hxxp://),图片的地址就写这个协议,返回值就是数据库里面的图片……但是这个方法似乎比建服务器还要麻烦,而且好像要写注册表,不够绿色,会被咔吧拦截……

相关文档:http://www.itzhe.cn/article/20080313/110593.html

使用webbrowser控件,打开内存中的MHT文件


我在内存中有一个MHT文件, 请问, 如何才能让WebBrowser把它显示出来, 注重:是在内存中, 而不是释放到硬盘上然后访问文件?
网友回复:用IPersistStreamInit可以向WebBrowser控件加载html的内容,有没有什么办法让其中的图片也从内存加载,而不是通过文件?
网友回复:除非你自己实现URL Moniker,否则系统无法从流中加载引用的资源,最多只能加载根文档,而不能加载根文档中指示的其它资源
网友回复:能否说的具体一些
网友回复:找到下面的帖子,但是还是不够具体.原贴如下:

For the "one file" requirement, you probably want to add the mht to your executable as a resource. This can be done by viewing the project's properties on the Resources tab. Click Add Resource, Add Existing File. Choose the file. After doing this, I would recommend changing the FileType on the Properties window to Binary.

You could now use System.IO.Path.GetTempFileName and System.IO.File.WriteAllBytes(tempFileName,

Properties.Resources.MyResourceName) to write it to a temporary file. Then use the WebBrowser.Navigate method on that temporary file.

If you really do not want to write the temp file, I think the only alternative is to implement a "temporary protocol handler" (i.e., a special prefix such as custom:// instead of http://). This is entirely COM interop and involves the IInternetSession::RegisterNameSpace method. It requires you provide classes implementing the IInternetProtocol and IInternetProtocolRoot interfaces. This may well be too much work for your scenario.

网友回复:说得很清楚了,需要自己实现一个名字空间过滤器,所有对这个名字空间的请求都会重定向到你的实现代码中,由你来负责下载文件数据,此时你就可以从流中获得需要的任何资源并返回给浏览器。你需要实现IInternetProtocol和IInternetProtocolRoot接口,最重要的方法是Start和Read
网友回复:找到下面的帖子,但是还是不够具体.原贴如下:

http://www.samool.com/delphibbs/305/3054554.htm

After very long sleeplessness, and googling, I found a way to load MHT
directly to the Webbrowser, without saving it to disk, at all.

All the images seem to render perfectly, and all comes from a Stream.

To use it, you have to use the Asynchronous Pluggable Protocol.
A sample is here:
http://www.euromind.com/iedelphi/app/namespacehandler.htm

With it, you can make a namespace, say myHTTP://www.mySite.com/ and it
works within your EXE file (available to your EXE ONLY). Then you
navigate to the myHTTP://www.mySite.com/sample.mht and then the
webbrowser uses the Asynchronouse Pluggable Protocol to provide it
with the MHT file. Once the event is fired you can provide the MHT to
it from a Memo, from a Stream which has MHT. Then the webbrowser will
navigate there. It's like a webbserver in your EXE!!! (Just an analogy).

具体代码如何实现呢?

网友回复:网上去找找如何实现Asynchronous Pluggable Protocol,有代码也有教程,记得一定要用IInternetSession::RegisterNameSpace登记后才能使用。
网友回复:在Read内如何让系统解析MHT文件呢?
网友回复:在read中如何通过特定的协议打开 mht文件
网友回复:方法1:james正解
方法2:http://www.unmht.org/unmht/en_index.html
这是个mht文件格式的ff插件,含源码(js写的解析器),我一直在用,没有碰到解析不了的mht。
网友回复:HRESULT STDMETHODCALLTYPE CSampleAPP::Read(
/* [length_is][size_is][out][in] */ void __RPC_FAR *pv,
/* [in] */ ULONG cb,
/* [out] */ ULONG __RPC_FAR *pcbRead)
{
if (lRead < filesize)
{
*pcbRead = filesize - lRead;
if (*pcbRead > cb)
*pcbRead = cb;
memcpy(pv, Buffer lRead, *pcbRead);
lRead = *pcbRead;
return S_OK;
}
return S_FALSE;


}

网友回复:
一异步插件式协议处理器
要让Internet Explorer 从内存里MHT内容显示出来需要用到异步插件式协议处理器这个非凡结构
,Internet Explorer 是通过URL 来找到需要下载的资源的位置的URL 的全称
是Uniform Resource Locators 即统一资源定位器。在Internet Explorer 中当输入一个URL 时Internet Explorer 会提取出URL 中的scheme然后到注册表中HKEY_CLASSES_ROOT\PROTOCOLS\Handler\ <scheme> 处找到一个COM类
的CLSID 这个COM 类就是一个APP 创建出这个COM 类的一个对象后Internet Explorer
会把从URL 下载资源的任务交给这个APP 对象下载的过程是这样的

1. Internet Explorer 调用异步插件式协议处理器 对象的IInternetProtocolInfo:: ParseUrl 方法告诉异步插件式协议处理器对象资源下载的地址。
2. Internet Explorer 调用异步插件式协议处理器 对象的IInternetProtocolRoot::Start 方法为了不让Internet Explorer 的用户界面因为下载尚未完成而死锁住调用过程是异步的因此这时异步插件式协议处理器 应该立即返回。
3. 异步插件式协议处理器 对象到Internet 上开始下载文件
4. 接收到数据后异步插件式协议处理器 对象回调Internet Explorer 的IInternetProtocolSink::ReportData 方法通知Internet Explorer 可以开始读取数据了
5. Internet Explorer 调用异步插件式协议处理器 的IInternetProtocol::Read 方法读取下载到的数据
说实话,我没有完全看懂……在MSDN上面找到了Asynchronous Pluggable Protocols的相关信息,先做个标记http://msdn.microsoft.com/en-us/library/aa767743(VS.85).aspx
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-2-16 00:16:31 | 显示全部楼层
还没完:
6.异步插件式协议处理器 对象回调Internet Explorer 的IInternetProtocolSink::ReportProgress 方法报告下载进程
7. 重复步骤4-6 直到文件下载完毕此时异步插件式协议处理器对象回调Internet Explorer 的
IInternetProtocolSink::ReportResult 方法告知下载结束
8. Internet Explorer 依次调用异步插件式协议处理器 对象的IInternetProtocol 接口中的LockRequest Terminate Read 和UnlockRequest 方法将剩下的数据全部读出。
这样Internet Explorer 把从URL 下载资源的任务完全交到了异步插件式协议处理器 手中同时从上面这个过程中我们可以看到Internet Explorer 并没有要求资源一定要通过网络下载


还有一点需要注重就是除了上面讲到的在注册表中注册异步插件式协议处理器 的方法外
Internet Explorer 还提供了另一种注册异步插件式协议处理器的方法即调用
IInternetSession::RegisterNameSpace 方法,用这种方法注册的异步插件式协议处理器 效果一样但注册后的异步插件式协议处理器 仅在当前进程中起作用对其他进程没有任何影响这样即使在其他进程的Internet Explorer 中输入相同的URL 也无法得到URL


网友回复:其实你这样做会麻烦很多,即使你使用了异步可插入协议,你自己还是需要了解mht文件的构造,因为你要能从这个流中自己找到需要的其它资源才能返回给浏览器。
最简单的办法还是保存成一个临时文件,然后直接让浏览器打开这个文件,用过后你可以删除文件。
网友回复:Asynchronous Pluggable Protocol 协议看懂了,如何系统如何识别MHT文件?
网友回复:找到下面的一段文字:

除了上面的协议扩展外,IE还支持NameSpace Handler以及Mime-Handler两种APP扩展。其中NameSpace扩展是对特定名字空间进行处理的协议扩展,比如假如我们注册一个对名字空间 <hubdog> ,则当IE处理http://hubdog..net、mailto:hubdog@263.net的URL 时,一旦碰到hubdog名字空间,就会调用我们的NameSpace Handler进行处理,而不管URL是基于http协议的还是ftp等其它协议的都进行处理。从实现的角度来看,NameSpace的实现方法和前面的协议扩展几乎一样,除了注册时要填写的注册表项内容不同而已。


而Mime协议扩展处理的主要是对一些非凡的媒体资源如图片,声音文件进行处理,比如下表是IE默认支持的一些媒体形式。

text/richtext

text/html

audio/x-aiff

audio/basic

audio/wav

image/gif

image/jpeg




假如那天哪天你发明一种新的音乐形式,比如扩展名为.sy,就可以注册一个Mime扩展对 .sy文件处理,让IE播放相应的声音。


Mime扩展除了需要支持IInternetProtocol接口外,还必须实现IInternetProtocolSink接口,接口定义如下:

IInternetProtocolSink = interface
['{79eac9e5-baf9-11ce-8c82-00aa004ba90b}']
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;
end;


数据通讯方式上来看,Mime扩展同一般的协议扩展差别比较大,通讯的流程是这样的:

1. 首先,IE会在碰到相应资源下载请求时,调用扩展的Start方法来启动下载过程。

2. 然后IE会调用扩展的ReportProgress方法,告知扩展被下载的数据保存的缓存文件名称。

3. 当IE下载完原始数据后,会调用扩展的ReportData方法通知扩展预备对原始数据进行加工处理。

4. 这时,扩展需要调用IE提供的IInternetProtocol接口的Read方法来获得原始数据。

5. 对原始数据处理后,扩展要调用IE的IInternetProtocolSink接口的ReportData方法通知IE数据处理完毕。

6. 最后,IE调用扩展的Read方法获得处理后的数据。

可以看出来同一般协议扩展的纯主动向IE返回数据的方式不同,Mime的数据通讯方式即有被动的接收IE获取的原始数据,也有将处理后的数据返回IE的主动通讯方式。

觉得MHT文件 系统自己能识别的
网友回复:我知道mht的格式,而且也知道该如何从流中读取mht中保存的任意一个资源,但是我认为你没有必要去深究这个问题,没有实际意义,本来能简单解决的问题,为什么一定要搞得这么复杂。
网友回复:Known MIME Types
Hard-coded tests exist for the following MIME types that currently exist in URL Moniker.

text/richtext
text/html
audio/x-aiff
audio/basic
audio/wav
image/gif
image/jpeg
image/pjpeg
image/tiff
image/x-png
image/x-xbitmap
image/bmp
image/x-jg
image/x-emf
image/x-wmf
video/avi
video/mpeg
application/postscript
application/base64
application/macbinhex40
application/pdf
application/x-compressed
application/x-zip-compressed
application/x-gzip-compressed
application/java
application/x-msdownload

网友回复:有意义的,因为开发的是网络考试治理系统,试题出现在临时文件中,轻易泄密,在使用的时候,你就不能删除临时文件,你使用完了才能删除,此时就可能出现泄密问题.
网友回复:application/base64 这个是MHT文件的 MIME吗?

网友回复:在什么时候,告诉 URL Moniker,要读取的文件类型是MHT格式?
网友回复:问题难点不在于怎么告诉moniker,而是moniker到哪获取资源,你把资源都藏起来了,神也没办法获取。

你的mht是从哪里来的?
网友回复:引用 jameshooo "我知道mht的格式,而且也知道该如何从流中读取mht中保存的任意一个资源"

jameshooo 能否告诉从流中读取mht文件的思路
网友回复:下面这个文章是 用C 解析base64编码的
http://www.adp-gmbh.ch/cpp/common/base64.html
网友回复:请问 jameshooo ie的内部是如何解析 硬盘上的MHT文件
网友回复:file://C:\abc\xxxx.mht
ie使用的是file协议,前提是要求以文件形式存在
网友回复:这个IInternetSession 注册的是全进程公用的,但是我现在要实现的是一个多线程的(或者说是有多个利用IWebbrowser的视窗)程序,对于不同的视窗,需要从不同的数据源获取数据. 如何才能把这个父窗口的相关信息传递给IInternetProtocolRoot? 类似的例子如Outlook express 显示邮件的内容的时候每个窗口看的信件都是不一样的。谢谢
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-2-16 00:20:05 | 显示全部楼层
还有更麻烦+WS的方法五:自己解析并渲染HTML(只需要实现一小部分功能就可以,反正MSDN也不会用到多少高级HTML功能,但是也是很麻烦),或者干脆不用HTML,用RTF格式或别的什么格式,但是这样也要求解析HTML并转换格式,还是很麻烦……而且也要实现渲染……
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-2-18 20:35:57 | 显示全部楼层
哈哈,用注册一个临时协议的方法,成功了!!(VB6的Bug太多,调试了半天)先贴一个图作为留念……
无标题-1.gif
回复 支持 反对

使用道具 举报

发表于 2010-2-18 22:25:25 | 显示全部楼层
老汉的印象中临时的也写注册表。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-2-18 23:53:37 | 显示全部楼层
6# msflexgrid

怎么到现在才有人来……前两天我没做出来跑到这里问问题的时候半个人也不回答……因此我决定这次连源代码和bin都不放出来,就给一个图片给你们看……

另外经注册表编辑器搜索发现,在我的程序运行的时候不存在任何一个注册表项包含hxxp,说明临时的协议不写注册表(临时的协议仅在当前进程有效)……
回复 支持 反对

使用道具 举报

发表于 2010-2-19 10:00:16 | 显示全部楼层
6# msflexgrid  

另外经注册表编辑器搜索发现,在我的程序运行的时候不存在任何一个注册表项包含hxxp,说明临时的协议不写注册表(临时的协议仅在当前进程有效)……
acme_pjz 发表于 2010-2-18 23:53

有的,系统自动建的,进程 结束会自动删除。
我以前也用临时的,不过我直接注册到http 这样比较美观


建议用监视器看,编辑器搜索太慢了吧。。。
后来我用ACX多线程,一个线程当HTTP,就不会在注册表协议了,
不过会被IE缓存另外好像在注册表的别的地方,你说过测试后发现VB引用里面多了F**Good
回复 支持 反对

使用道具 举报

发表于 2010-2-19 10:21:08 | 显示全部楼层
6# msflexgrid  

怎么到现在才有人来……前两天我没做出来跑到这里问问题的时候半个人也不回答……因此我决定这次连源代码和bin都不放出来,就给一个图片给你们看……

acme_pjz 发表于 2010-2-18 23:53

哈哈,我一般不上这个区,前几天忙着美化我的那个超极无敌宇宙最强……

不放代码也好,免得出现这种情况
http://www.vbgood.com/viewthread.php?tid=91062&highlight=

其实也不难,印象中(好像是3年前)我搞的那个临时的好像不到100行代码(含注释掉测试的代码+VB自动生成的代码)。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2010-2-19 17:41:05 | 显示全部楼层
8# msflexgrid

没有的,我就是在进程运行的时候看的,确实没有……某regmon在我这里运行BSOD……
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

文字版|手机版|小黑屋|VBGood  

GMT+8, 2019-7-17 18:20

VB爱好者乐园(VBGood)
快速回复 返回顶部 返回列表