none
WebBrowser AccessViolationException RRS feed

  • Вопрос

  • Здравствуйте, подскажите как избавиться от исключения AccessViolationException в WebBrowser.

    Возникает оно не периодически бывает через 100000 загрузок сайта, а бывает через 10, в общем не предсказуемо.

    Задача стоит в том, что бы получать запрос сайта через асинхронный сокет, и в ответ посылать скрин сайта.

    Это код для работы сокета ->

     

    using System;
    using System.Text;
    using System.Net.Sockets;
    using System.Threading;
    using System.Net;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace WebShotServer.Classes
    {
     public class Listener
     {
      private static Parameters parameters;
      private Socket listener;
    
      private static ManualResetEvent allDone = new ManualResetEvent(false);
    
      private class StateObject
      {
       public Socket workSocket = null;
       public const int bufferSize = 1024;
       public byte[] buffer = new byte[bufferSize];
       public StringBuilder sb = new StringBuilder();
      }
    
      public Listener(Parameters param)
      {
       parameters = param;
       this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
       this.listener.Bind(new IPEndPoint(IPAddress.Any, parameters.port));
       this.listener.Listen(1000);
      }
    
      public void START()
      {
       try
       {
        Console.WriteLine("\n--------------------------------------------\nОжидание соединения...");
        while (true)
        {
         allDone.Reset();
         listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
         allDone.WaitOne();
        }
    
       }
       catch (SocketException error)
       {
        Console.WriteLine(error.ToString());
       }
      }
    
      public static void AcceptCallback(IAsyncResult ar)
      {
       allDone.Set();
    
       Socket listen = (Socket)ar.AsyncState;
       Socket handler = listen.EndAccept(ar);
    
       StateObject state = new StateObject();
       state.workSocket = handler;
    
       handler.BeginReceive(state.buffer, 0, StateObject.bufferSize, 0,
        new AsyncCallback(ReadCallback), state);
      }
    
      public static void ReadCallback(IAsyncResult ar)
      {
       
    
       String messageURL = String.Empty;
    
       StateObject state = (StateObject)ar.AsyncState;
       Socket WorkSocket = state.workSocket;
    
       int bytesRead = WorkSocket.EndReceive(ar);
    
       if (bytesRead > 0)
       {
        messageURL = Encoding.Unicode.GetString(state.buffer, 0, bytesRead);
    
        Console.WriteLine("Запрос миниатюры по адресу: {0}", messageURL);
    
        Thumbnail thumbnail = new Thumbnail(parameters, messageURL);
    
        Thread thread = new Thread(thumbnail.GetThumbnail);
    
    
        thread.SetApartmentState(ApartmentState.STA);
    
    
        thread.Start();
    
    
        thread.Join();
    
    
        Image webShot = thumbnail.resultThumbnail;
     
    
    
        ImageConverter imageConverter = new ImageConverter();
    
        byte[] byteData = (byte[])imageConverter.ConvertTo(webShot, typeof(byte[]));
    
        int size = byteData.Length;
    
        byte[] datasize = new byte[4];
    
        datasize = BitConverter.GetBytes(size);
    
        PicSize picSize = new PicSize();
    
        picSize.WorkSocket = WorkSocket;
        picSize.datasize = datasize;
        picSize.pic = byteData;
    
    
        //уничтожаем
        webShot.Dispose();
        
        byteData = null;
        imageConverter = null;
        thread.Abort();
        
        thread = null;
        thumbnail = null;
        messageURL = null;
    
        WorkSocket.BeginSend(picSize.datasize, 0, datasize.Length, 0, new AsyncCallback(SendCallbackOne), picSize);
       }
      }
    
      public class PicSize
      {
       public Socket WorkSocket;
       public byte[] datasize;
       public byte[] pic;
      }
    
      private static void SendCallbackOne(IAsyncResult ar)
      {
       try
       {
        PicSize picsize = (PicSize)ar.AsyncState;
    
        Socket handler = picsize.WorkSocket;
    
        int bytesSent = handler.EndSend(ar);
    
        handler.BeginSend(picsize.pic, 0, picsize.pic.Length, 0, new AsyncCallback(SendCallbackTwo), handler);
    
       }
       catch (Exception error)
       {
        Console.WriteLine(error.ToString());
       }
    
    
      }
    
      private static void SendCallbackTwo(IAsyncResult ar)
      {
       try
       {
        Socket handler = (Socket)ar.AsyncState;
    
        int bytesSent = handler.EndSend(ar);
    
        Console.WriteLine("- Миниатюра сайта отправлена клиенту.");
    
        handler.Shutdown(SocketShutdown.Both);
        handler.Close();
       }
       catch (Exception error)
       {
        Console.WriteLine(error.ToString());
       }
    
      }
     }
    }
    
    

     


    А это собственно класс для получения скриншота ->

     

    using System;
    using System.Net;
    using System.Drawing;
    using System.Windows.Forms;
    using System.Drawing.Drawing2D;
    using System.Security.Permissions;
    using System.Threading;
    
    namespace WebShotServer.Classes
    {
     [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
     public class Thumbnail
     {
      public string errorMessage;
      private HttpWebRequest webRequest;
      public Bitmap resultThumbnail;
      private Parameters parameters;
      private string url;
      
      private object loker = new object();
    
      public Thumbnail(Parameters parameters, string url)
      {
       this.parameters = parameters;
       this.url = url;
       this.resultThumbnail = null;
       this.webRequest = null;
       this.errorMessage = null;
      }
    
      [STAThread]
      public void GetThumbnail()
      {
    
       lock (loker)
       {
    
        this.url =
         this.url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) ?
         this.url : this.url = "http://" + this.url;
    
        try
        {
         this.webRequest = (HttpWebRequest)WebRequest.Create(url);
         this.webRequest.AllowAutoRedirect = true;
         this.webRequest.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)";
         this.webRequest.Referer = "http://www.ru";
         this.webRequest.ContentType = "text/html";
         this.webRequest.Accept = "*/*";
         this.webRequest.KeepAlive = false;
    
         using (HttpWebResponse webResponse = (HttpWebResponse)this.webRequest.GetResponse())
         {
          string x = webResponse.StatusDescription;
         }
        }
        catch (Exception error)
        {
         this.errorMessage = error.Message;
         this.resultThumbnail = ReturnErrorThumbnail(0);
         this.parameters = null;
         this.url = null;
         this.webRequest = null;
         
         return;
        }
    
        WebBrowser webBrowser = new WebBrowser();
    
        webBrowser.Size = new Size(this.parameters.browserWidth, this.parameters.browserHeight);
        webBrowser.ScrollBarsEnabled = false;
        webBrowser.ScriptErrorsSuppressed = true;
    
        this.webRequest = (HttpWebRequest)WebRequest.Create(url);
        this.webRequest.AllowAutoRedirect = true;
        this.webRequest.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)";
        this.webRequest.Referer = "http://www.ru";
        this.webRequest.ContentType = "text/html";
        this.webRequest.AllowWriteStreamBuffering = true;
        this.webRequest.AutomaticDecompression = DecompressionMethods.GZip;
        this.webRequest.Method = "GET";
        this.webRequest.Proxy = null;
        this.webRequest.ReadWriteTimeout = 20;
    
        HttpStatusCode status;
    
        try
        {
         using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
         {
          status = webResponse.StatusCode;
         }
        }
        catch (Exception error)
        {
         this.errorMessage = error.Message;
         this.resultThumbnail = ReturnErrorThumbnail(0);
    
         webBrowser.Dispose();
         this.parameters = null;
         this.url = null;
         this.webRequest = null;
         return;
        }
    
        if (status == HttpStatusCode.OK || status == HttpStatusCode.Moved)
        {
         webBrowser.Navigate(url);
    
         try
         {
          System.Timers.Timer timer = new System.Timers.Timer(parameters.timeOut);
          timer.AutoReset = false;
          timer.Start();
    
    
          while ((webBrowser.ReadyState.ToString() != "Complete"))
          {
    
           if (timer.Enabled == false)
           {
            this.resultThumbnail = ReturnErrorThumbnail(0);
            timer.Dispose();
            webBrowser.Dispose();
            this.parameters = null;
            this.url = null;
            this.webRequest = null;
            Console.WriteLine("\n---Время ожидания вышло.---\n");
            return;
           }
           Application.DoEvents();
          }
         }
         catch (AccessViolationException error)
         {
          Console.WriteLine(error.ToString());
          this.resultThumbnail = ReturnErrorThumbnail(0);
          webBrowser.Dispose();
          this.parameters = null;
          this.url = null;
          this.webRequest = null;
          return;
         }
        }
        else
        {
         this.resultThumbnail = ReturnErrorThumbnail(0);
         this.parameters = null;
         this.url = null;
         this.webRequest = null;
         webBrowser.Dispose();
         return;
        }
    
        if (this.parameters.browserAbsolute)
        {
         webBrowser.Width = webBrowser.Document.Body.ScrollRectangle.Width;
         webBrowser.Height = webBrowser.Document.Body.ScrollRectangle.Height;
        }
    
        Bitmap bitmap = new Bitmap(this.parameters.browserWidth, this.parameters.browserHeight);
        Rectangle bitmapRect = new Rectangle(0, 0, this.parameters.browserWidth, this.parameters.browserHeight);
    
        webBrowser.DrawToBitmap(bitmap, bitmapRect);
    
        if (this.parameters.picHeight == this.parameters.browserHeight &&
         this.parameters.picWidth == this.parameters.browserWidth)
        {
         this.resultThumbnail = (Bitmap)bitmap.Clone();
    
         this.parameters = null;
         this.url = null;
         this.webRequest = null;
         webBrowser.Dispose();
         bitmap.Dispose();
         return;
        }
        else
        {
         Bitmap thumbnail = new Bitmap(this.parameters.picWidth, this.parameters.picHeight);
         using (Graphics graphics = Graphics.FromImage(thumbnail))
         {
          graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
          graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
          graphics.DrawImage(bitmap, new Rectangle(0, 0, this.parameters.picWidth, this.parameters.picHeight), bitmapRect, GraphicsUnit.Pixel);
         }
    
    
         this.parameters = null;
         this.url = null;
         this.webRequest = null;
         webBrowser.Dispose();
    
         resultThumbnail = (Bitmap)thumbnail.Clone();
    
         bitmap.Dispose();
         thumbnail.Dispose();
    
        }
       }
      }
    
      private Bitmap ReturnErrorThumbnail(int codeError)
      {
       //обработка кода ошибки 
       return new Bitmap(this.parameters.picWidth, this.parameters.picHeight);
      }
     }
    }
    
    

    А вот и сама ошибка ->

    System.AccessViolationException не обработано

      Message=Попытка чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена.

      Source=mscorlib

      StackTrace:

           в System.StubHelpers.InterfaceMarshaler.ConvertToManaged(IntPtr pUnk, IntPtr itfMT, IntPtr classMT, Int32 flags)

           в System.Windows.Forms.UnsafeNativeMethods.IHTMLDocument2.GetLocation()

           в System.Windows.Forms.WebBrowser.get_Document()

           в System.Windows.Forms.WebBrowser.get_ReadyState()

           в WebShotServer.Classes.Thumbnail.GetThumbnail() в D:\!Work\WEBSHOT\WebShot\WebShotServer\Classes\Thumbnail.cs:строка 117

           в System.Threading.ThreadHelper.ThreadStart_Context(Object state)

           в System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)

           в System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

           в System.Threading.ThreadHelper.ThreadStart()

      InnerException: 

     

     

     


    15 августа 2011 г. 7:56

