|
Thanks Douglas, this article is very helpful. But I have a question need suggestions: how can we make the same with Firefox (if can, this project will be very powerful)?
Any suggestion is appreciate.
Regards,
Danh.
|
|
|
|
|
Helpful,
Thank you.
|
|
|
|
|
Wow!
Let me say this, this was the most amazing and fun filled article i found on code project.
I hope the comments section comes back to life, so that the article can get more improvements.
If anyone is there reading this, i would like to know is there a way to determine whether the IE is minimized or not, so that instead of getting a black image, the app can just show a message, like maximize IE to get a screen shot.
I would once again like to thank the author Douglas M.Weems for such a beautiful article.
|
|
|
|
|
I see lots of this code around which calls Print or PrintWindow to a Bitmap based HDC. Is it possible to get an enhanced metafile from a WebBrowser object with vector contents. So far all I'm able to get is a BitBlt record wrapped in an EMF using OleDraw or IViewObject::Draw.
-Jason
|
|
|
|
|
Hi,
Thanks for the code! I was able to successfully do a screen shot of my browser window. However this seems to identical to User32.GetDesktopWindow() that I had also used. I dont want anything but the actual browser window (just like ALT+PrintScreen) Is there a way to modify variables/function parameters or use a different dll function to just capture the window without anything else in background? Please advise, thanks so much!
|
|
|
|
|
as title, always got the same value which equals the client height and width.
cannot scroll:
http://www.google.com/mail
http://www.google.com/reader
can be scrolled:
http://www.google.com/nwshp?tab=mn
http://www.google.com/calendar/render?tab=oc
Do you have any idea?
|
|
|
|
|
There is a vertical line on the picture if browser window has horizontal scrollbar.
|
|
|
|
|
Try this:
Rectangle realArea = new Rectangle( 3, 0, screenfrag.Width - 3, screenfrag.Height);
g2.DrawImage(screenfrag, brwLeft + URLExtraLeft, brwTop + URLExtraHeight, realArea ,GraphicsUnit.Pixel);
|
|
|
|
|
Copy These Lines to Form1.cs ...
/* ---------------------------------------------------------------------------
*
* Copyright (c) Doug Weems.
*
* You may use this code for fun and knowledge.
* You can compile and use the application as is or copy out what you need.
* This code makes for a really useful tool.
*
* ---------------------------------------------------------------------------
*/
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Drawing.Imaging;
using SHDocVw;
using mshtml;
namespace IEWindowCapture
{
/// <summary>
/// This is the working code for "IE Complete Web Window Image Capture". IECWWIC for short.
/// Just kidding. Call it, "WebPageToImage".
/// This tool will pick up one open IE window and capture the entire web page to a single jpeg.
/// It is best if you only are running the IE instance that you are interested in.
/// The quality and size of the image can be adjusted and standard resolution screen sizes and web page name
/// can be added to the image.
/// Author: Doug Weems
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.GroupBox grpWebCapture;
private System.Windows.Forms.LinkLabel lnkOpenCapture;
private System.Windows.Forms.CheckBox chkShowGuides;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.ComboBox cmbResolution;
private System.Windows.Forms.Label lblResolution;
private System.Windows.Forms.Label lblQuality;
private System.Windows.Forms.ComboBox cmbQuality;
private System.Windows.Forms.CheckBox chkWriteURL;
private System.Windows.Forms.Button button1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public frmMain()
{
InitializeComponent();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(frmMain));
this.grpWebCapture = new System.Windows.Forms.GroupBox();
this.lnkOpenCapture = new System.Windows.Forms.LinkLabel();
this.chkShowGuides = new System.Windows.Forms.CheckBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.cmbResolution = new System.Windows.Forms.ComboBox();
this.lblResolution = new System.Windows.Forms.Label();
this.lblQuality = new System.Windows.Forms.Label();
this.cmbQuality = new System.Windows.Forms.ComboBox();
this.chkWriteURL = new System.Windows.Forms.CheckBox();
this.button1 = new System.Windows.Forms.Button();
this.grpWebCapture.SuspendLayout();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// grpWebCapture
//
this.grpWebCapture.Controls.Add(this.lnkOpenCapture);
this.grpWebCapture.Controls.Add(this.chkShowGuides);
this.grpWebCapture.Controls.Add(this.groupBox1);
this.grpWebCapture.Controls.Add(this.chkWriteURL);
this.grpWebCapture.Controls.Add(this.button1);
this.grpWebCapture.Location = new System.Drawing.Point(28, 12);
this.grpWebCapture.Name = "grpWebCapture";
this.grpWebCapture.Size = new System.Drawing.Size(256, 208);
this.grpWebCapture.TabIndex = 41;
this.grpWebCapture.TabStop = false;
this.grpWebCapture.Text = "Capture Web Page";
//
// lnkOpenCapture
//
this.lnkOpenCapture.Location = new System.Drawing.Point(16, 136);
this.lnkOpenCapture.Name = "lnkOpenCapture";
this.lnkOpenCapture.Size = new System.Drawing.Size(128, 16);
this.lnkOpenCapture.TabIndex = 36;
this.lnkOpenCapture.TabStop = true;
this.lnkOpenCapture.Text = "Open Capture Directory";
this.lnkOpenCapture.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lnkOpenCapture_LinkClicked);
//
// chkShowGuides
//
this.chkShowGuides.Location = new System.Drawing.Point(16, 112);
this.chkShowGuides.Name = "chkShowGuides";
this.chkShowGuides.Size = new System.Drawing.Size(200, 16);
this.chkShowGuides.TabIndex = 34;
this.chkShowGuides.Text = "draw Standard Resolution Guides";
//
// groupBox1
//
this.groupBox1.Controls.Add(this.cmbResolution);
this.groupBox1.Controls.Add(this.lblResolution);
this.groupBox1.Controls.Add(this.lblQuality);
this.groupBox1.Controls.Add(this.cmbQuality);
this.groupBox1.ForeColor = System.Drawing.Color.Black;
this.groupBox1.Location = new System.Drawing.Point(16, 16);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(200, 80);
this.groupBox1.TabIndex = 39;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Reduce File Size by reducing Quality and/or Resolution";
//
// cmbResolution
//
this.cmbResolution.Items.AddRange(new object[] {
"100",
"90",
"80",
"70",
"60",
"50",
"40"});
this.cmbResolution.Location = new System.Drawing.Point(120, 32);
this.cmbResolution.Name = "cmbResolution";
this.cmbResolution.Size = new System.Drawing.Size(48, 21);
this.cmbResolution.TabIndex = 31;
this.cmbResolution.Text = "90";
//
// lblResolution
//
this.lblResolution.Location = new System.Drawing.Point(24, 32);
this.lblResolution.Name = "lblResolution";
this.lblResolution.Size = new System.Drawing.Size(88, 16);
this.lblResolution.TabIndex = 35;
this.lblResolution.Text = "% Capture Size";
this.lblResolution.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// lblQuality
//
this.lblQuality.Location = new System.Drawing.Point(24, 56);
this.lblQuality.Name = "lblQuality";
this.lblQuality.Size = new System.Drawing.Size(88, 16);
this.lblQuality.TabIndex = 38;
this.lblQuality.Text = "Quality";
this.lblQuality.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// cmbQuality
//
this.cmbQuality.Items.AddRange(new object[] {
"100",
"90",
"80",
"70",
"50",
"30",
"10"});
this.cmbQuality.Location = new System.Drawing.Point(120, 56);
this.cmbQuality.Name = "cmbQuality";
this.cmbQuality.Size = new System.Drawing.Size(48, 21);
this.cmbQuality.TabIndex = 37;
this.cmbQuality.Text = "70";
//
// chkWriteURL
//
this.chkWriteURL.Location = new System.Drawing.Point(16, 96);
this.chkWriteURL.Name = "chkWriteURL";
this.chkWriteURL.Size = new System.Drawing.Size(176, 16);
this.chkWriteURL.TabIndex = 32;
this.chkWriteURL.Text = "write URL name on Image";
//
// button1
//
this.button1.Cursor = System.Windows.Forms.Cursors.Hand;
this.button1.ForeColor = System.Drawing.Color.White;
this.button1.Image = ((System.Drawing.Image)(resources.GetObject("button1.Image")));
this.button1.Location = new System.Drawing.Point(176, 144);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(48, 40);
this.button1.TabIndex = 29;
this.button1.TextAlign = System.Drawing.ContentAlignment.TopCenter;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(304, 238);
this.Controls.Add(this.grpWebCapture);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "frmMain";
this.Text = "Capture";
this.grpWebCapture.ResumeLayout(false);
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmMain());
}
//We need some system dll functions.
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/, IntPtr next /*HWND*/, string sClassName, IntPtr sWindowTitle);
[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)]
public static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);
[DllImport("user32.Dll")]
public static extern void GetClassName(int h, StringBuilder s, int nMaxCount);
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
public const int GW_CHILD = 5;
public const int GW_HWNDNEXT = 2;
int heightsize;
int widthsize;
int screenHeight;
int screenWidth;
public bool IsDTDDocument(object document)
{
// XHtml declare flag string
string DocTypeContent = @"-//W3C//DTD";
mshtml.IHTMLDocument3 document3 = (mshtml.IHTMLDocument3)document;
mshtml.IHTMLDOMChildrenCollection domChilds = (mshtml.IHTMLDOMChildrenCollection)document3.childNodes;
mshtml.IHTMLDOMNode domNode = (mshtml.IHTMLDOMNode)domChilds.item(0);
return domNode.nodeValue.ToString().Contains(DocTypeContent);
}
private void button1_Click(object sender, System.EventArgs e)
{
//TODO In Next Version:
//Add cursor capture
//Add file naming option
//Add visible screen capture
//Make captured image a DDB not a DIB bitmap.
Cursor.Current = Cursors.WaitCursor;
SHDocVw.WebBrowser m_browser = null;
SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindowsClass();
//Find first availble browser window.
//Application can easily be modified to loop through and capture all open windows.
string filename;
foreach (SHDocVw.WebBrowser ie in shellWindows)
{
filename = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
if (filename.Equals("iexplore"))
{
m_browser = ie;
break;
}
}
if (m_browser == null)
{
MessageBox.Show("No Browser Open");
return;
}
//Assign Browser Document
mshtml.IHTMLDocument2 myDoc = (mshtml.IHTMLDocument2)m_browser.Document;
mshtml.IHTMLDocument3 doc3 = (mshtml.IHTMLDocument3)myDoc;
//URL Location
string myLocalLink = myDoc.url;
int URLExtraHeight = 0;
int URLExtraLeft = 0;
//Adjustment variable for capture size.
if (chkWriteURL.Checked == true)
URLExtraHeight = 25;
//TrimHeight and TrimLeft trims off some captured IE graphics.
int trimHeight = 3;
int trimLeft = 3;
//Use UrlExtra height to carry trimHeight.
URLExtraHeight = URLExtraHeight - trimHeight;
URLExtraLeft = URLExtraLeft - trimLeft;
if (!IsDTDDocument(myDoc))
{
myDoc.body.setAttribute("scroll", "yes", 0);
//Get Browser Window Height
heightsize = (int)myDoc.body.getAttribute("scrollHeight", 0);
widthsize = (int)myDoc.body.getAttribute("scrollWidth", 0);
//Get Screen Height
screenHeight = (int)myDoc.body.getAttribute("clientHeight", 0);
screenWidth = (int)myDoc.body.getAttribute("clientWidth", 0);
}
else
{
doc3.documentElement.setAttribute("scroll", "Yes", 0);
//Get Browser Window Height
heightsize = (int)doc3.documentElement.getAttribute("scrollHeight", 0);
widthsize = (int)doc3.documentElement.getAttribute("scrollWidth", 0);
//Get Screen Height
screenHeight = (int)doc3.documentElement.getAttribute("clientHeight", 0);
screenWidth = (int)doc3.documentElement.getAttribute("clientWidth", 0);
}
//Get bitmap to hold screen fragment.
Bitmap bm = new Bitmap(screenWidth, screenHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
//Create a target bitmap to draw into.
Bitmap bm2 = new Bitmap(widthsize + URLExtraLeft, heightsize + URLExtraHeight - trimHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
Graphics g2 = Graphics.FromImage(bm2);
Graphics g = null;
IntPtr hdc;
Image screenfrag = null;
int brwTop = 0;
int brwLeft = 0;
int myPage = 0;
IntPtr myIntptr = (IntPtr)m_browser.HWND;
//Get inner browser window.
int hwndInt = myIntptr.ToInt32();
IntPtr hwnd = myIntptr;
hwnd = GetWindow(hwnd, GW_CHILD);
StringBuilder sbc = new StringBuilder(256);
//Get Browser "Document" Handle
while (hwndInt != 0) {
hwndInt = hwnd.ToInt32();
GetClassName(hwndInt, sbc, 256);
if(sbc.ToString().IndexOf("Shell DocObject View", 0) > -1) //IE6
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
if (sbc.ToString().IndexOf("TabWindowClass", 0) > -1) //IE7
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
if (sbc.ToString().IndexOf("Frame Tab", 0) > -1) // IE8
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "TabWindowClass", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
}
//Get Screen Height (for bottom up screen drawing)
while ((myPage * screenHeight) < heightsize)
{
if (!IsDTDDocument(myDoc))
myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * myPage, 0);
else
doc3.documentElement.setAttribute("scrollTop", (screenHeight - 5) * myPage, 0);
++myPage;
}
//Rollback the page count by one
--myPage;
int myPageWidth = 0;
while ((myPageWidth * screenWidth) < widthsize)
{
if (!IsDTDDocument(myDoc))
myDoc.body.setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, 0);
else
doc3.documentElement.setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, 0);
if (!IsDTDDocument(myDoc))
brwLeft = (int)myDoc.body.getAttribute("scrollLeft", 0);
else
brwLeft = (int)doc3.documentElement.getAttribute("scrollLeft", 0);
for (int i = myPage; i >= 0; --i)
{
//Shoot visible window
g = Graphics.FromImage(bm);
hdc = g.GetHdc();
if (!IsDTDDocument(myDoc))
myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * i, 0);
else
doc3.documentElement.setAttribute("scrollTop", (screenHeight - 5) * i, 0);
if (!IsDTDDocument(myDoc))
brwTop = (int)myDoc.body.getAttribute("scrollTop", 0);
else
brwTop = (int)doc3.documentElement.getAttribute("scrollTop", 0);
PrintWindow(hwnd, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
screenfrag = Image.FromHbitmap(bm.GetHbitmap());
g2.DrawImage(screenfrag, brwLeft + URLExtraLeft, brwTop + URLExtraHeight);
}
++myPageWidth;
}
//Draw Standard Resolution Guides
if(chkShowGuides.Checked == true)
{
// Create pen.
int myWidth = 1;
Pen myPen = new Pen(Color.Navy, myWidth);
Pen myShadowPen = new Pen(Color.NavajoWhite, myWidth);
// Create coordinates of points that define line.
float x1 = -(float)myWidth - 1 + URLExtraLeft;
float y1 = -(float)myWidth - 1 + URLExtraHeight;
float x600 = 600.0F + (float)myWidth+1;
float y480 = 480.0F + (float)myWidth+1;
float x2 = 800.0F + (float)myWidth+1;
float y2 = 600.0F + (float)myWidth+1;
float x3 = 1024.0F + (float)myWidth+1;
float y3 = 768.0F + (float)myWidth+1;
float x1280 = 1280.0F + (float)myWidth+1;
float y1024 = 1024.0F + (float)myWidth+1;
// Draw line to screen.
g2.DrawRectangle(myPen, x1, y1, x600+myWidth, y480+myWidth);
g2.DrawRectangle(myPen, x1, y1, x2+myWidth, y2+myWidth);
g2.DrawRectangle(myPen, x1, y1, x3+myWidth, y3+myWidth);
g2.DrawRectangle(myPen, x1, y1, x1280+myWidth, y1024+myWidth);
// Create font and brush.
Font drawFont = new Font("Arial", 12);
SolidBrush drawBrush = new SolidBrush(Color.Navy);
SolidBrush drawBrush2 = new SolidBrush(Color.NavajoWhite);
// Set format of string.
StringFormat drawFormat = new StringFormat();
drawFormat.FormatFlags = StringFormatFlags.FitBlackBox;
// Draw string to screen.
g2.DrawString("600 x 480", drawFont, drawBrush, 5, y480 - 20 + URLExtraHeight, drawFormat);
g2.DrawString("800 x 600", drawFont, drawBrush, 5, y2 - 20 + URLExtraHeight, drawFormat);
g2.DrawString("1024 x 768", drawFont, drawBrush, 5, y3 - 20 + URLExtraHeight, drawFormat);
g2.DrawString("1280 x 1024", drawFont, drawBrush, 5, y1024 - 20 + URLExtraHeight, drawFormat);
}
//Write URL
if (chkWriteURL.Checked == true)
{ //Backfill URL paint location
SolidBrush whiteBrush = new SolidBrush(Color.White);
Rectangle fillRect = new Rectangle(0, 0, widthsize, URLExtraHeight+2);
Region fillRegion = new Region(fillRect);
g2.FillRegion(whiteBrush, fillRegion);
SolidBrush drawBrushURL = new SolidBrush(Color.Black);
Font drawFont = new Font("Arial", 12);
StringFormat drawFormat = new StringFormat();
drawFormat.FormatFlags = StringFormatFlags.FitBlackBox;
g2.DrawString(myLocalLink, drawFont, drawBrushURL, 0, 0, drawFormat);
}
//Reduce Resolution Size
double myResolution = Convert.ToDouble(cmbResolution.Text) * 0.01;
int finalWidth = (int)((widthsize + URLExtraLeft) * myResolution);
int finalHeight = (int)((heightsize + URLExtraHeight) * myResolution);
Bitmap finalImage = new Bitmap(finalWidth, finalHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
Graphics gFinal = Graphics.FromImage((Image)finalImage);
gFinal.DrawImage( bm2, 0, 0, finalWidth, finalHeight);
//Get Time Stamp
DateTime myTime = DateTime.Now;
String format = "MM.dd.hh.mm.ss";
//Create Directory to save image to.
Directory.CreateDirectory("C:\\IECapture");
//Write Image.
EncoderParameters eps = new EncoderParameters(1);
long myQuality = Convert.ToInt64(cmbQuality.Text);
eps.Param[0] = new EncoderParameter( System.Drawing.Imaging.Encoder.Quality, myQuality);
ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
finalImage.Save(@"c:\\IECapture\Captured_" + myTime.ToString(format) + ".jpg", ici, eps);
//Clean Up.
myDoc = null;
g.Dispose();
g2.Dispose();
gFinal.Dispose();
bm.Dispose();
bm2.Dispose();
finalImage.Dispose();
Cursor.Current = Cursors.Default;
}
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for(j = 0; j < encoders.Length; ++j)
{
if(encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
private void lnkOpenCapture_LinkClicked(object sender, System.Windows.Forms.LinkLabelLinkClickedEventArgs e)
{
Process.Start("explorer.exe", "C:\\IECapture");
}
}
}
|
|
|
|
|
It works fine in some cases but it also failed sometimes. I am still finding th root cause.
Failed Url: http://www.mobile01.com/newsdetail.php?id=7299
Please check!
|
|
|
|
|
This does not allow to take screen shot of scrollable pages.
|
|
|
|
|
//Get Browser Window Height
int heightsize = getAttribute("scrollHeight", myDoc, doc3);
int widthsize = getAttribute("scrollWidth", myDoc, doc3);
//Get Screen Height
int screenHeight = getAttribute("clientHeight", myDoc, doc3);
int screenWidth = getAttribute("clientWidth", myDoc, doc3);
the heightsize and screenHeight returns the same value
the widthsize and screenWidth returns the same value
so the loop does not count the number of pages
//Get Screen Height (for bottom up screen drawing)
while ((myPage * screenHeight) < heightsize)
{
setAttribute("scrollTop", (screenHeight - 5) * myPage, myDoc, doc3);
++myPage;
}
//Rollback the page count by one
--myPage;
Please let us know the problem ASAP
ff
|
|
|
|
|
Yeah I am using IE 9.
And the above code soesn't recognize both the scroll bars...
|
|
|
|
|
You cannot have the browser window minimized when taking the screenshot. Just thought I would share this in case someone else is making the same mistake.
|
|
|
|
|
Building on an earlier comment by Daniel Landers, I was able to make this app run with with IE versions 6,7, and 8. Here is the modification to the code to make it work. Find the comment to Get browser "Document" handle and replace the code between that and the "Get Screen Height (for bottom up screen drawing)" comment with the code below.
while (hwndInt != 0)
{
hwndInt = hwnd.ToInt32();
GetClassName(hwndInt, sbc, 256);
if(sbc.ToString().IndexOf("Shell DocObject View", 0) > -1)
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
if (sbc.ToString().IndexOf("TabWindowClass", 0) > -1)
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
if (sbc.ToString().IndexOf("Frame Tab", 0) > -1)
{
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "TabWindowClass", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
break;
}
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
}
|
|
|
|
|
This works better than the previous code, but does not solve all. Some pages now work fine in IE8 and some are still black.
For instance:
www.alpakka.org works kinda ok. Most of the page is rendered just fine
www.alpakkanorge.no is all black
www.vg.no is fine
www.abb.com mostly renders ok, but a part at the bottom is gone (blackened) like www.alpakka.org
|
|
|
|
|
This is really fits more in line with the black images comment below, but another user sent me a new function to replace my isDTDDocument function. This one seems to work a bit more reliably and reslved the problem on the pages you listed.
public bool IsDTDDocument(object document)
{
bool retVal = false;
IHTMLDocument5 doc5 = (IHTMLDocument5)document;
IHTMLDocument3 doc3 = (IHTMLDocument3)document;
if ((doc3.documentElement != null) && (!doc5.compatMode.Equals("BackCompat")))
{
retVal = true;
}
return retVal;
}
|
|
|
|
|
|
Navid Akhtar showed a solution for the Black Image problem in his comment titled "Capturing entire web page like msn.com" unfortunately he ended his comment with "Similarly update other location where we are trying to get/set attributes." This may have left some people with the code still not working for pages that have a Strict DTD set.
So to Recap what Navid said, the problem with Black images is that pages with a Strict DTD set have a different structure for accessing the document attributes. Instead of myDoc.body.getAttribute("attributeName") you have to create an object as an IHTMLDocument3 object and access the attributes with thes new object named "doc3" in the example as doc3.documentElement.getAttribute("attributeName").
So Here's a more complete set of code for performing this:
Step 1: This code corresponds to the bottom of the third code section in the article or line 289 of Form1.cs in the provided source code.
mshtml.IHTMLDocument2 myDoc = (mshtml.IHTMLDocument2)m_browser.Document;
mshtml.IHTMLDocument3 doc3 = (mshtml.IHTMLDocument3)myDoc ;
Step 2: Add the following Function to your code. I'm adding it to the bottom to not interfere with the line numbers I'll be mentioning later. This code is from Navid Akhtar's comment. I adjusted ths function to return false for documents with a Transitional DTD. Pages with a Transitional DTD work the same as those without a DTD.
public bool IsDTDDocument(object document)
{
bool retVal = false;
string DocTypeContent = @"-//W3C//DTD";
mshtml.IHTMLDocument3 document3 = (mshtml.IHTMLDocument3)document;
mshtml.IHTMLDOMChildrenCollection domChilds = (mshtml.IHTMLDOMChildrenCollection)document3.childNodes;
mshtml.IHTMLDOMNode domNode = (mshtml.IHTMLDOMNode)domChilds.item(0);
if (domNode.nodeValue.ToString().Contains(DocTypeContent) && !domNode.nodeValue.ToString().Contains("Transitional"))
retVal = true;
return retVal;
}
Step 3: I've created two more Functions to handle getting and setting attributes so we don't have to have a bunch of if ... else statements throughout the code. Again, I've added these to the end of the class.
public void setAttribute(string attribute, int value, mshtml.IHTMLDocument2 myDoc, mshtml.IHTMLDocument3 doc3)
{
if (!IsDTDDocument(myDoc))
myDoc.body.setAttribute(attribute, value, 0);
else
doc3.documentElement.setAttribute(attribute, value, 0);
}
public int getAttribute(string attribute, mshtml.IHTMLDocument2 myDoc, mshtml.IHTMLDocument3 doc3)
{
int retVal = 0;
if (!IsDTDDocument(myDoc))
retVal = (int)myDoc.body.getAttribute(attribute, 0);
else
retVal = (int)doc3.documentElement.getAttribute(attribute, 0);
return retVal;
}
Step 4. We go in and change all of the calls to get or set attributes to use the new functions.
change Line 310 - 318
From:
myDoc.body.setAttribute("scroll", "yes", 0);
int heightsize = (int)myDoc.body.getAttribute("scrollHeight", 0);
int widthsize = (int)myDoc.body.getAttribute("scrollWidth", 0);
int screenHeight = (int)myDoc.body.getAttribute("clientHeight", 0);
int screenWidth = (int)myDoc.body.getAttribute("clientWidth", 0);
To:
setAttribute("scroll", 1, myDoc, doc3);
int heightsize = getAttribute("scrollHeight", myDoc, doc3);
int widthsize = getAttribute("scrollWidth", myDoc, doc3);
int screenHeight = getAttribute("clientHeight", myDoc, doc3);
int screenWidth = getAttribute("clientWidth", myDoc, doc3);
Change Line 357
From:
myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * myPage, 0);
To:
setAttribute("scrollTop", (screenHeight - 5) * myPage, myDoc, doc3);
Change Lines 367 - 381
From:
myDoc.body.setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, 0);
brwLeft = (int)myDoc.body.getAttribute("scrollLeft", 0);
for (int i = myPage; i >= 0; --i)
{
g = Graphics.FromImage(bm);
hdc = g.GetHdc();
myDoc.body.setAttribute("scrollTop", (screenHeight - 5) * i, 0);
brwTop = (int)myDoc.body.getAttribute("scrollTop", 0);
PrintWindow(hwnd, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
screenfrag = Image.FromHbitmap(bm.GetHbitmap());
g2.DrawImage(screenfrag, brwLeft + URLExtraLeft, brwTop + URLExtraHeight);
}
To:
setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, myDoc, doc3);
brwLeft = getAttribute("scrollLeft", myDoc, doc3);
for (int i = myPage; i >= 0; --i)
{
g = Graphics.FromImage(bm);
hdc = g.GetHdc();
setAttribute("scrollTop", (screenHeight - 5) * i, myDoc, doc3);
brwTop = getAttribute("scrollTop", myDoc, Doc3);
PrintWindow(hwnd, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
screenfrag = Image.FromHbitmap(bm.GetHbitmap());
g2.DrawImage(screenfrag, brwLeft + URLExtraLeft, brwTop + URLExtraHeight);
}
This should make the code in this article work for all pages whether Strict DTD or not.
modified on Thursday, March 19, 2009 1:24 PM
|
|
|
|
|
Hi, I tried to follow your instruction step by step, but it still not work for me, the tool always return black image to me I'm sure the targe window(IE7) are not minize in taskbar.
|
|
|
|
|
Did you look at the IE7 & IE8 compatibility solution listed here?
|
|
|
|
|
Thank you for your patch! =) But some web-pages don't scrolling. For example www.microsoft.com.
|
|
|
|
|
Try replacing the isDTDDocument function with the following. It seems to be more reliable at determining which pages need to use which method for calculating page size.
public bool IsDTDDocument(object document)
{
bool retVal = false;
IHTMLDocument5 doc5 = (IHTMLDocument5)document;
IHTMLDocument3 doc3 = (IHTMLDocument3)document;
if ((doc3.documentElement != null) && (!doc5.compatMode.Equals("BackCompat")))
{
retVal = true;
}
return retVal;
}
|
|
|
|
|
Thank you! It's a good code.
|
|
|
|
|
I am able to get the image for the very first instance(First Tab) in IE7, but for the next instances(Tab) in IE7 it creates only Black images.
Is there any work around for this problem?
|
|
|
|
|