| //------------------------------------------------------------------------------ | |
| // 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; | |
| } | |
| } |