# [C++] Snapshot von Webcam machen



## C Coder (19. September 2004)

Hi!

Ich möchte gerne ein einfaches Bild von meiner Webcam bekommen OHNE irgendein Fenster erstellen zu müssen!

Gibts dafür ne Funktion, Code oder irgendwas aus dem OpenSource-Bereich?

Ich nutze Visual Studio 2002 unter XP
Bin echt am verzweifeln...


----------



## Kachelator (19. September 2004)

Ganz ohne HWND geht es nicht. Aber du musst das Bild ja nicht anzeigen. Bei dem Thema hilft dir Video for Windows (VfW) und das ist ja bereits eingebaut. 

http://www.webopedia.com/TERM/V/Video_for_Windows.html
http://msdn.microsoft.com/archive/d...irectx9_c/directx/htm/aboutcapturedevices.asp


----------



## C Coder (19. September 2004)

Harter Stoff, danke erstmal!

Wenns wirklich nicht ohne Fenster geht, gibts ne möglichkeit das zu verstecken,
das es nur als Prozess im Task-Manager auftaucht? (also nicht uner Anwendungen!)


----------



## Kachelator (19. September 2004)

> _Original geschrieben von C Coder _
> *Harter Stoff, danke erstmal!
> 
> Wenns wirklich nicht ohne Fenster geht, gibts ne möglichkeit das zu verstecken,
> das es nur als Prozess im Task-Manager auftaucht? (also nicht uner Anwendungen!) *


Klar, es zu verstecken ist kein Problem.
Ich suche gerade ein Testprojekt,  wo ich das mal gemacht habe, allerdings kann es noch eine Weile dauern, bis ich es finde. Und ich bin in den nächsten Tagen  nicht online. Vielleicht kann ja auch Endurion was zum Thema sagen; der hat mir nämlich gezeigt , wie es geht. 

Ah, ich habe es anscheinend schon einmal gepostet. Guck mal, ob dir das weiterhilft, und lass dich nicht von den Kommentaren irritieren -- die waren zu einer anderen Sache.

```
//... stdafx.h usw.

#include <vfw.h>

#pragma comment( lib, "vfw32.lib" )


// Der View hat ein Member für das Capturewindow
CChildView::CChildView()
{
  hwndCapture_  = 0;
}



/////////////////////////////////////////////////////////////////////
//-    OnCreate
/////////////////////////////////////////////////////////////////////
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd ::OnCreate(lpCreateStruct) == -1)
		return -1;
	
  InitCapture();

  Invalidate();
  return 0;
}


/////////////////////////////////////////////////////////////////////
//-    OnEraseBkgnd
/////////////////////////////////////////////////////////////////////
BOOL CChildView::OnEraseBkgnd(CDC* pDC) 
{
  return TRUE;
}

/////////////////////////////////////////////////////////////////////
//-  
//-    Videograbbing
//-  
/////////////////////////////////////////////////////////////////////
namespace
{
  BOOL StartCapture( HWND hwndCapture )
  {
    if ( hwndCapture == NULL )
    {
      return FALSE;
    }

    if ( !SendMessage( hwndCapture,WM_CAP_DRIVER_CONNECT, 0, 0 ) )
    {
      // kein Video-Input-Device gefunden
      DestroyWindow( hwndCapture );
      return FALSE;
    }

    SendMessage( hwndCapture, WM_CAP_SET_SCALE, (WPARAM)TRUE, 0 );
    SendMessage( hwndCapture, WM_CAP_SET_PREVIEW, 1, 0 );
    SendMessage( hwndCapture, WM_CAP_SET_PREVIEWRATE, 30, 0 );

    return TRUE;
  }

  void StopCapture( HWND hwndCapture )
  {
    if ( hwndCapture == NULL )
    {
      return;
    }
    SendMessage( hwndCapture, WM_CAP_STOP, 0, 0 );
    SendMessage( hwndCapture, WM_CAP_SET_PREVIEW, 0, 0 );
  }

  inline unsigned long C24TO15( unsigned long color )
  {
    return    ( ( ( ( color & 0xff0000 ) >> 16 ) >> 3 ) << 10 ) 
           |  ( ( ( ( color & 0x00ff00 ) >> 8  ) >> 3 ) << 5  ) 
           |  ( ( ( ( color & 0x0000ff ) >> 0  ) >> 3 ) << 0  ); 
  }
};

int CChildView::InitCapture()
{
  hwndCapture_  = capCreateCaptureWindow( "capture", 
                                        WS_OVERLAPPEDWINDOW,
                                        0,   0, 
                                        640,  480, 
                                        GetSafeHwnd(), 
                                        0 );
  
  ::SetWindowPos( hwndCapture_, NULL, 0, 0, 380, 285, SWP_NOZORDER );
  ::ShowWindow( hwndCapture_, SW_SHOW );
  StartCapture( hwndCapture_ );
  return 0;

}

void CChildView::OnDestroy() 
{
  if ( hwndCapture_ != NULL )
  {
    StopCapture( hwndCapture_ );
    ::SendMessage( hwndCapture_, WM_CAP_DRIVER_DISCONNECT, 0, 0 );
    ::DestroyWindow( hwndCapture_ );
    hwndCapture_ = NULL;
  }

	CWnd::OnDestroy();
}

void CChildView::OnDateiEinstellungen() 
{
  capDlgVideoFormat( hwndCapture_ );
}

/*-CaptureImage---------------------------------------------------------------+
 |                                                                            |
 +----------------------------------------------------------------------------*/
BOOL CChildView::CaptureImage()
{
  ::SendMessage( hwndCapture_, WM_CAP_GRAB_FRAME, 0, 0 );
  ::SendMessage( hwndCapture_, WM_CAP_EDIT_COPY, 0, 0 );

  if ( !::OpenClipboard( GetSafeHwnd() ) )
  {
    ::MessageBox( GetSafeHwnd(), "Konnte ClipBoard nicht anfordern.", "Fehler!", 0 );
    return FALSE;
  }
   
  HBITMAP hBitmap = (HBITMAP)GetClipboardData( CF_DIBV5 );
  if ( hBitmap == NULL )
  {
    CloseClipboard();
    ::MessageBox( GetSafeHwnd(), "Das Clipboard ist leer!", "Fehler", 0 );
    return FALSE;
  }
  
  BITMAPINFO* pInfo = ((BITMAPINFO*)hBitmap);
  LONG dwWidth      = pInfo->bmiHeader.biWidth;
  LONG dwHeight     = pInfo->bmiHeader.biHeight;
  WORD bitcount     = pInfo->bmiHeader.biBitCount;
  DWORD colorused   = pInfo->bmiHeader.biClrUsed;

  // für debugging
  //dh() << dwWidth << ", " << dwHeight << ", " << bitcount << ", " << colorused << "\n";
  //dh() << pInfo->bmiHeader.biSize << "\n"; 

  if ( bitcount == 24 )
  {
    int iLO = dwWidth;
    if ( iLO % 4 ) iLO += ( 4 - iLO % 4 );

    DWORD dwHeaderSize = 124;

    int targetwidth = m_pFrontPage->width();

    char* pBitmap = ( (char*) pInfo ) + dwHeaderSize + colorused * 4;

    for ( int j = 0; j < dwHeight; ++j )
    {
      for ( int i = 0; i < dwWidth; ++i )
      {
        unsigned long* pPixel = (unsigned long*)( pBitmap + i * 3 + j * iLO * 3 ); 
//#pragma TODO( "umbauen, damits auch für andere screenbreiten passt" )

        // HIER BEKOMMST DU JEDEN EINZELNEN PIXELWERT!  

        // das würde die pixel buffern:  
        //        (WORD)*( (WORD*)(m_pFrontPage->data()) + i + ( dwHeight - j - 1 ) *  targetwidth ) = C24TO15( *pPixel );
      }
    }
  }

  DeleteObject( hBitmap );
  CloseClipboard();

  return TRUE;
}

void CChildView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
  CaptureImage();
  StartCapture( hwndCapture_ );
	CWnd::OnLButtonDblClk(nFlags, point);
}

void CChildView::OnEditCopy() 
{
  CaptureImage();
  StartCapture( hwndCapture_ );
}
```


