How to use System.Windows.Forms.WebBrowser in a web app?

17,310

Solution 1

I have successfully used System.Windows.Forms.WebBrowser in a web app.

Just follow the steps above and add AspCompat="true" in the webform page:

Thank you for all the answers.

Solution 2

You could create your own worker thread and call SetApartmentState to 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.

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.)

Share:
17,310
Mike108
Author by

Mike108

Updated on June 04, 2022

Comments

  • Mike108
    Mike108 almost 2 years

    I found a code of winform here: 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.

    1. 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.

    2. I copy the WebPageBitmap.cs into my web app.

    3. I copy the Program.cs 's Main() to my web app as a Button_Click().

    4. When I click the button in my web app. It occurs an error:

    ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.

    How can I use System.Windows.Forms.WebBrowser in a web app to get a Web Site Thumbnail?

    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

    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;
                    }
                }
            }
        }
    }