C++ Builder Visual Components wrapping DirectX

Welcome to BCB-Tools.com Latest News

Development Tools Demo Applications Step-By-Step Tutorials Component Reference

Register our Tools Available Downloads

Frequently Asked Questions Links to other sites Information about the www.tdxlibrary.org website










    TECHNOLOGY COMPARISON
    Go to the Welcome Page
        TECH COMPARISON...

    Technology Comment...

    Let's compare Microsoft Visual C++ with Borland C++ Builder...
    They are both "best of breed" technologies... but which one is better?

    Using the TDx_Library, you can now do in 5-10 lines of Borland C++ Builder code
    what you previously would do writing 50-100 lines of Visual C++ code... plus 1000's more lines to get DirectX working.

    ...


  • Let's start with Borland C++ Builder...


  • Let's write two applications to animate a bitmap full-screen, and play a sound effect out the speakers...

    Here's the complete pseudo-code :-
    
    	#pragma link "TDx_Draw_Library_Install"
    	#pragma link "TDx_Sound_Library_Install"
    	
    	void __fastcall TMainForm::Button1Click( TObject* Sender )
    	{
    	DirectDraw->Create(NULL);
    	DirectSound->Create(NULL);
    	
    	DirectDraw->CreatePrimarySurface();
    	DirectSound->CreatePrimarySoundBuffer();
    	
    	DirectDraw->Blt();
    	DirectSound->Play();
    	
    	while (DirectSound->Playing) 
    		{
    		DirectDraw->Flip();
    		Sleep(1);
    		}
    	}
    	


    And here is the actual code required to animate a bitmap full-screen, with lots of other stuff thrown in...
    
    //---------------------------------------------------------------------------
    // File: TMainForm.cpp, TDx_Draw_Library, Example9 - Fast Page Flipping
    //
    // Date: 7th January, 2004
    // Author: Darren John Dwyer
    // Copyright: (c) 2002-2004 Darren John Dwyer, All Rights Reserved.
    //
    // Description:
    //
    // This example shows how to partially optimize page flipping.
    // It uses Application->OnIdle() instead of Timer1->OnTimer()
    // It uses global TCanvas's, rather than creating and destroying
    // each time a TCanvas is required.
    //
    // See later examples for increased frame rates.
    //
    //---------------------------------------------------------------------------
    #include 
    #pragma hdrstop
    //---------------------------------------------------------------------------
    #include "TMainForm.h"
    //---------------------------------------------------------------------------
    #if (__BORLANDC__ >= 0x0530) // BCB Version 3 +
        #pragma package(smart_init)
    #endif
    //---------------------------------------------------------------------------
    #pragma link "tddscaps"
    #pragma link "tddsurfacedesc"
    #pragma link "tdx_draw"
    #pragma link "tdx_drawsurface"
    #pragma resource "*.dfm"
    //---------------------------------------------------------------------------
    #pragma link "TDx_Draw"
    #pragma link "TDx_DrawSurface"
    #pragma link "TDDCaps"
    #pragma link "TDDPixelFormat"
    #pragma link "TDDSCaps"
    #pragma link "TDDSurfaceDesc"
    #pragma link "TDx_Draw_Library_Install"
    //---------------------------------------------------------------------------
    TMainForm *MainForm;
    //---------------------------------------------------------------------------
    AnsiString IntToHexStr( unsigned int hexvalue )
    {
    char* hexchars[16] = {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
    AnsiString string = "0x";
    int value = 0x10000000;
    for (int i=0;i<8;i++)
        {
        string += hexchars[hexvalue/value];
        hexvalue -= value * (hexvalue/value);
        value = value >> 4;
        }
    return string;
    }
    //---------------------------------------------------------------------------
    #define Msg(A)  {\
                    if (StatusMemo->Text.Length()>30000) StatusMemo->Text = "";\
                    StatusMemo->Lines->Add(A);\
                    }
    //---------------------------------------------------------------------------
    __fastcall TMainForm::TMainForm(TComponent* Owner)
        : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    __fastcall TMainForm::~TMainForm()
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::FormCreate(TObject *Sender)
    {
    Top=0;
    Left=0;
    Width=800;
    Height=600;
    
    canvas = new TCanvas();
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::FormDestroy(TObject *Sender)
    {
    Application->OnIdle = NULL;
    if (Dx_Draw1->Created) Dx_Draw1->Destroy();
    if (canvas) delete canvas;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::ExitButtonClick(TObject *Sender)
    {
    Close();
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::ClearButtonClick(TObject *Sender)
    {
    StatusMemo->Lines->Clear();
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Dx_Draw1Create(TObject *Sender)
    {
    NumModes=0;
    ModesListBox->Items->Clear();
    Dx_Draw1->EnumDisplayModes(0,NULL,NULL);
    
    Dx_Draw1->SetCooperativeLevel( Application->Handle, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE );
    
    // create a complex primary surface
    PrimarySurfaceDesc->Flags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
    PrimarySurfaceDesc->BackBufferCount = 1;
    PrimaryCaps->Caps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
    PrimarySurfaceDesc->SCaps = PrimaryCaps;
    PrimarySurface->Create( PrimarySurfaceDesc, Dx_Draw1 );
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Dx_Draw1Destroy(TObject *Sender)
    {
    PrimarySurface->Destroy();
    Dx_Draw1->SetCooperativeLevel( Application->Handle, DDSCL_NORMAL );
    if (Dx_Draw1->RestoreDisplayMode())
        {
        Top=0;
        Left=0;
        Width=800;
        Height=600;
        Invalidate();
        }
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Dx_Draw1Error(TObject *Sender, AnsiString Function,
        AnsiString Error, AnsiString ErrorMessage)
    {
    Msg("ERROR ["+Error+"]: "+Function+", "+ErrorMessage);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Dx_Draw1EnumDisplayModes(TObject *Sender,
          TDDSurfaceDesc *SurfaceDesc, void *Context, bool &Finished)
    {
    int width = SurfaceDesc->Width;
    int height = SurfaceDesc->Height;
    int refresh_rate = SurfaceDesc->RefreshRate;
    int bit_depth;
    
    if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_PALETTEINDEXED1) bit_depth = 1;
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_PALETTEINDEXED2) bit_depth = 2;
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_PALETTEINDEXED4) bit_depth = 4;
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_PALETTEINDEXED8) bit_depth = 8;
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_PALETTEINDEXEDTO8) bit_depth = 8;
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_ALPHA) bit_depth = SurfaceDesc->PixelFormat->AlphaBitDepth[0];
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_ALPHAPIXELS) bit_depth = SurfaceDesc->PixelFormat->AlphaBitDepth[0];
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_ALPHAPREMULT) bit_depth = SurfaceDesc->PixelFormat->AlphaBitDepth[0];
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_BUMPDUDV) bit_depth = SurfaceDesc->PixelFormat->BumpBitCount[0];
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_BUMPLUMINANCE) bit_depth = SurfaceDesc->PixelFormat->BumpBitCount[0];
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_RGB) bit_depth = SurfaceDesc->PixelFormat->RGBBitCount[0];
    else if (SurfaceDesc->PixelFormat->Flags[0] & DDPF_YUV) bit_depth = SurfaceDesc->PixelFormat->YUVBitCount[0];
    
    if (NumModesItems->Add( IntToStr(width)+"x"+IntToStr(height)+"x"+IntToStr(bit_depth)+" @ "+IntToStr(refresh_rate)+"Hz" );
        }
    else
        Finished = true;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::NextModeButtonClick(TObject *Sender)
    {
    if (ModesListBox->Items->Count>0)
        {
        Msg("Selecting Next Available Mode");
        if (ModesListBox->ItemIndex==ModesListBox->Items->Count-1) ModesListBox->ItemIndex=0;
        else ModesListBox->ItemIndex = ModesListBox->ItemIndex + 1;
        ModesListBox->OnClick(this);
        }
    else
        ModesListBox->ItemIndex = -1;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::ModesListBoxClick(TObject *Sender)
    {
    if (ModesListBox->ItemIndex!=-1)
        {
        int index = ModesListBox->ItemIndex;
        AnsiString name = ModesListBox->Items->Strings[index];
    
        Msg("Mode Selected: '"+name+"'");
        CurrentModeLabel->Caption = name;
        }
    else
        CurrentModeLabel->Caption = "-- default --";
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::PrimarySurfaceCreate(TObject *Sender)
    {
    Msg(">>> Primary Surface Created");
    
    // get it's attached backbuffer
    if (PrimarySurface->GetAttachedSurface( BackBufferCaps, BackBuffer ))
        // call the backbuffer::OnCreate() event manually.
        BackBuffer->OnCreate(this);
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::PrimarySurfaceDestroy(TObject *Sender)
    {
    Msg(">>> Primary Surface Destroy");
    if (BackBuffer->Created) BackBuffer->Destroy();
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::PrimarySurfaceSurfaceLost(TObject *Sender)
    {
    PrimarySurface->Restore();
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::ModesListBoxDblClick(TObject *Sender)
    {
    SelectModeButton->OnClick(this);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::SelectModeButtonClick(TObject *Sender)
    {
    if (ModesListBox->Items->Count>0)
        {
        ShowMessage("Please Note:\n\
    You may experience difficulty restoring your display mode.\n\
    To return to the original display mode at any time, press ALT-R (Restore) or ALT-X (eXit)" );
    
        int index = ModesListBox->ItemIndex;
        PrimarySurface->Destroy();
        if (Dx_Draw1->SetDisplayMode( Widths[index], Heights[index], BitDepths[index], RefreshRates[index], 0 ))
            {
            Msg("SelectModeButton> Display mode has been set" );
            }
        PrimarySurface->Create( PrimarySurfaceDesc, Dx_Draw1 );
        RepaintButton->OnClick(this);
        }
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::RepaintButtonClick(TObject *Sender)
    {
    Application->OnIdle = NULL;
    if (Dx_Draw1->Created) Dx_Draw1->FlipToGDISurface();
    
        int old_top = Top;
        Top=Screen->Height+1;
        Invalidate();
        Top=old_top;
        Invalidate();
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::BackBufferCreate(TObject *Sender)
    {
    Msg(">>> BackBuffer Created");
    
    Image2->AutoSize = false;
    Image2->Stretch = true;
    Image2->Width = Screen->Width;
    Image2->Height = Screen->Height;
    Image2->Canvas->StretchDraw( Image2->Canvas->ClipRect, Image1->Picture->Graphic );
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::BackBufferDestroy(TObject *Sender)
    {
    Msg(">>> BackBuffer Destroyed");
    }
    //---------------------------------------------------------------------------
    
    
    void __fastcall TMainForm::CreateButtonClick(TObject *Sender)
    {
    Dx_Draw1->Create(NULL);
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::FlipButtonClick(TObject *Sender)
    {
    ShowMessage("Please Note:\n\
    After the primary surface has been painted the contents of the current form\n\
    will no longer be visible though it is still active. To repaint the form\n\
    Press ALT-R (Restore) or to exit the application, press ALT-X (eXit)" );
    
    CurrentPageNumber = 0;
    Application->OnIdle = OnIdle;
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::OnIdle(TObject *Sender, bool& Done)
    {
    if (!BackBuffer->Created) return;
    if (!PrimarySurface->Created) return;
    
    // error-proof vcl code
    HDC hdc;
    if (BackBuffer->GetDC(&hdc))
        {
        try
            {
            // make sure to reassign the canvas so it paints in the right spot
            canvas->Handle = hdc;
    
            // paint the background star image
            canvas->CopyRect( canvas->ClipRect, Image2->Canvas, Image2->Canvas->ClipRect );
    
            // paint some text
            canvas->Brush->Style = bsClear;
            canvas->Pen->Style = psClear;
            canvas->Font->Name = "Arial";
            canvas->Font->Style = TFontStyles();
            canvas->Font->Size = 20;
            canvas->Font->Color = (TColor) RGB(0,0,0);
            canvas->TextOut( 2, 2, "Paint onto the BackBuffer, then flip to the Primary Surface" );
            canvas->Font->Color = (TColor) RGB(128,255,128);
            canvas->TextOut( 0, 0, "Paint onto the BackBuffer, then flip to the Primary Surface" );
    
            // and more text
            canvas->Brush->Style = bsClear;
            canvas->Font->Name = "Comic Sans MS";
            canvas->Font->Style = TFontStyles() << fsBold << fsItalic << fsUnderline << fsStrikeOut;
            canvas->Font->Size = 24;
            canvas->Font->Color = (TColor) RGB(0,0,0);
            canvas->TextOut( 102 + CurrentPageNumber, 42, "Frame# "+IntToStr(CurrentPageNumber) );
            canvas->Font->Color = (TColor) RGB(128+CurrentPageNumber%128,255,128+CurrentPageNumber%128);
            canvas->TextOut( 100 + CurrentPageNumber, 40, "Frame# "+IntToStr(CurrentPageNumber) );
    
            // and remove our temporary canvas handle
            canvas->Handle = NULL;
            }
        catch (Exception &e)
            {
            Application->OnIdle = NULL;
            }
    
        BackBuffer->ReleaseDC(hdc);
        }
    
    PrimarySurface->Flip( BackBuffer, DDFLIP_DONOTWAIT );
    CurrentPageNumber++;
    
    // continue immediately
    Done = false;
    }
    //---------------------------------------------------------------------------
    	


    And here is the code to play a sound effect, with lots of other stuff thrown in...
    
    //---------------------------------------------------------------------------
    // File: TMainForm.cpp
    //
    //  TDx_Sound_Library
    //  Example2 - Playing with Sounds
    //
    // Date: 9th January, 2004
    // Author: Darren John Dwyer
    // Copyright: (c) 2002-2004 Darren John Dwyer, All Rights Reserved.
    //
    // Description:
    //
    // This example shows how to manipulate sounds while they are playing,
    // including adjusting the volume, pan and frequency.
    //
    //---------------------------------------------------------------------------
    #include 
    #pragma hdrstop
    
    #include "TMainForm.h"
    //---------------------------------------------------------------------------
    #pragma link "TDx_Sound"
    #pragma link "TDx_SoundBuffer"
    #pragma link "TDSCaps"
    #pragma link "TDSBufferDesc"
    #pragma link "TDx_Sound_Library_Install"
    #pragma resource "*.dfm"
    //---------------------------------------------------------------------------
    TMainForm *MainForm;
    //---------------------------------------------------------------------------
    __fastcall TMainForm::TMainForm(TComponent* Owner)
        : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::FormCreate(TObject *Sender)
    {
    KnownDevices = new TStringList();
    KnownModules = new TStringList();
    KnownGuids = new TList();
    
    DevicesListBox->Items->Clear();
    if (Dx_Sound1->DSEnumerate( NULL ))
        {
        if (KnownDevices->Count>0)
            {
            DevicesListBox->ItemIndex = 0;
            Dx_Sound1->Create( (GUID*) KnownGuids->Items[DevicesListBox->ItemIndex] );
            }
        }
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::FormDestroy(TObject *Sender)
    {
    if (Dx_Sound1->Created) Dx_Sound1->Destroy();
    
    if (KnownGuids) delete KnownGuids;
    if (KnownModules) delete KnownModules;
    if (KnownDevices) delete KnownDevices;
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::DevicesListBoxClick(TObject *Sender)
    {
    if (Dx_Sound1->Created) Dx_Sound1->Destroy();
    NotCreatedLabel->Visible = !Dx_Sound1->Create( (GUID*) KnownGuids->Items[DevicesListBox->ItemIndex] );
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Dx_Sound1Destroy(TObject *Sender)
    {
    if (Dx_SoundBuffer1->Created) Dx_SoundBuffer1->Destroy();
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Dx_SoundBuffer1BufferLost(TObject *Sender)
    {
    Dx_SoundBuffer1->CreateFromFile( Edit1->Text, DSBufferDesc1, Dx_Sound1 );
    Dx_SoundBuffer1->Play(0,0);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::PlayButtonClick(TObject *Sender)
    {
    if (Paused)
        {
        Paused = false;
        if (LoopingCheckBox->Checked) Dx_SoundBuffer1->Play(0,DSBPLAY_LOOPING);
        else Dx_SoundBuffer1->Play(0,0);
        return;
        }
    
    if (Dx_SoundBuffer1->Created) Dx_SoundBuffer1->Destroy();
    if (Edit1->Text.Pos("*.WAV"))
        {
    //    StatusMemo->Lines->Add( "Cannot select *.WAV" );
        return;
        }
    if (Dx_SoundBuffer1->CreateFromFile( Edit1->Text, DSBufferDesc1, Dx_Sound1 ))
        {
        BufferSizeLabel->Caption = "Buffer Size: "+IntToStr(DSBufferDesc1->BufferBytes)+" bytes";
        if (LoopingCheckBox->Checked) Dx_SoundBuffer1->Play(0,DSBPLAY_LOOPING);
        else Dx_SoundBuffer1->Play(0,0);
        }
    else
        ShowMessage("Couldn't Create From File");
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Timer1Timer(TObject *Sender)
    {
    if (!Dx_SoundBuffer1->Created) return;
    
    if (Dx_SoundBuffer1->Playing)
        PlayingLabel->Caption = "Buffer is Playing...";
    else
        PlayingLabel->Caption = "Buffer is Stopped.";
    
    Dx_SoundBuffer1->GetCurrentPosition( &CurrentPlayPos, &CurrentWritePos );
    BufferPosLabel->Caption = "Buffer Position: "+IntToStr(CurrentPlayPos);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Dx_SoundBuffer1Create(TObject *Sender)
    {
    if (Dx_SoundBuffer1->Created)
        {
        Dx_SoundBuffer1->GetPan( &Pan );
        Dx_SoundBuffer1->GetVolume( &Volume );
        Dx_SoundBuffer1->GetFrequency( &Frequency );
    
        PanScrollBar->Position = Pan;
        VolumeScrollBar->Position = Volume;
        FrequencyScrollBar->Position = Frequency/10;    // see bugfix below
    
        PanLabel->Caption = "Pan: "+IntToStr((int) Pan);
        VolumeLabel->Caption = "Volume: "+IntToStr((int) Volume);
        FrequencyLabel->Caption = "Frequency: "+IntToStr((int) Frequency);
        }
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::PanScrollBarChange(TObject *Sender)
    {
    Pan = PanScrollBar->Position;
    if (Dx_SoundBuffer1->SetPan( Pan )) PanLabel->Caption = "Pan: "+IntToStr((int) Pan);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::VolumeScrollBarChange(TObject *Sender)
    {
    Volume = VolumeScrollBar->Position;
    if (Dx_SoundBuffer1->SetVolume( Volume )) VolumeLabel->Caption = "Volume: "+IntToStr((int) Volume);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::FrequencyScrollBarChange(TObject *Sender)
    {
    // There seems to be a bug in the TScrollBar, in which the TScrollBar does
    // not seem to handle ranges 0..100,000 correctly and truncates values.
    // So, we've fiddled with the FrequencyScrollBar's Position, Min, Max,
    // SmallChange & LargeChange properties so they fit a smaller scale 0..10,000,
    // which works appropriately.
    
    Frequency = FrequencyScrollBar->Position * 10;
    if (Dx_SoundBuffer1->SetFrequency( Frequency ))    FrequencyLabel->Caption = "Frequency: "+IntToStr(Frequency);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::Dx_SoundBuffer1Destroy(TObject *Sender)
    {
    Dx_SoundBuffer1->Stop();
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::FileListBox1DblClick(TObject *Sender)
    {
    PlayButtonClick(this);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::StopButtonClick(TObject *Sender)
    {
    Dx_SoundBuffer1->Stop();
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::RewindButtonClick(TObject *Sender)
    {
    Dx_SoundBuffer1->SetCurrentPosition(CurrentPlayPos-DSBufferDesc1->BufferBytes/10);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::ForwardButtonClick(TObject *Sender)
    {
    Dx_SoundBuffer1->SetCurrentPosition(CurrentPlayPos+DSBufferDesc1->BufferBytes/10);
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::PauseButtonClick(TObject *Sender)
    {
    if (Dx_SoundBuffer1->Playing)
        {
        Paused = Dx_SoundBuffer1->Stop();
        PlayingLabel->Caption = "Buffer is Paused..";
        }
    }
    //---------------------------------------------------------------------------
    void __fastcall TMainForm::ExitButtonClick(TObject *Sender)
    {
    Close();
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::Dx_Sound1Create(TObject *Sender)
    {
    Dx_Sound1->SetCooperativeLevel(Application->Handle, DSSCL_PRIORITY);
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TMainForm::Dx_Sound1DSEnumerate(TObject *Sender, GUID *Guid,
        AnsiString DriverDescription, AnsiString DriverModule, void *Context,
        bool &Finished)
    {
    if (KnownDevices && KnownModules && KnownGuids)
        {
        KnownDevices->Add( DriverDescription );
        KnownModules->Add( DriverModule );
        KnownGuids->Add( (void*) Guid );
        DevicesListBox->Items->Add( DriverDescription + ", ("+DriverModule+")" );
        }
    else
        Finished = true;
    }
    //---------------------------------------------------------------------------
    
    	





  • Let's do the same thing, with much less fancy stuff thrown in, using Microsoft Visual C++...


  • Let's write two applications to animate a bitmap full-screen, and play a sound effect our the speakers...

    Here's the complete code to animate a bitmap full-screen :-
    
    //-----------------------------------------------------------------------------
    // File: DDEx3.CPP
    //
    // Desc: Direct Draw example program 3.  Adds functionality to 
    //       example program 2.  Creates two offscreen surfaces in 
    //       addition to the primary surface and back buffer.  Loads
    //       a bitmap file into each offscreen surface.  Uses BltFast
    //       to copy the contents of an offscreen surface to the back
    //       buffer and then flips the buffers and copies the next 
    //       offscreen surface to the back buffer.  Press F12 to exit
    //       the program.  This program requires at least 1.2 Megs of 
    //       video ram.
    //
    // Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
    //-----------------------------------------------------------------------------
    
    #ifndef WIN32_LEAN_AND_MEAN
    #define WIN32_LEAN_AND_MEAN
    #endif
    //-----------------------------------------------------------------------------
    // Include files
    //-----------------------------------------------------------------------------
    #include 
    #include 
    #include 
    #include 
    #include "resource.h"
    #include "ddutil.h"
    
    //-----------------------------------------------------------------------------
    // Local definitions
    //-----------------------------------------------------------------------------
    #define NAME                "DDExample3"
    #define TITLE               "Direct Draw Example 3"
    
    //-----------------------------------------------------------------------------
    // Default settings
    //-----------------------------------------------------------------------------
    #define TIMER_ID            1
    #define TIMER_RATE          500
    
    //-----------------------------------------------------------------------------
    // Global data
    //-----------------------------------------------------------------------------
    LPDIRECTDRAW7               g_pDD = NULL;        // DirectDraw object
    LPDIRECTDRAWSURFACE7        g_pDDSPrimary = NULL;// DirectDraw primary surface
    LPDIRECTDRAWSURFACE7        g_pDDSBack = NULL;   // DirectDraw back surface
    LPDIRECTDRAWSURFACE7        g_pDDSOne = NULL;    // Offscreen surface 1
    LPDIRECTDRAWSURFACE7        g_pDDSTwo = NULL;    // Offscreen surface 2
    LPDIRECTDRAWPALETTE         g_pDDPal = NULL;     // The primary surface palette
    BOOL                        g_bActive = FALSE;   // Is application active?
    
    //-----------------------------------------------------------------------------
    // Local data
    //-----------------------------------------------------------------------------
    // Name of our bitmap resource.
    static char                 szBitmap[] = "DDEX3";
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: ReleaseAllObjects()
    // Desc: Finished with all objects we use; release them
    //-----------------------------------------------------------------------------
    static void
    ReleaseAllObjects(void)
    {
        if (g_pDD != NULL)
        {
            if (g_pDDSPrimary != NULL)
            {
                g_pDDSPrimary->Release();
                g_pDDSPrimary = NULL;
            }
            if (g_pDDSOne != NULL)
            {
                g_pDDSOne->Release();
                g_pDDSOne = NULL;
            }
            if (g_pDDSTwo != NULL)
            {
                g_pDDSTwo->Release();
                g_pDDSTwo = NULL;
            }
            if (g_pDDPal != NULL)
            {
                g_pDDPal->Release();
                g_pDDPal = NULL;
            }
            g_pDD->Release();
            g_pDD = NULL;
        }
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: InitFail()
    // Desc: This function is called if an initialization function fails
    //-----------------------------------------------------------------------------
    HRESULT
    InitFail(HWND hWnd, HRESULT hRet, LPCTSTR szError,...)
    {
        char                        szBuff[128];
        va_list                     vl;
    
        va_start(vl, szError);
        vsprintf(szBuff, szError, vl);
        ReleaseAllObjects();
        MessageBox(hWnd, szBuff, TITLE, MB_OK);
        DestroyWindow(hWnd);
        va_end(vl);
        return hRet;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: InitSurfaces()
    // Desc: This function reads the bitmap file FRNTBACK.BMP and stores half of it
    //       in offscreen surface 1 and the other half in offscreen surface 2.
    //-----------------------------------------------------------------------------
    BOOL 
    InitSurfaces(void)
    {
        HBITMAP                     hbm;
    
        // Load our bitmap resource.
        hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, 0,
                                  0, LR_CREATEDIBSECTION);
        if (hbm == NULL)
            return FALSE;
    
        DDCopyBitmap(g_pDDSOne, hbm, 0, 0, 640, 480);
        DDCopyBitmap(g_pDDSTwo, hbm, 0, 480, 640, 480);
        DeleteObject(hbm);
        return TRUE;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: RestoreAll()
    // Desc: Restore all lost objects
    //-----------------------------------------------------------------------------
    HRESULT 
    RestoreAll(void)
    {
        HRESULT                     hRet;
    
        hRet = g_pDDSPrimary->Restore();
        if (hRet == DD_OK)
        {
            hRet = g_pDDSOne->Restore();
            if (hRet == DD_OK)
            {
                hRet = g_pDDSTwo->Restore();
                if (hRet == DD_OK)
                {
                    InitSurfaces();
                }
            }
        }
        return hRet;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: UpdateFrame()
    // Desc: Displays the proper image for the page
    //-----------------------------------------------------------------------------
    static void
    UpdateFrame(HWND hWnd)
    {
        static BYTE                 phase = 0;
        HRESULT                     hRet;
        LPDIRECTDRAWSURFACE7        pdds;
        RECT                        rcRect;
    
        rcRect.left = 0;
        rcRect.top = 0;
        rcRect.right = 640;
        rcRect.bottom = 480;
        if (phase)
        {
            pdds = g_pDDSTwo;
            phase = 0;
        }
        else
        {
            pdds = g_pDDSOne;
            phase = 1;
        }
        while (TRUE)
        {
            hRet = g_pDDSBack->BltFast(0, 0, pdds, &rcRect, FALSE);
            if (hRet == DD_OK)
                break;
            if (hRet == DDERR_SURFACELOST)
            {
                hRet = RestoreAll();
                if (hRet != DD_OK)
                    break;
            }
            if (hRet != DDERR_WASSTILLDRAWING)
                break;
        }
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: WindowProc()
    // Desc: The Main Window Procedure
    //-----------------------------------------------------------------------------
    long FAR PASCAL
    WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        HRESULT                     hRet;
    
        switch (message)
        {
            case WM_ACTIVATE:
                // Pause if minimized
                g_bActive = !((BOOL)HIWORD(wParam));
                return 0L;
    
            case WM_DESTROY:
                // Clean up and close the app
                ReleaseAllObjects();
                PostQuitMessage(0);
                return 0L;
    
            case WM_KEYDOWN:
                // Handle any non-accelerated key commands
                switch (wParam)
                {
                    case VK_ESCAPE:
                    case VK_F12:
                        PostMessage(hWnd, WM_CLOSE, 0, 0);
                        return 0L;
                }
                break;
    
            case WM_SETCURSOR:
                // Turn off the cursor since this is a full-screen app
                SetCursor(NULL);
                return TRUE;
    
            case WM_TIMER:
                // Update and flip surfaces
                if (g_bActive && TIMER_ID == wParam)
                {
                    UpdateFrame(hWnd);
                    while (TRUE)
                    {
                        hRet = g_pDDSPrimary->Flip(NULL, 0);
                        if (hRet == DD_OK)
                            break;
                        if (hRet == DDERR_SURFACELOST)
                        {
                            hRet = RestoreAll();
                            if (hRet != DD_OK)
                                break;
                        }
                        if (hRet != DDERR_WASSTILLDRAWING)
                            break;
                    }
                }
                break;
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: InitApp()
    // Desc: Do work required for every instance of the application:
    //          Create the window, initialize data
    //-----------------------------------------------------------------------------
    static HRESULT
    InitApp(HINSTANCE hInstance, int nCmdShow)
    {
        HWND                        hWnd;
        WNDCLASS                    wc;
        DDSURFACEDESC2              ddsd;
        DDSCAPS2                    ddscaps;
        HRESULT                     hRet;
    
        // Set up and register window class
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WindowProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON));
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH )GetStockObject(BLACK_BRUSH);
        wc.lpszMenuName = NAME;
        wc.lpszClassName = NAME;
        RegisterClass(&wc);
    
        // Create a window
        hWnd = CreateWindowEx(WS_EX_TOPMOST,
                              NAME,
                              TITLE,
                              WS_POPUP,
                              0,
                              0,
                              GetSystemMetrics(SM_CXSCREEN),
                              GetSystemMetrics(SM_CYSCREEN),
                              NULL,
                              NULL,
                              hInstance,
                              NULL);
        if (!hWnd)
            return FALSE;
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
        SetFocus(hWnd);
    
        ///////////////////////////////////////////////////////////////////////////
        // Create the main DirectDraw object
        ///////////////////////////////////////////////////////////////////////////
        hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "DirectDrawCreateEx FAILED");
    
        // Get exclusive mode
        hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "SetCooperativeLevel FAILED");
    
        // Set the video mode to 640x480x8
        hRet = g_pDD->SetDisplayMode(640, 480, 8, 0, 0);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "SetDisplayMode FAILED");
    
        // Create the primary surface with 1 back buffer
        ZeroMemory(&ddsd, sizeof(ddsd));
        ddsd.dwSize = sizeof(ddsd);
        ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
        ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
                              DDSCAPS_FLIP |
                              DDSCAPS_COMPLEX;
        ddsd.dwBackBufferCount = 1;
        hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "CreateSurface FAILED");
    
        // Get a pointer to the back buffer
        ZeroMemory(&ddscaps, sizeof(ddscaps));
        ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
        hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "GetAttachedSurface FAILED");
    
        // Create a offscreen bitmap.
        ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
        ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
        ddsd.dwHeight = 480;
        ddsd.dwWidth = 640;
        hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSOne, NULL);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "CreateSurface FAILED");
    
        // Create another offscreen bitmap.
        hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSTwo, NULL);
        if (hRet != DD_OK)
            return InitFail(hWnd, hRet, "CreateSurface FAILED");
    
        // Create a Direct Draw Palette and associate it with the front buffer
        g_pDDPal = DDLoadPalette(g_pDD, szBitmap);
        if (g_pDDPal)
            g_pDDSPrimary->SetPalette(g_pDDPal);
        if (!InitSurfaces())
            return InitFail(hWnd, hRet, "InitSurfaces FAILED");
    
        // Create a timer to flip the pages
        if (TIMER_ID != SetTimer(hWnd, TIMER_ID, TIMER_RATE, NULL))
            return InitFail(hWnd, hRet, "SetTimer FAILED");
    
        return DD_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: WinMain()
    // Desc: Initialization, message loop
    //-----------------------------------------------------------------------------
    int PASCAL
    WinMain(HINSTANCE hInstance,
            HINSTANCE hPrevInstance,
            LPSTR lpCmdLine,
            int nCmdShow)
    {
        MSG                         msg;
    
        if (InitApp(hInstance, nCmdShow) != DD_OK)
            return FALSE;
    
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    }
    
    
    	


    Plus you need this code as well, to actually load the bitmap
    
    
    //-----------------------------------------------------------------------------
    // File: ddutil.cpp
    //
    // Desc: Routines for loading bitmap and palettes from resources
    //
    //
    // Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
    //-----------------------------------------------------------------------------
    
    #ifndef WIN32_LEAN_AND_MEAN
    #define WIN32_LEAN_AND_MEAN
    #endif
    
    //-----------------------------------------------------------------------------
    // Include files
    //-----------------------------------------------------------------------------
    #include 
    #include 
    #include 
    #include "ddutil.h"
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: DDLoadBitmap()
    // Desc: Create a DirectDrawSurface from a bitmap resource.
    //-----------------------------------------------------------------------------
    extern "C" IDirectDrawSurface7*
    DDLoadBitmap(IDirectDraw7 * pdd, LPCSTR szBitmap, int dx, int dy)
    {
        HBITMAP                 hbm;
        BITMAP                  bm;
        DDSURFACEDESC2          ddsd;
        IDirectDrawSurface7    *pdds;
    
        //
        //  Try to load the bitmap as a resource, if that fails, try it as a file
        //
        hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, dx,
                                  dy, LR_CREATEDIBSECTION);
        if (hbm == NULL)
            hbm = (HBITMAP) LoadImage(NULL, szBitmap, IMAGE_BITMAP, dx, dy,
                                      LR_LOADFROMFILE | LR_CREATEDIBSECTION);
        if (hbm == NULL)
            return NULL;
        //
        // Get size of the bitmap
        //
        GetObject(hbm, sizeof(bm), &bm);
        //
        // Create a DirectDrawSurface for this bitmap
        //
        ZeroMemory(&ddsd, sizeof(ddsd));
        ddsd.dwSize = sizeof(ddsd);
        ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
        ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
        ddsd.dwWidth = bm.bmWidth;
        ddsd.dwHeight = bm.bmHeight;
        if (pdd->CreateSurface(&ddsd, &pdds, NULL) != DD_OK)
            return NULL;
        DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);
        DeleteObject(hbm);
        return pdds;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: DDReLoadBitmap()
    // Desc: Load a bitmap from a file or resource into a directdraw surface.
    //       normaly used to re-load a surface after a restore.
    //-----------------------------------------------------------------------------
    HRESULT
    DDReLoadBitmap(IDirectDrawSurface7 * pdds, LPCSTR szBitmap)
    {
        HBITMAP                 hbm;
        HRESULT                 hr;
    
        //
        //  Try to load the bitmap as a resource, if that fails, try it as a file
        //
        hbm = (HBITMAP) LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP, 0,
                                  0, LR_CREATEDIBSECTION);
        if (hbm == NULL)
            hbm = (HBITMAP) LoadImage(NULL, szBitmap, IMAGE_BITMAP, 0, 0,
                                      LR_LOADFROMFILE | LR_CREATEDIBSECTION);
        if (hbm == NULL)
        {
            OutputDebugString("handle is null\n");
            return E_FAIL;
        }
        hr = DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);
        if (hr != DD_OK)
        {
            OutputDebugString("ddcopybitmap failed\n");
        }
        DeleteObject(hbm);
        return hr;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: DDCopyBitmap()
    // Desc: Draw a bitmap into a DirectDrawSurface
    //-----------------------------------------------------------------------------
    extern "C" HRESULT
    DDCopyBitmap(IDirectDrawSurface7 * pdds, HBITMAP hbm, int x, int y,
                 int dx, int dy)
    {
        HDC                     hdcImage;
        HDC                     hdc;
        BITMAP                  bm;
        DDSURFACEDESC2          ddsd;
        HRESULT                 hr;
    
        if (hbm == NULL || pdds == NULL)
            return E_FAIL;
        //
        // Make sure this surface is restored.
        //
        pdds->Restore();
        //
        // Select bitmap into a memoryDC so we can use it.
        //
        hdcImage = CreateCompatibleDC(NULL);
        if (!hdcImage)
            OutputDebugString("createcompatible dc failed\n");
        SelectObject(hdcImage, hbm);
        //
        // Get size of the bitmap
        //
        GetObject(hbm, sizeof(bm), &bm);
        dx = dx == 0 ? bm.bmWidth : dx;     // Use the passed size, unless zero
        dy = dy == 0 ? bm.bmHeight : dy;
        //
        // Get size of surface.
        //
        ddsd.dwSize = sizeof(ddsd);
        ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
        pdds->GetSurfaceDesc(&ddsd);
    
        if ((hr = pdds->GetDC(&hdc)) == DD_OK)
        {
            StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, x, y,
                       dx, dy, SRCCOPY);
            pdds->ReleaseDC(hdc);
        }
        DeleteDC(hdcImage);
        return hr;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: DDLoadPalette()
    // Desc: Create a DirectDraw palette object from a bitmap resource
    //       if the resource does not exist or NULL is passed create a
    //       default 332 palette.
    //-----------------------------------------------------------------------------
    extern "C" IDirectDrawPalette *
    DDLoadPalette(IDirectDraw7 * pdd, LPCSTR szBitmap)
    {
        IDirectDrawPalette     *ddpal;
        int                     i;
        int                     n;
        int                     fh;
        HRSRC                   h;
        LPBITMAPINFOHEADER      lpbi;
        PALETTEENTRY            ape[256];
        RGBQUAD                *prgb;
    
        //
        // Build a 332 palette as the default.
        //
        for (i = 0; i < 256; i++)
        {
            ape[i].peRed = (BYTE) (((i >> 5) & 0x07) * 255 / 7);
            ape[i].peGreen = (BYTE) (((i >> 2) & 0x07) * 255 / 7);
            ape[i].peBlue = (BYTE) (((i >> 0) & 0x03) * 255 / 3);
            ape[i].peFlags = (BYTE) 0;
        }
        //
        // Get a pointer to the bitmap resource.
        //
        if (szBitmap && (h = FindResource(NULL, szBitmap, RT_BITMAP)))
        {
            lpbi = (LPBITMAPINFOHEADER) LockResource(LoadResource(NULL, h));
            if (!lpbi)
                OutputDebugString("lock resource failed\n");
            prgb = (RGBQUAD *) ((BYTE *) lpbi + lpbi->biSize);
            if (lpbi == NULL || lpbi->biSize < sizeof(BITMAPINFOHEADER))
                n = 0;
            else if (lpbi->biBitCount > 8)
                n = 0;
            else if (lpbi->biClrUsed == 0)
                n = 1 << lpbi->biBitCount;
            else
                n = lpbi->biClrUsed;
            //
            //  A DIB color table has its colors stored BGR not RGB
            //  so flip them around.
            //
            for (i = 0; i < n; i++)
            {
                ape[i].peRed = prgb[i].rgbRed;
                ape[i].peGreen = prgb[i].rgbGreen;
                ape[i].peBlue = prgb[i].rgbBlue;
                ape[i].peFlags = 0;
            }
        }
        else if (szBitmap && (fh = _lopen(szBitmap, OF_READ)) != -1)
        {
            BITMAPFILEHEADER        bf;
            BITMAPINFOHEADER        bi;
    
            _lread(fh, &bf, sizeof(bf));
            _lread(fh, &bi, sizeof(bi));
            _lread(fh, ape, sizeof(ape));
            _lclose(fh);
            if (bi.biSize != sizeof(BITMAPINFOHEADER))
                n = 0;
            else if (bi.biBitCount > 8)
                n = 0;
            else if (bi.biClrUsed == 0)
                n = 1 << bi.biBitCount;
            else
                n = bi.biClrUsed;
            //
            //  A DIB color table has its colors stored BGR not RGB
            //  so flip them around.
            //
            for (i = 0; i < n; i++)
            {
                BYTE        r = ape[i].peRed;
    
                ape[i].peRed = ape[i].peBlue;
                ape[i].peBlue = r;
            }
        }
        pdd->CreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL);
        return ddpal;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: DDColorMatch()
    // Desc: Convert a RGB color to a pysical color.
    //       We do this by leting GDI SetPixel() do the color matching
    //       then we lock the memory and see what it got mapped to.
    //-----------------------------------------------------------------------------
    extern "C" DWORD
    DDColorMatch(IDirectDrawSurface7 * pdds, COLORREF rgb)
    {
        COLORREF                rgbT;
        HDC                     hdc;
        DWORD                   dw = CLR_INVALID;
        DDSURFACEDESC2          ddsd;
        HRESULT                 hres;
    
        //
        //  Use GDI SetPixel to color match for us
        //
        if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
        {
            rgbT = GetPixel(hdc, 0, 0);     // Save current pixel value
            SetPixel(hdc, 0, 0, rgb);       // Set our value
            pdds->ReleaseDC(hdc);
        }
        //
        // Now lock the surface so we can read back the converted color
        //
        ddsd.dwSize = sizeof(ddsd);
        while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING)
            ;
        if (hres == DD_OK)
        {
            dw = *(DWORD *) ddsd.lpSurface;                 // Get DWORD
            if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32)
                dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1;  // Mask it to bpp
            pdds->Unlock(NULL);
        }
        //
        //  Now put the color that was there back.
        //
        if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
        {
            SetPixel(hdc, 0, 0, rgbT);
            pdds->ReleaseDC(hdc);
        }
        return dw;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: DDSetColorKey()
    // Desc: Set a color key for a surface, given a RGB.
    //       If you pass CLR_INVALID as the color key, the pixel
    //       in the upper-left corner will be used.
    //-----------------------------------------------------------------------------
    extern "C" HRESULT
    DDSetColorKey(IDirectDrawSurface7 * pdds, COLORREF rgb)
    {
        DDCOLORKEY              ddck;
    
        ddck.dwColorSpaceLowValue = DDColorMatch(pdds, rgb);
        ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
        return pdds->SetColorKey(DDCKEY_SRCBLT, &ddck);
    }
    
    
    
    	


    ...

    And here's the code to play a sound effect...
    
    //-----------------------------------------------------------------------------
    // File: PlaySound.cpp
    //
    // Desc: DirectSound support for how to load a wave file and play it using a 
    //       static DirectSound buffer.
    //
    // Copyright (c) 1999 Microsoft Corp. All rights reserved.
    //-----------------------------------------------------------------------------
    #define STRICT
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "resource.h"
    #include "WavRead.h"
    
    
    
    
    //-----------------------------------------------------------------------------
    // Function-prototypes
    //-----------------------------------------------------------------------------
    extern VOID OnEnablePlayUI( HWND hDlg, BOOL bEnable );
    extern VOID SetFileUI( HWND hDlg, TCHAR* strFileName );
    
    VOID LoadWaveFile( TCHAR* strFileName );
    HRESULT CreateStaticBuffer( HWND hDlg, TCHAR* strFileName );
    HRESULT FillBuffer();
    HRESULT RestoreBuffers();
    
    
    
    
    //-----------------------------------------------------------------------------
    // Defines, constants, and global variables
    //-----------------------------------------------------------------------------
    #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
    #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
    
    LPDIRECTSOUND       g_pDS            = NULL;
    LPDIRECTSOUNDBUFFER g_pDSBuffer      = NULL;
    LPDIRECTSOUNDNOTIFY g_pDSNotify      = NULL;
    CWaveSoundRead*     g_pWaveSoundRead = NULL;
    DWORD               g_dwBufferBytes;
    
    
    
    //-----------------------------------------------------------------------------
    // Name: InitDirectSound()
    // Desc: Initilizes DirectSound
    //-----------------------------------------------------------------------------
    HRESULT InitDirectSound( HWND hDlg )
    {
        HRESULT             hr;
        LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;
    
        // Initialize COM
        if( hr = CoInitialize( NULL ) )
            return hr;
    
        // Create IDirectSound using the primary sound device
        if( FAILED( hr = DirectSoundCreate( NULL, &g_pDS, NULL ) ) )
            return hr;
    
        // Set coop level to DSSCL_PRIORITY
        if( FAILED( hr = g_pDS->SetCooperativeLevel( hDlg, DSSCL_PRIORITY ) ) )
            return hr;
    
        // Get the primary buffer 
        DSBUFFERDESC dsbd;
        ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
        dsbd.dwSize        = sizeof(DSBUFFERDESC);
        dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER;
        dsbd.dwBufferBytes = 0;
        dsbd.lpwfxFormat   = NULL;
           
        if( FAILED( hr = g_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
            return hr;
    
        // Set primary buffer format to 22kHz and 16-bit output.
        WAVEFORMATEX wfx;
        ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); 
        wfx.wFormatTag      = WAVE_FORMAT_PCM; 
        wfx.nChannels       = 2; 
        wfx.nSamplesPerSec  = 22050; 
        wfx.wBitsPerSample  = 16; 
        wfx.nBlockAlign     = wfx.wBitsPerSample / 8 * wfx.nChannels;
        wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
    
        if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
            return hr;
    
        SAFE_RELEASE( pDSBPrimary );
    
        return S_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: FreeDirectSound()
    // Desc: Releases DirectSound 
    //-----------------------------------------------------------------------------
    HRESULT FreeDirectSound()
    {
        SAFE_DELETE( g_pWaveSoundRead );
    
        // Release DirectSound interfaces
        SAFE_RELEASE( g_pDSBuffer );
        SAFE_RELEASE( g_pDS ); 
    
        // Release COM
        CoUninitialize();
    
        return S_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: LoadWaveFile()
    // Desc: Loads the wave file into a secondary static DirectSound buffer
    //-----------------------------------------------------------------------------
    VOID LoadWaveFile( HWND hDlg, TCHAR* strFileName )
    {
        // Create the sound buffer object from the wave file data
        if( FAILED( CreateStaticBuffer( hDlg, strFileName ) ) )
        {        
            SetFileUI( hDlg, TEXT("Couldn't create sound buffer.") ); 
        }
        else // The sound buffer was successfully created
        {
            // Fill the buffer with wav data
            FillBuffer();
    
            // Update the UI controls to show the sound as the file is loaded
            SetFileUI( hDlg, strFileName );
            OnEnablePlayUI( hDlg, TRUE );
        }
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: CreateStaticBuffer()
    // Desc: Creates a wave file, sound buffer and notification events 
    //-----------------------------------------------------------------------------
    HRESULT CreateStaticBuffer( HWND hDlg, TCHAR* strFileName )
    {
        HRESULT hr; 
    
        // Free any previous globals 
        SAFE_DELETE( g_pWaveSoundRead );
        SAFE_RELEASE( g_pDSBuffer );
    
        // Create a new wave file class
        g_pWaveSoundRead = new CWaveSoundRead();
    
        // Load the wave file
        if( FAILED( g_pWaveSoundRead->Open( strFileName ) ) )
        {
            SetFileUI( hDlg, TEXT("Bad wave file.") );
        }
    
        // Set up the direct sound buffer, and only request the flags needed
        // since each requires some overhead and limits if the buffer can 
        // be hardware accelerated
        DSBUFFERDESC dsbd;
        ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
        dsbd.dwSize        = sizeof(DSBUFFERDESC);
        dsbd.dwFlags       = DSBCAPS_STATIC;
        dsbd.dwBufferBytes = g_pWaveSoundRead->m_ckIn.cksize;
        dsbd.lpwfxFormat   = g_pWaveSoundRead->m_pwfx;
    
        // Create the static DirectSound buffer 
        if( FAILED( hr = g_pDS->CreateSoundBuffer( &dsbd, &g_pDSBuffer, NULL ) ) )
            return hr;
    
        // Remember how big the buffer is
        g_dwBufferBytes = dsbd.dwBufferBytes;
    
        return S_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: FillBuffer()
    // Desc: Fill the DirectSound buffer with data from the wav file
    //-----------------------------------------------------------------------------
    HRESULT FillBuffer()
    {
        HRESULT hr; 
        BYTE*   pbWavData; // Pointer to actual wav data 
        UINT    cbWavSize; // Size of data
        VOID*   pbData  = NULL;
        VOID*   pbData2 = NULL;
        DWORD   dwLength;
        DWORD   dwLength2;
    
        // The size of wave data is in pWaveFileSound->m_ckIn
        INT nWaveFileSize = g_pWaveSoundRead->m_ckIn.cksize;
    
        // Allocate that buffer.
        pbWavData = new BYTE[ nWaveFileSize ];
        if( NULL == pbWavData )
            return E_OUTOFMEMORY;
    
        if( FAILED( hr = g_pWaveSoundRead->Read( nWaveFileSize, 
                                               pbWavData, 
                                               &cbWavSize ) ) )           
            return hr;
    
        // Reset the file to the beginning 
        g_pWaveSoundRead->Reset();
    
        // Lock the buffer down
        if( FAILED( hr = g_pDSBuffer->Lock( 0, g_dwBufferBytes, &pbData, &dwLength, 
                                       &pbData2, &dwLength2, 0L ) ) )
            return hr;
    
        // Copy the memory to it.
        memcpy( pbData, pbWavData, g_dwBufferBytes );
    
        // Unlock the buffer, we don't need it anymore.
        g_pDSBuffer->Unlock( pbData, g_dwBufferBytes, NULL, 0 );
        pbData = NULL;
    
        // We dont need the wav file data buffer anymore, so delete it 
        SAFE_DELETE( pbWavData );
    
        return S_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: PlayBuffer()
    // Desc: User hit the "Play" button, so play the DirectSound buffer
    //-----------------------------------------------------------------------------
    BOOL IsBufferPlaying() 
    {
        DWORD dwStatus = 0;
    
        if( NULL == g_pDSBuffer )
            return E_FAIL;
    
        g_pDSBuffer->GetStatus( &dwStatus );
    
        if( dwStatus & DSBSTATUS_PLAYING )
            return TRUE;
        else 
            return FALSE;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: PlayBuffer()
    // Desc: User hit the "Play" button, so play the DirectSound buffer
    //-----------------------------------------------------------------------------
    HRESULT PlayBuffer( BOOL bLooped )
    {
        HRESULT hr;
    
        if( NULL == g_pDSBuffer )
            return E_FAIL;
    
        // Restore the buffers if they are lost
        if( FAILED( hr = RestoreBuffers() ) )
            return hr;
    
        // Play buffer 
        DWORD dwLooped = bLooped ? DSBPLAY_LOOPING : 0L;
        if( FAILED( hr = g_pDSBuffer->Play( 0, 0, dwLooped ) ) )
            return hr;
    
        return S_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: StopBuffer()
    // Desc: Stop the DirectSound buffer from playing 
    //-----------------------------------------------------------------------------
    VOID StopBuffer( BOOL bResetPosition ) 
    {
        if( NULL == g_pDSBuffer )
            return;
    
        g_pDSBuffer->Stop();
    
        if( bResetPosition )
            g_pDSBuffer->SetCurrentPosition( 0L );    
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: IsSoundPlaying()
    // Desc: Checks to see if a sound is playing and returns TRUE if it is.
    //-----------------------------------------------------------------------------
    BOOL IsSoundPlaying()
    {
        if( g_pDSBuffer )
        {  
            DWORD dwStatus = 0;
            g_pDSBuffer->GetStatus( &dwStatus );
            return( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
        }
        else
        {
            return FALSE;
        }
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: RestoreBuffers()
    // Desc: Restore lost buffers and fill them up with sound if possible
    //-----------------------------------------------------------------------------
    HRESULT RestoreBuffers()
    {
        HRESULT hr;
    
        if( NULL == g_pDSBuffer )
            return S_OK;
    
        DWORD dwStatus;
        if( FAILED( hr = g_pDSBuffer->GetStatus( &dwStatus ) ) )
            return hr;
    
        if( dwStatus & DSBSTATUS_BUFFERLOST )
        {
            // Since the app could have just been activated, then
            // DirectSound may not be giving us control yet, so 
            // the restoring the buffer may fail.  
            // If it does, sleep until DirectSound gives us control.
            do 
            {
                hr = g_pDSBuffer->Restore();
                if( hr == DSERR_BUFFERLOST )
                    Sleep( 10 );
            }
            while( hr = g_pDSBuffer->Restore() );
    
            if( FAILED( hr = FillBuffer() ) )
                return hr;
        }
    
        return S_OK;
    }
    
    	


    Plus you need this code as well, to load the sound data from a .wav file
    
    //-----------------------------------------------------------------------------
    // File: WavRead.cpp
    //
    // Desc: Wave file support for loading and playing Wave files using DirectSound 
    //       buffers.
    //
    // Copyright (c) 1999 Microsoft Corp. All rights reserved.
    //-----------------------------------------------------------------------------
    #include 
    #include "WavRead.h"
    
    
    
    
    //-----------------------------------------------------------------------------
    // Defines, constants, and global variables
    //-----------------------------------------------------------------------------
    #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
    #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: ReadMMIO()
    // Desc: Support function for reading from a multimedia I/O stream
    //-----------------------------------------------------------------------------
    HRESULT ReadMMIO( HMMIO hmmioIn, MMCKINFO* pckInRIFF, WAVEFORMATEX** ppwfxInfo )
    {
        MMCKINFO        ckIn;           // chunk info. for general use.
        PCMWAVEFORMAT   pcmWaveFormat;  // Temp PCM structure to load in.       
    
        *ppwfxInfo = NULL;
    
        if( ( 0 != mmioDescend( hmmioIn, pckInRIFF, NULL, 0 ) ) )
            return E_FAIL;
    
        if( (pckInRIFF->ckid != FOURCC_RIFF) ||
            (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
            return E_FAIL;
    
        // Search the input file for for the 'fmt ' chunk.
        ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
        if( 0 != mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK) )
            return E_FAIL;
    
        // Expect the 'fmt' chunk to be at least as large as ;
        // if there are extra parameters at the end, we'll ignore them
           if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
               return E_FAIL;
    
        // Read the 'fmt ' chunk into .
        if( mmioRead( hmmioIn, (HPSTR) &pcmWaveFormat, 
                      sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
            return E_FAIL;
    
        // Allocate the waveformatex, but if its not pcm format, read the next
        // word, and thats how many extra bytes to allocate.
        if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
        {
            if( NULL == ( *ppwfxInfo = new WAVEFORMATEX ) )
                return E_FAIL;
    
            // Copy the bytes from the pcm structure to the waveformatex structure
            memcpy( *ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat) );
            (*ppwfxInfo)->cbSize = 0;
        }
        else
        {
            // Read in length of extra bytes.
            WORD cbExtraBytes = 0L;
            if( mmioRead( hmmioIn, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
                return E_FAIL;
    
            *ppwfxInfo = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
            if( NULL == *ppwfxInfo )
                return E_FAIL;
    
            // Copy the bytes from the pcm structure to the waveformatex structure
            memcpy( *ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat) );
            (*ppwfxInfo)->cbSize = cbExtraBytes;
    
            // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
            if( mmioRead( hmmioIn, (CHAR*)(((BYTE*)&((*ppwfxInfo)->cbSize))+sizeof(WORD)),
                          cbExtraBytes ) != cbExtraBytes )
            {
                delete *ppwfxInfo;
                *ppwfxInfo = NULL;
                return E_FAIL;
            }
        }
    
        // Ascend the input file out of the 'fmt ' chunk.
        if( 0 != mmioAscend( hmmioIn, &ckIn, 0 ) )
        {
            delete *ppwfxInfo;
            *ppwfxInfo = NULL;
            return E_FAIL;
        }
    
        return S_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: WaveOpenFile()
    // Desc: This function will open a wave input file and prepare it for reading,
    //       so the data can be easily read with WaveReadFile. Returns 0 if
    //       successful, the error code if not.
    //-----------------------------------------------------------------------------
    HRESULT WaveOpenFile( CHAR* strFileName, HMMIO* phmmioIn, WAVEFORMATEX** ppwfxInfo,
                      MMCKINFO* pckInRIFF )
    {
        HRESULT hr;
        HMMIO   hmmioIn = NULL;
        
        if( NULL == ( hmmioIn = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF|MMIO_READ ) ) )
            return E_FAIL;
    
        if( FAILED( hr = ReadMMIO( hmmioIn, pckInRIFF, ppwfxInfo ) ) )
        {
            mmioClose( hmmioIn, 0 );
            return hr;
        }
    
        *phmmioIn = hmmioIn;
    
        return S_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: WaveStartDataRead()
    // Desc: Routine has to be called before WaveReadFile as it searches for the
    //       chunk to descend into for reading, that is, the 'data' chunk.  For
    //       simplicity, this used to be in the open routine, but was taken out and
    //       moved to a separate routine so there was more control on the chunks
    //       that are before the data chunk, such as 'fact', etc...
    //-----------------------------------------------------------------------------
    HRESULT WaveStartDataRead( HMMIO* phmmioIn, MMCKINFO* pckIn,
                               MMCKINFO* pckInRIFF )
    {
        // Seek to the data
        if( -1 == mmioSeek( *phmmioIn, pckInRIFF->dwDataOffset + sizeof(FOURCC),
                            SEEK_SET ) )
            return E_FAIL;
    
        // Search the input file for for the 'data' chunk.
        pckIn->ckid = mmioFOURCC('d', 'a', 't', 'a');
        if( 0 != mmioDescend( *phmmioIn, pckIn, pckInRIFF, MMIO_FINDCHUNK ) )
            return E_FAIL;
    
        return S_OK;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: WaveReadFile()
    // Desc: Reads wave data from the wave file. Make sure we're descended into
    //       the data chunk before calling this function.
    //          hmmioIn      - Handle to mmio.
    //          cbRead       - # of bytes to read.   
    //          pbDest       - Destination buffer to put bytes.
    //          cbActualRead - # of bytes actually read.
    //-----------------------------------------------------------------------------
    HRESULT WaveReadFile( HMMIO hmmioIn, UINT cbRead, BYTE* pbDest,
                          MMCKINFO* pckIn, UINT* cbActualRead )
    {
        MMIOINFO mmioinfoIn;         // current status of 
    
        *cbActualRead = 0;
    
        if( 0 != mmioGetInfo( hmmioIn, &mmioinfoIn, 0 ) )
            return E_FAIL;
                    
        UINT cbDataIn = cbRead;
        if( cbDataIn > pckIn->cksize ) 
            cbDataIn = pckIn->cksize;       
    
        pckIn->cksize -= cbDataIn;
        
        for( DWORD cT = 0; cT < cbDataIn; cT++ )
        {
            // Copy the bytes from the io to the buffer.
            if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
            {
                if( 0 != mmioAdvance( hmmioIn, &mmioinfoIn, MMIO_READ ) )
                    return E_FAIL;
    
                if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
                    return E_FAIL;
            }
    
            // Actual copy.
            *((BYTE*)pbDest+cT) = *((BYTE*)mmioinfoIn.pchNext);
            mmioinfoIn.pchNext++;
        }
    
        if( 0 != mmioSetInfo( hmmioIn, &mmioinfoIn, 0 ) )
            return E_FAIL;
    
        *cbActualRead = cbDataIn;
        return S_OK;
    }
    
    
    
      
    //-----------------------------------------------------------------------------
    // Name: CWaveSoundRead()
    // Desc: Constructs the class
    //-----------------------------------------------------------------------------
    CWaveSoundRead::CWaveSoundRead()
    {
        m_pwfx   = NULL;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: ~CWaveSoundRead()
    // Desc: Destructs the class
    //-----------------------------------------------------------------------------
    CWaveSoundRead::~CWaveSoundRead()
    {
        Close();
        SAFE_DELETE( m_pwfx );
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: Open()
    // Desc: Opens a wave file for reading
    //-----------------------------------------------------------------------------
    HRESULT CWaveSoundRead::Open( CHAR* strFilename )
    {
        SAFE_DELETE( m_pwfx );
    
        HRESULT  hr;
        
        if( FAILED( hr = WaveOpenFile( strFilename, &m_hmmioIn, &m_pwfx, &m_ckInRiff ) ) )
            return hr;
    
        if( FAILED( hr = Reset() ) )
            return hr;
    
        return hr;
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: Reset()
    // Desc: Resets the internal m_ckIn pointer so reading starts from the 
    //       beginning of the file again 
    //-----------------------------------------------------------------------------
    HRESULT CWaveSoundRead::Reset()
    {
        return WaveStartDataRead( &m_hmmioIn, &m_ckIn, &m_ckInRiff );
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: Read()
    // Desc: Reads a wave file into a pointer and returns how much read
    //       using m_ckIn to determine where to start reading from
    //-----------------------------------------------------------------------------
    HRESULT CWaveSoundRead::Read( UINT nSizeToRead, BYTE* pbData, UINT* pnSizeRead )
    {
        return WaveReadFile( m_hmmioIn, nSizeToRead, pbData, &m_ckIn, pnSizeRead );
    }
    
    
    
    
    //-----------------------------------------------------------------------------
    // Name: Close()
    // Desc: Closes an open wave file 
    //-----------------------------------------------------------------------------
    HRESULT CWaveSoundRead::Close()
    {
        mmioClose( m_hmmioIn, 0 );
        return S_OK;
    }
    
    
    
    
    	






  • Want More Information? Click Below...


  • Technology Comment...




















Top

Welcome |  Latest News |  Tools |  Demos |  Tutorials |  Reference |  Register |  Downloads
FAQ |  Links |  Site Information

This page is Copyright © 2000-2021++ Darren John Dwyer, Australia. All Rights Reserved.
Borland C++ Builder, CBuilder, etc are Trademarks of Borland Corporation.
DirectX, DirectDraw, Windows, etc are Trademarks of Microsoft Corporation.