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

// File: VideoCtl.cpp

//

// Desc: DirectShow base classes.

//

// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.

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





#include "streams.h"

#include "ddmm.h"



// Load a string from the resource file string table. The buffer must be at

// least STR_MAX_LENGTH bytes. The easiest way to use this is to declare a

// buffer in the property page class and use it for all string loading. It

// cannot be static as multiple property pages may be active simultaneously



TCHAR *WINAPI StringFromResource(TCHAR *pBuffer, int iResourceID) {

    if(LoadString(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) {

        return TEXT("");

    }

    return pBuffer;

}



#ifdef UNICODE

char *WINAPI StringFromResource(char *pBuffer, int iResourceID) {

    if(LoadStringA(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) {

        return "";

    }

    return pBuffer;

}

#endif







// Property pages typically are called through their OLE interfaces. These

// use UNICODE strings regardless of how the binary is built. So when we

// load strings from the resource file we sometimes want to convert them

// to UNICODE. This method is passed the target UNICODE buffer and does a

// convert after loading the string (if built UNICODE this is not needed)

// On WinNT we can explicitly call LoadStringW which saves two conversions



#ifndef UNICODE



WCHAR * WINAPI WideStringFromResource(WCHAR *pBuffer, int iResourceID) {

    *pBuffer = 0;



    if(g_amPlatform == VER_PLATFORM_WIN32_NT) {

        LoadStringW(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH);

    }

    else {



        CHAR szBuffer[STR_MAX_LENGTH];

        DWORD dwStringLength = LoadString(g_hInst,iResourceID,szBuffer,STR_MAX_LENGTH);

        // if we loaded a string convert it to wide characters, ensuring

        // that we also null terminate the result.

        if(dwStringLength++) {

            MultiByteToWideChar(CP_ACP,0,szBuffer,dwStringLength,pBuffer,STR_MAX_LENGTH);

        }

    }

    return pBuffer;

}



#endif





// Helper function to calculate the size of the dialog



BOOL WINAPI GetDialogSize(int iResourceID,

                          DLGPROC pDlgProc,

                          LPARAM lParam,

                          SIZE *pResult) {

    RECT rc;

    HWND hwnd;



    // Create a temporary property page



    hwnd = CreateDialogParam(g_hInst,

        MAKEINTRESOURCE(iResourceID),

        GetDesktopWindow(),

        pDlgProc,

        lParam);

    if(hwnd == NULL) {

        return FALSE;

    }



    GetWindowRect(hwnd, &rc);

    pResult->cx = rc.right - rc.left;

    pResult->cy = rc.bottom - rc.top;



    DestroyWindow(hwnd);

    return TRUE;

}





// Class that aggregates on the IDirectDraw interface. Although DirectDraw

// has the ability in its interfaces to be aggregated they're not currently

// implemented. This makes it difficult for various parts of Quartz that want

// to aggregate these interfaces. In particular the video renderer passes out

// media samples that expose IDirectDraw and IDirectDrawSurface. The filter

// graph manager also exposes IDirectDraw as a plug in distributor. For these

// objects we provide these aggregation classes that republish the interfaces



STDMETHODIMP CAggDirectDraw::NonDelegatingQueryInterface(REFIID riid, void **ppv) {

    ASSERT(m_pDirectDraw);



    // Do we have this interface



    if(riid == IID_IDirectDraw) {

        return GetInterface((IDirectDraw *)this,ppv);

    }

    else {

        return CUnknown::NonDelegatingQueryInterface(riid,ppv);

    }

}





STDMETHODIMP CAggDirectDraw::Compact() {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->Compact();

}





STDMETHODIMP CAggDirectDraw::CreateClipper(DWORD dwFlags,LPDIRECTDRAWCLIPPER *lplpDDClipper,IUnknown *pUnkOuter) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->CreateClipper(dwFlags,lplpDDClipper,pUnkOuter);

}





STDMETHODIMP CAggDirectDraw::CreatePalette(DWORD dwFlags,LPPALETTEENTRY lpColorTable,LPDIRECTDRAWPALETTE *lplpDDPalette,IUnknown *pUnkOuter) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->CreatePalette(dwFlags,lpColorTable,lplpDDPalette,pUnkOuter);

}





STDMETHODIMP CAggDirectDraw::CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc,LPDIRECTDRAWSURFACE *lplpDDSurface,IUnknown *pUnkOuter) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->CreateSurface(lpDDSurfaceDesc,lplpDDSurface,pUnkOuter);

}





STDMETHODIMP CAggDirectDraw::DuplicateSurface(LPDIRECTDRAWSURFACE lpDDSurface,LPDIRECTDRAWSURFACE *lplpDupDDSurface) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->DuplicateSurface(lpDDSurface,lplpDupDDSurface);

}





STDMETHODIMP CAggDirectDraw::EnumDisplayModes(DWORD dwSurfaceDescCount,LPDDSURFACEDESC lplpDDSurfaceDescList,LPVOID lpContext,LPDDENUMMODESCALLBACK lpEnumCallback) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->EnumDisplayModes(dwSurfaceDescCount,lplpDDSurfaceDescList,lpContext,lpEnumCallback);

}





STDMETHODIMP CAggDirectDraw::EnumSurfaces(DWORD dwFlags,LPDDSURFACEDESC lpDDSD,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumCallback) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->EnumSurfaces(dwFlags,lpDDSD,lpContext,lpEnumCallback);

}





STDMETHODIMP CAggDirectDraw::FlipToGDISurface() {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->FlipToGDISurface();

}





STDMETHODIMP CAggDirectDraw::GetCaps(LPDDCAPS lpDDDriverCaps,LPDDCAPS lpDDHELCaps) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->GetCaps(lpDDDriverCaps,lpDDHELCaps);

}





STDMETHODIMP CAggDirectDraw::GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->GetDisplayMode(lpDDSurfaceDesc);

}





STDMETHODIMP CAggDirectDraw::GetFourCCCodes(LPDWORD lpNumCodes,LPDWORD lpCodes) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->GetFourCCCodes(lpNumCodes,lpCodes);

}





STDMETHODIMP CAggDirectDraw::GetGDISurface(LPDIRECTDRAWSURFACE *lplpGDIDDSurface) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->GetGDISurface(lplpGDIDDSurface);

}





STDMETHODIMP CAggDirectDraw::GetMonitorFrequency(LPDWORD lpdwFrequency) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->GetMonitorFrequency(lpdwFrequency);

}





STDMETHODIMP CAggDirectDraw::GetScanLine(LPDWORD lpdwScanLine) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->GetScanLine(lpdwScanLine);

}





STDMETHODIMP CAggDirectDraw::GetVerticalBlankStatus(LPBOOL lpblsInVB) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->GetVerticalBlankStatus(lpblsInVB);

}





STDMETHODIMP CAggDirectDraw::Initialize(GUID *lpGUID) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->Initialize(lpGUID);

}





STDMETHODIMP CAggDirectDraw::RestoreDisplayMode() {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->RestoreDisplayMode();

}





STDMETHODIMP CAggDirectDraw::SetCooperativeLevel(HWND hWnd,DWORD dwFlags) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->SetCooperativeLevel(hWnd,dwFlags);

}





STDMETHODIMP CAggDirectDraw::SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->SetDisplayMode(dwWidth,dwHeight,dwBpp);

}





STDMETHODIMP CAggDirectDraw::WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent) {

    ASSERT(m_pDirectDraw);

    return m_pDirectDraw->WaitForVerticalBlank(dwFlags,hEvent);

}





// Class that aggregates an IDirectDrawSurface interface. Although DirectDraw

// has the ability in its interfaces to be aggregated they're not currently

// implemented. This makes it difficult for various parts of Quartz that want

// to aggregate these interfaces. In particular the video renderer passes out

// media samples that expose IDirectDraw and IDirectDrawSurface. The filter

// graph manager also exposes IDirectDraw as a plug in distributor. For these

// objects we provide these aggregation classes that republish the interfaces



STDMETHODIMP CAggDrawSurface::NonDelegatingQueryInterface(REFIID riid, void **ppv) {

    ASSERT(m_pDirectDrawSurface);



    // Do we have this interface



    if(riid == IID_IDirectDrawSurface) {

        return GetInterface((IDirectDrawSurface *)this,ppv);

    }

    else {

        return CUnknown::NonDelegatingQueryInterface(riid,ppv);

    }

}





