FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour TWebCam
Posts: 1070
Joined: Sun Oct 09, 2005 10:41 PM

TWebCam

Posted: Sun May 10, 2026 05:56 PM

HOla amigos... A algunos de vosotros les funciona la cámara web para tomas fotografías en una app de FiveWin ? gracias

Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: TWebCam

Posted: Sun May 10, 2026 07:56 PM

Sí, FiveWin tiene soporte para cámara web y funciona para tomar fotografías. Existen varias opciones:

Clase TWebCam

La clase TWebCam permite capturar video de una webcam usando la API de Windows Video for Windows (VFW). Puede mostrar vista previa en vivo, guardar imágenes estáticas como BMP y grabar video 0-cite-0 .

Métodos clave para fotografías:

  • SaveFile( cFileName ) - Captura una imagen estática y la guarda como .bmp 0-cite-1
  • Initialize() - Conecta a la webcam e inicia la vista previa en vivo 0-cite-2
  • Finalize() - Desconecta y detiene la vista previa 0-cite-3

Ejemplo básico:

#include "FiveWin.ch"
#include "WebCam.ch"

function Main()
   local oWnd, oCam
   

   DEFINE WINDOW oWnd TITLE "Webcam Demo" SIZE 680, 540
   

   oCam := TWebCam():New( oWnd, 10, 10, 640, 480, .T. )
   

   // Guardar una foto:
   // oCam:SaveFile( "photo.bmp" )
   

   ACTIVATE WINDOW oWnd ;
      ON INIT oCam:Initialize()
   

return nil

Clase tWebCamPhoto (ejemplo específico)

Hay un ejemplo más completo en samples/misc/photos.prg con la clase tWebCamPhoto que implementa una interfaz específica para capturar fotografías con botones para capturar, transferir al portapapeles, configurar formato y fuente de video 0-cite-5 .

Ejemplos disponibles

  • samples/web/webcam.prg - Demo completo de la clase TWebCam con menú para capturar imágenes y video 0-cite-6
  • samples/misc/photos.prg - Ejemplo específico para tomar fotografías con webcam 0-cite-7
  • samples/misc/dshow.prg - Ejemplo usando DirectShow para captura de cámara 0-cite-8

La funcionalidad está implementada y hay ejemplos funcionales en el repositorio.

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 668
Joined: Fri Oct 21, 2005 05:54 AM

Re: TWebCam

Posted: Tue Jul 28, 2026 03:53 PM

Dear Mr.Antonio,

Our TWebCam class which uses "AVICAP32.DLL" is not able to work most of the times with
latest WebCams in Windows Versions like Win10, Win11. It is generating the Black Screen
and no image is seen.

As per ChatGpt:

If AVICAP32.DLL is showing a black screen, it is usually not a problem with the DLL itself.
The Video for Windows (VfW) API that avicap32.dll uses is over 20 years old, and many
modern webcams no longer fully support it.

I recommend switching to DirectShow or Media Foundation

Since I know you're developing VisualCampus with FiveWin + xHarbour, and you previously
asked for a TWebCamPhoto class, I recommend avoiding avicap32.dll for new development.

A modern implementation using:

DirectShow (Windows XP–11 compatible)
or Media Foundation (Windows 7–11)

will work with virtually all modern USB webcams,
provide smooth live preview,
support high resolutions (720p, 1080p, etc.),
avoid the black-screen issue,
integrate cleanly with your FiveWin/xHarbour application.

By the way I tested:
samples/misc/dshow.prg - Example using DirectShow for camera capture

It is giving lot of compilation errors.

Please guide me with a proper solution.

Regards,

-Ramesh Babu P

Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: TWebCam

Posted: Tue Jul 28, 2026 05:07 PM

Dear Ramesh,

dshow.prg // Live webcam preview and snapshot using DirectShow

// Live webcam preview and snapshot using DirectShow (no qedit.dll)
//
// The preview is rendered by DirectShow's default video renderer, which is
// reparented into the FiveWin dialog through IVideoWindow. Snapshots are
// taken with IBasicVideo::GetCurrentImage(), so neither qedit.dll nor
// ISampleGrabber (both unavailable on modern Windows) are required.
//
// Build (recommended, Windows SDK toolchain):
//    build_new.bat dshow hm64      // Harbour + MSVC 64
//    build_new.bat dshow hm32      // Harbour + MSVC 32
//
// The C block below adds the needed libraries with #pragma comment( lib, ... )
// for MSVC: strmiids.lib quartz.lib ole32.lib oleaut32.lib
//
// Borland: BCC has no DirectShow headers/libs of its own, so point it to the
// Windows SDK, i.e. add to the compile and link steps:
//    -I"C:\Program Files (x86)\Windows Kits\10\Include\<ver>\um"
//    -L"C:\Program Files (x86)\Windows Kits\10\Lib\<ver>\um\x86"
//    strmiids.lib quartz.lib
// and convert the SDK COFF libs to OMF with coff2omf when using BCC32.

#include "FiveWin.ch"

//----------------------------------------------------------------------------//

function Main()

   local oDlg, oImg, oFont
   local pCam := 0
   local cFile := ".\dshowphoto.bmp"
   local nX := 10, nY := 10, nWidth := 480, nHeight := 360

   DEFINE FONT oFont NAME "Segoe UI" SIZE 0, -13

   DEFINE DIALOG oDlg SIZE 1000, 830 PIXEL TITLE "DirectShow webcam" FONT oFont

   @ nY, nWidth + 20 IMAGE oImg OF oDlg SIZE nWidth, nHeight PIXEL ADJUST

   @ nHeight + 20, nWidth + 20 BUTTON "Take &photo" OF oDlg SIZE 90, 24 PIXEL ;
      ACTION TakePhoto( pCam, oImg, cFile )

   @ nHeight + 20, nWidth + 120 BUTTON "&Exit" OF oDlg SIZE 90, 24 PIXEL ;
      ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED ;
      ON INIT ( pCam := DShowCamera( oDlg:hWnd, nX, nY, nWidth, nHeight ) ) ;
      VALID ( DShowClose( pCam ), pCam := 0, .T. )

   oFont:End()

return nil

//----------------------------------------------------------------------------//

function TakePhoto( pCam, oImg, cFile )

   if pCam == nil .or. pCam == 0
      MsgAlert( "No camera available", "DirectShow" )
      return nil
   endif

   if DShowSnapShot( pCam, cFile )
      oImg:LoadImage( , cFile )
      oImg:Refresh()
   endif

return nil

//----------------------------------------------------------------------------//

#pragma BEGINDUMP

#pragma warning(disable:4996)

#include <hbapi.h>
#include <stdio.h>
#include <dshow.h>
#include <uuids.h>
#include <objbase.h>

#ifdef _MSC_VER
   #pragma comment( lib, "strmiids.lib" )
   #pragma comment( lib, "quartz.lib" )
   #pragma comment( lib, "ole32.lib" )
   #pragma comment( lib, "oleaut32.lib" )
#endif

// The Harbour generated .c file is compiled as C (cl -TC, bcc32, gcc), so all
// COM calls below use the C style vtable syntax.

typedef struct
{
   IGraphBuilder *        pGraph;
   ICaptureGraphBuilder2 *pBuilder;
   IBaseFilter *          pCap;
   IMediaControl *        pMediaControl;
   IVideoWindow *         pVideoWindow;
   IBasicVideo *          pBasicVideo;
} DSHOW_CAM;

#define DS_RELEASE( p )  do { if( ( p ) != NULL ) { ( p )->lpVtbl->Release( p ); ( p ) = NULL; } } while( 0 )

static void ds_Error( const char * szMsg, HRESULT hr )
{
   static const char s_szHex[ 16 ] = { '0', '1', '2', '3', '4', '5', '6', '7',
                                      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
   char          szText[ 256 ];
   unsigned long ulValue = ( unsigned long ) hr;
   int           iLen = 0, i;

   while( szMsg[ iLen ] != '\0' && iLen < 200 )
   {
      szText[ iLen ] = szMsg[ iLen ];
      iLen++;
   }

   szText[ iLen++ ] = '\n';
   szText[ iLen++ ] = '0';
   szText[ iLen++ ] = 'x';

   for( i = 28; i >= 0; i -= 4 )
      szText[ iLen++ ] = s_szHex[ ( ulValue >> i ) & 0x0F ];

   szText[ iLen ] = '\0';

   MessageBox( 0, szText, "DirectShow error", MB_ICONEXCLAMATION | MB_OK );
}

static IBaseFilter * ds_FirstCaptureDevice( void )
{
   ICreateDevEnum * pDevEnum = NULL;
   IEnumMoniker *   pEnum = NULL;
   IMoniker *       pMoniker = NULL;
   IBaseFilter *    pCap = NULL;
   HRESULT          hr;

   hr = CoCreateInstance( &CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
                          &IID_ICreateDevEnum, ( void ** ) &pDevEnum );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the system device enumerator", hr );
      return NULL;
   }

   hr = pDevEnum->lpVtbl->CreateClassEnumerator( pDevEnum, &CLSID_VideoInputDeviceCategory, &pEnum, 0 );

   if( hr != S_OK )   // S_FALSE means the category is empty
   {
      ds_Error( "No video capture devices found", hr );
      DS_RELEASE( pDevEnum );
      return NULL;
   }

   while( pEnum->lpVtbl->Next( pEnum, 1, &pMoniker, NULL ) == S_OK )
   {
      hr = pMoniker->lpVtbl->BindToObject( pMoniker, 0, 0, &IID_IBaseFilter, ( void ** ) &pCap );

  DS_RELEASE( pMoniker );

  if( SUCCEEDED( hr ) )
     break;

  pCap = NULL;
   }

   DS_RELEASE( pEnum );
   DS_RELEASE( pDevEnum );

   if( pCap == NULL )
      ds_Error( "Could not bind any video capture device", hr );

   return pCap;
}

// DShowCamera( hWndParent, nX, nY, nWidth, nHeight ) --> pCam
HB_FUNC( DSHOWCAMERA )
{
   HWND        hWndParent = ( HWND ) ( HB_PTRUINT ) hb_parnll( 1 );
   long        x = ( long ) hb_parnl( 2 );
   long        y = ( long ) hb_parnl( 3 );
   long        w = ( long ) hb_parnl( 4 );
   long        h = ( long ) hb_parnl( 5 );
   DSHOW_CAM * pCam;
   HRESULT     hr;

   pCam = ( DSHOW_CAM * ) hb_xgrab( sizeof( DSHOW_CAM ) );
   ZeroMemory( pCam, sizeof( DSHOW_CAM ) );

   hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );

   if( FAILED( hr ) )
   {
      ds_Error( "CoInitializeEx failed", hr );
      hb_xfree( pCam );
      hb_retnll( 0 );
      return;
   }

   hr = CoCreateInstance( &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                          &IID_IGraphBuilder, ( void ** ) &pCam->pGraph );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the filter graph", hr );
      goto failure;
   }

   hr = CoCreateInstance( &CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
                          &IID_ICaptureGraphBuilder2, ( void ** ) &pCam->pBuilder );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the capture graph builder", hr );
      goto failure;
   }

   hr = pCam->pBuilder->lpVtbl->SetFiltergraph( pCam->pBuilder, pCam->pGraph );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not attach the capture graph builder to the graph", hr );
      goto failure;
   }

   pCam->pCap = ds_FirstCaptureDevice();

   if( pCam->pCap == NULL )
      goto failure;

   hr = pCam->pGraph->lpVtbl->AddFilter( pCam->pGraph, pCam->pCap, L"Capture Filter" );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not add the capture filter to the graph", hr );
      goto failure;
   }

   // The default video renderer is created here by DirectShow itself
   hr = pCam->pBuilder->lpVtbl->RenderStream( pCam->pBuilder, &PIN_CATEGORY_PREVIEW,
                                              &MEDIATYPE_Video, ( IUnknown * ) pCam->pCap,
                                              NULL, NULL );

   if( FAILED( hr ) )
   {
      // Cameras without a preview pin only expose the capture pin
      hr = pCam->pBuilder->lpVtbl->RenderStream( pCam->pBuilder, &PIN_CATEGORY_CAPTURE,
                                                 &MEDIATYPE_Video, ( IUnknown * ) pCam->pCap,
                                                 NULL, NULL );

  if( FAILED( hr ) )
  {
     ds_Error( "Could not render the preview video stream", hr );
     goto failure;
  }
   }

   hr = pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IVideoWindow,
                                              ( void ** ) &pCam->pVideoWindow );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not get the IVideoWindow interface", hr );
      goto failure;
   }

   hr = pCam->pVideoWindow->lpVtbl->put_Owner( pCam->pVideoWindow, ( OAHWND ) hWndParent );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not set the video window owner", hr );
      goto failure;
   }

   pCam->pVideoWindow->lpVtbl->put_WindowStyle( pCam->pVideoWindow, WS_CHILD | WS_CLIPSIBLINGS );
   pCam->pVideoWindow->lpVtbl->put_MessageDrain( pCam->pVideoWindow, ( OAHWND ) hWndParent );

   hr = pCam->pVideoWindow->lpVtbl->SetWindowPosition( pCam->pVideoWindow, x, y, w, h );

   if( FAILED( hr ) )
      ds_Error( "Could not set the video window position", hr );

   pCam->pVideoWindow->lpVtbl->put_Visible( pCam->pVideoWindow, OATRUE );

   // Optional, only used for snapshots
   pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IBasicVideo,
                                         ( void ** ) &pCam->pBasicVideo );

   hr = pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IMediaControl,
                                              ( void ** ) &pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not get the IMediaControl interface", hr );
      goto failure;
   }

   hr = pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not run the filter graph", hr );
      goto failure;
   }

   hb_retnll( ( HB_LONGLONG ) ( HB_PTRUINT ) pCam );
   return;

failure:

   DS_RELEASE( pCam->pMediaControl );
   DS_RELEASE( pCam->pBasicVideo );
   DS_RELEASE( pCam->pVideoWindow );
   DS_RELEASE( pCam->pCap );
   DS_RELEASE( pCam->pBuilder );
   DS_RELEASE( pCam->pGraph );

   hb_xfree( pCam );

   CoUninitialize();

   hb_retnll( 0 );
}

// DShowSetPos( pCam, nX, nY, nWidth, nHeight ) --> lSuccess
HB_FUNC( DSHOWSETPOS )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pVideoWindow == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pVideoWindow->lpVtbl->SetWindowPosition( pCam->pVideoWindow,
      ( long ) hb_parnl( 2 ), ( long ) hb_parnl( 3 ),
      ( long ) hb_parnl( 4 ), ( long ) hb_parnl( 5 ) ) ) );
}

// DShowPlay( pCam ) --> lSuccess
HB_FUNC( DSHOWPLAY )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pMediaControl == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl ) ) );
}

// DShowStop( pCam ) --> lSuccess
HB_FUNC( DSHOWSTOP )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pMediaControl == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pMediaControl->lpVtbl->Stop( pCam->pMediaControl ) ) );
}

