C# 如何在 Web 应用程序中使用 System.Windows.Forms.WebBrowser?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1119549/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use System.Windows.Forms.WebBrowser in a web app?
提问by Mike108
I found a code of winform here: http://www.wincustomize.com/articles.aspx?aid=136426&c=1
我在这里找到了一个 winform 的代码:http: //www.wincustomize.com/articles.aspx?aid=136426&c =1
And it works fine as a winform. But I want to run the code in a web app.
它作为一个 winform 运行良好。但我想在网络应用程序中运行代码。
I add the references of System.Windows.Forms and the Microsoft.mshtml.dll in the C:\Program Files\Microsoft.NET\Primary Interop Assemblies\ to my web app.
I copy the WebPageBitmap.cs into my web app.
I copy the Program.cs 's Main() to my web app as a Button_Click().
When I click the button in my web app. It occurs an error:
我将 C:\Program Files\Microsoft.NET\Primary Interop Assemblies\ 中的 System.Windows.Forms 和 Microsoft.mshtml.dll 的引用添加到我的 Web 应用程序中。
我将 WebPageBitmap.cs 复制到我的网络应用程序中。
我将 Program.cs 的 Main() 作为 Button_Click() 复制到我的网络应用程序。
当我单击 Web 应用程序中的按钮时。它发生错误:
ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.
ActiveX 控件“8856f961-340a-11d0-a96b-00c04fd705a2”无法实例化,因为当前线程不在单线程单元中。
How can I use System.Windows.Forms.WebBrowser in a web app to get a Web Site Thumbnail?
如何在 Web 应用程序中使用 System.Windows.Forms.WebBrowser 来获取网站缩略图?
public partial class Capture01 : System.Web.UI.Page
{
public delegate void WebBrowserDocumentCompletedEventHandler(object sender, WebBrowserDocumentCompletedEventArgs e);
[STAThread]
protected void Button1_Click(object sender, EventArgs e)
{
int width = 1024;
int height = 900;
int thumbwidth = width;
int thumbheight = height;
string fileName = "image01.jpg";
string url = "http://www.iweixtest.cn/WE/Site/1647/index.aspx";
thumbwidth = 150;
thumbheight = 100;
//WebPageBitmap webBitmap = new WebPageBitmap(args[0], width, height, false, 10000);
WebPageBitmap webBitmap = new WebPageBitmap(url, width, height, false, 10000);
if (webBitmap.IsOk)
{
webBitmap.Fetch();
Bitmap thumbnail = webBitmap.GetBitmap(thumbwidth, thumbheight);
//thumbnail.Save(args[1], ImageFormat.Jpeg);
thumbnail.Save(fileName, ImageFormat.Jpeg);
thumbnail.Dispose();
}
else
{
MessageBox.Show(webBitmap.ErrorMessage);
}
}
}
WebPageBitmap.cs
网页位图.cs
namespace GetSiteThumbnail
{
/// <summary>
/// Thanks for the solution to the "sometimes not painting sites to Piers Lawson
/// Who performed some extensive research regarding the origianl implementation.
/// You can find his codeproject profile here:
/// http://www.codeproject.com/script/Articles/MemberArticles.aspx?amid=39324
/// </summary>
[InterfaceType(1)]
[Guid("3050F669-98B5-11CF-BB82-00AA00BDCE0B")]
public interface IHTMLElementRender2
{
void DrawToDC(IntPtr hdc);
void SetDocumentPrinter(string bstrPrinterName, ref _RemotableHandle hdc);
}
/// <summary>
/// Code by Adam Najmanowicz
/// http://www.codeproject.com/script/Membership/Profiles.aspx?mid=923432
/// http://blog.najmanowicz.com/
/// Some improvements suggested by Frank Herget
/// http://www.artviper.net/
/// </summary>
class WebPageBitmap
{
private WebBrowser webBrowser;
private string url;
private int width;
private int height;
private bool isOk;
private string errorMessage;
public string ErrorMessage
{
get { return errorMessage; }
}
public bool IsOk
{
get { return isOk; }
set { isOk = value; }
}
public WebPageBitmap(string url, int width, int height, bool scrollBarsEnabled, int wait)
{
this.width = width;
this.height = height;
this.url =
url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) ?
url : this.url = "http://" + url;
try
// needed as the script throws an exeception if the host is not found
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(this.url);
req.AllowAutoRedirect = true;
//req.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 1.1.4322)"; //成功
req.UserAgent = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
//req.Referer = "http://www.cognifide.com";
req.ContentType = "text/html";
req.Accept = "*/*";
req.KeepAlive = false;
using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
{
string x = resp.StatusDescription;
}
}
catch (Exception ex)
{
errorMessage = ex.Message;
isOk = false;
return;
}
isOk = true; // public, to check in program.cs if the domain is found, so the image can be saved
webBrowser = new WebBrowser();
webBrowser.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(documentCompletedEventHandler);
webBrowser.Size = new Size(width, height);
webBrowser.ScrollBarsEnabled = false;
}
/// <summary>
/// Fetches the image
/// </summary>
/// <returns>true is the operation ended with a success</returns>
public bool Fetch()
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.AllowAutoRedirect = true;
//req.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 1.1.4322)";
req.UserAgent = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
//req.Referer = "http://www.cognifide.com";
req.ContentType = "text/html";
req.AllowWriteStreamBuffering = true;
req.AutomaticDecompression = DecompressionMethods.GZip;
req.Method = "GET";
req.Proxy = null;
req.ReadWriteTimeout = 20;
HttpStatusCode status;
using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
{
status = resp.StatusCode;
}
if (status == HttpStatusCode.OK || status == HttpStatusCode.Moved)
{
webBrowser.Navigate(url);
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
return true;
}
else
{
return false;
}
}
private void documentCompletedEventHandler(object sender, WebBrowserDocumentCompletedEventArgs e)
{
((WebBrowser)sender).Document.Window.Error +=
new HtmlElementErrorEventHandler(SuppressScriptErrorsHandler);
}
public void SuppressScriptErrorsHandler(object sender, HtmlElementErrorEventArgs e)
{
e.Handled = true;
MessageBox.Show("Error!");
}
internal Bitmap GetBitmap(int thumbwidth, int thumbheight)
{
IHTMLDocument2 rawDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;
IHTMLElement rawBody = rawDoc.body;
IHTMLElementRender2 render = (IHTMLElementRender2)rawBody;
Bitmap bitmap = new Bitmap(width, height);
Rectangle bitmapRect = new Rectangle(0, 0, width, height);
// Interesting thing that despite using the renderer later
// this following line is still necessary or
// the background may not be painted on some websites.
webBrowser.DrawToBitmap(bitmap, bitmapRect);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
IntPtr graphicshdc = graphics.GetHdc();
render.DrawToDC(graphicshdc);
graphics.ReleaseHdc(graphicshdc);
graphics.Dispose();
if (thumbheight == height && thumbwidth == width)
{
return bitmap;
}
else
{
Bitmap thumbnail = new Bitmap(thumbwidth, thumbheight);
using (Graphics gfx = Graphics.FromImage(thumbnail))
{
// high quality image sizing
gfx.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic; // make it look pretty
gfx.DrawImage(bitmap, new Rectangle(0, 0, thumbwidth, thumbheight), bitmapRect, GraphicsUnit.Pixel);
}
bitmap.Dispose();
return thumbnail;
}
}
}
}
}
采纳答案by Mike108
I have successfully used System.Windows.Forms.WebBrowser in a web app.
我已经在 Web 应用程序中成功使用了 System.Windows.Forms.WebBrowser。
Just follow the steps above and add AspCompat="true" in the webform page:
只需按照上述步骤并在 webform 页面中添加 AspCompat="true" 即可:
Thank you for all the answers.
谢谢大家的回答。
回答by Powerlord
The short answer is that nothing in System.Windows is intended to be used in a web app.
简短的回答是 System.Windows 中的任何内容都不能用于 Web 应用程序。
System.Windows.Forms are client controls. However, web applications run on the server side, and have their own UI elements in System.Web.UI.
System.Windows.Forms 是客户端控件。但是,Web 应用程序在服务器端运行,并且在 System.Web.UI 中有自己的 UI 元素。
mshtml may be another stumbling block. I honestly couldn't say if it would be accessible from IIS.
mshtml 可能是另一个绊脚石。老实说,我不能说它是否可以从 IIS 访问。
There may be another way to do it, but I'll let someone who knows more about it than I do answer that part.
可能有另一种方法可以做到这一点,但我会让比我更了解它的人回答那部分。
回答by Bradley Grainger
You could create your own worker thread and call SetApartmentStateto change it to an STA thread; this thread could do the work of rendering web pages. However, a lot of inter-thread communication would be required and, as R. Bemrose said, the System.Windows
classes aren't really designed to be used inside a web app.
您可以创建自己的工作线程并调用SetApartmentState将其更改为 STA 线程;这个线程可以完成渲染网页的工作。然而,将需要大量的线程间通信,而且正如 R. Bemrose 所说,这些System.Windows
类并不是真正设计为在 Web 应用程序中使用的。
Another approach would be to rewrite the sample application (as a .EXE) to take two parameters: (1) the URL to download, and (2) the output location for the screenshot image. Your web app could create a temp path (for the output file), launch this program (with Process.Start), wait for it to finish, load the output file it created, then delete the temp file once it had been sent to the client or was otherwise no longer necessary. (It would, of course, need to have different error handling than displaying a message box if something went wrong.)
另一种方法是重写示例应用程序(作为 .EXE)以采用两个参数:(1) 要下载的 URL,以及 (2) 屏幕截图图像的输出位置。您的 Web 应用程序可以创建一个临时路径(用于输出文件),启动该程序(使用Process.Start),等待它完成,加载它创建的输出文件,然后在将临时文件发送到客户或以其他方式不再需要。(当然,如果出现问题,它需要有与显示消息框不同的错误处理。)