STDMETHODIMP CAggDrawSurface::AddAttachedSurface(LPDIRECTDRAWSURFACE lpDDSAttachedSurface) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->AddAttachedSurface(lpDDSAttachedSurface);

}





STDMETHODIMP CAggDrawSurface::AddOverlayDirtyRect(LPRECT lpRect) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->AddOverlayDirtyRect(lpRect);

}





STDMETHODIMP CAggDrawSurface::Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx);

}





STDMETHODIMP CAggDrawSurface::BltBatch(LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->BltBatch(lpDDBltBatch,dwCount,dwFlags);

}





STDMETHODIMP CAggDrawSurface::BltFast(DWORD dwX,DWORD dwY,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwTrans) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->BltFast(dwX,dwY,lpDDSrcSurface,lpSrcRect,dwTrans);

}





STDMETHODIMP CAggDrawSurface::DeleteAttachedSurface(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSAttachedSurface) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->DeleteAttachedSurface(dwFlags,lpDDSAttachedSurface);

}





STDMETHODIMP CAggDrawSurface::EnumAttachedSurfaces(LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->EnumAttachedSurfaces(lpContext,lpEnumSurfacesCallback);

}





STDMETHODIMP CAggDrawSurface::EnumOverlayZOrders(DWORD dwFlags,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpfnCallback) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->EnumOverlayZOrders(dwFlags,lpContext,lpfnCallback);

}





STDMETHODIMP CAggDrawSurface::Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->Flip(lpDDSurfaceTargetOverride,dwFlags);

}





STDMETHODIMP CAggDrawSurface::GetAttachedSurface(LPDDSCAPS lpDDSCaps,LPDIRECTDRAWSURFACE *lplpDDAttachedSurface) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetAttachedSurface(lpDDSCaps,lplpDDAttachedSurface);

}





STDMETHODIMP CAggDrawSurface::GetBltStatus(DWORD dwFlags) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetBltStatus(dwFlags);

}





STDMETHODIMP CAggDrawSurface::GetCaps(LPDDSCAPS lpDDSCaps) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetCaps(lpDDSCaps);

}





STDMETHODIMP CAggDrawSurface::GetClipper(LPDIRECTDRAWCLIPPER *lplpDDClipper) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetClipper(lplpDDClipper);

}





STDMETHODIMP CAggDrawSurface::GetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetColorKey(dwFlags,lpDDColorKey);

}





STDMETHODIMP CAggDrawSurface::GetDC(HDC *lphDC) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetDC(lphDC);

}





STDMETHODIMP CAggDrawSurface::GetFlipStatus(DWORD dwFlags) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetFlipStatus(dwFlags);

}





STDMETHODIMP CAggDrawSurface::GetOverlayPosition(LPLONG lpdwX,LPLONG lpdwY) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetOverlayPosition(lpdwX,lpdwY);

}





STDMETHODIMP CAggDrawSurface::GetPalette(LPDIRECTDRAWPALETTE *lplpDDPalette) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetPalette(lplpDDPalette);

}





STDMETHODIMP CAggDrawSurface::GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->GetPixelFormat(lpDDPixelFormat);

}





// A bit of a warning here: Our media samples in DirectShow aggregate on

// IDirectDraw and IDirectDrawSurface (ie are available through IMediaSample

// by QueryInterface). Unfortunately the underlying DirectDraw code cannot

// be aggregated so we have to use these classes. The snag is that when we

// call a different surface and pass in this interface as perhaps the source

// surface the call will fail because DirectDraw dereferences the pointer to

// get at its private data structures. Therefore we supply this workaround to give

// access to the real IDirectDraw surface. A filter can call GetSurfaceDesc

// and we will fill in the lpSurface pointer with the real underlying surface



STDMETHODIMP CAggDrawSurface::GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc) {

    ASSERT(m_pDirectDrawSurface);



    // First call down to the underlying DirectDraw



    HRESULT hr = m_pDirectDrawSurface->GetSurfaceDesc(lpDDSurfaceDesc);

    if(FAILED(hr)) {

        return hr;

    }



    // Store the real DirectDrawSurface interface

    lpDDSurfaceDesc->lpSurface = m_pDirectDrawSurface;

    return hr;

}