// DShowSnapShot( pCam, cBmpFile ) --> lSuccess
HB_FUNC( DSHOWSNAPSHOT )
{
   DSHOW_CAM *        pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );
   const char *       szFile = hb_parc( 2 );
   long               lSize = 0;
   char *             pDib;
   BITMAPINFOHEADER * pBmi;
   BITMAPFILEHEADER   bmfh;
   DWORD              dwPalette = 0;
   FILE *             hFile;
   HRESULT            hr;

   if( pCam == NULL || pCam->pBasicVideo == NULL || szFile == NULL )
   {
      ds_Error( "No camera available for the snapshot", E_POINTER );
      hb_retl( HB_FALSE );
      return;
   }

   // GetCurrentImage() requires the graph to be paused
   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Pause( pCam->pMediaControl );

   hr = pCam->pBasicVideo->lpVtbl->GetCurrentImage( pCam->pBasicVideo, &lSize, NULL );

   if( FAILED( hr ) || lSize <= ( long ) sizeof( BITMAPINFOHEADER ) )
   {
      ds_Error( "Could not retrieve the size of the current image", hr );

  if( pCam->pMediaControl != NULL )
     pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

  hb_retl( HB_FALSE );
  return;
   }

   pDib = ( char * ) hb_xgrab( lSize );

   hr = pCam->pBasicVideo->lpVtbl->GetCurrentImage( pCam->pBasicVideo, &lSize, ( long * ) pDib );

   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not retrieve the current image", hr );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   // The returned buffer is a packed DIB: BITMAPINFOHEADER + palette + pixels
   pBmi = ( BITMAPINFOHEADER * ) pDib;

   if( pBmi->biBitCount <= 8 )
      dwPalette = ( pBmi->biClrUsed ? pBmi->biClrUsed : ( DWORD ) ( 1 << pBmi->biBitCount ) ) * sizeof( RGBQUAD );
   else if( pBmi->biCompression == BI_BITFIELDS )
      dwPalette = 3 * sizeof( DWORD );

   bmfh.bfType      = 0x4D42;   // "BM"
   bmfh.bfSize      = ( DWORD ) ( sizeof( BITMAPFILEHEADER ) + lSize );
   bmfh.bfReserved1 = 0;
   bmfh.bfReserved2 = 0;
   bmfh.bfOffBits   = ( DWORD ) ( sizeof( BITMAPFILEHEADER ) + pBmi->biSize + dwPalette );

   hFile = fopen( szFile, "wb" );

   if( hFile == NULL )
   {
      ds_Error( "Could not create the bitmap file", E_ACCESSDENIED );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   if( fwrite( &bmfh, 1, sizeof( bmfh ), hFile ) != sizeof( bmfh ) ||
       fwrite( pDib, 1, ( size_t ) lSize, hFile ) != ( size_t ) lSize )
   {
      ds_Error( "Could not write the bitmap file", E_FAIL );
      fclose( hFile );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   fclose( hFile );
   hb_xfree( pDib );

   hb_retl( HB_TRUE );
}

// DShowClose( pCam ) --> NIL
HB_FUNC( DSHOWCLOSE )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL )
      return;

   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Stop( pCam->pMediaControl );

   if( pCam->pVideoWindow != NULL )
   {
      pCam->pVideoWindow->lpVtbl->put_Visible( pCam->pVideoWindow, OAFALSE );
      pCam->pVideoWindow->lpVtbl->put_MessageDrain( pCam->pVideoWindow, ( OAHWND ) 0 );
      pCam->pVideoWindow->lpVtbl->put_Owner( pCam->pVideoWindow, ( OAHWND ) 0 );
   }

   DS_RELEASE( pCam->pMediaControl );
   DS_RELEASE( pCam->pBasicVideo );
   DS_RELEASE( pCam->pVideoWindow );
   DS_RELEASE( pCam->pCap );
   DS_RELEASE( pCam->pBuilder );
   DS_RELEASE( pCam->pGraph );

   hb_xfree( pCam );

   CoUninitialize();
}

#pragma ENDDUMP
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 8716
Joined: Tue Dec 20, 2005 07:36 PM

Re: TWebCam

Posted: Tue Jul 28, 2026 05:24 PM
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ FiveWin for xHarbour 26.03 - Mar. 2026          Harbour development power  ³Ü
³ (c) FiveTech 1993-2026 for Microsoft Windows 9X/NT/200X/ME/XP/Vista/7/8/10 ³Û
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ
ÿ ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
Compiling...
xHarbour 1.3.2 Intl. (SimpLex) (Build 20260103)
Copyright 1999-2026, http://www.xharbour.org http://www.harbour-project.org/
Compiling 'DSHOW.prg' and generating preprocessed output to 'DSHOW.ppo'...

Done.

Lines 39, Functions/Procedures 2, pCodes 158
Embarcadero C++ 7.70 for Win32 Copyright (c) 1993-2023 Embarcadero Technologies, Inc.
DSHOW.c:
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 2911: Possible use of 'cchDestLength' before definition in function StringCchCatExA
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 3022: Possible use of 'cchDestLength' before definition in function StringCchCatExW
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 3247: Possible use of 'cchDestLength' before definition in function StringCbCatExA
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 3355: Possible use of 'cchDestLength' before definition in function StringCbCatExW
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 3893: Possible use of 'cchDestLength' before definition in function StringCchCatNExA
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 4005: Possible use of 'cchDestLength' before definition in function StringCchCatNExW
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 4234: Possible use of 'cchDestLength' before definition in function StringCbCatNExA
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 4347: Possible use of 'cchDestLength' before definition in function StringCbCatNExW
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22024: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22025: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22027: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22028: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22030: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22031: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22033: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22034: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22036: Bit fields must be signed or unsigned int
Warning W8137 DSHOW.prg 48: Deprecated #import directive encountered. Please use the TLIBIMP utility instead.
Error E2503 DSHOW.prg 48: Missing or incorrect version of TypeLibImport.dll
Error E2451 DSHOW.prg 56: Undefined symbol 'Run' in function HB_FUN_DSHOWPLAY
Warning W8004 DSHOW.prg 57: 'pMediaControl' is assigned a value that is never used in function HB_FUN_DSHOWPLAY
Error E2451 DSHOW.prg 63: Undefined symbol 'Stop' in function HB_FUN_DSHOWSTOP
Warning W8004 DSHOW.prg 64: 'pMediaControl' is assigned a value that is never used in function HB_FUN_DSHOWSTOP
Error E2451 DSHOW.prg 85: Undefined symbol 'DexterLib' in function HB_FUN_DSHOWCAMERA
Error E2379 DSHOW.prg 85: Statement missing ; in function HB_FUN_DSHOWCAMERA
Error E2342 DSHOW.prg 96: Type mismatch in parameter 'rclsid' (wanted 'const _GUID * const', got '_GUID') in function HB_FUN_DSHOWCAMERA
Error E2342 DSHOW.prg 103: Type mismatch in parameter 'rclsid' (wanted 'const _GUID * const', got '_GUID') in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 108: Undefined symbol 'SetFiltergraph' in function HB_FUN_DSHOWCAMERA
Warning W8045 DSHOW.prg 114: No declaration for function 'IID_PPV_ARGS' in function HB_FUN_DSHOWCAMERA
Error E2342 DSHOW.prg 114: Type mismatch in parameter 'rclsid' (wanted 'const _GUID * const', got '_GUID') in function HB_FUN_DSHOWCAMERA
Error E2193 DSHOW.prg 114: Too few parameters in call to 'CoCreateInstance' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 119: Undefined symbol 'CreateClassEnumerator' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 128: Undefined symbol 'Next' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 138: Undefined symbol 'BindToStorage' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 143: Undefined symbol 'Read' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 146: Undefined symbol 'bstrVal' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 148: Undefined symbol 'Release' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 166: Undefined symbol 'BindToStorage' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 168: Undefined symbol 'Read' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 173: Undefined symbol 'BindToObject' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 180: Undefined symbol 'AddFilter' in function HB_FUN_DSHOWCAMERA
Error E2342 DSHOW.prg 188: Type mismatch in parameter 'rclsid' (wanted 'const _GUID * const', got '_GUID') in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 194: Undefined symbol 'QueryInterface' in function HB_FUN_DSHOWCAMERA
Error E2121 DSHOW.prg 195: Function call missing ) in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 201: Undefined symbol 'pSampleGrabber' in function HB_FUN_DSHOWCAMERA
Error E2140 DSHOW.prg 207: Declaration is not allowed here in function HB_FUN_DSHOWCAMERA
Error E2293 DSHOW.prg 211: ) expected in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 217: Undefined symbol 'AddFilter' in function HB_FUN_DSHOWCAMERA
Error E2342 DSHOW.prg 225: Type mismatch in parameter 'rclsid' (wanted 'const _GUID * const', got '_GUID') in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 231: Undefined symbol 'AddFilter' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 237: Undefined symbol 'RenderStream' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 244: Undefined symbol 'RenderStream' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 252: Undefined symbol 'QueryInterface' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 261: Undefined symbol 'Run' in function HB_FUN_DSHOWCAMERA
Error E2451 DSHOW.prg 273: Undefined symbol 'HB_LONGLONG' in function HB_FUN_DSHOWCAMERA
Error E2293 DSHOW.prg 273: ) expected in function HB_FUN_DSHOWCAMERA
Warning W8004 DSHOW.prg 274: 'pBuffer' is assigned a value that is never used in function HB_FUN_DSHOWCAMERA
Warning W8004 DSHOW.prg 274: 'pMediaControl' is assigned a value that is never used in function HB_FUN_DSHOWCAMERA
Warning W8004 DSHOW.prg 274: 'pCap' is assigned a value that is never used in function HB_FUN_DSHOWCAMERA
Warning W8004 DSHOW.prg 274: 'pPropBag' is assigned a value that is never used in function HB_FUN_DSHOWCAMERA
Warning W8004 DSHOW.prg 274: 'pMoniker' is assigned a value that is never used in function HB_FUN_DSHOWCAMERA
Warning W8004 DSHOW.prg 274: 'pEnum' is assigned a value that is never used in function HB_FUN_DSHOWCAMERA
Warning W8004 DSHOW.prg 274: 'pDevEnum' is assigned a value that is never used in function HB_FUN_DSHOWCAMERA
*** 35 errors in Compile ***
* Linking errors *

Regards, saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 8716
Joined: Tue Dec 20, 2005 07:36 PM

Re: TWebCam

Posted: Tue Jul 28, 2026 05:27 PM
Antonio Linares wrote:

Dear Ramesh,

dshow.prg // Live webcam preview and snapshot using DirectShow

// Live webcam preview and snapshot using DirectShow (no qedit.dll)
//
// The preview is rendered by DirectShow's default video renderer, which is
// reparented into the FiveWin dialog through IVideoWindow. Snapshots are
// taken with IBasicVideo::GetCurrentImage(), so neither qedit.dll nor
// ISampleGrabber (both unavailable on modern Windows) are required.
//
// Build (recommended, Windows SDK toolchain):
//    build_new.bat dshow hm64      // Harbour + MSVC 64
//    build_new.bat dshow hm32      // Harbour + MSVC 32
//
// The C block below adds the needed libraries with #pragma comment( lib, ... )
// for MSVC: strmiids.lib quartz.lib ole32.lib oleaut32.lib
//
// Borland: BCC has no DirectShow headers/libs of its own, so point it to the
// Windows SDK, i.e. add to the compile and link steps:
//    -I"C:\Program Files (x86)\Windows Kits\10\Include\<ver>\um"
//    -L"C:\Program Files (x86)\Windows Kits\10\Lib\<ver>\um\x86"
//    strmiids.lib quartz.lib
// and convert the SDK COFF libs to OMF with coff2omf when using BCC32.

#include "FiveWin.ch"

//----------------------------------------------------------------------------//

function Main()

   local oDlg, oImg, oFont
   local pCam := 0
   local cFile := ".\dshowphoto.bmp"
   local nX := 10, nY := 10, nWidth := 480, nHeight := 360

   DEFINE FONT oFont NAME "Segoe UI" SIZE 0, -13

   DEFINE DIALOG oDlg SIZE 1000, 830 PIXEL TITLE "DirectShow webcam" FONT oFont

   @ nY, nWidth + 20 IMAGE oImg OF oDlg SIZE nWidth, nHeight PIXEL ADJUST

   @ nHeight + 20, nWidth + 20 BUTTON "Take &photo" OF oDlg SIZE 90, 24 PIXEL ;
      ACTION TakePhoto( pCam, oImg, cFile )

   @ nHeight + 20, nWidth + 120 BUTTON "&Exit" OF oDlg SIZE 90, 24 PIXEL ;
      ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED ;
      ON INIT ( pCam := DShowCamera( oDlg:hWnd, nX, nY, nWidth, nHeight ) ) ;
      VALID ( DShowClose( pCam ), pCam := 0, .T. )

   oFont:End()

return nil

//----------------------------------------------------------------------------//

function TakePhoto( pCam, oImg, cFile )

   if pCam == nil .or. pCam == 0
      MsgAlert( "No camera available", "DirectShow" )
      return nil
   endif

   if DShowSnapShot( pCam, cFile )
      oImg:LoadImage( , cFile )
      oImg:Refresh()
   endif

return nil

//----------------------------------------------------------------------------//

#pragma BEGINDUMP

#pragma warning(disable:4996)

#include <hbapi.h>
#include <stdio.h>
#include <dshow.h>
#include <uuids.h>
#include <objbase.h>

#ifdef _MSC_VER
   #pragma comment( lib, "strmiids.lib" )
   #pragma comment( lib, "quartz.lib" )
   #pragma comment( lib, "ole32.lib" )
   #pragma comment( lib, "oleaut32.lib" )
#endif

// The Harbour generated .c file is compiled as C (cl -TC, bcc32, gcc), so all
// COM calls below use the C style vtable syntax.

typedef struct
{
   IGraphBuilder *        pGraph;
   ICaptureGraphBuilder2 *pBuilder;
   IBaseFilter *          pCap;
   IMediaControl *        pMediaControl;
   IVideoWindow *         pVideoWindow;
   IBasicVideo *          pBasicVideo;
} DSHOW_CAM;

#define DS_RELEASE( p )  do { if( ( p ) != NULL ) { ( p )->lpVtbl->Release( p ); ( p ) = NULL; } } while( 0 )

static void ds_Error( const char * szMsg, HRESULT hr )
{
   static const char s_szHex[ 16 ] = { '0', '1', '2', '3', '4', '5', '6', '7',
                                      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
   char          szText[ 256 ];
   unsigned long ulValue = ( unsigned long ) hr;
   int           iLen = 0, i;

   while( szMsg[ iLen ] != '\0' && iLen < 200 )
   {
      szText[ iLen ] = szMsg[ iLen ];
      iLen++;
   }

   szText[ iLen++ ] = '\n';
   szText[ iLen++ ] = '0';
   szText[ iLen++ ] = 'x';

   for( i = 28; i >= 0; i -= 4 )
      szText[ iLen++ ] = s_szHex[ ( ulValue >> i ) & 0x0F ];

   szText[ iLen ] = '\0';

   MessageBox( 0, szText, "DirectShow error", MB_ICONEXCLAMATION | MB_OK );
}

static IBaseFilter * ds_FirstCaptureDevice( void )
{
   ICreateDevEnum * pDevEnum = NULL;
   IEnumMoniker *   pEnum = NULL;
   IMoniker *       pMoniker = NULL;
   IBaseFilter *    pCap = NULL;
   HRESULT          hr;

   hr = CoCreateInstance( &CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
                          &IID_ICreateDevEnum, ( void ** ) &pDevEnum );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the system device enumerator", hr );
      return NULL;
   }

   hr = pDevEnum->lpVtbl->CreateClassEnumerator( pDevEnum, &CLSID_VideoInputDeviceCategory, &pEnum, 0 );

   if( hr != S_OK )   // S_FALSE means the category is empty
   {
      ds_Error( "No video capture devices found", hr );
      DS_RELEASE( pDevEnum );
      return NULL;
   }

   while( pEnum->lpVtbl->Next( pEnum, 1, &pMoniker, NULL ) == S_OK )
   {
      hr = pMoniker->lpVtbl->BindToObject( pMoniker, 0, 0, &IID_IBaseFilter, ( void ** ) &pCap );

  DS_RELEASE( pMoniker );

  if( SUCCEEDED( hr ) )
     break;

  pCap = NULL;
   }

   DS_RELEASE( pEnum );
   DS_RELEASE( pDevEnum );

   if( pCap == NULL )
      ds_Error( "Could not bind any video capture device", hr );

   return pCap;
}

