Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. How do you save images loaded in a Microsoft Web Browser Control?

How do you save images loaded in a Microsoft Web Browser Control?

Scheduled Pinned Locked Moved C#
performancetutorialquestion
12 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Heath Stewart

    When you get the image URL by enumerating IHTMLDocument2.images, make sure you are getting the absolute URL including the host information and scheme. If the server's giving you "Bad Request" then use a HttpWebRequest which will give you a little more feedback. You could invoke the Save As functionality by using IWebBrowser.ExecWB with parameters that are documented in the Platform SDK under "Web Development". Visit http://msdn.microsoft.com/library[^] for details. Basically, execute something like this:

    axWebBrowser1.ExecWB(
    71, // IDM_SAVEAS
    0, // OLECMDEXECOPT_DODEFAULT,
    path, // The path to save the file
    null);

    The first two parameters - enums - should also be defined in Interop.SHDocVw.dll or Microsoft.mshtml.dll; I really don't remember off-hand. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

    K Offline
    K Offline
    kayhustle
    wrote on last edited by
    #3

    Ok, if I use HttpWebRequest to reload the url of the image,when I execute GetRequestStream, it throws an exception that says "cannot send a content-body with this verb type". For the webbrowser.ExecWB, I looked over the documentation and it saves that the first parameter is like clicking on the File menu item, and then selecting Save As... What I would need using this implementation would be to right click on an image in the browser and execute Save As... Any ideas? Thanks

    H 1 Reply Last reply
    0
    • K kayhustle

      Ok, if I use HttpWebRequest to reload the url of the image,when I execute GetRequestStream, it throws an exception that says "cannot send a content-body with this verb type". For the webbrowser.ExecWB, I looked over the documentation and it saves that the first parameter is like clicking on the File menu item, and then selecting Save As... What I would need using this implementation would be to right click on an image in the browser and execute Save As... Any ideas? Thanks

      H Offline
      H Offline
      Heath Stewart
      wrote on last edited by
      #4

      There's no support for that via IOleCommandTarget (see the docs). You would be able to, however, copy the filename from the save location + "filename_files" directory. Most often, the image retains the filename (only doesn't when a collision occurs). To simulate a user click would require getting the client X and Y coordinates, translating those to screen coordinates, then simulating a right mouse click. You would then have to guess where "Save Image As..." is located (tends to change positions with versions) and simulate a click. This is all very error-prone. Why are you using GetRequestStream, though? You do something like this:

      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
      "https://somesecureserver/path/image.gif");
      HttpWebResponse response = (HttpWebResponse)request.GetResponse();
      // Now write out the response to a file

      Unless you plan on POST'ing information to the site, you don't need the request stream. You should look at the examples in the .NET Framework SDK documentation. For HttpWebRequest and HttpWebResponse there's quite a unique examples. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

      K 1 Reply Last reply
      0
      • H Heath Stewart

        There's no support for that via IOleCommandTarget (see the docs). You would be able to, however, copy the filename from the save location + "filename_files" directory. Most often, the image retains the filename (only doesn't when a collision occurs). To simulate a user click would require getting the client X and Y coordinates, translating those to screen coordinates, then simulating a right mouse click. You would then have to guess where "Save Image As..." is located (tends to change positions with versions) and simulate a click. This is all very error-prone. Why are you using GetRequestStream, though? You do something like this:

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
        "https://somesecureserver/path/image.gif");
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        // Now write out the response to a file

        Unless you plan on POST'ing information to the site, you don't need the request stream. You should look at the examples in the .NET Framework SDK documentation. For HttpWebRequest and HttpWebResponse there's quite a unique examples. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

        K Offline
        K Offline
        kayhustle
        wrote on last edited by
        #5

        Ok, after parsing the html code in WebBrowser for the url of the image. I execute

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();

        Right in the call to GetResponse I get the Bad Request Exception that I got using the WebClient class. Is there something else I must assign to my request so that it knows this request is being made from the same app as the WebBrowser? Thanks

        H 1 Reply Last reply
        0
        • K kayhustle

          Ok, after parsing the html code in WebBrowser for the url of the image. I execute

          HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
          HttpWebResponse response = (HttpWebResponse)request.GetResponse();

          Right in the call to GetResponse I get the Bad Request Exception that I got using the WebClient class. Is there something else I must assign to my request so that it knows this request is being made from the same app as the WebBrowser? Thanks

          H Offline
          H Offline
          Heath Stewart
          wrote on last edited by
          #6

          The WebBrowser is an in-process component of your application - it is in the same process. What you're asking for is very ambiguous. You can set the UserAgent to the same as that for the WebBrowser control, but that doesn't necessarily mean it'll work. You need to be more specific. Is an actual exception being thrown? If so, what is it? If not, is the server returning a page? Have you debugged your code and made sure that your URL is defined correctly while stepping through your code. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

          K 1 Reply Last reply
          0
          • H Heath Stewart

            The WebBrowser is an in-process component of your application - it is in the same process. What you're asking for is very ambiguous. You can set the UserAgent to the same as that for the WebBrowser control, but that doesn't necessarily mean it'll work. You need to be more specific. Is an actual exception being thrown? If so, what is it? If not, is the server returning a page? Have you debugged your code and made sure that your URL is defined correctly while stepping through your code. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

            K Offline
            K Offline
            kayhustle
            wrote on last edited by
            #7

            I've checked my code, and the url for the image is correct. When I execute GetResponse for the request, a System.Net.WebException is thrown with the message {"The remote server returned an error: (400) Bad Request." } Do you know how I would get the UserAgent of the WebBrowser control? Thank you,

            H 1 Reply Last reply
            0
            • K kayhustle

              I've checked my code, and the url for the image is correct. When I execute GetResponse for the request, a System.Net.WebException is thrown with the message {"The remote server returned an error: (400) Bad Request." } Do you know how I would get the UserAgent of the WebBrowser control? Thank you,

              H Offline
              H Offline
              Heath Stewart
              wrote on last edited by
              #8

              You don't - nor can you (at least not in its entirety) - set the WebBrowser's user-agent. You set it on the HttpWebRequest. See the HttpWebBrowser.UserAgent property in the .NET Framework SDK documentation. You could programmatically set this to be the same as the WebBrowser control's with something like this:

              IHTMLWindow2 window = (IHTMLWindow2)axWebBrowser;
              if (window != null)
              {
              httpRequest.UserAgent = window.navigator.userAgent;
              }

              That still may not solve the problem. You need to figure out why the server is returning HTTP error code 400. Setting the user-agent may help, but there's many other things that could be wrong. If you have access to the server, check the lots. If it's ASP.NET, open trace.axd in your browser off the web application's root (like http://localhost/myapp/trace.axd). Tracing has to be turned on for that to work, though, and has to allow connections from your host. All that information is in the .NET Framework SDK under the ASP.NET configuration documentation. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

              K 1 Reply Last reply
              0
              • H Heath Stewart

                You don't - nor can you (at least not in its entirety) - set the WebBrowser's user-agent. You set it on the HttpWebRequest. See the HttpWebBrowser.UserAgent property in the .NET Framework SDK documentation. You could programmatically set this to be the same as the WebBrowser control's with something like this:

                IHTMLWindow2 window = (IHTMLWindow2)axWebBrowser;
                if (window != null)
                {
                httpRequest.UserAgent = window.navigator.userAgent;
                }

                That still may not solve the problem. You need to figure out why the server is returning HTTP error code 400. Setting the user-agent may help, but there's many other things that could be wrong. If you have access to the server, check the lots. If it's ASP.NET, open trace.axd in your browser off the web application's root (like http://localhost/myapp/trace.axd). Tracing has to be turned on for that to work, though, and has to allow connections from your host. All that information is in the .NET Framework SDK under the ASP.NET configuration documentation. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

                K Offline
                K Offline
                kayhustle
                wrote on last edited by
                #9

                Hmm, when I try to do that cast,(IHTMLWindow2)axWebBrowser;, it throws an invalid cast exception. Is there a different way to cast it? Thanks

                H 1 Reply Last reply
                0
                • K kayhustle

                  Hmm, when I try to do that cast,(IHTMLWindow2)axWebBrowser;, it throws an invalid cast exception. Is there a different way to cast it? Thanks

                  H Offline
                  H Offline
                  Heath Stewart
                  wrote on last edited by
                  #10

                  Then the WebBrowser control doesn't implement the IHTMLWindow2 interface (from a COM perspective - not from .NET*). My mistake. What you'll have to do then is cast WebBrowser.Document to an IHTMLDocument2 (defined in Microsoft.mshtml.dll) then use IHTMLDocument2.parentWindow and cast that to an IHTMLWindow2. That will get you the reference you need (don't forget to check for null!) to navigator.userAgent, just like you would in script in DHTML. * When the ComImportAttribute is present on a type, the CLR does a QueryInterface for an interface on an object instead of a cast as performed in IL instructions. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

                  K 1 Reply Last reply
                  0
                  • H Heath Stewart

                    Then the WebBrowser control doesn't implement the IHTMLWindow2 interface (from a COM perspective - not from .NET*). My mistake. What you'll have to do then is cast WebBrowser.Document to an IHTMLDocument2 (defined in Microsoft.mshtml.dll) then use IHTMLDocument2.parentWindow and cast that to an IHTMLWindow2. That will get you the reference you need (don't forget to check for null!) to navigator.userAgent, just like you would in script in DHTML. * When the ComImportAttribute is present on a type, the CLR does a QueryInterface for an interface on an object instead of a cast as performed in IL instructions. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

                    K Offline
                    K Offline
                    kayhustle
                    wrote on last edited by
                    #11

                    Interesting, I've definitely learned a lot. I was able to make the cast and pass in the user agent. However, it still sends the 400 bad request exception. What I found though, which is strange is that I can navigate to the image using the webbrowser control using the same or even a different Web Browser Control. Once the browser has navigated I can call this getimage() function, which grabs the picture indirectly from the graphics card buffer. The downside to this is that the browser has to be in focus of course. I still don't get why it would send a bad request to the HttpWebRequest and not to a browser object, but I'm still glad that I can at least grab the picture indirectly. Thanks,

                    private void getimage()
                    {
                    Control c = this.axWebBrowser1 as Control;
                    Bitmap bmp = CaptureControl(c);
                    bmp.Save("codeword.jpeg",ImageFormat.Jpeg);
                    }
                    
                    [System.Runtime.InteropServices.DllImport("gdi32.dll")] private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, System.Int32 dwRop);
                    		public static Bitmap CaptureControl(System.Windows.Forms.Control control)
                    		{
                    			Graphics g1 = control.CreateGraphics();
                    			Bitmap bitmap = new Bitmap(control.ClientRectangle.Width, control.ClientRectangle.Height, g1);
                    			Graphics g2 = Graphics.FromImage(bitmap);
                    			IntPtr dc1 = g1.GetHdc();
                    			try
                    			{
                    				IntPtr dc2 = g2.GetHdc();
                    				try
                    				{
                    					BitBlt(dc2, 0, 0, control.ClientRectangle.Width, control.ClientRectangle.Height, dc1, 0, 0, 13369376);
                    				}
                    				finally
                    				{
                    					g2.ReleaseHdc(dc2);
                    				}
                    			}
                    			finally
                    			{
                    				g1.ReleaseHdc(dc1);
                    			}
                    			return bitmap;
                    		}
                    
                    H 1 Reply Last reply
                    0
                    • K kayhustle

                      Interesting, I've definitely learned a lot. I was able to make the cast and pass in the user agent. However, it still sends the 400 bad request exception. What I found though, which is strange is that I can navigate to the image using the webbrowser control using the same or even a different Web Browser Control. Once the browser has navigated I can call this getimage() function, which grabs the picture indirectly from the graphics card buffer. The downside to this is that the browser has to be in focus of course. I still don't get why it would send a bad request to the HttpWebRequest and not to a browser object, but I'm still glad that I can at least grab the picture indirectly. Thanks,

                      private void getimage()
                      {
                      Control c = this.axWebBrowser1 as Control;
                      Bitmap bmp = CaptureControl(c);
                      bmp.Save("codeword.jpeg",ImageFormat.Jpeg);
                      }
                      
                      [System.Runtime.InteropServices.DllImport("gdi32.dll")] private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, System.Int32 dwRop);
                      		public static Bitmap CaptureControl(System.Windows.Forms.Control control)
                      		{
                      			Graphics g1 = control.CreateGraphics();
                      			Bitmap bitmap = new Bitmap(control.ClientRectangle.Width, control.ClientRectangle.Height, g1);
                      			Graphics g2 = Graphics.FromImage(bitmap);
                      			IntPtr dc1 = g1.GetHdc();
                      			try
                      			{
                      				IntPtr dc2 = g2.GetHdc();
                      				try
                      				{
                      					BitBlt(dc2, 0, 0, control.ClientRectangle.Width, control.ClientRectangle.Height, dc1, 0, 0, 13369376);
                      				}
                      				finally
                      				{
                      					g2.ReleaseHdc(dc2);
                      				}
                      			}
                      			finally
                      			{
                      				g1.ReleaseHdc(dc1);
                      			}
                      			return bitmap;
                      		}
                      
                      H Offline
                      H Offline
                      Heath Stewart
                      wrote on last edited by
                      #12

                      You have a major error in your code - though it's a good workaround to solving your problem: anything that implements IDisposable - including (and especially!) Graphics and Bitmap - should be disposed when you're finished. A good way in C# is like so:

                      using (Graphics g1 = control.CreateGraphics())
                      {
                      // ...
                      }

                      The using block makes sure that Dispose is called, even in case of error. It amounts to this:

                      Graphics g1 = control.CreateGraphics();
                      try
                      {
                      // ...
                      }
                      finally
                      {
                      if (g1 != null) g1.Dispose();
                      }

                      Actually, the object is always cast to IDisposable in the finally block so that explicit interface implementations are handled correctly, but I didn't want to confuse you. Other than that, this should work. If you don't dispose your Graphics and Bitmaps above, you'll be leaking resources (memory). Note that you don't have to dispose of controls, though. All Control derivatives encapsulates window handles (HWNDs) that are automatically destroyed. Disposing them is not necessary. In order to see why you're getting HTTP 400, you need to take a look at the HTTP request and response. A simple packet sniffer will help. Make sure that you're also requesting https://... A poorly implemented HTTP daemon expecting an SSL socket connection may return 400. There's many other reasons why this might be failing, however. If you're POSTing data from a web browser, for example, you need to do it again (but can be dangerous! you don't want to order a $4,500 segway twice now, do you?!). Like I said, the source of your error judging by your description is impossible to determine. You just have to get down and dirty and debug your code, including the HTTP request and responses sent from both your web browser (i.e., the WebBrowser control that you're embedding) as well as your HttpWebRequest and HttpWebResponse. This posting is provided "AS IS" with no warranties, and confers no rights. Software Design Engineer Developer Division Sustained Engineering Microsoft [My Articles]

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups