3

I have this line:

Process.Start("chrome.exe",
                "http://www.cnn.com");

It's openning a new chrome browser window. I want to do two things:

  1. To convert/save the chrome window as image.
  2. To hide this window.

This is the code im trying now in a new class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Drawing;

namespace GatherLinks
{
    class WebSiteScreenShot
    {
        [DllImport("user32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
        [DllImport("user32.dll")]
        public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);

        public WebSiteScreenShot()
        {

        }

        public void WhateverMethod()
        {
            //initialize process and get hWnd
            Process putty = Process.Start("chrome.exe",
                "http://www.cnn.com");
            putty.WaitForInputIdle();
            IntPtr winHandle = putty.MainWindowHandle;

            //print screen
            RECT rc;
            GetWindowRect(winHandle, out rc);

            Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);
            Graphics gfxBmp = Graphics.FromImage(bmp);
            IntPtr hdcBitmap = gfxBmp.GetHdc();

            PrintWindow(winHandle, hdcBitmap, 0);

            gfxBmp.ReleaseHdc(hdcBitmap);
            gfxBmp.Dispose();

            bmp.Save("c:\\temp\\test.png", ImageFormat.Png);

            //hides window
            ShowWindowAsync(winHandle, 0);
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            private int _Left;
            private int _Top;
            private int _Right;
            private int _Bottom;

            public RECT(RECT Rectangle)
                : this(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
            {
            }
            public RECT(int Left, int Top, int Right, int Bottom)
            {
                _Left = Left;
                _Top = Top;
                _Right = Right;
                _Bottom = Bottom;
            }

            public int X
            {
                get { return _Left; }
                set { _Left = value; }
            }
            public int Y
            {
                get { return _Top; }
                set { _Top = value; }
            }
            public int Left
            {
                get { return _Left; }
                set { _Left = value; }
            }
            public int Top
            {
                get { return _Top; }
                set { _Top = value; }
            }
            public int Right
            {
                get { return _Right; }
                set { _Right = value; }
            }
            public int Bottom
            {
                get { return _Bottom; }
                set { _Bottom = value; }
            }
            public int Height
            {
                get { return _Bottom - _Top; }
                set { _Bottom = value + _Top; }
            }
            public int Width
            {
                get { return _Right - _Left; }
                set { _Right = value + _Left; }
            }
            public Point Location
            {
                get { return new Point(Left, Top); }
                set
                {
                    _Left = value.X;
                    _Top = value.Y;
                }
            }
            public Size Size
            {
                get { return new Size(Width, Height); }
                set
                {
                    _Right = value.Width + _Left;
                    _Bottom = value.Height + _Top;
                }
            }

            public static implicit operator Rectangle(RECT Rectangle)
            {
                return new Rectangle(Rectangle.Left, Rectangle.Top, Rectangle.Width, Rectangle.Height);
            }
            public static implicit operator RECT(Rectangle Rectangle)
            {
                return new RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom);
            }
            public static bool operator ==(RECT Rectangle1, RECT Rectangle2)
            {
                return Rectangle1.Equals(Rectangle2);
            }
            public static bool operator !=(RECT Rectangle1, RECT Rectangle2)
            {
                return !Rectangle1.Equals(Rectangle2);
            }

            public override string ToString()
            {
                return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}";
            }

            public override int GetHashCode()
            {
                return ToString().GetHashCode();
            }

            public bool Equals(RECT Rectangle)
            {
                return Rectangle.Left == _Left && Rectangle.Top == _Top && Rectangle.Right == _Right && Rectangle.Bottom == _Bottom;
            }

            public override bool Equals(object Object)
            {
                if (Object is RECT)
                {
                    return Equals((RECT)Object);
                }
                else if (Object is Rectangle)
                {
                    return Equals(new RECT((Rectangle)Object));
                }

                return false;
            }
        }

    }
}

First of all the window of the chrome was open and not hide. Second im getting on start an exception on the line:

Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);

The exception is:

ArguemntException Parameter is not valid

I see that bmp is null and Width and Height are 0

I used this code in Form1 like this:

WebSiteScreenShot wsss;

Then in the constructor:

wsss = new WebSiteScreenShot();
wsss.WhateverMethod();

And use a breakpoint and got the exception.

This is the exception full message:

System.ArgumentException was unhandled
  HResult=-2147024809
  Message=Parameter is not valid.
  Source=System.Drawing
  StackTrace:
       at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
       at GatherLinks.WebSiteScreenShot.WhateverMethod() in d:\C-Sharp\GatherLinks\GatherLinks-2\GatherLinks\GatherLinks\WebSiteScreenShot.cs:line 38
       at GatherLinks.Form1..ctor() in d:\C-Sharp\GatherLinks\GatherLinks-2\GatherLinks\GatherLinks\Form1.cs:line 71
       at GatherLinks.Program.Main() in d:\C-Sharp\GatherLinks\GatherLinks-2\GatherLinks\GatherLinks\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
Haim Kashi
  • 399
  • 7
  • 19

2 Answers2

0

edit

I've added a process refresh and thread wait that should fix the problem of not having a MainWindowHandle when Chrome launches.

Things to note:

Process.Refresh will only work if another instance of chrome is NOT running (if chrome is already running the new Process will cause a new tab to be opened and will exit, hence process.Refresh will fail) - other approaches are possible to avoid this problem.

The thread sleep value might need to be tweaked for your needs, but some sort of wait period is necessary for the window handle to be created and the page to load.

end of edit

this should do it

  • it starts a process (notepad.exe in this case)
  • waits until it's loaded for user input and gets the main window handle
  • takes a print screen of the given process (I've used the solution Maurice proposed at Get a screenshot of a specific application for this, it is more complex than some other approaches but does not require the process to be in the foreground)
  • saves the image to c:\temp\test.png
  • hides the process window using ShowWindowAsync

...
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Drawing.Imaging;
...
...
        [DllImport("user32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
        [DllImport("user32.dll")]
        public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);


        public WhateverMethod()
        {
             //initialize process and get hWnd
            Process chrome = Process.Start("chrome.exe","http://www.cnn.com");

            //wait for chrome window to open AND page to load (important for process refresh)
            //you might need to increase the sleep time for the page to load or monitor the "loading" title on Chrome

            System.Threading.Thread.Sleep(4000);
            chrome.Refresh();
            IntPtr mainHandle = chrome.MainWindowHandle;    

           RECT rc;
           GetWindowRect(mainHandle, out rc);

            Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);
            Graphics gfxBmp = Graphics.FromImage(bmp);
            IntPtr hdcBitmap = gfxBmp.GetHdc();

            PrintWindow(mainHandle, hdcBitmap, 0);

            gfxBmp.ReleaseHdc(hdcBitmap);
            gfxBmp.Dispose();

            bmp.Save("c:\\temp\\test.png", ImageFormat.Png);
            ShowWindowAsync(mainHandle, 0);
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            private int _Left;
            private int _Top;
            private int _Right;
            private int _Bottom;

            public RECT(RECT Rectangle)
                : this(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
            {
            }
            public RECT(int Left, int Top, int Right, int Bottom)
            {
                _Left = Left;
                _Top = Top;
                _Right = Right;
                _Bottom = Bottom;
            }

            public int X
            {
                get { return _Left; }
                set { _Left = value; }
            }
            public int Y
            {
                get { return _Top; }
                set { _Top = value; }
            }
            public int Left
            {
                get { return _Left; }
                set { _Left = value; }
            }
            public int Top
            {
                get { return _Top; }
                set { _Top = value; }
            }
            public int Right
            {
                get { return _Right; }
                set { _Right = value; }
            }
            public int Bottom
            {
                get { return _Bottom; }
                set { _Bottom = value; }
            }
            public int Height
            {
                get { return _Bottom - _Top; }
                set { _Bottom = value + _Top; }
            }
            public int Width
            {
                get { return _Right - _Left; }
                set { _Right = value + _Left; }
            }
            public Point Location
            {
                get { return new Point(Left, Top); }
                set
                {
                    _Left = value.X;
                    _Top = value.Y;
                }
            }
            public Size Size
            {
                get { return new Size(Width, Height); }
                set
                {
                    _Right = value.Width + _Left;
                    _Bottom = value.Height + _Top;
                }
            }

            public static implicit operator Rectangle(RECT Rectangle)
            {
                return new Rectangle(Rectangle.Left, Rectangle.Top, Rectangle.Width, Rectangle.Height);
            }
            public static implicit operator RECT(Rectangle Rectangle)
            {
                return new RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom);
            }
            public static bool operator ==(RECT Rectangle1, RECT Rectangle2)
            {
                return Rectangle1.Equals(Rectangle2);
            }
            public static bool operator !=(RECT Rectangle1, RECT Rectangle2)
            {
                return !Rectangle1.Equals(Rectangle2);
            }

            public override string ToString()
            {
                return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}";
            }

            public override int GetHashCode()
            {
                return ToString().GetHashCode();
            }

            public bool Equals(RECT Rectangle)
            {
                return Rectangle.Left == _Left && Rectangle.Top == _Top && Rectangle.Right == _Right && Rectangle.Bottom == _Bottom;
            }

            public override bool Equals(object Object)
            {
                if (Object is RECT)
                {
                    return Equals((RECT)Object);
                }
                else if (Object is Rectangle)
                {
                    return Equals(new RECT((Rectangle)Object));
                }

                return false;
            }
        }

Community
  • 1
  • 1
Rafael Oltra
  • 1,239
  • 9
  • 15
  • Rafael I tried the code you added in the answer but i'm getting an erro/exception im updating my question with it. – Haim Kashi Jul 01 '13 at 07:06
  • I see now that maybe in Form1 i need to add first in the constructor: WebSiteScreenShot.GetWindowRect( but im not sure what to do with it ? – Haim Kashi Jul 01 '13 at 07:13
  • Hi Haim, current version should work - just make sure no other chrome instances are currently running – Rafael Oltra Jul 03 '13 at 18:47
-1

I think is late for give you an answer, but for anyone who have this issue, try: wkhtmltopdf and wkhtmltoimage. Those are open source (LGPLv3) command line tools to render HTML into PDF and various image formats using the Qt WebKit rendering engine. These run entirely "headless" and do not require a display or display service.

Basically you can convert an entire webpage, to PDF or Image format.

Community
  • 1
  • 1