// DShowCamera( hWndParent, nX, nY, nWidth, nHeight ) --> pCam
HB_FUNC( DSHOWCAMERA )
{
   HWND        hWndParent = ( HWND ) ( HB_PTRUINT ) hb_parnll( 1 );
   long        x = ( long ) hb_parnl( 2 );
   long        y = ( long ) hb_parnl( 3 );
   long        w = ( long ) hb_parnl( 4 );
   long        h = ( long ) hb_parnl( 5 );
   DSHOW_CAM * pCam;
   HRESULT     hr;

   pCam = ( DSHOW_CAM * ) hb_xgrab( sizeof( DSHOW_CAM ) );
   ZeroMemory( pCam, sizeof( DSHOW_CAM ) );

   hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );

   if( FAILED( hr ) )
   {
      ds_Error( "CoInitializeEx failed", hr );
      hb_xfree( pCam );
      hb_retnll( 0 );
      return;
   }

   hr = CoCreateInstance( &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                          &IID_IGraphBuilder, ( void ** ) &pCam->pGraph );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the filter graph", hr );
      goto failure;
   }

   hr = CoCreateInstance( &CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
                          &IID_ICaptureGraphBuilder2, ( void ** ) &pCam->pBuilder );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the capture graph builder", hr );
      goto failure;
   }

   hr = pCam->pBuilder->lpVtbl->SetFiltergraph( pCam->pBuilder, pCam->pGraph );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not attach the capture graph builder to the graph", hr );
      goto failure;
   }

   pCam->pCap = ds_FirstCaptureDevice();

   if( pCam->pCap == NULL )
      goto failure;

   hr = pCam->pGraph->lpVtbl->AddFilter( pCam->pGraph, pCam->pCap, L"Capture Filter" );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not add the capture filter to the graph", hr );
      goto failure;
   }

   // The default video renderer is created here by DirectShow itself
   hr = pCam->pBuilder->lpVtbl->RenderStream( pCam->pBuilder, &PIN_CATEGORY_PREVIEW,
                                              &MEDIATYPE_Video, ( IUnknown * ) pCam->pCap,
                                              NULL, NULL );

   if( FAILED( hr ) )
   {
      // Cameras without a preview pin only expose the capture pin
      hr = pCam->pBuilder->lpVtbl->RenderStream( pCam->pBuilder, &PIN_CATEGORY_CAPTURE,
                                                 &MEDIATYPE_Video, ( IUnknown * ) pCam->pCap,
                                                 NULL, NULL );

  if( FAILED( hr ) )
  {
     ds_Error( "Could not render the preview video stream", hr );
     goto failure;
  }
   }

   hr = pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IVideoWindow,
                                              ( void ** ) &pCam->pVideoWindow );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not get the IVideoWindow interface", hr );
      goto failure;
   }

   hr = pCam->pVideoWindow->lpVtbl->put_Owner( pCam->pVideoWindow, ( OAHWND ) hWndParent );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not set the video window owner", hr );
      goto failure;
   }

   pCam->pVideoWindow->lpVtbl->put_WindowStyle( pCam->pVideoWindow, WS_CHILD | WS_CLIPSIBLINGS );
   pCam->pVideoWindow->lpVtbl->put_MessageDrain( pCam->pVideoWindow, ( OAHWND ) hWndParent );

   hr = pCam->pVideoWindow->lpVtbl->SetWindowPosition( pCam->pVideoWindow, x, y, w, h );

   if( FAILED( hr ) )
      ds_Error( "Could not set the video window position", hr );

   pCam->pVideoWindow->lpVtbl->put_Visible( pCam->pVideoWindow, OATRUE );

   // Optional, only used for snapshots
   pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IBasicVideo,
                                         ( void ** ) &pCam->pBasicVideo );

   hr = pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IMediaControl,
                                              ( void ** ) &pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not get the IMediaControl interface", hr );
      goto failure;
   }

   hr = pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not run the filter graph", hr );
      goto failure;
   }

   hb_retnll( ( HB_LONGLONG ) ( HB_PTRUINT ) pCam );
   return;

failure:

   DS_RELEASE( pCam->pMediaControl );
   DS_RELEASE( pCam->pBasicVideo );
   DS_RELEASE( pCam->pVideoWindow );
   DS_RELEASE( pCam->pCap );
   DS_RELEASE( pCam->pBuilder );
   DS_RELEASE( pCam->pGraph );

   hb_xfree( pCam );

   CoUninitialize();

   hb_retnll( 0 );
}

// DShowSetPos( pCam, nX, nY, nWidth, nHeight ) --> lSuccess
HB_FUNC( DSHOWSETPOS )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pVideoWindow == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pVideoWindow->lpVtbl->SetWindowPosition( pCam->pVideoWindow,
      ( long ) hb_parnl( 2 ), ( long ) hb_parnl( 3 ),
      ( long ) hb_parnl( 4 ), ( long ) hb_parnl( 5 ) ) ) );
}

// DShowPlay( pCam ) --> lSuccess
HB_FUNC( DSHOWPLAY )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pMediaControl == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl ) ) );
}

// DShowStop( pCam ) --> lSuccess
HB_FUNC( DSHOWSTOP )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pMediaControl == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pMediaControl->lpVtbl->Stop( pCam->pMediaControl ) ) );
}

// DShowSnapShot( pCam, cBmpFile ) --> lSuccess
HB_FUNC( DSHOWSNAPSHOT )
{
   DSHOW_CAM *        pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );
   const char *       szFile = hb_parc( 2 );
   long               lSize = 0;
   char *             pDib;
   BITMAPINFOHEADER * pBmi;
   BITMAPFILEHEADER   bmfh;
   DWORD              dwPalette = 0;
   FILE *             hFile;
   HRESULT            hr;

   if( pCam == NULL || pCam->pBasicVideo == NULL || szFile == NULL )
   {
      ds_Error( "No camera available for the snapshot", E_POINTER );
      hb_retl( HB_FALSE );
      return;
   }

   // GetCurrentImage() requires the graph to be paused
   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Pause( pCam->pMediaControl );

   hr = pCam->pBasicVideo->lpVtbl->GetCurrentImage( pCam->pBasicVideo, &lSize, NULL );

   if( FAILED( hr ) || lSize <= ( long ) sizeof( BITMAPINFOHEADER ) )
   {
      ds_Error( "Could not retrieve the size of the current image", hr );

  if( pCam->pMediaControl != NULL )
     pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

  hb_retl( HB_FALSE );
  return;
   }

   pDib = ( char * ) hb_xgrab( lSize );

   hr = pCam->pBasicVideo->lpVtbl->GetCurrentImage( pCam->pBasicVideo, &lSize, ( long * ) pDib );

   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not retrieve the current image", hr );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   // The returned buffer is a packed DIB: BITMAPINFOHEADER + palette + pixels
   pBmi = ( BITMAPINFOHEADER * ) pDib;

   if( pBmi->biBitCount <= 8 )
      dwPalette = ( pBmi->biClrUsed ? pBmi->biClrUsed : ( DWORD ) ( 1 << pBmi->biBitCount ) ) * sizeof( RGBQUAD );
   else if( pBmi->biCompression == BI_BITFIELDS )
      dwPalette = 3 * sizeof( DWORD );

   bmfh.bfType      = 0x4D42;   // "BM"
   bmfh.bfSize      = ( DWORD ) ( sizeof( BITMAPFILEHEADER ) + lSize );
   bmfh.bfReserved1 = 0;
   bmfh.bfReserved2 = 0;
   bmfh.bfOffBits   = ( DWORD ) ( sizeof( BITMAPFILEHEADER ) + pBmi->biSize + dwPalette );

   hFile = fopen( szFile, "wb" );

   if( hFile == NULL )
   {
      ds_Error( "Could not create the bitmap file", E_ACCESSDENIED );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   if( fwrite( &bmfh, 1, sizeof( bmfh ), hFile ) != sizeof( bmfh ) ||
       fwrite( pDib, 1, ( size_t ) lSize, hFile ) != ( size_t ) lSize )
   {
      ds_Error( "Could not write the bitmap file", E_FAIL );
      fclose( hFile );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   fclose( hFile );
   hb_xfree( pDib );

   hb_retl( HB_TRUE );
}

// DShowClose( pCam ) --> NIL
HB_FUNC( DSHOWCLOSE )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL )
      return;

   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Stop( pCam->pMediaControl );

   if( pCam->pVideoWindow != NULL )
   {
      pCam->pVideoWindow->lpVtbl->put_Visible( pCam->pVideoWindow, OAFALSE );
      pCam->pVideoWindow->lpVtbl->put_MessageDrain( pCam->pVideoWindow, ( OAHWND ) 0 );
      pCam->pVideoWindow->lpVtbl->put_Owner( pCam->pVideoWindow, ( OAHWND ) 0 );
   }

   DS_RELEASE( pCam->pMediaControl );
   DS_RELEASE( pCam->pBasicVideo );
   DS_RELEASE( pCam->pVideoWindow );
   DS_RELEASE( pCam->pCap );
   DS_RELEASE( pCam->pBuilder );
   DS_RELEASE( pCam->pGraph );

   hb_xfree( pCam );

   CoUninitialize();
}

#pragma ENDDUMP
ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ FiveWin for xHarbour 26.03 - Mar. 2026          Harbour development power  ³Ü
³ (c) FiveTech 1993-2026 for Microsoft Windows 9X/NT/200X/ME/XP/Vista/7/8/10 ³Û
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ
ÿ ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
Compiling...
xHarbour 1.3.2 Intl. (SimpLex) (Build 20260103)
Copyright 1999-2026, http://www.xharbour.org http://www.harbour-project.org/
Compiling 'TESTE.prg' and generating preprocessed output to 'TESTE.ppo'...

Done.

Lines 69, Functions/Procedures 2, pCodes 246
Embarcadero C++ 7.70 for Win32 Copyright (c) 1993-2023 Embarcadero Technologies, Inc.
TESTE.c:
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 2911: Possible use of 'cchDestLength' before definition in function StringCchCatExA
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 3022: Possible use of 'cchDestLength' before definition in function StringCchCatExW
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 3247: Possible use of 'cchDestLength' before definition in function StringCbCatExA
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 3355: Possible use of 'cchDestLength' before definition in function StringCbCatExW
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 3893: Possible use of 'cchDestLength' before definition in function StringCchCatNExA
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 4005: Possible use of 'cchDestLength' before definition in function StringCchCatNExW
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 4234: Possible use of 'cchDestLength' before definition in function StringCbCatNExA
Warning W8013 c:\bcc77\bin\..\include\windows\sdk\strsafe.h 4347: Possible use of 'cchDestLength' before definition in function StringCbCatNExW
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22024: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22025: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22027: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22028: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22030: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22031: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22033: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22034: Bit fields must be signed or unsigned int
Warning W8005 c:\bcc77\bin\..\include\windows\sdk\strmif.h 22036: Bit fields must be signed or unsigned int
Error E2451 TESTE.prg 306: Undefined symbol 'HB_LONGLONG' in function HB_FUN_DSHOWCAMERA
Error E2108 TESTE.prg 306: Improper use of typedef 'HB_PTRUINT' in function HB_FUN_DSHOWCAMERA
Error E2293 TESTE.prg 306: ) expected in function HB_FUN_DSHOWCAMERA
*** 3 errors in Compile ***
* Linking errors *

Regards, saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 668
Joined: Fri Oct 21, 2005 05:54 AM

Re: TWebCam

Posted: Tue Jul 28, 2026 11:43 PM

Dear Mr.Antonio,

Thank your for your attention to my Post.

When I compiled DSHOW.PRG using FWH2603 + xHarbour 1.2.3 + BCC77 I am getting lot of compilation errors as shown above post by Mr.Karinha.

Can you please guide me to resolve the above compilation errors.

-Ramesh Babu P

Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: TWebCam

Posted: Wed Jul 29, 2026 02:59 AM

Dear Ramesh,

Please try this version compatible with xHarbour and BCC:

// Live webcam preview and snapshot using DirectShow (no qedit.dll)
//
// The preview is rendered by DirectShow's default video renderer, which is
// reparented into the FiveWin dialog through IVideoWindow. Snapshots are
// taken with IBasicVideo::GetCurrentImage(), so neither qedit.dll nor
// ISampleGrabber (both unavailable on modern Windows) are required.
//
// Build (recommended, Windows SDK toolchain):
//    build_new.bat dshow hm64      // Harbour + MSVC 64
//    build_new.bat dshow hm32      // Harbour + MSVC 32
//
// The C block below adds the needed libraries with #pragma comment( lib, ... )
// for MSVC: strmiids.lib quartz.lib ole32.lib oleaut32.lib
//
// Borland: BCC has no DirectShow headers/libs of its own, so point it to the
// Windows SDK, i.e. add to the compile and link steps:
//    -I"C:\Program Files (x86)\Windows Kits\10\Include\<ver>\um"
//    -L"C:\Program Files (x86)\Windows Kits\10\Lib\<ver>\um\x86"
//    strmiids.lib quartz.lib
// and convert the SDK COFF libs to OMF with coff2omf when using BCC32.

#include "FiveWin.ch"

//----------------------------------------------------------------------------//

function Main()

   local oDlg, oImg, oFont
   local pCam := 0
   local cFile := ".\dshowphoto.bmp"
   local nX := 10, nY := 10, nWidth := 480, nHeight := 360

   DEFINE FONT oFont NAME "Segoe UI" SIZE 0, -13

   DEFINE DIALOG oDlg SIZE 1000, 830 PIXEL TITLE "DirectShow webcam" FONT oFont

   @ nY, nWidth + 20 IMAGE oImg OF oDlg SIZE nWidth, nHeight PIXEL ADJUST

   @ nHeight + 20, nWidth + 20 BUTTON "Take &photo" OF oDlg SIZE 90, 24 PIXEL ;
      ACTION TakePhoto( pCam, oImg, cFile )

   @ nHeight + 20, nWidth + 120 BUTTON "&Exit" OF oDlg SIZE 90, 24 PIXEL ;
      ACTION oDlg:End()

   ACTIVATE DIALOG oDlg CENTERED ;
      ON INIT ( pCam := DShowCamera( oDlg:hWnd, nX, nY, nWidth, nHeight ) ) ;
      VALID ( DShowClose( pCam ), pCam := 0, .T. )

   oFont:End()