Ответы

  • > А сколько итераций вы ждали?

    ~300. видимо, повезло. ошибка появилась после перезагрузки системы.
    значит код надо переделать так, чтобы в потоке был messageloop и вместо проверки ReadyState перехватывать DocumentCompleted:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication9
    {
      using System;
      using System.Drawing;
      using System.Threading;
      using System.Windows.Forms;
      using System.Runtime.InteropServices;
    
      namespace WebBrowserInConsoleForMSDN
      {
        class Program
        {
          static void Main(string[] args)
          {
            int i = 0;
            while (true)
            {
              for (int j = 0; j < 5; j++)
              {
                Thread thread = new Thread(Start);
                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();
                Console.WriteLine(i++);
              }
              Thread.Sleep(600);
            }
          }
    
          static void Start()
          {
            var ac = new ApplicationContext();
            Application.Idle += delegate
            {
              Thumbnail thumbnail = new Thumbnail(ac);
              thumbnail.GetThumbnail();
            };
            Application.Run(ac);
          }
        }
    
        public class Thumbnail
        {
          [DllImport("user32.dll")]
          static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr hdc, uint drawingOptions);
    
          public Thumbnail(ApplicationContext ac) { _Context = ac; }
          private bool _Complete = false;
          private ApplicationContext _Context;
          private string url = "http://localhost";
          public void GetThumbnail()
          {
            using (WebBrowser webBrowser = new WebBrowser())
            {
              webBrowser.Size = new Size(400, 400);
              webBrowser.ScrollBarsEnabled = false;
              webBrowser.ScriptErrorsSuppressed = true;
              webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);
              webBrowser.Navigate(url);
              while (!_Complete) Application.DoEvents();
              _Context.ExitThread();
            }
          }
    
          void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
          {
            var webBrowser = (WebBrowser)sender;
            using (Image img = new Bitmap(webBrowser.Width, webBrowser.Height))
            {
              // получить изображение
              uint flags = 0x04 /*CLIENT*/ | 0x10 /*NONCLIENT*/ | 0x08 /*ERASEBKGND*/;
              using (Graphics g = Graphics.FromImage(img))
                SendMessage(webBrowser.Handle, 0x317 /*WM_PRINT*/, g.GetHdc(), flags);
              
              // ...
            }
            Console.WriteLine("\tОК");
            _Complete = true;
          }
        }
      }
    }
    

     

     

     

     

    • Предложено в качестве ответа Malobukv 17 августа 2011 г. 8:24
    • Помечено в качестве ответа Da1mon 17 августа 2011 г. 19:54
    17 августа 2011 г. 8:18
  • в класс Thumbnail надо добавить свойство Result, событие ResultChanged и изменить метод webBrowser_DocumentCompleted:
    public event EventHandler ResultChanged = delegate { };
    public Image Result { get; private set; }
    void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
      var webBrowser = (WebBrowser)sender;
    
      // получить изображение
      Image img = new Bitmap(webBrowser.Width, webBrowser.Height);
      uint flags = 0x04 /*CLIENT*/ | 0x10 /*NONCLIENT*/ | 0x08 /*ERASEBKGND*/;
      using (Graphics g = Graphics.FromImage(img))
        SendMessage(webBrowser.Handle, 0x317 /*WM_PRINT*/, g.GetHdc(), flags);
            
      // сохранить результат и уведомить подписчиков.
      this.Result = img;
      this.ResultChanged(this, EventArgs.Empty);
    
      Console.WriteLine("\tОК");
      _Complete = true;
    }
    
    также в методе, в котором создается Thumbnail, надо подключить обработчик к событию Thumbnail.ResultChanged.
    если Thumbnail'ов много, то их хранить в коллекции и удалять из коллекции в момент события Thumbnail.ResultChanged.
    • Предложено в качестве ответа Malobukv 19 августа 2011 г. 14:41
    • Помечено в качестве ответа Malobukv 20 августа 2011 г. 6:08
    19 августа 2011 г. 14:40

