private DocumentContainer(IHTMLWindow2 frameWindow, WindowDetails contentWindow, DocumentContainer parent) { //IWebBrowser2 webBrowser2 = frame as IWebBrowser2; //IHTMLDocument2 document2 = webBrowser2.Document as IHTMLDocument2; IHTMLDocument2 document2 = GetDocumentFromWindow(frameWindow); try { LOG.DebugFormat("frameWindow.name {0}", frameWindow.name); } catch { } try { LOG.DebugFormat("document2.url {0}",document2.url); } catch { } try { LOG.DebugFormat("document2.title {0}", document2.title); } catch { } this.parent = parent; // Calculate startLocation for the frames IHTMLWindow3 window3 = (IHTMLWindow3)document2.parentWindow; // IHTMLElement element = window2.document.body; // long x = 0; // long y = 0; // do { // x += element.offsetLeft; // y += element.offsetTop; // element = element.offsetParent; // } while (element != null); // startLocation = new Point((int)x, (int)y); Point contentWindowLocation = contentWindow.ClientRectangle.Location; int x = window3.screenLeft - contentWindowLocation.X; int y = window3.screenTop - contentWindowLocation.Y; startLocation = new Point(x, y); Init(document2, contentWindow); }
private DocumentContainer(IHTMLWindow2 frameWindow, WindowDetails contentWindow, DocumentContainer parent) { //IWebBrowser2 webBrowser2 = frame as IWebBrowser2; //IHTMLDocument2 document2 = webBrowser2.Document as IHTMLDocument2; IHTMLDocument2 document2 = GetDocumentFromWindow(frameWindow); try { LOG.DebugFormat("frameWindow.name {0}", frameWindow.name); name = frameWindow.name; } catch { } try { LOG.DebugFormat("document2.url {0}",document2.url); } catch { } try { LOG.DebugFormat("document2.title {0}", document2.title); } catch { } this.parent = parent; // Calculate startLocation for the frames IHTMLWindow2 window2 = document2.parentWindow; IHTMLWindow3 window3 = (IHTMLWindow3)window2; Point contentWindowLocation = contentWindow.WindowRectangle.Location; int x = window3.screenLeft - contentWindowLocation.X; int y = window3.screenTop - contentWindowLocation.Y; // Release IHTMLWindow 2+3 com objects releaseCom(window2); releaseCom(window3); startLocation = new Point(x, y); Init(document2, contentWindow); }
/// <summary> /// Private helper method for the constructors /// </summary> /// <param name="document2">IHTMLDocument2</param> /// <param name="contentWindow">WindowDetails</param> private void Init(IHTMLDocument2 document2, WindowDetails contentWindow) { this.document2 = document2; this.contentWindow = contentWindow; this.document3 = document2 as IHTMLDocument3; // Check what access method is needed for the document IHTMLDocument5 document5 = (IHTMLDocument5)document2; //compatibility mode affects how height is computed if ((document3.documentElement != null) && (!document5.compatMode.Equals("BackCompat"))) { isDTD = true; } else { isDTD = false; } Rectangle clientRectangle = contentWindow.WindowRectangle; try { IHTMLWindow3 window3 = (IHTMLWindow3)document2.parentWindow; IHTMLWindow2 window2 = (IHTMLWindow2)document2.parentWindow; IHTMLScreen2 screen2 = (IHTMLScreen2)window2.screen; IHTMLScreen screen = window2.screen; if (parent != null) { // Copy parent values zoomLevelX = parent.zoomLevelX; zoomLevelY = parent.zoomLevelY; viewportRectangle = parent.viewportRectangle; } else { //DisableScrollbars(document2); // Calculate zoom level zoomLevelX = (double)screen2.deviceXDPI/(double)screen2.logicalXDPI; zoomLevelY = (double)screen2.deviceYDPI/(double)screen2.logicalYDPI; // Calculate the viewport rectangle, needed if there is a frame around the html window LOG.DebugFormat("Screen {0}x{1}", ScaleX(screen.width), ScaleY(screen.height)); LOG.DebugFormat("Screen location {0},{1}", window3.screenLeft, window3.screenTop); LOG.DebugFormat("Window rectangle {0}", clientRectangle); LOG.DebugFormat("Client size {0}x{1}", ClientWidth, ClientHeight); int diffX = clientRectangle.Width - ClientWidth; int diffY = clientRectangle.Height - ClientHeight; // If there is a border around the inner window, the diff == 4 // If there is a border AND a scrollbar the diff == 20 if ((diffX == 4 || diffX >= 20) && (diffY == 4 || diffY >= 20)) { Point viewportOffset = new Point(2, 2); Size viewportSize = new Size(ClientWidth, ClientHeight); viewportRectangle = new Rectangle(viewportOffset, viewportSize); LOG.DebugFormat("viewportRect {0}", viewportRectangle); } } LOG.DebugFormat("Zoomlevel {0}, {1}", zoomLevelX, zoomLevelY); } catch (Exception e) { LOG.Warn("Can't get certain properties for documents, using default. due to: ", e); } LOG.DebugFormat("Calculated location {0} for {1}", startLocation, document2.title); sourceLocation = new Point(ScaleX((int)startLocation.X), ScaleY((int)startLocation.Y)); destinationLocation = new Point(ScaleX((int)startLocation.X), ScaleY((int)startLocation.Y)); try { if (name == null) { name = document2.title; } } catch { } try { url = document2.url; } catch { } if (parent != null) { return; } IHTMLFramesCollection2 frameCollection = (IHTMLFramesCollection2)document2.frames; for(int frame = 0; frame < frameCollection.length; frame++) { IHTMLWindow2 frameWindow = frameCollection.item(frame); try { DocumentContainer frameData = new DocumentContainer(frameWindow, contentWindow, this); // check if frame is hidden if (!frameData.isHidden) { LOG.DebugFormat("Creating DocumentContainer for Frame {0} found in window with rectangle {1}", frameData.name, frameData.SourceRectangle); frames.Add(frameData); } else { LOG.DebugFormat("Skipping frame {0}", frameData.Name); } } catch (Exception e) { LOG.Warn("Problem while trying to get information from a frame, skipping the frame!", e); } } // Correct iframe locations foreach (IHTMLElement frameElement in document3.getElementsByTagName("IFRAME")){ try { CorrectFrameLocations(frameElement); } catch (Exception e) { LOG.Warn("Problem while trying to get information from an iframe, skipping the frame!", e); } } }
/// <summary> /// Wrapper around getElementsByTagName /// </summary> /// <param name="tagName">tagName is the name of the tag to look for, e.g. "input"</param> /// <param name="retrieveAttributes">If true then all attributes are retrieved. This is slow!</param> /// <returns></returns> public List<ElementContainer> GetElementsByTagName(string tagName, string[] attributes) { List<ElementContainer> elements = new List<ElementContainer>(); foreach(IHTMLElement element in document3.getElementsByTagName(tagName)) { if (element.offsetWidth <= 0 || element.offsetHeight <= 0) { // not visisble continue; } ElementContainer elementContainer = new ElementContainer(); elementContainer.id = element.id; if (attributes != null) { foreach(string attributeName in attributes) { object attributeValue = element.getAttribute(attributeName, 0); if (attributeValue != null && attributeValue != DBNull.Value && !elementContainer.attributes.ContainsKey(attributeName)) { elementContainer.attributes.Add(attributeName, attributeValue.ToString()); } } } Point elementLocation = new Point((int)element.offsetLeft, (int)element.offsetTop); elementLocation.Offset(this.DestinationLocation); IHTMLElement parent = element.offsetParent; while (parent != null) { elementLocation.Offset((int)parent.offsetLeft, (int)parent.offsetTop); parent = parent.offsetParent; } Rectangle elementRectangle = new Rectangle(elementLocation, new Size((int)element.offsetWidth, (int)element.offsetHeight)); elementContainer.rectangle = elementRectangle; elements.Add(elementContainer); } return elements; }
/// <summary> /// Prepare the calculates for all the frames, move and fit... /// </summary> /// <param name="documentContainer"></param> /// <param name="capture"></param> /// <returns>Size of the complete page</returns> private static Size PrepareCapture(DocumentContainer documentContainer, ICapture capture) { // Calculate the page size int pageWidth = documentContainer.ScrollWidth; int pageHeight = documentContainer.ScrollHeight; // Here we loop over all the frames and try to make sure they don't overlap bool movedFrame; do { movedFrame = false; foreach(DocumentContainer currentFrame in documentContainer.Frames) { foreach(DocumentContainer otherFrame in documentContainer.Frames) { if (otherFrame.ID == currentFrame.ID) { continue; } // check if we need to move if (otherFrame.DestinationRectangle.IntersectsWith(currentFrame.DestinationRectangle) && !otherFrame.SourceRectangle.IntersectsWith(currentFrame.SourceRectangle)) { bool horizalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; bool verticalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; bool horizalMove = currentFrame.SourceLeft < currentFrame.DestinationLeft; bool verticalMove = currentFrame.SourceTop < currentFrame.DestinationTop; bool leftOf = currentFrame.SourceRight <= otherFrame.SourceLeft; bool belowOf = currentFrame.SourceBottom <= otherFrame.SourceTop; if ((horizalResize || horizalMove) && leftOf) { // Current frame resized horizontally, so move other horizontally LOG.DebugFormat("Moving Frame {0} horizontally to the right of {1}", otherFrame.Name, currentFrame.Name); otherFrame.DestinationLeft = currentFrame.DestinationRight; movedFrame = true; } else if ((verticalResize || verticalMove) && belowOf){ // Current frame resized vertically, so move other vertically LOG.DebugFormat("Moving Frame {0} vertically to the bottom of {1}", otherFrame.Name, currentFrame.Name); otherFrame.DestinationTop = currentFrame.DestinationBottom; movedFrame = true; } else { LOG.DebugFormat("Frame {0} intersects with {1}", otherFrame.Name, currentFrame.Name); } } } } } while(movedFrame); bool movedMouse = false; // Correct cursor location to be inside the window capture.MoveMouseLocation(-documentContainer.ContentWindow.Location.X, -documentContainer.ContentWindow.Location.Y); // See if the page has the correct size, as we capture the full frame content AND might have moved them // the normal pagesize will no longer be enough foreach(DocumentContainer frameData in documentContainer.Frames) { if (!movedMouse && frameData.SourceRectangle.Contains(capture.CursorLocation)) { // Correct mouse cursor location for scrolled position (so it shows on the capture where it really was) capture.MoveMouseLocation(frameData.ScrollLeft, frameData.ScrollTop); movedMouse = true; // Apply any other offset changes int offsetX = frameData.DestinationLocation.X - frameData.SourceLocation.X; int offsetY = frameData.DestinationLocation.Y - frameData.SourceLocation.Y; capture.MoveMouseLocation(offsetX, offsetY); } //Get Frame Width & Height pageWidth = Math.Max(pageWidth, frameData.DestinationRight); pageHeight = Math.Max(pageHeight, frameData.DestinationBottom); } // If the mouse hasn't been moved, it wasn't on a frame. So correct the mouse according to the scroll position of the document if (!movedMouse) { // Correct mouse cursor location capture.MoveMouseLocation(documentContainer.ScrollLeft, documentContainer.ScrollTop); } // Limit the size as the editor currently can't work with sizes > short.MaxValue if (pageWidth > short.MaxValue) { LOG.WarnFormat("Capture has a width of {0} which bigger than the maximum supported {1}, cutting width to the maxium.", pageWidth, short.MaxValue); pageWidth = Math.Min(pageWidth, short.MaxValue); } if (pageHeight > short.MaxValue) { LOG.WarnFormat("Capture has a height of {0} which bigger than the maximum supported {1}, cutting height to the maxium", pageHeight, short.MaxValue); pageHeight = Math.Min(pageHeight, short.MaxValue); } return new Size(pageWidth, pageHeight); }
/// <summary> /// Used as an example /// </summary> /// <param name="documentContainer"></param> /// <param name="graphicsTarget"></param> /// <param name="returnBitmap"></param> private static void ParseElements(DocumentContainer documentContainer, Graphics graphicsTarget, Bitmap returnBitmap) { foreach(ElementContainer element in documentContainer.GetElementsByTagName("input", new string[]{"greenshot"})) { if (element.attributes.ContainsKey("greenshot") && element.attributes["greenshot"] != null) { string greenshotAction = element.attributes["greenshot"]; if ("hide".Equals(greenshotAction)) { PixelizationFilter.Apply(graphicsTarget, returnBitmap, element.rectangle, 4); } else if ("red".Equals(greenshotAction)) { using (Brush brush = new SolidBrush(Color.Red)) { graphicsTarget.FillRectangle(brush, element.rectangle); } } } } }
/// <summary> /// Helper method which will retrieve the IHTMLDocument2 for the supplied window, /// or return the first if none is supplied. /// </summary> /// <param name="browserWindowDetails">The WindowDetails to get the IHTMLDocument2 for</param> /// <param name="document2">Ref to the IHTMLDocument2 to return</param> /// <returns>The WindowDetails to which the IHTMLDocument2 belongs</returns> private static DocumentContainer GetDocument(WindowDetails activeWindow) { DocumentContainer returnDocumentContainer = null; WindowDetails returnWindow = null; IHTMLDocument2 returnDocument2 = null; // alternative if no match WindowDetails alternativeReturnWindow = null; IHTMLDocument2 alternativeReturnDocument2 = null; // Find the IE window foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) { LOG.DebugFormat("Processing {0} - {1}", ieWindow.ClassName, ieWindow.Text); Accessible ieAccessible = null; WindowDetails directUIWD = IEHelper.GetDirectUI(ieWindow); if (directUIWD != null) { ieAccessible = new Accessible(directUIWD.Handle); } if (ieAccessible == null) { LOG.InfoFormat("Active Window is {0}", activeWindow.Text); if (!ieWindow.Equals(activeWindow)) { LOG.WarnFormat("No ieAccessible for {0}", ieWindow.Text); continue; } LOG.DebugFormat("No ieAccessible, but the active window is an IE window: {0}, ", ieWindow.Text); } try { // Get the Document IHTMLDocument2 document2 = null; uint windowMessage = User32.RegisterWindowMessage("WM_HTML_GETOBJECT"); if (windowMessage == 0) { LOG.WarnFormat("Couldn't register WM_HTML_GETOBJECT"); continue; } WindowDetails ieServer= ieWindow.GetChild("Internet Explorer_Server"); if (ieServer == null) { LOG.WarnFormat("No Internet Explorer_Server for {0}", ieWindow.Text); continue; } LOG.DebugFormat("Trying WM_HTML_GETOBJECT on {0}", ieServer.ClassName); UIntPtr response; User32.SendMessageTimeout(ieServer.Handle, windowMessage, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out response); if (response != UIntPtr.Zero) { document2 = (IHTMLDocument2)Accessible.ObjectFromLresult(response, typeof(IHTMLDocument).GUID, IntPtr.Zero); if (document2 == null) { LOG.Error("No IHTMLDocument2 found"); continue; } } else { LOG.Error("No answer on WM_HTML_GETOBJECT."); continue; } // Get the content window handle for the shellWindow.Document IOleWindow oleWindow = (IOleWindow)document2; IntPtr contentWindowHandle = IntPtr.Zero; if (oleWindow != null) { oleWindow.GetWindow(out contentWindowHandle); } if (contentWindowHandle != IntPtr.Zero) { // Get the HTMLDocument to check the hasFocus // See: http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/60c6c95d-377c-4bf4-860d-390840fce31c/ IHTMLDocument4 document4 = (IHTMLDocument4)document2; if (document4.hasFocus()) { LOG.DebugFormat("Matched focused document: {0}", document2.title); // Look no further, we got what we wanted! returnDocument2 = document2; returnWindow = new WindowDetails(contentWindowHandle); break; } try { if (ieWindow.Equals(activeWindow)) { returnDocument2 = document2; returnWindow = new WindowDetails(contentWindowHandle); break; } else if (ieAccessible != null && returnWindow == null && document2.title.Equals(ieAccessible.IEActiveTabCaption) ) { LOG.DebugFormat("Title: {0}", document2.title); returnDocument2 = document2; returnWindow = new WindowDetails(contentWindowHandle); } else { alternativeReturnDocument2 = document2; alternativeReturnWindow = new WindowDetails(contentWindowHandle); } } catch (Exception) { alternativeReturnDocument2 = document2; alternativeReturnWindow = new WindowDetails(contentWindowHandle); } } } catch (Exception e) { LOG.Error(e); LOG.DebugFormat("Major problem: Problem retrieving Document from {0}", ieWindow.Text); } } // check if we have something to return if (returnWindow != null) { // As it doesn't have focus, make sure it's active returnWindow.Restore(); returnWindow.GetParent(); // Create the container returnDocumentContainer = new DocumentContainer(returnDocument2, returnWindow); } if (returnDocumentContainer == null && alternativeReturnDocument2 != null) { // As it doesn't have focus, make sure it's active alternativeReturnWindow.Restore(); alternativeReturnWindow.GetParent(); // Create the container returnDocumentContainer = new DocumentContainer(alternativeReturnDocument2, alternativeReturnWindow); } return returnDocumentContainer; }
/// <summary> /// This method takes the actual capture of the document (frame) /// </summary> /// <param name="frameDocument"></param> /// <param name="contentWindowDetails">Needed for referencing the location of the frame</param> /// <returns>Bitmap with the capture</returns> private static void drawDocument(DocumentContainer documentContainer, WindowDetails contentWindowDetails, Graphics graphicsTarget) { documentContainer.setAttribute("scroll", 1); //Get Browser Window Width & Height int pageWidth = documentContainer.ScrollWidth; int pageHeight = documentContainer.ScrollHeight; if (pageWidth * pageHeight == 0) { LOG.WarnFormat("Empty page for DocumentContainer {0}: {1}", documentContainer.Name, documentContainer.Url); return; } //Get Screen Width & Height (this is better as the WindowDetails.ClientRectangle as the real visible parts are there! int viewportWidth = documentContainer.ClientWidth; int viewportHeight = documentContainer.ClientHeight; if (viewportWidth * viewportHeight == 0) { LOG.WarnFormat("Empty viewport for DocumentContainer {0}: {1}", documentContainer.Name, documentContainer.Url); return; } // Store the current location so we can set the browser back and use it for the mouse cursor int startLeft = documentContainer.ScrollLeft; int startTop = documentContainer.ScrollTop; LOG.DebugFormat("Capturing {4} with total size {0},{1} displayed with size {2},{3}", pageWidth, pageHeight, viewportWidth, viewportHeight, documentContainer.Name); // Variable used for looping horizontally int horizontalPage = 0; // The location of the browser, used as the destination into the bitmap target Point targetOffset = new Point(); // Loop of the pages and make a copy of the visible viewport while ((horizontalPage * viewportWidth) < pageWidth) { // Scroll to location documentContainer.ScrollLeft = viewportWidth * horizontalPage; targetOffset.X = documentContainer.ScrollLeft; // Variable used for looping vertically int verticalPage = 0; while ((verticalPage * viewportHeight) < pageHeight) { // Scroll to location documentContainer.ScrollTop = viewportHeight * verticalPage; //Shoot visible window targetOffset.Y = documentContainer.ScrollTop; // Draw the captured fragment to the target, but "crop" the scrollbars etc while capturing Size viewPortSize = new Size(viewportWidth, viewportHeight); Rectangle clientRectangle = new Rectangle(documentContainer.SourceLocation, viewPortSize); Image fragment = contentWindowDetails.PrintWindow(); if (fragment != null) { LOG.DebugFormat("Captured fragment size: {0}x{1}", fragment.Width, fragment.Height); try { // cut all junk, due to IE "border" we need to remove some parts Rectangle viewportRect = documentContainer.ViewportRectangle; if (!viewportRect.IsEmpty) { LOG.DebugFormat("Cropping to viewport: {0}", viewportRect); ImageHelper.Crop(ref fragment, ref viewportRect); } LOG.DebugFormat("Cropping to clientRectangle: {0}", clientRectangle); // Crop to clientRectangle if (ImageHelper.Crop(ref fragment, ref clientRectangle)) { Point targetLocation = new Point(documentContainer.DestinationLocation.X, documentContainer.DestinationLocation.Y); LOG.DebugFormat("Fragment targetLocation is {0}", targetLocation); targetLocation.Offset(targetOffset); LOG.DebugFormat("After offsetting the fragment targetLocation is {0}", targetLocation); LOG.DebugFormat("Drawing fragment of size {0} to {1}", fragment.Size, targetLocation); graphicsTarget.DrawImage(fragment, targetLocation); graphicsTarget.Flush(); } else { // somehow we are capturing nothing!? LOG.WarnFormat("Crop of {0} failed?", documentContainer.Name); break; } } finally { fragment.Dispose(); } } else { LOG.WarnFormat("Capture of {0} failed!", documentContainer.Name); } verticalPage++; } horizontalPage++; } // Return to where we were documentContainer.ScrollLeft = startLeft; documentContainer.ScrollTop = startTop; }
/// <summary> /// Capture the actual page (document) /// </summary> /// <param name="documentContainer">The document wrapped in a container</param> /// <returns>Bitmap with the page content as an image</returns> private static Bitmap capturePage(DocumentContainer documentContainer, ICapture capture, Size pageSize) { WindowDetails contentWindowDetails = documentContainer.ContentWindow; //Create a target bitmap to draw into with the calculated page size Bitmap returnBitmap = new Bitmap(pageSize.Width, pageSize.Height, PixelFormat.Format24bppRgb); using (Graphics graphicsTarget = Graphics.FromImage(returnBitmap)) { // Clear the target with the backgroundcolor Color clearColor = documentContainer.BackgroundColor; LOG.DebugFormat("Clear color: {0}", clearColor); graphicsTarget.Clear(clearColor); // Get the base document & draw it drawDocument(documentContainer, contentWindowDetails, graphicsTarget); // Loop over the frames and clear their source area so we don't see any artefacts foreach(DocumentContainer frameDocument in documentContainer.Frames) { using(Brush brush = new SolidBrush(clearColor)) { graphicsTarget.FillRectangle(brush, frameDocument.SourceRectangle); } } // Loop over the frames and capture their content foreach(DocumentContainer frameDocument in documentContainer.Frames) { drawDocument(frameDocument, contentWindowDetails, graphicsTarget); } } return returnBitmap; }
/// <summary> /// Capture the actual page (document) /// </summary> /// <param name="documentContainer">The document wrapped in a container</param> /// <returns>Bitmap with the page content as an image</returns> private static Bitmap capturePage(DocumentContainer documentContainer, ICapture capture) { WindowDetails contentWindowDetails = documentContainer.ContentWindow; // Calculate the page size int pageWidth = documentContainer.ScrollWidth; int pageHeight = documentContainer.ScrollHeight; // Here we loop over all the frames and try to make sure they don't overlap bool movedFrame; do { movedFrame = false; foreach(DocumentContainer currentFrame in documentContainer.Frames) { foreach(DocumentContainer otherFrame in documentContainer.Frames) { if (otherFrame.ID == currentFrame.ID) { continue; } // check if we need to move if (otherFrame.DestinationRectangle.IntersectsWith(currentFrame.DestinationRectangle) && !otherFrame.SourceRectangle.IntersectsWith(currentFrame.SourceRectangle)) { bool horizalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; bool verticalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; bool horizalMove = currentFrame.SourceLeft < currentFrame.DestinationLeft; bool verticalMove = currentFrame.SourceTop < currentFrame.DestinationTop; bool leftOf = currentFrame.SourceRight <= otherFrame.SourceLeft; bool belowOf = currentFrame.SourceBottom <= otherFrame.SourceTop; if ((horizalResize || horizalMove) && leftOf) { // Current frame resized horizontally, so move other horizontally LOG.DebugFormat("Moving Frame {0} horizontally to the right of {1}", otherFrame.Name, currentFrame.Name); otherFrame.DestinationLeft = currentFrame.DestinationRight; movedFrame = true; } else if ((verticalResize || verticalMove) && belowOf){ // Current frame resized vertically, so move other vertically LOG.DebugFormat("Moving Frame {0} vertically to the bottom of {1}", otherFrame.Name, currentFrame.Name); otherFrame.DestinationTop = currentFrame.DestinationBottom; movedFrame = true; } else { LOG.DebugFormat("Frame {0} intersects with {1}", otherFrame.Name, currentFrame.Name); } } } } } while(movedFrame); bool movedMouse = false; // Correct cursor location to be inside the window capture.MoveMouseLocation(-documentContainer.ContentWindow.Location.X, -documentContainer.ContentWindow.Location.Y); // See if the page has the correct size, as we capture the full frame content AND might have moved them // the normal pagesize will no longer be enough foreach(DocumentContainer frameData in documentContainer.Frames) { if (!movedMouse && frameData.SourceRectangle.Contains(capture.CursorLocation)) { // Correct mouse cursor location for scrolled position (so it shows on the capture where it really was) capture.MoveMouseLocation(frameData.ScrollLeft, frameData.ScrollTop); movedMouse = true; // Apply any other offset changes int offsetX = frameData.DestinationLocation.X - frameData.SourceLocation.X; int offsetY = frameData.DestinationLocation.Y - frameData.SourceLocation.Y; capture.MoveMouseLocation(offsetX, offsetY); } //Get Frame Width & Height pageWidth = Math.Max(pageWidth, frameData.DestinationRight); pageHeight = Math.Max(pageHeight, frameData.DestinationBottom); } // If the mouse hasn't been moved, it wasn't on a frame. So correct the mouse according to the scroll position of the document if (!movedMouse) { // Correct mouse cursor location capture.MoveMouseLocation(documentContainer.ScrollLeft, documentContainer.ScrollTop); } // Limit the size as the editor currently can't work with sizes > short.MaxValue if (pageWidth > short.MaxValue) { LOG.WarnFormat("Capture has a width of {0} which bigger than the maximum supported {1}, cutting width to the maxium.", pageWidth, short.MaxValue); pageWidth = Math.Min(pageWidth, short.MaxValue); } if (pageHeight > short.MaxValue) { LOG.WarnFormat("Capture has a height of {0} which bigger than the maximum supported {1}, cutting height to the maxium", pageHeight, short.MaxValue); pageHeight = Math.Min(pageHeight, short.MaxValue); } //Create a target bitmap to draw into with the calculated page size Bitmap returnBitmap = new Bitmap(pageWidth, pageHeight, PixelFormat.Format24bppRgb); using (Graphics graphicsTarget = Graphics.FromImage(returnBitmap)) { // Clear the target with the backgroundcolor Color clearColor = documentContainer.BackgroundColor; LOG.DebugFormat("Clear color: {0}", clearColor); graphicsTarget.Clear(clearColor); // Get the base document & draw it drawDocument(documentContainer, contentWindowDetails, graphicsTarget); //ParseElements(documentContainer, graphicsTarget, returnBitmap); // Loop over the frames and clear their source area so we don't see any artefacts foreach(DocumentContainer frameDocument in documentContainer.Frames) { using(Brush brush = new SolidBrush(clearColor)) { graphicsTarget.FillRectangle(brush, frameDocument.SourceRectangle); } } // Loop over the frames and capture their content foreach(DocumentContainer frameDocument in documentContainer.Frames) { drawDocument(frameDocument, contentWindowDetails, graphicsTarget); //ParseElements(frameDocument, graphicsTarget, returnBitmap); } } return returnBitmap; }
/// <summary> /// Helper method which will retrieve the IHTMLDocument2 for the supplied window, /// or return the first if none is supplied. /// </summary> /// <param name="browserWindow">The WindowDetails to get the IHTMLDocument2 for</param> /// <param name="document2">Ref to the IHTMLDocument2 to return</param> /// <returns>The WindowDetails to which the IHTMLDocument2 belongs</returns> private static DocumentContainer CreateDocumentContainer(WindowDetails browserWindow) { DocumentContainer returnDocumentContainer = null; WindowDetails returnWindow = null; IHTMLDocument2 returnDocument2 = null; // alternative if no match WindowDetails alternativeReturnWindow = null; IHTMLDocument2 alternativeReturnDocument2 = null; // Find the IE windows foreach (WindowDetails ieWindow in GetIEWindows()) { LOG.DebugFormat("Processing {0} - {1}", ieWindow.ClassName, ieWindow.Text); Accessible ieAccessible = null; WindowDetails directUIWD = IEHelper.GetDirectUI(ieWindow); if (directUIWD != null) { ieAccessible = new Accessible(directUIWD.Handle); } if (ieAccessible == null) { if (browserWindow != null) { LOG.InfoFormat("Active Window is {0}", browserWindow.Text); } if (!ieWindow.Equals(browserWindow)) { LOG.WarnFormat("No ieAccessible for {0}", ieWindow.Text); continue; } LOG.DebugFormat("No ieAccessible, but the active window is an IE window: {0}, ", ieWindow.Text); } try { // Get the Document IHTMLDocument2 document2 = getHTMLDocument(ieWindow); if (document2 == null) { continue; } // Get the content window handle for the shellWindow.Document IOleWindow oleWindow = (IOleWindow)document2; IntPtr contentWindowHandle = IntPtr.Zero; if (oleWindow != null) { oleWindow.GetWindow(out contentWindowHandle); } if (contentWindowHandle != IntPtr.Zero) { // Get the HTMLDocument to check the hasFocus // See: http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/60c6c95d-377c-4bf4-860d-390840fce31c/ IHTMLDocument4 document4 = (IHTMLDocument4)document2; if (document4.hasFocus()) { LOG.DebugFormat("Matched focused document: {0}", document2.title); // Look no further, we got what we wanted! returnDocument2 = document2; returnWindow = new WindowDetails(contentWindowHandle); break; } try { if (ieWindow.Equals(browserWindow)) { returnDocument2 = document2; returnWindow = new WindowDetails(contentWindowHandle); break; } if (ieAccessible != null && returnWindow == null && document2.title.Equals(ieAccessible.IEActiveTabCaption) ) { LOG.DebugFormat("Title: {0}", document2.title); returnDocument2 = document2; returnWindow = new WindowDetails(contentWindowHandle); } else { alternativeReturnDocument2 = document2; alternativeReturnWindow = new WindowDetails(contentWindowHandle); } } catch (Exception) { alternativeReturnDocument2 = document2; alternativeReturnWindow = new WindowDetails(contentWindowHandle); } } } catch (Exception e) { LOG.ErrorFormat("Major problem: Problem retrieving Document from {0}", ieWindow.Text); LOG.Error(e); } } // check if we have something to return if (returnWindow != null) { // As it doesn't have focus, make sure it's active returnWindow.Restore(); returnWindow.GetParent(); // Create the container try { returnDocumentContainer = new DocumentContainer(returnDocument2, returnWindow); } catch (Exception e) { LOG.Error("Major problem: Problem retrieving Document."); LOG.Error(e); } } if (returnDocumentContainer == null && alternativeReturnDocument2 != null) { // As it doesn't have focus, make sure it's active alternativeReturnWindow.Restore(); alternativeReturnWindow.GetParent(); // Create the container try { returnDocumentContainer = new DocumentContainer(alternativeReturnDocument2, alternativeReturnWindow); } catch (Exception e) { LOG.Error("Major problem: Problem retrieving Document."); LOG.Error(e); } } return returnDocumentContainer; }