return nil

//----------------------------------------------------------------------------//

function TakePhoto( pCam, oImg, cFile )

   if pCam == nil .or. pCam == 0
      MsgAlert( "No camera available", "DirectShow" )
      return nil
   endif

   if DShowSnapShot( pCam, cFile )
      oImg:LoadImage( , cFile )
      oImg:Refresh()
   endif

return nil

//----------------------------------------------------------------------------//

#pragma BEGINDUMP

#pragma warning(disable:4996)

#include <hbapi.h>
#include <stdio.h>

// xHarbour defines LONGLONG; Harbour uses HB_LONGLONG
#ifndef HB_LONGLONG
   #define HB_LONGLONG LONGLONG
#endif

// xHarbour keeps these in hbcompat.h (not pulled by hbapi.h)
#ifndef HB_FALSE
   #define HB_FALSE  0
#endif
#ifndef HB_TRUE
   #define HB_TRUE   1
#endif

// BCC cfg uses -w! (warnings as errors). Windows SDK DirectShow headers
// trigger W8005 (ULONG bitfields) and W8013 (strsafe.h) — suppress for Borland.
#ifdef __BORLANDC__
   #pragma option push -w-8005 -w-8013
#endif

#include <dshow.h>
#include <uuids.h>
#include <objbase.h>

#ifdef __BORLANDC__
   #pragma option pop
#endif

#ifdef _MSC_VER
   #pragma comment( lib, "strmiids.lib" )
   #pragma comment( lib, "quartz.lib" )
   #pragma comment( lib, "ole32.lib" )
   #pragma comment( lib, "oleaut32.lib" )
#endif

// The Harbour generated .c file is compiled as C (cl -TC, bcc32, gcc), so all
// COM calls below use the C style vtable syntax.

typedef struct
{
   IGraphBuilder *        pGraph;
   ICaptureGraphBuilder2 *pBuilder;
   IBaseFilter *          pCap;
   IMediaControl *        pMediaControl;
   IVideoWindow *         pVideoWindow;
   IBasicVideo *          pBasicVideo;
   BOOL                   bComInit;   // TRUE if CoInitializeEx succeeded (S_OK/S_FALSE)
} DSHOW_CAM;

#define DS_RELEASE( p )  do { if( ( p ) != NULL ) { ( p )->lpVtbl->Release( p ); ( p ) = NULL; } } while( 0 )

static void ds_Error( const char * szMsg, HRESULT hr )
{
   static const char s_szHex[ 16 ] = { '0', '1', '2', '3', '4', '5', '6', '7',
                                      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
   char          szText[ 256 ];
   unsigned long ulValue = ( unsigned long ) hr;
   int           iLen = 0, i;

   while( szMsg[ iLen ] != '\0' && iLen < 200 )
   {
      szText[ iLen ] = szMsg[ iLen ];
      iLen++;
   }

   szText[ iLen++ ] = '\n';
   szText[ iLen++ ] = '0';
   szText[ iLen++ ] = 'x';

   for( i = 28; i >= 0; i -= 4 )
      szText[ iLen++ ] = s_szHex[ ( ulValue >> i ) & 0x0F ];

   szText[ iLen ] = '\0';

   MessageBox( 0, szText, "DirectShow error", MB_ICONEXCLAMATION | MB_OK );
}

static IBaseFilter * ds_FirstCaptureDevice( void )
{
   ICreateDevEnum * pDevEnum = NULL;
   IEnumMoniker *   pEnum = NULL;
   IMoniker *       pMoniker = NULL;
   IBaseFilter *    pCap = NULL;
   HRESULT          hr;

   hr = CoCreateInstance( &CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
                          &IID_ICreateDevEnum, ( void ** ) &pDevEnum );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the system device enumerator", hr );
      return NULL;
   }

   hr = pDevEnum->lpVtbl->CreateClassEnumerator( pDevEnum, &CLSID_VideoInputDeviceCategory, &pEnum, 0 );

   if( hr != S_OK )   // S_FALSE means the category is empty
   {
      ds_Error( "No video capture devices found", hr );
      DS_RELEASE( pDevEnum );
      return NULL;
   }

   while( pEnum->lpVtbl->Next( pEnum, 1, &pMoniker, NULL ) == S_OK )
   {
      hr = pMoniker->lpVtbl->BindToObject( pMoniker, 0, 0, &IID_IBaseFilter, ( void ** ) &pCap );

  DS_RELEASE( pMoniker );

  if( SUCCEEDED( hr ) )
     break;

  pCap = NULL;
   }

   DS_RELEASE( pEnum );
   DS_RELEASE( pDevEnum );

   if( pCap == NULL )
      ds_Error( "Could not bind any video capture device", hr );

   return pCap;
}

// DShowCamera( hWndParent, nX, nY, nWidth, nHeight ) --> pCam
HB_FUNC( DSHOWCAMERA )
{
   HWND        hWndParent = ( HWND ) ( HB_PTRUINT ) hb_parnll( 1 );
   long        x = ( long ) hb_parnl( 2 );
   long        y = ( long ) hb_parnl( 3 );
   long        w = ( long ) hb_parnl( 4 );
   long        h = ( long ) hb_parnl( 5 );
   DSHOW_CAM * pCam;
   HRESULT     hr;

   pCam = ( DSHOW_CAM * ) hb_xgrab( sizeof( DSHOW_CAM ) );
   ZeroMemory( pCam, sizeof( DSHOW_CAM ) );

   // FiveWin UI threads are already STA. COINIT_MULTITHREADED would fail with
   // RPC_E_CHANGED_MODE (0x80010106). DirectShow + IVideoWindow also expects STA.
   hr = CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );

   if( hr == S_OK || hr == S_FALSE )
   {
      // S_FALSE = COM already initialized with the same model on this thread
      pCam->bComInit = TRUE;
   }
   else if( hr == RPC_E_CHANGED_MODE )
   {
      // Already initialized with another model; COM is usable, do not uninit later
      pCam->bComInit = FALSE;
   }
   else if( FAILED( hr ) )
   {
      ds_Error( "CoInitializeEx failed", hr );
      hb_xfree( pCam );
      hb_retnll( 0 );
      return;
   }

   hr = CoCreateInstance( &CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
                          &IID_IGraphBuilder, ( void ** ) &pCam->pGraph );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the filter graph", hr );
      goto failure;
   }

   hr = CoCreateInstance( &CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
                          &IID_ICaptureGraphBuilder2, ( void ** ) &pCam->pBuilder );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not create the capture graph builder", hr );
      goto failure;
   }

   hr = pCam->pBuilder->lpVtbl->SetFiltergraph( pCam->pBuilder, pCam->pGraph );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not attach the capture graph builder to the graph", hr );
      goto failure;
   }

   pCam->pCap = ds_FirstCaptureDevice();

   if( pCam->pCap == NULL )
      goto failure;

   hr = pCam->pGraph->lpVtbl->AddFilter( pCam->pGraph, pCam->pCap, L"Capture Filter" );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not add the capture filter to the graph", hr );
      goto failure;
   }

   // The default video renderer is created here by DirectShow itself
   hr = pCam->pBuilder->lpVtbl->RenderStream( pCam->pBuilder, &PIN_CATEGORY_PREVIEW,
                                              &MEDIATYPE_Video, ( IUnknown * ) pCam->pCap,
                                              NULL, NULL );

   if( FAILED( hr ) )
   {
      // Cameras without a preview pin only expose the capture pin
      hr = pCam->pBuilder->lpVtbl->RenderStream( pCam->pBuilder, &PIN_CATEGORY_CAPTURE,
                                                 &MEDIATYPE_Video, ( IUnknown * ) pCam->pCap,
                                                 NULL, NULL );

  if( FAILED( hr ) )
  {
     ds_Error( "Could not render the preview video stream", hr );
     goto failure;
  }
   }

   hr = pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IVideoWindow,
                                              ( void ** ) &pCam->pVideoWindow );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not get the IVideoWindow interface", hr );
      goto failure;
   }

   hr = pCam->pVideoWindow->lpVtbl->put_Owner( pCam->pVideoWindow, ( OAHWND ) hWndParent );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not set the video window owner", hr );
      goto failure;
   }

   pCam->pVideoWindow->lpVtbl->put_WindowStyle( pCam->pVideoWindow, WS_CHILD | WS_CLIPSIBLINGS );
   pCam->pVideoWindow->lpVtbl->put_MessageDrain( pCam->pVideoWindow, ( OAHWND ) hWndParent );

   hr = pCam->pVideoWindow->lpVtbl->SetWindowPosition( pCam->pVideoWindow, x, y, w, h );

   if( FAILED( hr ) )
      ds_Error( "Could not set the video window position", hr );

   pCam->pVideoWindow->lpVtbl->put_Visible( pCam->pVideoWindow, OATRUE );

   // Optional, only used for snapshots
   pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IBasicVideo,
                                         ( void ** ) &pCam->pBasicVideo );

   hr = pCam->pGraph->lpVtbl->QueryInterface( pCam->pGraph, &IID_IMediaControl,
                                              ( void ** ) &pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not get the IMediaControl interface", hr );
      goto failure;
   }

   hr = pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not run the filter graph", hr );
      goto failure;
   }

   hb_retnll( ( HB_LONGLONG ) ( HB_PTRUINT ) pCam );
   return;

failure:

   DS_RELEASE( pCam->pMediaControl );
   DS_RELEASE( pCam->pBasicVideo );
   DS_RELEASE( pCam->pVideoWindow );
   DS_RELEASE( pCam->pCap );
   DS_RELEASE( pCam->pBuilder );
   DS_RELEASE( pCam->pGraph );

   if( pCam->bComInit )
      CoUninitialize();

   hb_xfree( pCam );

   hb_retnll( 0 );
}

// DShowSetPos( pCam, nX, nY, nWidth, nHeight ) --> lSuccess
HB_FUNC( DSHOWSETPOS )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pVideoWindow == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pVideoWindow->lpVtbl->SetWindowPosition( pCam->pVideoWindow,
      ( long ) hb_parnl( 2 ), ( long ) hb_parnl( 3 ),
      ( long ) hb_parnl( 4 ), ( long ) hb_parnl( 5 ) ) ) );
}

// DShowPlay( pCam ) --> lSuccess
HB_FUNC( DSHOWPLAY )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pMediaControl == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl ) ) );
}

// DShowStop( pCam ) --> lSuccess
HB_FUNC( DSHOWSTOP )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL || pCam->pMediaControl == NULL )
   {
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( SUCCEEDED( pCam->pMediaControl->lpVtbl->Stop( pCam->pMediaControl ) ) );
}

// DShowSnapShot( pCam, cBmpFile ) --> lSuccess
HB_FUNC( DSHOWSNAPSHOT )
{
   DSHOW_CAM *        pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );
   const char *       szFile = hb_parc( 2 );
   long               lSize = 0;
   char *             pDib;
   BITMAPINFOHEADER * pBmi;
   BITMAPFILEHEADER   bmfh;
   DWORD              dwPalette = 0;
   FILE *             hFile;
   HRESULT            hr;

   if( pCam == NULL || pCam->pBasicVideo == NULL || szFile == NULL )
   {
      ds_Error( "No camera available for the snapshot", E_POINTER );
      hb_retl( HB_FALSE );
      return;
   }

   // GetCurrentImage() requires the graph to be paused
   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Pause( pCam->pMediaControl );

   hr = pCam->pBasicVideo->lpVtbl->GetCurrentImage( pCam->pBasicVideo, &lSize, NULL );

   if( FAILED( hr ) || lSize <= ( long ) sizeof( BITMAPINFOHEADER ) )
   {
      ds_Error( "Could not retrieve the size of the current image", hr );

  if( pCam->pMediaControl != NULL )
     pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

  hb_retl( HB_FALSE );
  return;
   }

   pDib = ( char * ) hb_xgrab( lSize );

   hr = pCam->pBasicVideo->lpVtbl->GetCurrentImage( pCam->pBasicVideo, &lSize, ( long * ) pDib );

   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Run( pCam->pMediaControl );

   if( FAILED( hr ) )
   {
      ds_Error( "Could not retrieve the current image", hr );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   // The returned buffer is a packed DIB: BITMAPINFOHEADER + palette + pixels
   pBmi = ( BITMAPINFOHEADER * ) pDib;

   if( pBmi->biBitCount <= 8 )
      dwPalette = ( pBmi->biClrUsed ? pBmi->biClrUsed : ( DWORD ) ( 1 << pBmi->biBitCount ) ) * sizeof( RGBQUAD );
   else if( pBmi->biCompression == BI_BITFIELDS )
      dwPalette = 3 * sizeof( DWORD );

   bmfh.bfType      = 0x4D42;   // "BM"
   bmfh.bfSize      = ( DWORD ) ( sizeof( BITMAPFILEHEADER ) + lSize );
   bmfh.bfReserved1 = 0;
   bmfh.bfReserved2 = 0;
   bmfh.bfOffBits   = ( DWORD ) ( sizeof( BITMAPFILEHEADER ) + pBmi->biSize + dwPalette );

   hFile = fopen( szFile, "wb" );

   if( hFile == NULL )
   {
      ds_Error( "Could not create the bitmap file", E_ACCESSDENIED );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   if( fwrite( &bmfh, 1, sizeof( bmfh ), hFile ) != sizeof( bmfh ) ||
       fwrite( pDib, 1, ( size_t ) lSize, hFile ) != ( size_t ) lSize )
   {
      ds_Error( "Could not write the bitmap file", E_FAIL );
      fclose( hFile );
      hb_xfree( pDib );
      hb_retl( HB_FALSE );
      return;
   }

   fclose( hFile );
   hb_xfree( pDib );

   hb_retl( HB_TRUE );
}

// DShowClose( pCam ) --> NIL
HB_FUNC( DSHOWCLOSE )
{
   DSHOW_CAM * pCam = ( DSHOW_CAM * ) ( HB_PTRUINT ) hb_parnll( 1 );

   if( pCam == NULL )
      return;

   if( pCam->pMediaControl != NULL )
      pCam->pMediaControl->lpVtbl->Stop( pCam->pMediaControl );

   if( pCam->pVideoWindow != NULL )
   {
      pCam->pVideoWindow->lpVtbl->put_Visible( pCam->pVideoWindow, OAFALSE );
      pCam->pVideoWindow->lpVtbl->put_MessageDrain( pCam->pVideoWindow, ( OAHWND ) 0 );
      pCam->pVideoWindow->lpVtbl->put_Owner( pCam->pVideoWindow, ( OAHWND ) 0 );
   }

   DS_RELEASE( pCam->pMediaControl );
   DS_RELEASE( pCam->pBasicVideo );
   DS_RELEASE( pCam->pVideoWindow );
   DS_RELEASE( pCam->pCap );
   DS_RELEASE( pCam->pBuilder );
   DS_RELEASE( pCam->pGraph );

   if( pCam->bComInit )
      CoUninitialize();

   hb_xfree( pCam );
}

#pragma ENDDUMP
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 668
Joined: Fri Oct 21, 2005 05:54 AM

Re: TWebCam

Posted: Wed Jul 29, 2026 11:19 PM

Dear Mr.Antonio,

I am getting the following errors with your revised xHarbour comptiable DSHOW.PRG:

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³ FiveWin for xHarbour 26.06 - Jun. 2026 Harbour development power ³Ü
³ (c) FiveTech 1993-2026 for M.S Windows 9X/NT/200X/ME/XP/Vista/7/8/10/11 ³Û
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ
ÿ ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß
Compiling...
xHarbour 1.3.2 Intl. (SimpLex) (Build 20260605)
Copyright 1999-2026, http://www.xharbour.org http://www.harbour-project.org/
Compiling 'dshow.prg' and generating preprocessed output to 'dshow.ppo'...

100
200
.
.
300

400
Generating C source output to 'dshow.c'...
Done.

Lines 69, Functions/Procedures 2, pCodes 246
Embarcadero C++ 7.70 for Win32 Copyright (c) 1993-2023 Embarcadero Technologies, Inc.
DSHOW.c:
Warning W8013 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strsafe.h 2911: Possible use of 'cchDestLength' before definition in function StringCchCatExA
Warning W8013 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strsafe.h 3022: Possible use of 'cchDestLength' before definition in function StringCchCatExW
Warning W8013 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strsafe.h 3247: Possible use of 'cchDestLength' before definition in function StringCbCatExA
Warning W8013 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strsafe.h 3355: Possible use of 'cchDestLength' before definition in function StringCbCatExW
Warning W8013 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strsafe.h 3893: Possible use of 'cchDestLength' before definition in function StringCchCatNExA
Warning W8013 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strsafe.h 4005: Possible use of 'cchDestLength' before definition in function StringCchCatNExW
Warning W8013 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strsafe.h 4234: Possible use of 'cchDestLength' before definition in function StringCbCatNExA
Warning W8013 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strsafe.h 4347: Possible use of 'cchDestLength' before definition in function StringCbCatNExW
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22024: Bit fields must be signed or unsigned int
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22025: Bit fields must be signed or unsigned int
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22027: Bit fields must be signed or unsigned int
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22028: Bit fields must be signed or unsigned int
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22030: Bit fields must be signed or unsigned int
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22031: Bit fields must be signed or unsigned int
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22033: Bit fields must be signed or unsigned int
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22034: Bit fields must be signed or unsigned int
Warning W8005 c:\MyProjects\MyLanguages\Bcc77\bin\..\include\windows\sdk\strmif.h 22036: Bit fields must be signed or unsigned int
Error E2451 dshow.prg 306: Undefined symbol 'HB_LONGLONG' in function HB_FUN_DSHOWCAMERA
Error E2108 dshow.prg 306: Improper use of typedef 'HB_PTRUINT' in function HB_FUN_DSHOWCAMERA
Error E2293 dshow.prg 306: ) expected in function HB_FUN_DSHOWCAMERA
*** 3 errors in Compile ***

  • Linking errors *

Regards,

-Ramesh Babu P

Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: TWebCam

Posted: Thu Jul 30, 2026 04:21 AM

Dear Ramesh,

Could you please double check that you are trying to build the latest version ?

See this code in dshow.prg:

#ifndef HB_LONGLONG
   #define HB_LONGLONG LONGLONG
#endif

HB_LONGLONG is not available for xHarbour, so if should have been defined as LONGLONG.
In your errors, it shows as HB_LONGLONG

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 668
Joined: Fri Oct 21, 2005 05:54 AM

Re: TWebCam

Posted: Thu Jul 30, 2026 02:14 PM

Dear Mr.Antonio,

This is the code from c:\fwh_2603\samples\misc\dshow.prg I am trying to compile and
getting compilation errors.

#include "FiveWin.ch"

#define GWL_STYLE -16

function Main()

   local oWnd, hWnd, oCamera, pMediaControl
   

   DEFINE WINDOW oWnd

   oCamera = TControl()
   

   oCamera:bLClicked = { || TakePhoto( oCamera ) }

   ACTIVATE WINDOW oWnd MAXIMIZED ;
      ON INIT ( pMediaControl := DShowCamera(),;
                SetParent( hWnd := FindWindow( 0, "ActiveMovie Window" ), oWnd:hWnd ),;
                SetWindowLong( hWnd, GWL_STYLE, nOr( WS_CHILD, WS_VISIBLE ) ),;
                SetWindowPos( hWnd, 0, 15, 15, 300, 300 ),;
                oCamera:oWnd := oWnd, oCamera:hWnd := hWnd, oCamera:Link() )

return nil

function TakePhoto( oCamera )

   static oBmp

   oCamera:SaveToBmp( "photo.bmp" )
   

   if oBmp == nil
      @ 1, 60 BITMAP oBmp OF oCamera:oWnd FILENAME "photo.bmp"
   else   

      oBmp:LoadImage( , "photo.bmp" )
      oBmp:Refresh()
   endif   

return nil   

#pragma BEGINDUMP

#pragma warning(disable:4996)

#include <hbapi.h>
#include <dshow.h>
#include <uuids.h>
#include <objbase.h>

#import "qedit.dll" raw_interfaces_only named_guids

EXTERN_C const CLSID CLSID_NullRenderer;
EXTERN_C const CLSID CLSID_SampleGrabber;

HB_FUNC( DSHOWPLAY )
{
   IMediaControl * pMediaControl = ( IMediaControl * ) hb_parnll( 1 );

   pMediaControl->Run();
}   

HB_FUNC( DSHOWSTOP )
{
   IMediaControl * pMediaControl = ( IMediaControl * ) hb_parnll( 1 );

   pMediaControl->Stop();
}   

HB_FUNC( DSHOWCAMERA )
{
   HRESULT hr;
   ICreateDevEnum *pDevEnum = NULL;
   IEnumMoniker *pEnum = NULL;
   IMoniker *pMoniker = NULL;
   IPropertyBag *pPropBag = NULL;
   IGraphBuilder *pGraph = NULL;
   ICaptureGraphBuilder2 *pBuilder = NULL;
   IBaseFilter *pCap = NULL;
   IBaseFilter *pSampleGrabberFilter = NULL;
   IBaseFilter *pNullRenderer = NULL;
   IMediaControl *pMediaControl = NULL;
   char *pBuffer = NULL;
   VARIANT var;
	int n = 0;
	int device_number = 0;
	char device_name[ 100 ];
   char char_buffer[100];
   DexterLib::ISampleGrabber *pSampleGrabber = NULL;

   strcpy( device_name, "" );

   hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );

   if( hr != S_OK )
      MessageBox( 0, "CoInitializeEx error", "ok", 0 );

   hr = CoCreateInstance( CLSID_FilterGraph, NULL,
 			  CLSCTX_INPROC_SERVER, IID_IGraphBuilder,
			  ( void ** ) &pGraph );
           

   if( hr != S_OK )
      MessageBox( 0, "CoCreateInstance error", "ok", 0 );
      

hr = CoCreateInstance( CLSID_CaptureGraphBuilder2, NULL,
		CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
		( void ** ) &pBuilder );      

   if( hr != S_OK )
      MessageBox( 0, "CoCreateInstance 2 error", "ok", 0 );

hr = ( ( ICaptureGraphBuilder * ) pBuilder )->SetFiltergraph( pGraph );
   
if( hr != S_OK )
	MessageBox( 0, "Could not attach capture graph builder to graph", "ok", 0 ); 
  
hr = CoCreateInstance( CLSID_SystemDeviceEnum, NULL,
		CLSCTX_INPROC_SERVER, IID_PPV_ARGS( &pDevEnum ) );
     
if( hr != S_OK )
	MessageBox( 0, "Could not crerate system device enumerator", "ok", 0 );
  
hr = pDevEnum->CreateClassEnumerator(
				CLSID_VideoInputDeviceCategory, &pEnum, 0 );
           
if( hr != S_OK )
	MessageBox( 0, "No video devices found", "ok", 0 );      
  
while(1)
{
	// Access next device
	hr = pEnum->Next(1, &pMoniker, NULL);
	if( hr == S_OK )
		n++; // increment device count
  else   
     break;
	
	// If device was specified by name rather than number...
	if( device_number == 0 )
	{
		// Get video input device name
		hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
		if (hr == S_OK)
		{
			// Get current device name
			VariantInit(&var);
			hr = pPropBag->Read(L"FriendlyName", &var, 0);
			
			// Convert to a normal C string, i.e. char*
			sprintf(char_buffer, "%ls", var.bstrVal);
			VariantClear(&var);
			pPropBag->Release();
			pPropBag = NULL;
			
			// Exit loop if current device name matched devname
        // MessageBox( 0, char_buffer, "device_name", 0 );
        
			if (strcmp(device_name, char_buffer) == 0) break;
		}
		else
     {
			MessageBox( 0, "Error getting device names", "ok", 0 );
        break;
     }   
	}
	else if (n >= device_number) break;
}   
   
// Get video input device name
hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
VariantInit(&var);
hr = pPropBag->Read(L"FriendlyName", &var, 0);
// MessageBoxW( 0, L"Capture device", var.bstrVal, 0 );
VariantClear(&var);   
   
// Create capture filter and add to graph
hr = pMoniker->BindToObject(0, 0,
				IID_IBaseFilter, (void**)&pCap);
           
if( hr != S_OK ) 
  MessageBox( 0, "Could not create capture filter", "ok", 0 );   

// Add capture filter to graph
hr = pGraph->AddFilter(pCap, L"Capture Filter");
   
if( hr != S_OK ) 
  MessageBox( 0, "Could not add capture filter to graph", "ok", 0 );

// Create sample grabber filter
hr = CoCreateInstance(CLSID_SampleGrabber, NULL,
	CLSCTX_INPROC_SERVER, IID_IBaseFilter,
	(void**)&pSampleGrabberFilter);
  
if( hr != S_OK )
	MessageBox( 0, "Could not create Sample Grabber filter", "ok", 0 );

// Query the ISampleGrabber interface of the sample grabber filter
hr = pSampleGrabberFilter->QueryInterface(
		DexterLib::IID_ISampleGrabber, (void**)&pSampleGrabber);
     
if( hr != S_OK )
	MessageBox( 0, "Could not get ISampleGrabber interface to sample grabber filter", "ok", 0 );

// Enable sample buffering in the sample grabber filter
hr = pSampleGrabber->SetBufferSamples(TRUE);
   
if( hr != S_OK )
	MessageBox( 0, "Could not enable sample buffering in the sample grabber", "ok", 0 );

// Set media type in sample grabber filter
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
hr = pSampleGrabber->SetMediaType((DexterLib::_AMMediaType *)&mt);
   
if( hr != S_OK )
	MessageBox( 0, "Could not set media type in sample grabber", "ok", 0 );

// Add sample grabber filter to filter graph
hr = pGraph->AddFilter(pSampleGrabberFilter, L"SampleGrab");
   
if( hr != S_OK )
	MessageBox( 0, "Could not add Sample Grabber to filter graph", "ok", 0 );

// Create Null Renderer filter
hr = CoCreateInstance(CLSID_NullRenderer, NULL,
	CLSCTX_INPROC_SERVER, IID_IBaseFilter,
	(void**)&pNullRenderer);

   if( hr != S_OK )
		MessageBox( 0, "Could not create Null Renderer filter", "ok", 0 );

// Add Null Renderer filter to filter graph
hr = pGraph->AddFilter(pNullRenderer, L"NullRender");

   if( hr != S_OK )
		MessageBox( 0, "Could not add Null Renderer to filter graph", "ok", 0 );
      

   // Connect up the filter graph's capture stream
	hr = pBuilder->RenderStream(
		&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,
		pCap,  pSampleGrabberFilter, pNullRenderer);
      

if( hr != S_OK )
	MessageBox( 0, "Could not render capture video stream", "ok", 0 );

hr = pBuilder->RenderStream(
			&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
			pCap, NULL, NULL);

   if (hr != S_OK && hr != VFW_S_NOPREVIEWPIN)
			MessageBox( 0, "Could not render preview video stream", "ok", 0 );

// Get media control interfaces to graph builder object
hr = pGraph->QueryInterface(IID_IMediaControl,
				(void**)&pMediaControl);

   if( hr != S_OK ) 
      MessageBox( 0, "Could not get media control interface", "ok", 0 );

// Run graph
while(1)
{
	hr = pMediaControl->Run();
	
	// Hopefully, the return value was S_OK or S_FALSE
	if (hr == S_OK) break; // graph is now running
	if (hr == S_FALSE) continue; // graph still preparing to run
	
	// If the Run function returned something else,
	// there must be a problem
	// fprintf(stderr, "Error: %u\n", hr);
	MessageBox( 0, "Could not run filter graph", "ok", 0 );
}
   
   hb_retnll( ( HB_LONGLONG ) pMediaControl );
}

#pragma ENDDUMP

And the link script is :

@ECHO OFF
CLS
ECHO ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
ECHO ³ FiveWin for xHarbour 26.06 - Jun. 2026          Harbour development power  ³Ü
ECHO ³ (c) FiveTech 1993-2026 for M.S Windows 9X/NT/200X/ME/XP/Vista/7/8/10/11    ³Û
ECHO ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙÛ
ECHO ÿ ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß

if A%1 == A GOTO :SINTAX
if NOT EXIST %1.prg GOTO :NOEXIST

ECHO Compiling...

if "%FWDIR%" == "" set FWDIR=c:\MyProjects\MyLanguages\fwh_2603
if "%XHDIR%" == "" set XHDIR=c:\MyProjects\MyLanguages\xharbour

rem if "%2" == "/b" set GT=gtwin
rem if not "%2" == "/b" set GT=gtgui
set GT=gtgui

set hdir=%XHDIR%
set hdirl=%hdir%\lib
set bcdir=c:\MyProjects\MyLanguages\Bcc77
set fwh=%FWDIR%

%hdir%\bin\harbour %1 /n /i%fwh%\include;%hdir%\include /w /p %2 %3 > comp.log 2> warnings.log
IF ERRORLEVEL 1 GOTO COMPILEERRORS
@type comp.log
@type warnings.log

echo -O2 -e%1.exe -I%hdir%\include -I%bcdir%\include %1.c > b32.bc
%bcdir%\bin\bcc32 -M -c -v @b32.bc
:ENDCOMPILE

IF EXIST %1.rc %bcdir%\bin\brc32.exe -r -I%bcdir%\include -I%bcdir%\include\windows\sdk %1

echo -L%bcdir%\lib;%bcdir%\lib\psdk + > b32.bc
echo %bcdir%\lib\c0w32.obj + >> b32.bc
echo %1.obj, + >> b32.bc
echo %1.exe, + >> b32.bc
echo %1.map, + >> b32.bc
echo %fwh%\lib\Fivehx.lib %fwh%\lib\FiveHC.lib %fwh%\lib\libmysql.lib + >> b32.bc
rem echo %fwh%\lib\drxlsx32x_bcc.lib + >> b32.bc
rem echo %fwh%\lib\xlsxlibhbbccx.lib + >> b32.bc
echo %fwh%\lib\pgsql.lib %fwh%\lib\libpq.lib + >> b32.bc
echo %hdirl%\hbhpdf.lib + >> b32.bc
echo %hdirl%\libharu.lib + >> b32.bc
echo %hdirl%\png.lib + >> b32.bc
echo %hdirl%\rtl.lib + >> b32.bc
echo %hdirl%\vm.lib + >> b32.bc
echo %hdirl%\%GT%.lib + >> b32.bc
echo %hdirl%\lang.lib + >> b32.bc
echo %hdirl%\macro.lib + >> b32.bc
echo %hdirl%\rdd.lib + >> b32.bc
echo %hdirl%\dbfntx.lib + >> b32.bc
echo %hdirl%\dbfcdx.lib + >> b32.bc
echo %hdirl%\dbffpt.lib + >> b32.bc
echo %hdirl%\hbsix.lib + >> b32.bc
echo %hdirl%\debug.lib + >> b32.bc
echo %hdirl%\common.lib + >> b32.bc
echo %hdirl%\codepage.lib + >> b32.bc
echo %hdirl%\pp.lib + >> b32.bc
echo %hdirl%\pcrepos.lib + >> b32.bc
echo %hdirl%\ct.lib + >> b32.bc
echo %hdirl%\zlib.lib + >> b32.bc
echo %hdirl%\hbzip.lib + >> b32.bc
echo %hdirl%\libmisc.lib + >> b32.bc
echo %hdirl%\tip.lib + >> b32.bc
echo %hdirl%\hbzebra.lib + >> b32.bc
rem echo %hdirl%\png.lib + >> b32.bc