Все ответы

  • вместо while ((webBrowser.ReadyState.ToString() != "Complete")) { ... Application.DoEvents(); }
    попробуйте так:  
    while ((webBrowser.ReadyState != WebBrowserReadyState.Complete)) {
       Application.DoEvents();    // WebBrowser выполнит все что ему требуется до своего Dispose, если timer остановлен
       if (timer.Enabled == false) ... 
    }

    15 августа 2011 г. 8:52
  • вместо while ((webBrowser.ReadyState.ToString() != "Complete")) { ... Application.DoEvents(); }
    попробуйте так:  
    while ((webBrowser.ReadyState != WebBrowserReadyState.Complete)) {
       Application.DoEvents();    // WebBrowser выполнит все что ему требуется до своего Dispose, если timer остановлен
       if (timer.Enabled == false) ... 
    }

    Не без разницы,я побывал все равно вылетает исключение. 

    Пробовал вообще без таймера, та же самая история.

    Мне кажется что тут проблема с приватностью доступа и потоками, но что именно я не знаю.

    Забыл уточнить ошибка возникает при чтении свойства ReadyState
    15 августа 2011 г. 9:07
  • какая версия .NET? у меня 4.0 работает нормально. ниже фрагмент на почти C# (просто VS далеко) ... думаю, будет понятно:

    var ev = new Threading.ManualResetEvent(false)
    var thumbnail = null
    void run() {    // метод должен выполняться в отдельном STA-потоке
       var wb = new WebBrowser()
       // подключаем обработчик; вызывается раньше чем завершится while;
       wb.DocumentCompleted +=  {
           if e.Url = wb.Url then    // т.к. событие возникает для каждого iframe
               // здесь создаем thumbnail 
               thumbnail = ...
               ev.Set()   // отпускаем вызвавший поток  
       }
      // загружаем страницу
      wb.Navigate(url)
      // ждем 
      while wb.IsBusy || wb.ReadyState != WebBrowserReadyState.Complete {
         Application.DoEvents() }
    }
    // ждем вызов ev.Set(); текущий поток блокируется
    var res = ev.WaitOne(1000)   // блокировка снимается, если ev.Set() не будет вызван в течение 1 сек.
    if res = true {
          // скриншот получен вовремя
          thumbnail ...
    }

    15 августа 2011 г. 15:25
  • какая версия .NET? у меня 4.0 работает нормально. ниже фрагмент на почти C# (просто VS далеко) ... думаю, будет понятно:

    var ev = new Threading.ManualResetEvent(false)
    var thumbnail = null
    void run() {    // метод должен выполняться в отдельном STA-потоке
       var wb = new WebBrowser()
       // подключаем обработчик; вызывается раньше чем завершится while;
       wb.DocumentCompleted +=  {
           if e.Url = wb.Url then    // т.к. событие возникает для каждого iframe
               // здесь создаем thumbnail 
               thumbnail = ...
               ev.Set()   // отпускаем вызвавший поток  
       }
      // загружаем страницу
      wb.Navigate(url)
      // ждем 
      while wb.IsBusy || wb.ReadyState != WebBrowserReadyState.Complete {
         Application.DoEvents() }
    }
    // ждем вызов ev.Set(); текущий поток блокируется
    var res = ev.WaitOne(1000)   // блокировка снимается, если ev.Set() не будет вызван в течение 1 сек.
    if res = true {
          // скриншот получен вовремя
          thumbnail ...
    }

    Ок, попробую переписать потестить.

    15 августа 2011 г. 16:17
  • > это у вас mono?

    это ленивый-C# :) просто набирал прямо здесь в редакторе.

    15 августа 2011 г. 16:28
  • Не та же самая история.
    15 августа 2011 г. 16:40
  • попробуйте создать отдельный проект. обычное windows приложение. в котором будет только код загрузки webbrowser. без permissions.
    а еще лучше вначале проверить работает ли загрузка в webbrowser, когда он находится на form.

    15 августа 2011 г. 17:39
  • попробуйте создать отдельный проект. обычное windows приложение. в котором будет только код загрузки webbrowser. без permissions.
    а еще лучше вначале проверить работает ли загрузка в webbrowser, когда он находится на form.

    Ну собственно сделал простенькое консольное приложение для тестинга - запускается бесконечный цикл, в каждой итерации запускаться 5 потоков для загрузки webBrowser, в итоге ошибка осталась, на все том же ReadyState :(

    Вот код -> 

    using System;
    using System.Drawing;
    using System.Threading;
    using System.Windows.Forms;
    
    namespace WebBrowserInConsoleForMSDN
    {
      class Program
      {
        static void Main(string[] args)
        {
          int i = 0;
          while (true)
          {
            for (int j = 0; j < 5; j++)
            {
              Thumbnail thumbnail = new Thumbnail();
              Thread thread = new Thread(thumbnail.GetThumbnail);
              thread.SetApartmentState(ApartmentState.STA);
              thread.Start();
              Console.WriteLine(i++.ToString());
            }
            Thread.Sleep(300);
          }
        }
      }
    
      public class Thumbnail
      {
        private string url = "http://localhost:3012/Default.aspx";
        public void GetThumbnail()
        {
          WebBrowser webBrowser = new WebBrowser();
          webBrowser.Size = new Size(400, 400);
          webBrowser.ScrollBarsEnabled = false;
          webBrowser.ScriptErrorsSuppressed = true;
          webBrowser.Navigate(url);
    
          while ((webBrowser.ReadyState != WebBrowserReadyState.Complete))
          {
            Application.DoEvents();
          }
    
          Bitmap bitmap = new Bitmap(400, 400);
          Rectangle bitmapRect = new Rectangle(0, 0, 400, 400);
          webBrowser.DrawToBitmap(bitmap, bitmapRect);
          Console.WriteLine("\tОК");
        }
      }
    }
    


    16 августа 2011 г. 9:48
  • только что проверил. работает без ошибок в Microsoft Visual Studio 2010 Version 10.0.40219.1 SP1Rel, Microsoft .NET Framework Version 4.0.30319 SP1Rel, все Hotfix установлены. браузер IE9 version 9.0.8112.16421

    16 августа 2011 г. 12:54
  • только что проверил. работает без ошибок в Microsoft Visual Studio 2010 Version 10.0.40219.1 SP1Rel, Microsoft .NET Framework Version 4.0.30319 SP1Rel, все Hotfix установлены. браузер IE9 version 9.0.8112.16421

    А сколько итераций вы ждали?

    Я два раза запускал, первый раз на 273 вылетела, второй раз на 3564.

    И виснет не только у меня, во первых пробывал сам на других машинах + у людей в интернете тоже такие проблемы.

    У меня Win7 x64 sp1, студия, фраймворк и IE такие же.

    16 августа 2011 г. 19:10
  • > А сколько итераций вы ждали?

    ~300. видимо, повезло. ошибка появилась после перезагрузки системы.
    значит код надо переделать так, чтобы в потоке был messageloop и вместо проверки ReadyState перехватывать DocumentCompleted:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication9
    {
      using System;
      using System.Drawing;
      using System.Threading;
      using System.Windows.Forms;
      using System.Runtime.InteropServices;
    
      namespace WebBrowserInConsoleForMSDN
      {
        class Program
        {
          static void Main(string[] args)
          {
            int i = 0;
            while (true)
            {
              for (int j = 0; j < 5; j++)
              {
                Thread thread = new Thread(Start);
                thread.SetApartmentState(ApartmentState.STA);
                thread.Start();
                Console.WriteLine(i++);
              }
              Thread.Sleep(600);
            }
          }
    
          static void Start()
          {
            var ac = new ApplicationContext();
            Application.Idle += delegate
            {
              Thumbnail thumbnail = new Thumbnail(ac);
              thumbnail.GetThumbnail();
            };
            Application.Run(ac);
          }
        }
    
        public class Thumbnail
        {
          [DllImport("user32.dll")]
          static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr hdc, uint drawingOptions);
    
          public Thumbnail(ApplicationContext ac) { _Context = ac; }
          private bool _Complete = false;
          private ApplicationContext _Context;
          private string url = "http://localhost";
          public void GetThumbnail()
          {
            using (WebBrowser webBrowser = new WebBrowser())
            {
              webBrowser.Size = new Size(400, 400);
              webBrowser.ScrollBarsEnabled = false;
              webBrowser.ScriptErrorsSuppressed = true;
              webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);
              webBrowser.Navigate(url);
              while (!_Complete) Application.DoEvents();
              _Context.ExitThread();
            }
          }
    
          void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
          {
            var webBrowser = (WebBrowser)sender;
            using (Image img = new Bitmap(webBrowser.Width, webBrowser.Height))
            {
              // получить изображение
              uint flags = 0x04 /*CLIENT*/ | 0x10 /*NONCLIENT*/ | 0x08 /*ERASEBKGND*/;
              using (Graphics g = Graphics.FromImage(img))
                SendMessage(webBrowser.Handle, 0x317 /*WM_PRINT*/, g.GetHdc(), flags);
              
              // ...
            }
            Console.WriteLine("\tОК");
            _Complete = true;
          }
        }
      }
    }
    

     

     

     

     

    • Предложено в качестве ответа Malobukv 17 августа 2011 г. 8:24
    • Помечено в качестве ответа Da1mon 17 августа 2011 г. 19:54
    17 августа 2011 г. 8:18
  • Протестировал, все работает отлично :)

    Спасибо вам огромное за помощь!

    Надо почитать про messageLoop, можете что нибудь посоветовать, желательно на русском?


    17 августа 2011 г. 19:57
  • > Надо почитать про messageLoop

    http://www.gotdotnet.ru/blogs/msdn/6349/ - Простая и безопасная реализация многопоточности в Windows Forms. (есть схема Window message queue и потоков).
    http://msdn.microsoft.com/ru-ru/magazine/cc163417.aspx - Обработка сообщения в консольных приложениях.

    17 августа 2011 г. 23:38
  • Извинить за тупой вопрос, но как тогда добраться до изображение, из последнего листинга, в главный метод Main???
    19 августа 2011 г. 10:58
  • в класс Thumbnail надо добавить свойство Result, событие ResultChanged и изменить метод webBrowser_DocumentCompleted:
    public event EventHandler ResultChanged = delegate { };
    public Image Result { get; private set; }
    void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
      var webBrowser = (WebBrowser)sender;
    
      // получить изображение
      Image img = new Bitmap(webBrowser.Width, webBrowser.Height);
      uint flags = 0x04 /*CLIENT*/ | 0x10 /*NONCLIENT*/ | 0x08 /*ERASEBKGND*/;
      using (Graphics g = Graphics.FromImage(img))
        SendMessage(webBrowser.Handle, 0x317 /*WM_PRINT*/, g.GetHdc(), flags);
            
      // сохранить результат и уведомить подписчиков.
      this.Result = img;
      this.ResultChanged(this, EventArgs.Empty);
    
      Console.WriteLine("\tОК");
      _Complete = true;
    }
    
    также в методе, в котором создается Thumbnail, надо подключить обработчик к событию Thumbnail.ResultChanged.
    если Thumbnail'ов много, то их хранить в коллекции и удалять из коллекции в момент события Thumbnail.ResultChanged.
    • Предложено в качестве ответа Malobukv 19 августа 2011 г. 14:41
    • Помечено в качестве ответа Malobukv 20 августа 2011 г. 6:08
    19 августа 2011 г. 14:40
  • Ага, все понял, еще раз спасибо :)
    19 августа 2011 г. 19:55