title: How to copy image without using the clipboard?
body: <p>Question: I have the below code to capture an image from a webcam.</p>
  
  <p>My problem is this part:</p>
  
  <pre><code>SendMessage(hCaptureWnd, WM_CAP_COPY, 0, 0);                    // copy it to the clipboard
  </code></pre>
  
  <p>What it does is copy the image from the window to the clipboard, and then create a byte array out of it.</p>
  
  <p>It works - as long as you don't use the clipboard while the program is running.<br />
  The problem is, this doesn't even work for myself, as I sometimes copy something while Visual Studio takes ages to start debug the web application, and then it crashes.</p>
  
  <p>So here my question:<br />
  How can I get the image without using the clipboard ?
  Or more specifically, how to transform hCaptureWnd to System.Drawing.Image ?</p>
  
  <p><hr />
  -- Edit:<br />
  I missed to say "without creating a file, i want a byte array".<br />
  It's a web application, so the user the application runs under shouldn't have write access to the file system (writing to a file only for temporary testing) ...<br />
  -- End Edit:</p>
  
  <hr />
  
  <pre><code>/// &lt;summary&gt;
  /// Captures a frame from the webcam and returns the byte array associated
  /// with the captured image
  /// &lt;/summary&gt;
  /// &lt;param name="connectDelay"&gt;number of milliseconds to wait between connect 
  /// and capture - necessary for some cameras that take a while to 'warm up'&lt;/param&gt;
  /// &lt;returns&gt;byte array representing a bitmp or null (if error or no webcam)&lt;/returns&gt;
  private static byte[] InternalCaptureToByteArray(int connectDelay = 500)
  {
      Clipboard.Clear();                                              // clear the clipboard
      int hCaptureWnd = capCreateCaptureWindowA("ccWebCam", 0, 0, 0,  // create the hidden capture window
          350, 350, 0, 0);
      SendMessage(hCaptureWnd, WM_CAP_CONNECT, 0, 0);                 // send the connect message to it
      Thread.Sleep(connectDelay);                                     // sleep the specified time
      SendMessage(hCaptureWnd, WM_CAP_GET_FRAME, 0, 0);               // capture the frame
      SendMessage(hCaptureWnd, WM_CAP_COPY, 0, 0);                    // copy it to the clipboard
      SendMessage(hCaptureWnd, WM_CAP_DISCONNECT, 0, 0);              // disconnect from the camera
      Bitmap bitmap = (Bitmap)Clipboard.GetDataObject().GetData(DataFormats.Bitmap);  // copy into bitmap
  
      if (bitmap == null)
          return null;
  
      using (MemoryStream stream = new MemoryStream())
      {
          bitmap.Save(stream, ImageFormat.Bmp);    // get bitmap bytes
          return stream.ToArray();
      } // End Using stream
  
  } // End Function InternalCaptureToByteArray
  </code></pre>
  
  <p>Note (<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd756879(v=vs.85).aspx" rel="nofollow">http://msdn.microsoft.com/en-us/library/windows/desktop/dd756879(v=vs.85).aspx</a>):</p>
  
  <pre><code>HWND VFWAPI capCreateCaptureWindow(
    LPCTSTR lpszWindowName,
    DWORD dwStyle,
    int x,
    int y,
    int nWidth,
    int nHeight,
    HWND hWnd,
    int nID
  );
  
  
  #define VFWAPI  WINAPI 
  
  typedef HANDLE HWND;
  typedef PVOID HANDLE;
  typedef void *PVOID;
  </code></pre>
  
  <p>Full code for reference</p>
  
  <pre><code>using System;
  using System.IO;
  using System.Drawing;
  using System.Threading;
  using System.Windows.Forms;
  using System.Drawing.Imaging;
  using System.Collections.Generic;
  using System.Runtime.InteropServices;
  
  
  // http://www.creativecodedesign.com/node/66
  // http://www.barebonescoder.com/2012/01/finding-your-web-cam-with-c-directshow-net/
  // http://www.codeproject.com/Articles/15219/WebCam-Fast-Image-Capture-Service-using-WIA
  // http://www.c-sharpcorner.com/uploadfile/yougerthen/integrate-the-web-webcam-functionality-using-C-Sharp-net-and-com-part-viii/
  // http://forums.asp.net/t/1410057.aspx
  
  
  namespace cc.Utility
  {
  
  
      // bool isCaptured = ccWebCam.CaptureSTA("capture.jpg"); // Access to path C:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\10.0\capture.jpg" denied.
      // byte[] captureBytes = ccWebCam.CaptureSTA();
  
      /// &lt;summary&gt;
      /// Timur Kovalev (http://www.creativecodedesign.com):
      /// This class provides a method of capturing a webcam image via avicap32.dll api.
      /// &lt;/summary&gt;    
      public static class ccWebCam
      {
          #region *** PInvoke Stuff - methods to interact with capture window ***
  
          [DllImport("user32", EntryPoint = "SendMessage")]
          private static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
  
          [DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindowA")]
          private static extern int capCreateCaptureWindowA(string lpszWindowName, int dwStyle, 
              int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);  
  
  
          private const int WM_CAP_CONNECT = 1034;
          private const int WM_CAP_DISCONNECT = 1035;
          private const int WM_CAP_COPY = 1054;
          private const int WM_CAP_GET_FRAME = 1084;
  
  
          #endregion
  
  
          private static object objWebCamThreadLock = new object();
  
  
          //CaptureToFile(@"D:\Stefan.Steiger\Documents\Visual Studio 2010\Projects\Post_Ipag\image3.jpg"):
          public static bool Capture(string filePath, int connectDelay = 500)
          {
              lock (objWebCamThreadLock)
              {
                  return cc.Utility.ccWebCam.InternalCaptureAsFileInThread(filePath, connectDelay);
              }
          } // End Treadsafe Function Capture
  
  
          public static byte[] Capture(int connectDelay = 500)
          {
              lock (objWebCamThreadLock)
              {
                  return InternalCaptureToByteArrayInThread(connectDelay);
              }
          } // End Treadsafe Function Capture
  
  
          /// &lt;summary&gt;
          /// Captures a frame from the webcam and returns the byte array associated
          /// with the captured image. The image is also stored in a file
          /// &lt;/summary&gt;
          /// &lt;param name="filePath"&gt;path the file wher ethe image will be saved&lt;/param&gt;
          /// &lt;param name="connectDelay"&gt;number of milliseconds to wait between connect 
          /// and capture - necessary for some cameras that take a while to 'warm up'&lt;/param&gt;
          /// &lt;returns&gt;true on success, false on failure&lt;/returns&gt;
          private static bool InternalCaptureAsFileInThread(string filePath, int connectDelay = 500)
          {
              bool success = false;
              Thread catureThread = new Thread(() =&gt;
              {
                  success = InternalCaptureAsFile(filePath, connectDelay);
              });
              catureThread.SetApartmentState(ApartmentState.STA);
              catureThread.Start();
              catureThread.Join();
              return success;
          } // End Function InternalCaptureAsFileInThread
  
  
          /// &lt;summary&gt;
          /// Captures a frame from the webcam and returns the byte array associated
          /// with the captured image. The image is also stored in a file
          /// &lt;/summary&gt;
          /// &lt;param name="filePath"&gt;path the file wher ethe image will be saved&lt;/param&gt;
          /// &lt;param name="connectDelay"&gt;number of milliseconds to wait between connect 
          /// and capture - necessary for some cameras that take a while to 'warm up'&lt;/param&gt;
          /// &lt;returns&gt;true on success, false on failure&lt;/returns&gt;
          private static bool InternalCaptureAsFile(string filePath, int connectDelay = 500)
          {
              byte[] capture = ccWebCam.InternalCaptureToByteArray(connectDelay);
              if (capture != null)
              {
                  // Access to path C:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\10.0\image1.jpg" denied.
                  File.WriteAllBytes(filePath, capture);
                  return true;
              }
              return false;
          } // End Function InternalCaptureAsFile
  
  
          /// &lt;summary&gt;
          /// Captures a frame from the webcam and returns the byte array associated
          /// with the captured image. Runs in a newly-created STA thread which is 
          /// required for this method of capture
          /// &lt;/summary&gt;
          /// &lt;param name="connectDelay"&gt;number of milliseconds to wait between connect 
          /// and capture - necessary for some cameras that take a while to 'warm up'&lt;/param&gt;
          /// &lt;returns&gt;byte array representing a bitmp or null (if error or no webcam)&lt;/returns&gt;
          private static byte[] InternalCaptureToByteArrayInThread(int connectDelay = 500)
          {
              byte[] bytes = null;
              Thread catureThread = new Thread(() =&gt;
              {
                  bytes = InternalCaptureToByteArray(connectDelay);
              });
              catureThread.SetApartmentState(ApartmentState.STA);
              catureThread.Start();
              catureThread.Join();
              return bytes;
          } // End Function InternalCaptureToByteArrayInThread
  
  
          /// &lt;summary&gt;
          /// Captures a frame from the webcam and returns the byte array associated
          /// with the captured image
          /// &lt;/summary&gt;
          /// &lt;param name="connectDelay"&gt;number of milliseconds to wait between connect 
          /// and capture - necessary for some cameras that take a while to 'warm up'&lt;/param&gt;
          /// &lt;returns&gt;byte array representing a bitmp or null (if error or no webcam)&lt;/returns&gt;
          private static byte[] InternalCaptureToByteArray(int connectDelay = 500)
          {
              Clipboard.Clear();                                              // clear the clipboard
              int hCaptureWnd = capCreateCaptureWindowA("ccWebCam", 0, 0, 0,  // create the hidden capture window
                  350, 350, 0, 0);
              SendMessage(hCaptureWnd, WM_CAP_CONNECT, 0, 0);                 // send the connect message to it
              Thread.Sleep(connectDelay);                                     // sleep the specified time
              SendMessage(hCaptureWnd, WM_CAP_GET_FRAME, 0, 0);               // capture the frame
              SendMessage(hCaptureWnd, WM_CAP_COPY, 0, 0);                    // copy it to the clipboard
              SendMessage(hCaptureWnd, WM_CAP_DISCONNECT, 0, 0);              // disconnect from the camera
              Bitmap bitmap = (Bitmap)Clipboard.GetDataObject().GetData(DataFormats.Bitmap);  // copy into bitmap
  
              if (bitmap == null)
                  return null;
  
              using (MemoryStream stream = new MemoryStream())
              {
                  bitmap.Save(stream, ImageFormat.Bmp);    // get bitmap bytes
                  return stream.ToArray();
              } // End Using stream
  
          } // End Function InternalCaptureToByteArray
  
  
      }
  
  
  }
  </code></pre>
  
  <hr>
  
  <p>I tried like this, but it only gets a black image...</p>
  
  <pre><code>    [DllImport("user32.dll")]
      static extern IntPtr GetWindowDC(IntPtr hWnd);
  
      [DllImport("gdi32.dll", SetLastError = true)]
      static extern IntPtr CreateCompatibleDC(IntPtr hdc);
  
      enum TernaryRasterOperations : uint
      {
          /// &lt;summary&gt;dest = source&lt;/summary&gt;
          SRCCOPY = 0x00CC0020,
          /// &lt;summary&gt;dest = source OR dest&lt;/summary&gt;
          SRCPAINT = 0x00EE0086,
          /// &lt;summary&gt;dest = source AND dest&lt;/summary&gt;
          SRCAND = 0x008800C6,
          /// &lt;summary&gt;dest = source XOR dest&lt;/summary&gt;
          SRCINVERT = 0x00660046,
          /// &lt;summary&gt;dest = source AND (NOT dest)&lt;/summary&gt;
          SRCERASE = 0x00440328,
          /// &lt;summary&gt;dest = (NOT source)&lt;/summary&gt;
          NOTSRCCOPY = 0x00330008,
          /// &lt;summary&gt;dest = (NOT src) AND (NOT dest)&lt;/summary&gt;
          NOTSRCERASE = 0x001100A6,
          /// &lt;summary&gt;dest = (source AND pattern)&lt;/summary&gt;
          MERGECOPY = 0x00C000CA,
          /// &lt;summary&gt;dest = (NOT source) OR dest&lt;/summary&gt;
          MERGEPAINT = 0x00BB0226,
          /// &lt;summary&gt;dest = pattern&lt;/summary&gt;
          PATCOPY = 0x00F00021,
          /// &lt;summary&gt;dest = DPSnoo&lt;/summary&gt;
          PATPAINT = 0x00FB0A09,
          /// &lt;summary&gt;dest = pattern XOR dest&lt;/summary&gt;
          PATINVERT = 0x005A0049,
          /// &lt;summary&gt;dest = (NOT dest)&lt;/summary&gt;
          DSTINVERT = 0x00550009,
          /// &lt;summary&gt;dest = BLACK&lt;/summary&gt;
          BLACKNESS = 0x00000042,
          /// &lt;summary&gt;dest = WHITE&lt;/summary&gt;
          WHITENESS = 0x00FF0062,
          /// &lt;summary&gt;
          /// Capture window as seen on screen.  This includes layered windows 
          /// such as WPF windows with AllowsTransparency="true"
          /// &lt;/summary&gt;
          CAPTUREBLT = 0x40000000
      }
  
      [DllImport("gdi32.dll")]
      [return: MarshalAs(UnmanagedType.Bool)]
      static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
  
      [DllImport("gdi32.dll")]
      static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
  
      [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
      static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
  
      [DllImport("gdi32.dll")]
      static extern bool DeleteDC(IntPtr hdc);
  
      [DllImport("user32.dll")]
      static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);
  
      [DllImport("gdi32.dll")]
      static extern bool DeleteObject(IntPtr hObject);
  
  
      public static void ScreenshotWindow(IntPtr windowHandle)
      {
          Rect Rect = new Rect();
  
          GetWindowRect(windowHandle, ref Rect);
          int width = Rect.Right - Rect.Left;
          int height = Rect.Bottom - Rect.Top;
  
          IntPtr windowDeviceContext = GetWindowDC(windowHandle);
          IntPtr destDeviceContext = CreateCompatibleDC(windowDeviceContext);
          IntPtr bitmapHandle = CreateCompatibleBitmap(windowDeviceContext, width, height);
          IntPtr oldObject = SelectObject(destDeviceContext, bitmapHandle);
  
          BitBlt(destDeviceContext, 0, 0, width, height, windowDeviceContext, 0, 0, TernaryRasterOperations.CAPTUREBLT | TernaryRasterOperations.SRCCOPY);
          SelectObject(destDeviceContext, oldObject);
  
          DeleteDC(destDeviceContext);
          ReleaseDC(windowHandle, destDeviceContext);
  
  
          Image screenshot = Image.FromHbitmap(bitmapHandle);
          DeleteObject(bitmapHandle);
  
          screenshot.Save("d:\\temp\\mywebcamimage.png", System.Drawing.Imaging.ImageFormat.Png);
  
          /*
          // TODO - Remove above save when it works
          using (MemoryStream stream = new MemoryStream())
          {
              screenshot.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
              return stream.ToArray();
          }
          */
      }
  </code></pre>
  
  <p>And then this after <code>SendMessage(hCaptureWnd, WM_CAP_GET_FRAME, 0, 0);</code></p>
  
  <pre><code>ScreenshotWindow(new IntPtr(hCaptureWnd));
  </code></pre>