STDMETHODIMP CAggDrawSurface::Initialize(LPDIRECTDRAW lpDD,LPDDSURFACEDESC lpDDSurfaceDesc) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->Initialize(lpDD,lpDDSurfaceDesc);

}





STDMETHODIMP CAggDrawSurface::IsLost() {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->IsLost();

}





STDMETHODIMP CAggDrawSurface::Lock(LPRECT lpDestRect,LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->Lock(lpDestRect,lpDDSurfaceDesc,dwFlags,hEvent);

}





STDMETHODIMP CAggDrawSurface::ReleaseDC(HDC hDC) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->ReleaseDC(hDC);

}





STDMETHODIMP CAggDrawSurface::Restore() {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->Restore();

}





STDMETHODIMP CAggDrawSurface::SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->SetClipper(lpDDClipper);

}





STDMETHODIMP CAggDrawSurface::SetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->SetColorKey(dwFlags,lpDDColorKey);

}





STDMETHODIMP CAggDrawSurface::SetOverlayPosition(LONG dwX,LONG dwY) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->SetOverlayPosition(dwX,dwY);

}





STDMETHODIMP CAggDrawSurface::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->SetPalette(lpDDPalette);

}





STDMETHODIMP CAggDrawSurface::Unlock(LPVOID lpSurfaceData) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->Unlock(lpSurfaceData);

}





STDMETHODIMP CAggDrawSurface::UpdateOverlay(LPRECT lpSrcRect,LPDIRECTDRAWSURFACE lpDDDestSurface,LPRECT lpDestRect,DWORD dwFlags,LPDDOVERLAYFX lpDDOverlayFX) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->UpdateOverlay(lpSrcRect,lpDDDestSurface,lpDestRect,dwFlags,lpDDOverlayFX);

}





STDMETHODIMP CAggDrawSurface::UpdateOverlayDisplay(DWORD dwFlags) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->UpdateOverlayDisplay(dwFlags);

}





STDMETHODIMP CAggDrawSurface::UpdateOverlayZOrder(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSReference) {

    ASSERT(m_pDirectDrawSurface);

    return m_pDirectDrawSurface->UpdateOverlayZOrder(dwFlags,lpDDSReference);

}





// DirectShow must work on multiple platforms.  In particular, it also runs on

// Windows NT 3.51 which does not have DirectDraw capabilities. The filters

// cannot therefore link statically to the DirectDraw library. To make their

// lives that little bit easier we provide this class that manages loading

// and unloading the library and creating the initial IDirectDraw interface



CLoadDirectDraw::CLoadDirectDraw() :

    m_pDirectDraw(NULL),

    m_hDirectDraw(NULL) {

}





// Destructor forces unload



CLoadDirectDraw::~CLoadDirectDraw() {

    ReleaseDirectDraw();



    if(m_hDirectDraw) {

        NOTE("Unloading library");

        FreeLibrary(m_hDirectDraw);

    }

}





// We can't be sure that DirectDraw is always available so we can't statically

// link to the library. Therefore we load the library, get the function entry

// point addresses and call them to create the driver objects. We return S_OK

// if we manage to load DirectDraw correctly otherwise we return E_NOINTERFACE

// We initialise a DirectDraw instance by explicitely loading the library and

// calling GetProcAddress on the DirectDrawCreate entry point that it exports



// On a multi monitor system, we can get the DirectDraw object for any

// monitor (device) with the optional szDevice parameter