rem Uncomment these two lines to use Advantage RDD
rem echo %hdir%\lib\rddads.lib + >> b32.bc
rem echo %hdir%\lib\Ace32.lib + >> b32.bc

echo %bcdir%\lib\cw32.lib + >> b32.bc
echo %bcdir%\lib\import32.lib + >> b32.bc
echo %bcdir%\lib\psdk\uuid.lib + >> b32.bc
echo %bcdir%\lib\ws2_32.lib + >> b32.bc
echo %bcdir%\lib\psdk\odbc32.lib + >> b32.bc
echo %bcdir%\lib\psdk\rasapi32.lib + >> b32.bc
echo %bcdir%\lib\psdk\nddeapi.lib + >> b32.bc
echo %bcdir%\lib\psdk\msimg32.lib + >> b32.bc
echo %bcdir%\lib\psdk\psapi.lib + >> b32.bc
echo %bcdir%\lib\psdk\uxtheme.lib + >> b32.bc
echo %bcdir%\lib\psdk\gdiplus.lib + >> b32.bc
echo %bcdir%\lib\psdk\iphlpapi.lib + >> b32.bc
echo %bcdir%\lib\psdk\shell32.lib, >> b32.bc

IF EXIST %1.res echo %1.res >> b32.bc

rem uncomment this line to use the debugger and comment the following one
if %GT% == gtwin %bcdir%\bin\ilink32 -Gn -Tpe -s -v @b32.bc
IF ERRORLEVEL 1 GOTO LINKERROR
if %GT% == gtgui %bcdir%\bin\ilink32 -Gn -aa -Tpe -s -v @b32.bc
IF ERRORLEVEL 1 GOTO LINKERROR
ECHO * Application successfully built *
%1
GOTO EXIT
ECHO

rem delete temporary files
@del %1.c

:COMPILEERRORS
@type comp.log
ECHO * Compile errors *
GOTO EXIT

:LINKERROR
ECHO * Linking errors *
GOTO EXIT

