¿Sería algo válido representar el segundo webbrowser o "reflejo" como una simple imagen estática o captura del primer webbroser?, o por lo contrario ambos webbrowsers tienen que ser "utilizables"?
Lo primero te ahorraría muchos comecocos de cerebro:
Para dicha metodología puedes tomar como referencia para analizar el código y llevarlo a cabo con las fucniones
TakeScreenshotFromRegion o
TakeScreenshotFromObject, preferiblemente esta última, ya que la captura mediante regíon pues... es eso, una región del escritorio, donde si superpones ventanas encima del webbrowser éstas se capturarán.
Las funciones las puedes encontrar en el código fuente de mi API ElektroKit:
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Takes a screenshot of a screen region.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code>
''' Dim jpgCodec As ImageCodecInfo =
''' (From codec As ImageCodecInfo In ImageCodecInfo.GetImageDecoders
''' Where codec.FormatID = ImageFormat.Jpeg.Guid).SingleOrDefault
'''
''' Dim encoderParams As New EncoderParameters(1)
''' Dim qualityEncoder As Imaging.Encoder = Imaging.Encoder.Quality
''' Dim qualityParameter As New EncoderParameter(qualityEncoder, 80)
''' encoderParams.Param(0) = qualityParameter
'''
''' Dim screenShot As Image = TakeScreenshotFromRegion(New Point(0, 0), New Size(256, 256), includeMouse:=True)
''' screenShot.Save("C:\Screenshot.jpg", jpgCodec, encoderParams)
''' Process.Start("C:\Screenshot.jpg")
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <param name="location">
''' The X-coordinate is the point at the upper-left corner of the region.
''' The Y-coordinate is the point at the upper-left corner of the region.
''' </param>
'''
''' <param name="size">
''' The size of the area to be transferred.
''' </param>
'''
''' <param name="includeMouse">
''' If set to <see langword="True"/>, the mouse is drawn in the resulting image.
''' </param>
'''
''' <param name="pixelFormat">
''' The image pixel format.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The resulting image.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Function TakeScreenshotFromRegion(ByVal location As Drawing.Point,
ByVal size As System.Drawing.Size,
Optional ByVal includeMouse As Boolean = False,
Optional ByVal pixelFormat As PixelFormat = PixelFormat.Format24bppRgb) As Image
Dim bmp As New Bitmap(size.Width, size.Height, pixelFormat)
Using g As Graphics = Graphics.FromImage(bmp)
g.InterpolationMode = InterpolationMode.Default
g.PixelOffsetMode = PixelOffsetMode.Default
g.CopyFromScreen(location, Drawing.Point.Empty, bmp.Size)
' Draw the cursor in the image.
If includeMouse Then
Dim mousePoint As Drawing.Point = Control.MousePosition
mousePoint.X -= location.X
mousePoint.Y -= location.Y
Cursors.Arrow.Draw(g, New Rectangle(mousePoint.X, mousePoint.Y, Cursors.Arrow.Size.Width, Cursors.Arrow.Size.Height))
End If
End Using
Return bmp
End Function
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Takes a screenshot of an object in the screen.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <example> This is a code example.
''' <code>
''' Dim jpgCodec As ImageCodecInfo =
''' (From codec As ImageCodecInfo In ImageCodecInfo.GetImageDecoders
''' Where codec.FormatID = ImageFormat.Jpeg.Guid).SingleOrDefault
'''
''' Dim encoderParams As New EncoderParameters(1)
''' Dim qualityEncoder As Imaging.Encoder = Imaging.Encoder.Quality
''' Dim qualityParameter As New EncoderParameter(qualityEncoder, 80)
''' encoderParams.Param(0) = qualityParameter
'''
''' Dim hwnd As IntPtr = Process.GetProcessesByName("notepad").FirstOrDefault.MainWindowHandle
'''
''' Dim screenShot As Image = TakeScreenshotFromObject(hwnd, includeMouse:=True)
''' screenShot.Save("C:\Screenshot.jpg", jpgCodec, encoderParams)
''' Process.Start("C:\Screenshot.jpg")
''' </code>
''' </example>
''' ----------------------------------------------------------------------------------------------------
''' <param name="hwnd">
''' The <see cref="IntPtr"/> window handle to the object.
''' </param>
'''
''' <param name="includeMouse">
''' If set to <see langword="True"/>, the mouse is drawn in the resulting image.
''' </param>
'''
''' <param name="pixelFormat">
''' The image pixel format.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The resulting image.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="System.ComponentModel.Win32Exception">
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Function TakeScreenshotFromObject(ByVal hwnd As IntPtr,
Optional ByVal includeMouse As Boolean = False,
Optional ByVal pixelFormat As PixelFormat = PixelFormat.Format24bppRgb) As Image
' Activate the object window. Don't care about Win32 error code.
NativeMethods.SetForegroundWindow(hwnd)
NativeMethods.ShowWindow(hwnd, WindowState.Normal)
Dim result As Boolean
Dim win32Err As Integer
Dim win32rect As Rect
result = NativeMethods.GetWindowRect(hwnd, win32rect)
win32Err = Marshal.GetLastWin32Error
If Not (result) Then
Throw New Win32Exception([error]:=win32Err)
Else
Dim rect As Rectangle = win32rect
Dim bmp As New Bitmap(rect.Size.Width, rect.Size.Height, pixelFormat)
Using g As Graphics = Graphics.FromImage(bmp)
g.InterpolationMode = InterpolationMode.Default
g.PixelOffsetMode = PixelOffsetMode.Default
g.CopyFromScreen(rect.Location, New Drawing.Point(0, 0), bmp.Size)
' Draw the cursor in the image.
If includeMouse Then
Dim mousePoint As Drawing.Point = Control.MousePosition
mousePoint.X -= rect.Location.X
mousePoint.Y -= rect.Location.Y
Cursors.Arrow.Draw(g, New Rectangle(mousePoint.X, mousePoint.Y, Cursors.Arrow.Size.Width, Cursors.Arrow.Size.Height))
End If
End Using
Return bmp
End If
End Function
( los P/Invokes referenciados en el bloque de la función
TakeScreenshotFromObject los puedes encontrar en la class
NativeMethods del Namespace
ElektroKit.Interop.Win32 )
Ejemplo de uso que utilicé para la imagen GIF de arriba:
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Public NotInheritable Class Form1 : Inherits Form
Dim img As Image
Private Sub Form1_Shown(ByVal sender As Object, ByVal e As EventArgs) _
Handles MyBase.Shown
Timer1.Interval = 30
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If (img IsNot Nothing) Then
img.Dispose()
End If
img = TakeScreenshotFromRegion(Me.PointToScreen(WebBrowser1.Location), WebBrowser1.Size, CheckBox1.Checked)
PictureBox1.BackgroundImage = img
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
WebBrowser1.Navigate(TextBox1.Text)
End Sub
Public Shared Function TakeScreenshotFromRegion(ByVal location As Drawing.Point,
ByVal size As System.Drawing.Size,
Optional ByVal includeMouse As Boolean = False,
Optional ByVal pixelFormat As PixelFormat = PixelFormat.Format24bppRgb) As Image
Dim bmp As New Bitmap(size.Width, size.Height, pixelFormat)
Using g As Graphics = Graphics.FromImage(bmp)
g.InterpolationMode = InterpolationMode.Default
g.PixelOffsetMode = PixelOffsetMode.Default
g.CopyFromScreen(location, Drawing.Point.Empty, bmp.Size)
If includeMouse Then
Dim mousePoint As Drawing.Point = Control.MousePosition
mousePoint.X -= location.X
mousePoint.Y -= location.Y
Cursors.Arrow.Draw(g, New Rectangle(mousePoint.X, mousePoint.Y, Cursors.Arrow.Size.Width, Cursors.Arrow.Size.Height))
End If
End Using
Return bmp
End Function
End Class
...Pero como ya mencioné, deberías utilziar la otra función,
TakeScreenshotFromObject, no es plan de darte hasta el código funcional todo hecho, jeje, así que te animo a hacerlo con la otra función tomando como base ese ejemplo.
Si por lo contrario quieres hacer que ambos webbrowsers sean manejables pues... vas a tener que esforzarte mucho, mucho más.
Se me ocurre que una posible manera sería heredar la Class del WebBrowser y en lugar de instanciar uno, instanciar dos, y empezar a sustituir y overridear todos los métodos base posibles para hacer las mismas llamadas al segundo control instanciado al mismo tiempo que se hace al primero (por ejemplo, sustituir el método Navigate y sus overloads para llamar al método base "Navigate" de ambos webbrowsers a la vez), pero no se muy bien cuan buenos o malos resultados tendría esta metodología sin haberla puesto en práctica, ya que resulta un coñazo hacer eso.
Saludos