HRESULT CLoadDirectDraw::LoadDirectDraw(LPSTR szDevice) {

    PDRAWCREATE pDrawCreate;

    PDRAWENUM pDrawEnum;

    LPDIRECTDRAWENUMERATEEXA pDrawEnumEx;

    HRESULT hr = NOERROR;



    NOTE("Entering DoLoadDirectDraw");



    // Is DirectDraw already loaded



    if(m_pDirectDraw) {

        NOTE("Already loaded");

        ASSERT(m_hDirectDraw);

        return NOERROR;

    }



    // Make sure the library is available



    if(!m_hDirectDraw) {

        UINT ErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);

        m_hDirectDraw = LoadLibrary(TEXT("DDRAW.DLL"));

        SetErrorMode(ErrorMode);



        if(m_hDirectDraw == NULL) {

            DbgLog((LOG_ERROR,1,TEXT("Can't load DDRAW.DLL")));

            NOTE("No library");

            return E_NOINTERFACE;

        }

    }



    // Get the DLL address for the creator function



    pDrawCreate = (PDRAWCREATE)GetProcAddress(m_hDirectDraw,"DirectDrawCreate");

    // force ANSI, we assume it

    pDrawEnum = (PDRAWENUM)GetProcAddress(m_hDirectDraw,"DirectDrawEnumerateA");

    pDrawEnumEx = (LPDIRECTDRAWENUMERATEEXA)GetProcAddress(m_hDirectDraw,

        "DirectDrawEnumerateExA");



    // We don't NEED DirectDrawEnumerateEx, that's just for multimon stuff

    if(pDrawCreate == NULL || pDrawEnum == NULL) {

        DbgLog((LOG_ERROR,1,TEXT("Can't get functions: Create=%x Enum=%x"),

            pDrawCreate, pDrawEnum));

        NOTE("No entry point");

        ReleaseDirectDraw();

        return E_NOINTERFACE;

    }



    DbgLog((LOG_TRACE,3,TEXT("Creating DDraw for device %s"),

        szDevice ? szDevice : "<NULL>"));



    // Create a DirectDraw display provider for this device, using the fancy

    // multimon-aware version, if it exists

    if(pDrawEnumEx)

        m_pDirectDraw = DirectDrawCreateFromDeviceEx(szDevice, pDrawCreate,

            pDrawEnumEx);

    else

        m_pDirectDraw = DirectDrawCreateFromDevice(szDevice, pDrawCreate,

            pDrawEnum);



    if(m_pDirectDraw == NULL) {

        DbgLog((LOG_ERROR,1,TEXT("Can't create DDraw")));

        NOTE("No instance");

        ReleaseDirectDraw();

        return E_NOINTERFACE;

    }

    return NOERROR;

}





// Called to release any DirectDraw provider we previously loaded. We may be

// called at any time especially when something goes horribly wrong and when

// we need to clean up before returning so we can't guarantee that all state

// variables are consistent so free only those really allocated allocated

// This should only be called once all reference counts have been released



void CLoadDirectDraw::ReleaseDirectDraw() {

    NOTE("Releasing DirectDraw driver");



    // Release any DirectDraw provider interface



    if(m_pDirectDraw) {

        NOTE("Releasing instance");

        m_pDirectDraw->Release();

        m_pDirectDraw = NULL;

    }



}





// Return NOERROR (S_OK) if DirectDraw has been loaded by this object



HRESULT CLoadDirectDraw::IsDirectDrawLoaded() {

    NOTE("Entering IsDirectDrawLoaded");



    if(m_pDirectDraw == NULL) {

        NOTE("DirectDraw not loaded");

        return S_FALSE;

    }

    return NOERROR;

}





// Return the IDirectDraw interface we look after



LPDIRECTDRAW CLoadDirectDraw::GetDirectDraw() {

    NOTE("Entering GetDirectDraw");



    if(m_pDirectDraw == NULL) {

        NOTE("No DirectDraw");

        return NULL;

    }



    NOTE("Returning DirectDraw");

    m_pDirectDraw->AddRef();

    return m_pDirectDraw;

}





// Are we running on Direct Draw version 1?  We need to find out as

// we rely on specific bug fixes in DirectDraw 2 for fullscreen playback. To

// find out, we simply see if it supports IDirectDraw2.  Only version 2 and

// higher support this.



BOOL CLoadDirectDraw::IsDirectDrawVersion1() {



    if(m_pDirectDraw == NULL)

        return FALSE;



    IDirectDraw2 *p = NULL;

    HRESULT hr = m_pDirectDraw->QueryInterface(IID_IDirectDraw2, (void **)&p);

    if(p)

        p->Release();

    if(hr == NOERROR) {

        DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 2 or greater")));

        return FALSE;

    }

    else {

        DbgLog((LOG_TRACE,3,TEXT("Direct Draw Version 1")));

        return TRUE;

    }

}