----------



## C Coder (19. September 2004)

Super Danke!
Das mit dem einzelnen Bild klappt jetzt schon sehr gut!

Nur jetzt hab ich son dämliches Fenster auf dem Desktop rumliegen... 
Wie bekomme ich das jetzt versteckt(evtl. TrayLeiste oder service)?


----------



## Kachelator (20. September 2004)

Ich kann dir im Moment auch nicht genau sagen, wie es geht -- keine Zeit, zu stöbern -- und paste hier einfach mal einen Schnipsel aus einer Dialoganwendung, die auch als Shell-Icon existierte:

```
// zeitdlg.cpp:

NOTIFYICONDATA nidIcon;

BYTE        *pSound       = NULL;
BYTE        *pSoundAlarm  = NULL;

#define UPDATEFILE "Q:\\Zeitverwaltung\\Zeit_Exe\\Zeit.exe"

extern CZeitApp theApp;

void CZeitDlg::MakeIcon()
{
  nidIcon.cbSize  = sizeof( NOTIFYICONDATA );
  nidIcon.hWnd    = GetSafeHwnd();
  TRACE( "nidIcon.hWnd %u\n", nidIcon.hWnd );
  nidIcon.uID     = 0;
  nidIcon.uFlags  = NIF_TIP | NIF_ICON | NIF_MESSAGE;
  nidIcon.uCallbackMessage = WM_NOTIFY_SIZER;
  nidIcon.hIcon = theApp.LoadIcon( MAKEINTRESOURCE( IDR_MAINFRAME ) );
  wsprintf( nidIcon.szTip, "Zeitverwaltung" );
  Shell_NotifyIcon( NIM_ADD, &nidIcon );
  ::DestroyIcon( nidIcon.hIcon );
}

void CZeitDlg::DestroyIcon()
{
  nidIcon.cbSize  = sizeof( NOTIFYICONDATA );
  nidIcon.hWnd    = GetSafeHwnd();
  TRACE( "nidIcon.hWnd %u\n", nidIcon.hWnd );
  nidIcon.uID     = 0;
  Shell_NotifyIcon( NIM_DELETE, &nidIcon );
}

CZeitDlg::CZeitDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CZeitDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CZeitDlg)
	//}}AFX_DATA_INIT
	
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

  Create(IDD);
}
```
  Hoffentlich habe ich keine wichtige Stelle vergessen. Viel Glück!

Ach so, MakeIcon() wird in OnInitDialog aufgerufen.


----------



## C Coder (20. September 2004)

Danke erstmal, ich werds mal ausprobieren!


----------



## Endurion (20. September 2004)

Ein einfaches ShowWindow( SW_HIDE ) sollte das Fenster auch aus der Taskleiste verbannen.

Ansonsten dem Fenster zusätzlich den Stil WS_EX_TOOLWINDOW  verpassen. Das zwingt Windows auch, das Fenster nicht in die Taskleiste zu kleben.


----------



## C Coder (24. September 2004)

@Endurion 
  Danke, habs ausprobiert, funktioniert
@Kacheltor
  Sieht interessant aus, ich werds mal probieren einzubauen


----------