:SINTAX
ECHO    SYNTAX: Build [Program]     {-- No especifiques la extensi?n PRG
ECHO                                {-- Don't specify .PRG extension
GOTO EXIT

:NOEXIST
ECHO The specified PRG %1 does not exist

:EXIT

For your information I am using FWH_2603 + xHarbur 1.3.2 (20260605) + bcc77

Regards,
-Ramesh Babu P

Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: TWebCam

Posted: Thu Jul 30, 2026 06:58 PM

Dear Ramesh,

This version works perfectly with xHarbour and bcc7.7

Please try it :idea:

dshow.prg

// Webcam live preview + snapshot (FiveWin)
//
// Uses Media Foundation via mfcam.dll (NOT DirectShow).
// FaceTime + Win11: DirectShow delivers black frames; MF works
// (verified with camtest_mf64.exe).
//
// Build:
//   build_mfcam.bat               mfcam.dll (32-bit) in this folder
//   build_new.bat dshow xb32
//
// Left IMAGE = live preview.  Right IMAGE = snapshot.

#include "FiveWin.ch"

#define GWL_STYLE       -16
#define WS_CLIPCHILDREN 0x02000000

static s_oLive  := nil
static s_oSnap  := nil
static s_oTimer := nil
static s_lOpen  := .F.

//----------------------------------------------------------------------------//

function Main()

   local oDlg, oFont
   local cSnap := ".\dshowphoto.bmp"
   local nW := 640, nH := 480

   s_oLive  := nil
   s_oSnap  := nil
   s_oTimer := nil
   s_lOpen  := .F.

   DEFINE FONT oFont NAME "Segoe UI" SIZE 0, -13

   DEFINE DIALOG oDlg SIZE 1040, 580 PIXEL TRUEPIXEL ;
      TITLE "Webcam (Media Foundation)" FONT oFont

   @ 10, 10 IMAGE s_oLive OF oDlg SIZE nW, nH PIXEL ADJUST

   @ 10, nW + 30 SAY "Snapshot" OF oDlg PIXEL
   @ 30, nW + 30 IMAGE s_oSnap OF oDlg SIZE 320, 240 PIXEL ADJUST

   @ nH + 20, 10 SAY "Live preview (Media Foundation / mfcam.dll)" OF oDlg PIXEL

   @ nH + 20, nW + 30 BUTTON "Take &photo" OF oDlg SIZE 100, 28 PIXEL ;
      ACTION TakePhoto( cSnap )

   @ nH + 20, nW + 150 BUTTON "&Exit" OF oDlg SIZE 80, 28 PIXEL ;
      ACTION oDlg:End()

   oDlg:bInit := {|| CamInit( oDlg ) }

   ACTIVATE DIALOG oDlg CENTERED ;
      VALID ( CamClose(), .T. )

   oFont:End()

return nil

//----------------------------------------------------------------------------//

static function CamInit( oDlg )

   SetWindowLong( oDlg:hWnd, GWL_STYLE, ;
      nOr( GetWindowLong( oDlg:hWnd, GWL_STYLE ), WS_CLIPCHILDREN ) )

   if s_lOpen
      return nil
   endif

   if ! MfCamLoad( "mfcam.dll" )
      MsgAlert( "Cannot load mfcam.dll" + CRLF + CRLF + ;
                "From samples\misc run:" + CRLF + ;
                "   build_mfcam.bat" + CRLF + CRLF + ;
                "Then keep mfcam.dll next to dshow.exe", "Webcam" )
      return nil
   endif

   if MfCamOpen() == 0
      MsgAlert( "Media Foundation could not open the camera." + CRLF + ;
                "Close browser/Teams if they use it.", "Webcam" )
      MfCamUnload()
      return nil
   endif

   s_lOpen := .T.

   s_oTimer := TTimer():New( 66, {|| CamTick() }, oDlg )
   s_oTimer:Activate()
   CamTick()

return nil

//----------------------------------------------------------------------------//

static function CamTick()

   local cFrame := ".\dshow_frame.bmp"

   if ! s_lOpen .or. s_oLive == nil
      return nil
   endif

   if MfCamSaveBmp( cFrame ) != 0 .and. File( cFrame )
      s_oLive:LoadImage( , cFrame )
      s_oLive:Refresh()
   endif

return nil

//----------------------------------------------------------------------------//

static function CamClose()

   if s_oTimer != nil
      s_oTimer:Deactivate()
      s_oTimer:End()
      s_oTimer := nil
   endif

   if s_lOpen
      MfCamClose()
      s_lOpen := .F.
   endif

   MfCamUnload()

return nil

//----------------------------------------------------------------------------//

function TakePhoto( cFile )

   if ! s_lOpen
      MsgAlert( "Camera is not running", "Webcam" )
      return nil
   endif

   if MfCamSaveBmp( cFile ) != 0 .and. File( cFile )
      if s_oSnap != nil
         s_oSnap:LoadImage( , cFile )
         s_oSnap:Refresh()
      endif
   else
      MsgAlert( "Snapshot failed", "Webcam" )
   endif

return nil

//----------------------------------------------------------------------------//

#pragma BEGINDUMP

#include <hbapi.h>
#include <windows.h>
#include <string.h>

#ifndef HB_FALSE
   #define HB_FALSE 0
   #define HB_TRUE  1
#endif

typedef int  ( WINAPI * PFN_OPEN  )( void );
typedef void ( WINAPI * PFN_CLOSE )( void );
typedef int  ( WINAPI * PFN_SAVE  )( const char * );

static HMODULE   s_hDll   = NULL;
static PFN_OPEN  s_pOpen  = NULL;
static PFN_CLOSE s_pClose = NULL;
static PFN_SAVE  s_pSave  = NULL;

static FARPROC ds_get( HMODULE h, const char * a, const char * b, const char * c )
{
   FARPROC p = GetProcAddress( h, a );
   if( ! p && b ) p = GetProcAddress( h, b );
   if( ! p && c ) p = GetProcAddress( h, c );
   return p;
}

/* MfCamLoad( cDllName ) --> lOk */
HB_FUNC( MFCAMLOAD )
{
   const char * sz = hb_parc( 1 );
   char path[ MAX_PATH ];
   HMODULE hExe;
   DWORD n;

   if( s_hDll )
   {
      hb_retl( HB_TRUE );
      return;
   }

   if( ! sz || ! sz[ 0 ] )
      sz = "mfcam.dll";

   /* 1) as given  2) next to EXE */
   s_hDll = LoadLibraryA( sz );
   if( ! s_hDll )
   {
      hExe = GetModuleHandleA( NULL );
      n = GetModuleFileNameA( hExe, path, MAX_PATH );
      if( n > 0 && n < MAX_PATH )
      {
         char * slash = strrchr( path, '\\' );
         if( slash )
         {
            slash[ 1 ] = '\0';
            strncat( path, sz, MAX_PATH - strlen( path ) - 1 );
            s_hDll = LoadLibraryA( path );
         }
      }
   }

   if( ! s_hDll )
   {
      hb_retl( HB_FALSE );
      return;
   }

   /* MSVC stdcall decoration: _Name@N  or undecorated with /EXPORT */
   s_pOpen  = ( PFN_OPEN )  ds_get( s_hDll, "MfCam_Open",  "_MfCam_Open@0",  "MfCam_Open@0" );
   s_pClose = ( PFN_CLOSE ) ds_get( s_hDll, "MfCam_Close", "_MfCam_Close@0", "MfCam_Close@0" );
   s_pSave  = ( PFN_SAVE )  ds_get( s_hDll, "MfCam_SaveBmp", "_MfCam_SaveBmp@4", "MfCam_SaveBmp@4" );

   if( ! s_pOpen || ! s_pClose || ! s_pSave )
   {
      FreeLibrary( s_hDll );
      s_hDll = NULL;
      s_pOpen = NULL;
      s_pClose = NULL;
      s_pSave = NULL;
      hb_retl( HB_FALSE );
      return;
   }

   hb_retl( HB_TRUE );
}

/* MfCamUnload() */
HB_FUNC( MFCAMUNLOAD )
{
   if( s_hDll )
   {
      FreeLibrary( s_hDll );
      s_hDll = NULL;
   }
   s_pOpen = NULL;
   s_pClose = NULL;
   s_pSave = NULL;
}

/* MfCamOpen() --> nOk (1/0) */
HB_FUNC( MFCAMOPEN )
{
   hb_retni( s_pOpen ? s_pOpen() : 0 );
}

/* MfCamClose() */
HB_FUNC( MFCAMCLOSE )
{
   if( s_pClose )
      s_pClose();
}

/* MfCamSaveBmp( cFile ) --> nOk (1/0) */
HB_FUNC( MFCAMSAVEBMP )
{
   const char * sz = hb_parc( 1 );
   hb_retni( ( s_pSave && sz ) ? s_pSave( sz ) : 0 );
}

#pragma ENDDUMP
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 668
Joined: Fri Oct 21, 2005 05:54 AM

Re: TWebCam

Posted: Fri Jul 31, 2026 12:13 AM

Dear Mr.Antonio,

Thank you very much for the revised code.

It is getting compiled without any Errors.

When I run it, it is leaving a message :

Cannot load mfcam.dll
From samples\misc run:
build_mfcam.bat
Then keep mfcam.dll next to dshow.exe

The bat File "build_mfcam.bat" is not found under samples\misc

Can you please share it with me and also please share 'MFCAM.DLL'

Regards,

-Ramesh Babu P

Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: TWebCam

Posted: Fri Jul 31, 2026 09:09 AM

Dear Ramesh,

Fixed version, no external DLL required. Working fine with xHarbour and bcc

dshow.prg

// Webcam live preview + snapshot (FiveWin)
//
// Uses Media Foundation via self-contained C code embedded below
// (#pragma BEGINDUMP): no external mfcam.dll is needed at runtime.
// MF/COM entry points are resolved at runtime with LoadLibrary /
// GetProcAddress (ole32, mfplat, mf, mfreadwrite), so it builds with
// BCC32 without mf*.lib or the MF SDK headers.
// FaceTime + Win11: DirectShow delivers black frames; MF works
// (verified with camtest_mf64.exe).
//
// Build:
//   build_new.bat dshow xb32
//
// Left IMAGE = live preview.  Right IMAGE = snapshot.

#include "FiveWin.ch"

#define GWL_STYLE       -16
#define WS_CLIPCHILDREN 0x02000000

static s_oLive  := nil
static s_oSnap  := nil
static s_oTimer := nil
static s_lOpen  := .F.

//----------------------------------------------------------------------------//

function Main()

   local oDlg, oFont
   local cSnap := ".\dshowphoto.bmp"
   local nW := 640, nH := 480

   s_oLive  := nil
   s_oSnap  := nil
   s_oTimer := nil
   s_lOpen  := .F.

   DEFINE FONT oFont NAME "Segoe UI" SIZE 0, -13

   DEFINE DIALOG oDlg SIZE 1040, 580 PIXEL TRUEPIXEL ;
      TITLE "Webcam (Media Foundation)" FONT oFont

   @ 10, 10 IMAGE s_oLive OF oDlg SIZE nW, nH PIXEL ADJUST

   @ 10, nW + 30 SAY "Snapshot" OF oDlg PIXEL
   @ 30, nW + 30 IMAGE s_oSnap OF oDlg SIZE 320, 240 PIXEL ADJUST

   @ nH + 20, 10 SAY "Live preview (Media Foundation)" OF oDlg PIXEL

   @ nH + 20, nW + 30 BUTTON "Take &photo" OF oDlg SIZE 100, 28 PIXEL ;
      ACTION TakePhoto( cSnap )

   @ nH + 20, nW + 150 BUTTON "&Exit" OF oDlg SIZE 80, 28 PIXEL ;
      ACTION oDlg:End()

   oDlg:bInit := {|| CamInit( oDlg ) }

   ACTIVATE DIALOG oDlg CENTERED ;
      VALID ( CamClose(), .T. )

   oFont:End()

return nil

//----------------------------------------------------------------------------//

static function CamInit( oDlg )

   SetWindowLong( oDlg:hWnd, GWL_STYLE, ;
      nOr( GetWindowLong( oDlg:hWnd, GWL_STYLE ), WS_CLIPCHILDREN ) )

   if s_lOpen
      return nil
   endif

   if MfCamOpen() == 0
      MsgAlert( "Media Foundation could not open the camera." + CRLF + ;
                "Close browser/Teams if they use it.", "Webcam" )
      return nil
   endif

   s_lOpen := .T.

   s_oTimer := TTimer():New( 66, {|| CamTick() }, oDlg )
   s_oTimer:Activate()
   CamTick()

return nil

//----------------------------------------------------------------------------//

static function CamTick()

   local cFrame := ".\dshow_frame.bmp"

   if ! s_lOpen .or. s_oLive == nil
      return nil
   endif

   if MfCamSaveBmp( cFrame ) != 0 .and. File( cFrame )
      s_oLive:LoadImage( , cFrame )
      s_oLive:Refresh()
   endif

return nil

//----------------------------------------------------------------------------//

static function CamClose()

   if s_oTimer != nil
      s_oTimer:Deactivate()
      s_oTimer:End()
      s_oTimer := nil
   endif

   if s_lOpen
      MfCamClose()
      s_lOpen := .F.
   endif

return nil

//----------------------------------------------------------------------------//

function TakePhoto( cFile )

   if ! s_lOpen
      MsgAlert( "Camera is not running", "Webcam" )
      return nil
   endif

   if MfCamSaveBmp( cFile ) != 0 .and. File( cFile )
      if s_oSnap != nil
         s_oSnap:LoadImage( , cFile )
         s_oSnap:Refresh()
      endif
   else
      MsgAlert( "Snapshot failed", "Webcam" )
   endif

return nil

//----------------------------------------------------------------------------//

#pragma BEGINDUMP

/* =====================================================================
 * Media Foundation webcam ÔÇö self-contained C (converted from mfcam.cpp)
 *
 * BCC32 ships no mfapi.h / mfidl.h / mfreadwrite.h and this build does
 * not link mf*.lib, so everything MF-related is declared locally:
 * GUIDs, minimal COM vtables (called by index) and function pointers
 * resolved at runtime via LoadLibrary/GetProcAddress from ole32.dll,
 * mfplat.dll, mf.dll and mfreadwrite.dll. No mfcam.dll is needed.
 *
 * Harbour API (used by the UI above):
 *    MfCamOpen()            --> 1 ok / 0 fail
 *    MfCamClose()
 *    MfCamSaveBmp( cFile )  --> 1 ok / 0 fail
 * ===================================================================== */

#include <hbapi.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

#ifndef HB_FALSE
   #define HB_FALSE 0
   #define HB_TRUE  1
#endif

#ifndef COINIT_APARTMENTTHREADED
   #define COINIT_APARTMENTTHREADED 0x2
#endif
#ifndef RPC_E_CHANGED_MODE
   #define RPC_E_CHANGED_MODE ( ( HRESULT ) 0x80010106L )
#endif

#define MFC_MF_VERSION         ( ( 2UL << 16 ) | 0x70 )
#define MFC_STARTUP_LITE       1
#define MFC_FIRST_VIDEO_STREAM 0xFFFFFFFCL
#define MFC_ENDOFSTREAM        0x2L

/* COM vtable indexes (0-based), verified against the Windows SDK
 * mfobjects.h / mfidl.h / mfreadwrite.h */
#define IX_RELEASE          2   /* IUnknown::Release                    */
#define IX_GETUINT64        8   /* IMFAttributes::GetUINT64             */
#define IX_GETALLOCSTRING   13  /* IMFAttributes::GetAllocatedString    */
#define IX_SETUINT32        21  /* IMFAttributes::SetUINT32             */
#define IX_SETGUID          24  /* IMFAttributes::SetGUID               */
#define IX_ACTIVATEOBJECT   33  /* IMFActivate::ActivateObject          */
#define IX_SHUTDOWNOBJECT   34  /* IMFActivate::ShutdownObject          */
#define IX_BUF_LOCK         3   /* IMFMediaBuffer::Lock                 */
#define IX_BUF_UNLOCK       4   /* IMFMediaBuffer::Unlock               */
#define IX_SMP_CONVERT      41  /* IMFSample::ConvertToContiguousBuffer */
#define IX_RDR_GETCURMT     6   /* IMFSourceReader::GetCurrentMediaType */
#define IX_RDR_SETCURMT     7   /* IMFSourceReader::SetCurrentMediaType */
#define IX_RDR_READSAMPLE   9   /* IMFSourceReader::ReadSample          */

typedef struct MFCGUID_
{
   unsigned long  d1;
   unsigned short d2;
   unsigned short d3;
   unsigned char  d4[ 8 ];
} MFCGUID;

static const MFCGUID IID_IMFMediaSource =          /* 279a808d-aec7-40c8-9c6b-a6b492c78a66 */
   { 0x279a808dUL, 0xaec7, 0x40c8, { 0x9c, 0x6b, 0xa6, 0xb4, 0x92, 0xc7, 0x8a, 0x66 } };
static const MFCGUID MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE =  /* c60ac5fe-252a-478f-a0ef-bc8fa5f7cad3 */
   { 0xc60ac5feUL, 0x252a, 0x478f, { 0xa0, 0xef, 0xbc, 0x8f, 0xa5, 0xf7, 0xca, 0xd3 } };
static const MFCGUID MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID =  /* 8ac3587a-4ae7-42d8-99e0-0a6013eef90f */
   { 0x8ac3587aUL, 0x4ae7, 0x42d8, { 0x99, 0xe0, 0x0a, 0x60, 0x13, 0xee, 0xf9, 0x0f } };
static const MFCGUID MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME =  /* 60d0e559-52f8-4fa2-bbce-acdb34a8ec01 */
   { 0x60d0e559UL, 0x52f8, 0x4fa2, { 0xbb, 0xce, 0xac, 0xdb, 0x34, 0xa8, 0xec, 0x01 } };
static const MFCGUID MF_MT_MAJOR_TYPE =            /* 48eba18e-f8c9-4687-bf11-0a74c9f96a8f */
   { 0x48eba18eUL, 0xf8c9, 0x4687, { 0xbf, 0x11, 0x0a, 0x74, 0xc9, 0xf9, 0x6a, 0x8f } };
static const MFCGUID MF_MT_SUBTYPE =               /* f7e34c9a-42e8-4714-b74b-cb29d72c35e5 */
   { 0xf7e34c9aUL, 0x42e8, 0x4714, { 0xb7, 0x4b, 0xcb, 0x29, 0xd7, 0x2c, 0x35, 0xe5 } };
static const MFCGUID MF_MT_FRAME_SIZE =            /* 1652c33d-d6b2-4012-b834-72030849a37d */
   { 0x1652c33dUL, 0xd6b2, 0x4012, { 0xb8, 0x34, 0x72, 0x03, 0x08, 0x49, 0xa3, 0x7d } };
static const MFCGUID MFMediaType_Video =           /* 73646976-0000-0010-8000-00aa00389b71 */
   { 0x73646976UL, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
static const MFCGUID MFVideoFormat_RGB32 =         /* 00000016-0000-0010-8000-00aa00389b71 */
   { 0x00000016UL, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
static const MFCGUID MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING =  /* fb394f3d-ccf1-42ee-bbb3-f9b845d5681d */
   { 0xfb394f3dUL, 0xccf1, 0x42ee, { 0xbb, 0xb3, 0xf9, 0xb8, 0x45, 0xd5, 0x68, 0x1d } };

/* --- dynamically resolved API (ole32 / mfplat / mf / mfreadwrite) --- */

typedef HRESULT ( WINAPI * PFN_CoInitializeEx )( LPVOID, DWORD );
typedef void    ( WINAPI * PFN_CoUninitialize )( void );
typedef void    ( WINAPI * PFN_CoTaskMemFree )( LPVOID );
typedef HRESULT ( WINAPI * PFN_MFStartup )( ULONG, DWORD );
typedef HRESULT ( WINAPI * PFN_MFShutdown )( void );
typedef HRESULT ( WINAPI * PFN_MFCreateAttributes )( void **, unsigned int );
typedef HRESULT ( WINAPI * PFN_MFCreateMediaType )( void ** );
typedef HRESULT ( WINAPI * PFN_MFEnumDeviceSources )( void *, void ***, unsigned int * );
typedef HRESULT ( WINAPI * PFN_MFCreateSourceReaderFromMediaSource )( void *, void *, void ** );

static PFN_CoInitializeEx   s_pCoInitializeEx = NULL;
static PFN_CoUninitialize   s_pCoUninitialize = NULL;
static PFN_CoTaskMemFree    s_pCoTaskMemFree  = NULL;
static PFN_MFStartup        s_pMFStartup      = NULL;
static PFN_MFShutdown       s_pMFShutdown     = NULL;
static PFN_MFCreateAttributes s_pMFCreateAttributes = NULL;
static PFN_MFCreateMediaType  s_pMFCreateMediaType  = NULL;
static PFN_MFEnumDeviceSources s_pMFEnumDeviceSources = NULL;
static PFN_MFCreateSourceReaderFromMediaSource s_pMFCreateSourceReader = NULL;

static int s_libs_state = -1;   /* -1 not tried, 0 failed, 1 ok */

static int MfLoadLibs( void )
{
   HMODULE hOle, hPlat, hMf, hRw;

   if( s_libs_state >= 0 )
      return s_libs_state;

   s_libs_state = 0;

   hOle  = LoadLibraryA( "ole32.dll" );
   hPlat = LoadLibraryA( "mfplat.dll" );
   hMf   = LoadLibraryA( "mf.dll" );
   hRw   = LoadLibraryA( "mfreadwrite.dll" );
   if( ! hOle || ! hPlat || ! hMf || ! hRw )
      return 0;

   s_pCoInitializeEx = ( PFN_CoInitializeEx ) GetProcAddress( hOle, "CoInitializeEx" );
   s_pCoUninitialize = ( PFN_CoUninitialize ) GetProcAddress( hOle, "CoUninitialize" );
   s_pCoTaskMemFree  = ( PFN_CoTaskMemFree )  GetProcAddress( hOle, "CoTaskMemFree" );
   s_pMFStartup      = ( PFN_MFStartup )      GetProcAddress( hPlat, "MFStartup" );
   s_pMFShutdown     = ( PFN_MFShutdown )     GetProcAddress( hPlat, "MFShutdown" );
   s_pMFCreateAttributes = ( PFN_MFCreateAttributes ) GetProcAddress( hPlat, "MFCreateAttributes" );
   s_pMFCreateMediaType  = ( PFN_MFCreateMediaType )  GetProcAddress( hPlat, "MFCreateMediaType" );
   s_pMFEnumDeviceSources = ( PFN_MFEnumDeviceSources ) GetProcAddress( hMf, "MFEnumDeviceSources" );
   s_pMFCreateSourceReader = ( PFN_MFCreateSourceReaderFromMediaSource )
                             GetProcAddress( hRw, "MFCreateSourceReaderFromMediaSource" );

   if( ! s_pCoInitializeEx || ! s_pCoUninitialize || ! s_pCoTaskMemFree ||
       ! s_pMFStartup || ! s_pMFShutdown || ! s_pMFCreateAttributes ||
       ! s_pMFCreateMediaType || ! s_pMFEnumDeviceSources || ! s_pMFCreateSourceReader )
      return 0;

   /* keep the DLLs loaded for the process lifetime */
   s_libs_state = 1;
   return 1;
}

/* --- minimal COM helpers (call through the vtable by index) --- */

typedef ULONG   ( WINAPI * PFN_ComRelease )( void * );
typedef ULONG   ( WINAPI * PFN_ComAddRef )( void * );
typedef HRESULT ( WINAPI * PFN_AttrGetUINT64 )( void *, const MFCGUID *, ULONGLONG * );
typedef HRESULT ( WINAPI * PFN_AttrGetAllocatedString )( void *, const MFCGUID *, WCHAR **, unsigned int * );
typedef HRESULT ( WINAPI * PFN_AttrSetUINT32 )( void *, const MFCGUID *, unsigned int );
typedef HRESULT ( WINAPI * PFN_AttrSetGUID )( void *, const MFCGUID *, const MFCGUID * );
typedef HRESULT ( WINAPI * PFN_ActActivateObject )( void *, const MFCGUID *, void ** );
typedef HRESULT ( WINAPI * PFN_ActShutdownObject )( void * );
typedef HRESULT ( WINAPI * PFN_BufLock )( void *, BYTE **, DWORD *, DWORD * );
typedef HRESULT ( WINAPI * PFN_BufUnlock )( void * );
typedef HRESULT ( WINAPI * PFN_SmpConvert )( void *, void ** );
typedef HRESULT ( WINAPI * PFN_RdrGetCurrentMediaType )( void *, DWORD, void ** );
typedef HRESULT ( WINAPI * PFN_RdrSetCurrentMediaType )( void *, DWORD, DWORD *, void * );
typedef HRESULT ( WINAPI * PFN_RdrReadSample )( void *, DWORD, DWORD, DWORD *, DWORD *, LONGLONG *, void ** );

static void ** MfVTable( void * obj )
{
   return * ( void *** ) obj;
}

static ULONG MfRelease( void * obj )
{
   return ( ( PFN_ComRelease ) MfVTable( obj )[ IX_RELEASE ] )( obj );
}

static ULONG MfAddRef( void * obj )
{
   return ( ( PFN_ComAddRef ) MfVTable( obj )[ 1 ] )( obj );
}

static HRESULT MfAttrGetUINT64( void * obj, const MFCGUID * key, ULONGLONG * val )
{
   return ( ( PFN_AttrGetUINT64 ) MfVTable( obj )[ IX_GETUINT64 ] )( obj, key, val );
}

static HRESULT MfAttrGetAllocatedString( void * obj, const MFCGUID * key,
                                         WCHAR ** val, unsigned int * len )
{
   return ( ( PFN_AttrGetAllocatedString ) MfVTable( obj )[ IX_GETALLOCSTRING ] )
          ( obj, key, val, len );
}

static HRESULT MfAttrSetUINT32( void * obj, const MFCGUID * key, unsigned int val )
{
   return ( ( PFN_AttrSetUINT32 ) MfVTable( obj )[ IX_SETUINT32 ] )( obj, key, val );
}

static HRESULT MfAttrSetGUID( void * obj, const MFCGUID * key, const MFCGUID * val )
{
   return ( ( PFN_AttrSetGUID ) MfVTable( obj )[ IX_SETGUID ] )( obj, key, val );
}

static HRESULT MfActivateObject( void * obj, const MFCGUID * iid, void ** ppv )
{
   return ( ( PFN_ActActivateObject ) MfVTable( obj )[ IX_ACTIVATEOBJECT ] )( obj, iid, ppv );
}

static HRESULT MfShutdownObject( void * obj )
{
   return ( ( PFN_ActShutdownObject ) MfVTable( obj )[ IX_SHUTDOWNOBJECT ] )( obj );
}

static HRESULT MfBufLock( void * obj, BYTE ** data, DWORD * maxLen, DWORD * curLen )
{
   return ( ( PFN_BufLock ) MfVTable( obj )[ IX_BUF_LOCK ] )( obj, data, maxLen, curLen );
}

static HRESULT MfBufUnlock( void * obj )
{
   return ( ( PFN_BufUnlock ) MfVTable( obj )[ IX_BUF_UNLOCK ] )( obj );
}

static HRESULT MfSampleConvert( void * obj, void ** ppBuf )
{
   return ( ( PFN_SmpConvert ) MfVTable( obj )[ IX_SMP_CONVERT ] )( obj, ppBuf );
}

static HRESULT MfReaderGetCurrentMediaType( void * obj, DWORD stream, void ** ppType )
{
   return ( ( PFN_RdrGetCurrentMediaType ) MfVTable( obj )[ IX_RDR_GETCURMT ] )
          ( obj, stream, ppType );
}

static HRESULT MfReaderSetCurrentMediaType( void * obj, DWORD stream, DWORD * reserved, void * type )
{
   return ( ( PFN_RdrSetCurrentMediaType ) MfVTable( obj )[ IX_RDR_SETCURMT ] )
          ( obj, stream, reserved, type );
}

static HRESULT MfReaderReadSample( void * obj, DWORD stream, DWORD flags,
                                   DWORD * actual, DWORD * stFlags,
                                   LONGLONG * ts, void ** ppSample )
{
   return ( ( PFN_RdrReadSample ) MfVTable( obj )[ IX_RDR_READSAMPLE ] )
          ( obj, stream, flags, actual, stFlags, ts, ppSample );
}

/* --- webcam state --- */

static void * g_reader   = NULL;   /* IMFSourceReader */
static void * g_activate = NULL;   /* IMFActivate     */
static int g_w = 0, g_h = 0;
static int g_good = 0, g_black = 0;
static BYTE * g_rgb = NULL;
static int g_rgbSize = 0;
static CRITICAL_SECTION g_cs;
static int g_cs_init = 0;
static int g_com = 0;
static int g_mf = 0;

static void MfCamCloseImpl( void );

static void MfEnsureCs( void )
{
   if( ! g_cs_init )
   {
      InitializeCriticalSection( &g_cs );
      g_cs_init = 1;
   }
}

static int MfNameIsBad( const WCHAR * name )
{
   WCHAR low[ 256 ];
   size_t i, n;
   if( ! name ) return 1;
   n = wcslen( name );
   if( n > 255 ) n = 255;
   for( i = 0; i < n; i++ )
   {
      WCHAR c = name[ i ];
      if( c >= L'A' && c <= L'Z' ) c = ( WCHAR )( c + 32 );
      low[ i ] = c;
   }
   low[ n ] = 0;
   return wcsstr( low, L"remote desktop" ) != NULL || wcsstr( low, L"obs virtual" ) != NULL;
}

static HRESULT MfPickDevice( void ** ppActivate )
{
   void * attr = NULL;
   void ** devices = NULL;
   unsigned int count = 0, i, chosen = ( unsigned int ) -1;
   WCHAR * name = NULL;
   HRESULT hr;

   *ppActivate = NULL;
   hr = s_pMFCreateAttributes( &attr, 1 );
   if( FAILED( hr ) ) return hr;
   hr = MfAttrSetGUID( attr, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
                       &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID );
   if( FAILED( hr ) ) { MfRelease( attr ); return hr; }

   hr = s_pMFEnumDeviceSources( attr, &devices, &count );
   MfRelease( attr );
   if( FAILED( hr ) ) return hr;
   if( count == 0 ) { s_pCoTaskMemFree( devices ); return HRESULT_FROM_WIN32( ERROR_NOT_FOUND ); }

   for( i = 0; i < count; i++ )
   {
      unsigned int len = 0;
      name = NULL;
      if( FAILED( MfAttrGetAllocatedString( devices[ i ], &MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
                                            &name, &len ) ) || ! name )
         continue;
      if( ! MfNameIsBad( name ) )
      {
         if( wcsstr( name, L"FaceTime" ) || wcsstr( name, L"Camera" ) || wcsstr( name, L"Webcam" ) )
         {
            if( chosen == ( unsigned int ) -1 || wcsstr( name, L"FaceTime" ) )
               chosen = i;
         }
         else if( chosen == ( unsigned int ) -1 )
            chosen = i;
      }
      s_pCoTaskMemFree( name );
   }

   if( chosen == ( unsigned int ) -1 )
   {
      for( i = 0; i < count; i++ ) MfRelease( devices[ i ] );
      s_pCoTaskMemFree( devices );
      return HRESULT_FROM_WIN32( ERROR_NOT_FOUND );
   }

   *ppActivate = devices[ chosen ];
   MfAddRef( *ppActivate );
   for( i = 0; i < count; i++ ) MfRelease( devices[ i ] );
   s_pCoTaskMemFree( devices );
   return S_OK;
}

static HRESULT MfConfigureReader( void * reader )
{
   void * type = NULL;
   void * cur = NULL;
   unsigned int w = 0, h = 0;
   ULONGLONG fs = 0;
   HRESULT hr;

   hr = s_pMFCreateMediaType( &type );
   if( FAILED( hr ) ) return hr;
   MfAttrSetGUID( type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video );
   MfAttrSetGUID( type, &MF_MT_SUBTYPE, &MFVideoFormat_RGB32 );
   MfReaderSetCurrentMediaType( reader, MFC_FIRST_VIDEO_STREAM, NULL, type );
   MfRelease( type );
   /* if RGB32 fails, keep default and hope for conversion via ENABLE_VIDEO_PROCESSING */

   hr = MfReaderGetCurrentMediaType( reader, MFC_FIRST_VIDEO_STREAM, &cur );
   if( SUCCEEDED( hr ) && cur )
   {
      /* MFGetAttributeSize(): frame size is packed as HI32=width, LO32=height */
      if( SUCCEEDED( MfAttrGetUINT64( cur, &MF_MT_FRAME_SIZE, &fs ) ) )
      {
         w = ( unsigned int ) ( fs >> 32 );
         h = ( unsigned int ) ( fs & 0xFFFFFFFF );
      }
      MfRelease( cur );
   }
   if( w == 0 || h == 0 ) { w = 640; h = 480; }

   g_w = ( int ) w;
   g_h = ( int ) h;
   g_rgbSize = g_w * g_h * 3;
   free( g_rgb );
   g_rgb = ( BYTE * ) malloc( ( size_t ) g_rgbSize );
   if( ! g_rgb ) return ( HRESULT ) 0x8007000EL; /* E_OUTOFMEMORY */
   memset( g_rgb, 0, ( size_t ) g_rgbSize );
   return S_OK;
}

static int MfIsBlack( const BYTE * p, int nbytes )
{
   int i, step = 64, nz = 0, n = 0;
   for( i = 0; i < nbytes; i += step )
   {
      n++;
      if( p[ i ] > 12 ) nz++;
   }
   return nz * 20 < n;
}

static int MfSampleToRgb( void * sample )
{
   void * buf = NULL;
   BYTE * data = NULL;
   DWORD maxLen = 0, curLen = 0;
   HRESULT hr;
   int ok = 0;

   hr = MfSampleConvert( sample, &buf );
   if( FAILED( hr ) ) return 0;
   hr = MfBufLock( buf, &data, &maxLen, &curLen );
   if( FAILED( hr ) || ! data || curLen == 0 ) { MfRelease( buf ); return 0; }

   if( ( int ) curLen >= g_w * g_h * 4 )
   {
      int y, x;
      for( y = 0; y < g_h; y++ )
      {
         const BYTE * src = data + y * g_w * 4;
         BYTE * dst = g_rgb + ( g_h - 1 - y ) * g_w * 3;
         for( x = 0; x < g_w; x++ )
         {
            dst[ 0 ] = src[ 0 ];
            dst[ 1 ] = src[ 1 ];
            dst[ 2 ] = src[ 2 ];
            dst += 3;
            src += 4;
         }
      }
      ok = 1;
   }
   else if( ( int ) curLen >= g_w * g_h * 3 )
   {
      int y;
      for( y = 0; y < g_h; y++ )
         memcpy( g_rgb + ( g_h - 1 - y ) * g_w * 3, data + y * g_w * 3, ( size_t ) g_w * 3 );
      ok = 1;
   }

   if( ok )
   {
      if( MfIsBlack( g_rgb, g_rgbSize ) ) g_black++;
      else g_good++;
   }

   MfBufUnlock( buf );
   MfRelease( buf );
   return ok;
}

static int MfPullFrame( void )
{
   DWORD stream = 0, flags = 0;
   LONGLONG ts = 0;
   void * sample = NULL;
   HRESULT hr;
   int ok;

   if( ! g_reader ) return 0;

   hr = MfReaderReadSample( g_reader, MFC_FIRST_VIDEO_STREAM,
                            0, &stream, &flags, &ts, &sample );
   if( FAILED( hr ) || ! sample ) return 0;
   if( flags & MFC_ENDOFSTREAM ) { MfRelease( sample ); return 0; }

   EnterCriticalSection( &g_cs );
   ok = MfSampleToRgb( sample );
   LeaveCriticalSection( &g_cs );
   MfRelease( sample );
   return ok;
}

static int MfCamOpenImpl( void )
{
   void * src = NULL;
   void * ra = NULL;
   HRESULT hr;

   if( ! MfLoadLibs() ) return 0;

   MfEnsureCs();
   MfCamCloseImpl();   /* reset any previous session, as mfcam.cpp did */

   hr = s_pCoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
   if( hr == S_OK || hr == S_FALSE ) g_com = 1;
   else if( hr == RPC_E_CHANGED_MODE ) g_com = 0;
   else return 0;

   hr = s_pMFStartup( MFC_MF_VERSION, MFC_STARTUP_LITE );
   if( FAILED( hr ) )
   {
      if( g_com ) s_pCoUninitialize();
      g_com = 0;
      return 0;
   }
   g_mf = 1;

   hr = MfPickDevice( &g_activate );
   if( FAILED( hr ) || ! g_activate )
   {
      if( g_mf ) { s_pMFShutdown(); g_mf = 0; }
      if( g_com ) { s_pCoUninitialize(); g_com = 0; }
      return 0;
   }

   hr = MfActivateObject( g_activate, &IID_IMFMediaSource, &src );
   if( FAILED( hr ) )
   {
      MfShutdownObject( g_activate );
      MfRelease( g_activate );
      g_activate = NULL;
      if( g_mf ) { s_pMFShutdown(); g_mf = 0; }
      if( g_com ) { s_pCoUninitialize(); g_com = 0; }
      return 0;
   }

   hr = s_pMFCreateAttributes( &ra, 2 );
   if( SUCCEEDED( hr ) && ra )
   {
      MfAttrSetUINT32( ra, &MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, 1 );
      hr = s_pMFCreateSourceReader( src, ra, &g_reader );
      MfRelease( ra );
   }
   else
      hr = s_pMFCreateSourceReader( src, NULL, &g_reader );

   MfRelease( src );
   if( FAILED( hr ) || ! g_reader )
   {
      MfShutdownObject( g_activate );
      MfRelease( g_activate );
      g_activate = NULL;
      if( g_mf ) { s_pMFShutdown(); g_mf = 0; }
      if( g_com ) { s_pCoUninitialize(); g_com = 0; }
      return 0;
   }

   if( FAILED( MfConfigureReader( g_reader ) ) )
   {
      MfRelease( g_reader );
      g_reader = NULL;
      MfShutdownObject( g_activate );
      MfRelease( g_activate );
      g_activate = NULL;
      if( g_mf ) { s_pMFShutdown(); g_mf = 0; }
      if( g_com ) { s_pCoUninitialize(); g_com = 0; }
      return 0;
   }

   /* warm-up a few frames */
   {
      int i;
      for( i = 0; i < 5; i++ )
         MfPullFrame();
   }
   return 1;
}

static void MfCamCloseImpl( void )
{
   MfEnsureCs();
   EnterCriticalSection( &g_cs );

   if( g_reader ) { MfRelease( g_reader ); g_reader = NULL; }
   if( g_activate )
   {
      MfShutdownObject( g_activate );
      MfRelease( g_activate );
      g_activate = NULL;
   }
   free( g_rgb );
   g_rgb = NULL;
   g_rgbSize = 0;
   g_w = g_h = 0;
   g_good = g_black = 0;

   LeaveCriticalSection( &g_cs );

   if( g_mf ) { s_pMFShutdown(); g_mf = 0; }
   if( g_com ) { s_pCoUninitialize(); g_com = 0; }
}

static int MfCamSaveBmpImpl( const char * path )
{
   BITMAPFILEHEADER bmfh;
   BITMAPINFOHEADER bih;
   FILE * fp;
   int rowSize, imgSize, y;
   BYTE pad[ 4 ] = { 0, 0, 0, 0 };
   int padn;

   if( ! path || ! path[ 0 ] ) return 0;
   if( ! MfPullFrame() ) return 0;
   if( ! g_rgb || g_w <= 0 ) return 0;

   rowSize = ( ( g_w * 3 + 3 ) / 4 ) * 4;
   imgSize = rowSize * g_h;
   padn = rowSize - g_w * 3;

   ZeroMemory( &bih, sizeof( bih ) );
   bih.biSize = sizeof( bih );
   bih.biWidth = g_w;
   bih.biHeight = g_h;
   bih.biPlanes = 1;
   bih.biBitCount = 24;
   bih.biCompression = BI_RGB;
   bih.biSizeImage = ( DWORD ) imgSize;

   bmfh.bfType = 0x4D42;
   bmfh.bfOffBits = sizeof( bmfh ) + sizeof( bih );
   bmfh.bfSize = bmfh.bfOffBits + imgSize;
   bmfh.bfReserved1 = bmfh.bfReserved2 = 0;

   fp = fopen( path, "wb" );
   if( ! fp ) return 0;

   EnterCriticalSection( &g_cs );
   fwrite( &bmfh, 1, sizeof( bmfh ), fp );
   fwrite( &bih, 1, sizeof( bih ), fp );
   for( y = 0; y < g_h; y++ )
   {
      fwrite( g_rgb + y * g_w * 3, 1, ( size_t ) g_w * 3, fp );
      if( padn ) fwrite( pad, 1, ( size_t ) padn, fp );
   }
   LeaveCriticalSection( &g_cs );

   fclose( fp );
   return 1;
}

/* --- Harbour wrappers --- */

/* MfCamOpen() --> nOk (1/0) */
HB_FUNC( MFCAMOPEN )
{
   hb_retni( MfCamOpenImpl() );
}

/* MfCamClose() */
HB_FUNC( MFCAMCLOSE )
{
   MfCamCloseImpl();
}

/* MfCamSaveBmp( cFile ) --> nOk (1/0) */
HB_FUNC( MFCAMSAVEBMP )
{
   const char * sz = hb_parc( 1 );
   hb_retni( ( sz && sz[ 0 ] ) ? MfCamSaveBmpImpl( sz ) : 0 );
}

#pragma ENDDUMP
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 668
Joined: Fri Oct 21, 2005 05:54 AM

Re: TWebCam

Posted: Fri Jul 31, 2026 11:45 PM

Dear Mr.Antonio,

Excellent. :D :D :D

I am extremely thankful to you for your latest code. It is working simply fine.

By the way Can we have the same methods of TWebCam Class has like:

METHOD Connect
METHOD Disconnect
METHOD Clipboard( oBmp )
METHOD Save( oBmp, cFile, nQuality )
METHOD Source() with following values:
1) Camera Control
2) Brightness
3) Contrast
4) Exposure
5) White Balance
6) Zoom
7) Pan
8) Tilt
9) Focus
10) Gain
11) Backlight Compensation
Etc.


METHOD Format() with an array of different available Resolutions.


METHOD GetStatus()

METHOD Resize()

Regards,

-Ramesh Babu P