//------------------------------------------------------------------------------ | |
// 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 | |
LPTSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPTSTR pBuffer, int iResourceID) | |
{ | |
if (LoadString(g_hInst,iResourceID,pBuffer,STR_MAX_LENGTH) == 0) { | |
return TEXT(""); | |
} | |
return pBuffer; | |
} | |
#ifdef UNICODE | |
LPSTR WINAPI StringFromResource(__out_ecount(STR_MAX_LENGTH) LPSTR 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 | |
LPWSTR WINAPI WideStringFromResource(__out_ecount(STR_MAX_LENGTH) LPWSTR 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, | |
__out 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, __deref_out 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, __deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper, __inout_opt IUnknown *pUnkOuter) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->CreateClipper(dwFlags,lplpDDClipper,pUnkOuter); | |
} | |
STDMETHODIMP CAggDirectDraw::CreatePalette(DWORD dwFlags, | |
__in LPPALETTEENTRY lpColorTable, | |
__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette, | |
__inout_opt IUnknown *pUnkOuter) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->CreatePalette(dwFlags,lpColorTable,lplpDDPalette,pUnkOuter); | |
} | |
STDMETHODIMP CAggDirectDraw::CreateSurface(__in LPDDSURFACEDESC lpDDSurfaceDesc, | |
__deref_out LPDIRECTDRAWSURFACE *lplpDDSurface, | |
__inout_opt IUnknown *pUnkOuter) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->CreateSurface(lpDDSurfaceDesc,lplpDDSurface,pUnkOuter); | |
} | |
STDMETHODIMP CAggDirectDraw::DuplicateSurface(__in LPDIRECTDRAWSURFACE lpDDSurface, | |
__deref_out LPDIRECTDRAWSURFACE *lplpDupDDSurface) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->DuplicateSurface(lpDDSurface,lplpDupDDSurface); | |
} | |
STDMETHODIMP CAggDirectDraw::EnumDisplayModes(DWORD dwSurfaceDescCount, | |
__in LPDDSURFACEDESC lplpDDSurfaceDescList, | |
__in LPVOID lpContext, | |
__in LPDDENUMMODESCALLBACK lpEnumCallback) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->EnumDisplayModes(dwSurfaceDescCount,lplpDDSurfaceDescList,lpContext,lpEnumCallback); | |
} | |
STDMETHODIMP CAggDirectDraw::EnumSurfaces(DWORD dwFlags, | |
__in LPDDSURFACEDESC lpDDSD, | |
__in LPVOID lpContext, | |
__in 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(__out LPDDCAPS lpDDDriverCaps,__out LPDDCAPS lpDDHELCaps) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->GetCaps(lpDDDriverCaps,lpDDHELCaps); | |
} | |
STDMETHODIMP CAggDirectDraw::GetDisplayMode(__out LPDDSURFACEDESC lpDDSurfaceDesc) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->GetDisplayMode(lpDDSurfaceDesc); | |
} | |
STDMETHODIMP CAggDirectDraw::GetFourCCCodes(__inout LPDWORD lpNumCodes,__out_ecount(*lpNumCodes) LPDWORD lpCodes) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->GetFourCCCodes(lpNumCodes,lpCodes); | |
} | |
STDMETHODIMP CAggDirectDraw::GetGDISurface(__deref_out LPDIRECTDRAWSURFACE *lplpGDIDDSurface) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->GetGDISurface(lplpGDIDDSurface); | |
} | |
STDMETHODIMP CAggDirectDraw::GetMonitorFrequency(__out LPDWORD lpdwFrequency) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->GetMonitorFrequency(lpdwFrequency); | |
} | |
STDMETHODIMP CAggDirectDraw::GetScanLine(__out LPDWORD lpdwScanLine) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->GetScanLine(lpdwScanLine); | |
} | |
STDMETHODIMP CAggDirectDraw::GetVerticalBlankStatus(__out LPBOOL lpblsInVB) | |
{ | |
ASSERT(m_pDirectDraw); | |
return m_pDirectDraw->GetVerticalBlankStatus(lpblsInVB); | |
} | |
STDMETHODIMP CAggDirectDraw::Initialize(__in 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, __deref_out 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(__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->AddAttachedSurface(lpDDSAttachedSurface); | |
} | |
STDMETHODIMP CAggDrawSurface::AddOverlayDirtyRect(__in LPRECT lpRect) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->AddOverlayDirtyRect(lpRect); | |
} | |
STDMETHODIMP CAggDrawSurface::Blt(__in LPRECT lpDestRect, | |
__in LPDIRECTDRAWSURFACE lpDDSrcSurface, | |
__in LPRECT lpSrcRect, | |
DWORD dwFlags, | |
__in LPDDBLTFX lpDDBltFx) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->Blt(lpDestRect,lpDDSrcSurface,lpSrcRect,dwFlags,lpDDBltFx); | |
} | |
STDMETHODIMP CAggDrawSurface::BltBatch(__in_ecount(dwCount) LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->BltBatch(lpDDBltBatch,dwCount,dwFlags); | |
} | |
STDMETHODIMP CAggDrawSurface::BltFast(DWORD dwX,DWORD dwY, | |
__in LPDIRECTDRAWSURFACE lpDDSrcSurface, | |
__in LPRECT lpSrcRect, | |
DWORD dwTrans) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->BltFast(dwX,dwY,lpDDSrcSurface,lpSrcRect,dwTrans); | |
} | |
STDMETHODIMP CAggDrawSurface::DeleteAttachedSurface(DWORD dwFlags, | |
__in LPDIRECTDRAWSURFACE lpDDSAttachedSurface) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->DeleteAttachedSurface(dwFlags,lpDDSAttachedSurface); | |
} | |
STDMETHODIMP CAggDrawSurface::EnumAttachedSurfaces(__in LPVOID lpContext, | |
__in LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->EnumAttachedSurfaces(lpContext,lpEnumSurfacesCallback); | |
} | |
STDMETHODIMP CAggDrawSurface::EnumOverlayZOrders(DWORD dwFlags, | |
__in LPVOID lpContext, | |
__in LPDDENUMSURFACESCALLBACK lpfnCallback) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->EnumOverlayZOrders(dwFlags,lpContext,lpfnCallback); | |
} | |
STDMETHODIMP CAggDrawSurface::Flip(__in LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->Flip(lpDDSurfaceTargetOverride,dwFlags); | |
} | |
STDMETHODIMP CAggDrawSurface::GetAttachedSurface(__in LPDDSCAPS lpDDSCaps, | |
__deref_out 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(__out LPDDSCAPS lpDDSCaps) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->GetCaps(lpDDSCaps); | |
} | |
STDMETHODIMP CAggDrawSurface::GetClipper(__deref_out LPDIRECTDRAWCLIPPER *lplpDDClipper) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->GetClipper(lplpDDClipper); | |
} | |
STDMETHODIMP CAggDrawSurface::GetColorKey(DWORD dwFlags,__out LPDDCOLORKEY lpDDColorKey) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->GetColorKey(dwFlags,lpDDColorKey); | |
} | |
STDMETHODIMP CAggDrawSurface::GetDC(__out 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(__out LPLONG lpdwX,__out LPLONG lpdwY) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->GetOverlayPosition(lpdwX,lpdwY); | |
} | |
STDMETHODIMP CAggDrawSurface::GetPalette(__deref_out LPDIRECTDRAWPALETTE *lplpDDPalette) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->GetPalette(lplpDDPalette); | |
} | |
STDMETHODIMP CAggDrawSurface::GetPixelFormat(__out 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(__out 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(__in LPDIRECTDRAW lpDD,__in LPDDSURFACEDESC lpDDSurfaceDesc) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->Initialize(lpDD,lpDDSurfaceDesc); | |
} | |
STDMETHODIMP CAggDrawSurface::IsLost() | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->IsLost(); | |
} | |
STDMETHODIMP CAggDrawSurface::Lock(__in LPRECT lpDestRect, | |
__inout 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(__in LPDIRECTDRAWCLIPPER lpDDClipper) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->SetClipper(lpDDClipper); | |
} | |
STDMETHODIMP CAggDrawSurface::SetColorKey(DWORD dwFlags,__in 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(__in LPDIRECTDRAWPALETTE lpDDPalette) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->SetPalette(lpDDPalette); | |
} | |
STDMETHODIMP CAggDrawSurface::Unlock(__in LPVOID lpSurfaceData) | |
{ | |
ASSERT(m_pDirectDrawSurface); | |
return m_pDirectDrawSurface->Unlock(lpSurfaceData); | |
} | |
STDMETHODIMP CAggDrawSurface::UpdateOverlay(__in LPRECT lpSrcRect, | |
__in LPDIRECTDRAWSURFACE lpDDDestSurface, | |
__in LPRECT lpDestRect, | |
DWORD dwFlags, | |
__in 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,__in 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(__in 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; | |
} | |
} |