mirror of
https://github.com/libretro/pcsx2.git
synced 2024-11-30 21:00:42 +00:00
ab9bdb009b
Update it to the version found at https://github.com/Microsoft/Windows-classic-samples , which is in an MIT licensed repo, and add the LICENSE file (edited to remove the SIL Open Font LICENSE part since that doesn't apply). Some modifications have been made to reduce the diff/stop git complaining (not including any file that wasn't in the previous version and removing the related header includes in streams.h, and fixing some but not all of the whitespace issues).
533 lines
15 KiB
C++
533 lines
15 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: WXUtil.h
|
|
//
|
|
// Desc: DirectShow base classes - defines helper classes and functions for
|
|
// building multimedia filters.
|
|
//
|
|
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
#ifndef __WXUTIL__
|
|
#define __WXUTIL__
|
|
|
|
// eliminate spurious "statement has no effect" warnings.
|
|
#pragma warning(disable: 4705)
|
|
|
|
// wrapper for whatever critical section we have
|
|
class CCritSec {
|
|
|
|
// make copy constructor and assignment operator inaccessible
|
|
|
|
CCritSec(const CCritSec &refCritSec);
|
|
CCritSec &operator=(const CCritSec &refCritSec);
|
|
|
|
CRITICAL_SECTION m_CritSec;
|
|
|
|
#ifdef DEBUG
|
|
public:
|
|
DWORD m_currentOwner;
|
|
DWORD m_lockCount;
|
|
BOOL m_fTrace; // Trace this one
|
|
public:
|
|
CCritSec();
|
|
~CCritSec();
|
|
void Lock();
|
|
void Unlock();
|
|
#else
|
|
|
|
public:
|
|
CCritSec() {
|
|
InitializeCriticalSection(&m_CritSec);
|
|
};
|
|
|
|
~CCritSec() {
|
|
DeleteCriticalSection(&m_CritSec);
|
|
};
|
|
|
|
void Lock() {
|
|
EnterCriticalSection(&m_CritSec);
|
|
};
|
|
|
|
void Unlock() {
|
|
LeaveCriticalSection(&m_CritSec);
|
|
};
|
|
#endif
|
|
};
|
|
|
|
//
|
|
// To make deadlocks easier to track it is useful to insert in the
|
|
// code an assertion that says whether we own a critical section or
|
|
// not. We make the routines that do the checking globals to avoid
|
|
// having different numbers of member functions in the debug and
|
|
// retail class implementations of CCritSec. In addition we provide
|
|
// a routine that allows usage of specific critical sections to be
|
|
// traced. This is NOT on by default - there are far too many.
|
|
//
|
|
|
|
#ifdef DEBUG
|
|
BOOL WINAPI CritCheckIn(CCritSec * pcCrit);
|
|
BOOL WINAPI CritCheckIn(const CCritSec * pcCrit);
|
|
BOOL WINAPI CritCheckOut(CCritSec * pcCrit);
|
|
BOOL WINAPI CritCheckOut(const CCritSec * pcCrit);
|
|
void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace);
|
|
#else
|
|
#define CritCheckIn(x) TRUE
|
|
#define CritCheckOut(x) TRUE
|
|
#define DbgLockTrace(pc, fT)
|
|
#endif
|
|
|
|
|
|
// locks a critical section, and unlocks it automatically
|
|
// when the lock goes out of scope
|
|
class CAutoLock {
|
|
|
|
// make copy constructor and assignment operator inaccessible
|
|
|
|
CAutoLock(const CAutoLock &refAutoLock);
|
|
CAutoLock &operator=(const CAutoLock &refAutoLock);
|
|
|
|
protected:
|
|
CCritSec * m_pLock;
|
|
|
|
public:
|
|
CAutoLock(CCritSec * plock)
|
|
{
|
|
m_pLock = plock;
|
|
m_pLock->Lock();
|
|
};
|
|
|
|
~CAutoLock() {
|
|
m_pLock->Unlock();
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// wrapper for event objects
|
|
class CAMEvent
|
|
{
|
|
|
|
// make copy constructor and assignment operator inaccessible
|
|
|
|
CAMEvent(const CAMEvent &refEvent);
|
|
CAMEvent &operator=(const CAMEvent &refEvent);
|
|
|
|
protected:
|
|
HANDLE m_hEvent;
|
|
public:
|
|
CAMEvent(BOOL fManualReset = FALSE, __inout_opt HRESULT *phr = NULL);
|
|
CAMEvent(__inout_opt HRESULT *phr);
|
|
~CAMEvent();
|
|
|
|
// Cast to HANDLE - we don't support this as an lvalue
|
|
operator HANDLE () const { return m_hEvent; };
|
|
|
|
void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));};
|
|
BOOL Wait(DWORD dwTimeout = INFINITE) {
|
|
return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0);
|
|
};
|
|
void Reset() { ResetEvent(m_hEvent); };
|
|
BOOL Check() { return Wait(0); };
|
|
};
|
|
|
|
|
|
// wrapper for event objects that do message processing
|
|
// This adds ONE method to the CAMEvent object to allow sent
|
|
// messages to be processed while waiting
|
|
|
|
class CAMMsgEvent : public CAMEvent
|
|
{
|
|
|
|
public:
|
|
|
|
CAMMsgEvent(__inout_opt HRESULT *phr = NULL);
|
|
|
|
// Allow SEND messages to be processed while waiting
|
|
BOOL WaitMsg(DWORD dwTimeout = INFINITE);
|
|
};
|
|
|
|
// old name supported for the time being
|
|
#define CTimeoutEvent CAMEvent
|
|
|
|
// support for a worker thread
|
|
|
|
#ifdef AM_NOVTABLE
|
|
// simple thread class supports creation of worker thread, synchronization
|
|
// and communication. Can be derived to simplify parameter passing
|
|
class AM_NOVTABLE CAMThread {
|
|
|
|
// make copy constructor and assignment operator inaccessible
|
|
|
|
CAMThread(const CAMThread &refThread);
|
|
CAMThread &operator=(const CAMThread &refThread);
|
|
|
|
CAMEvent m_EventSend;
|
|
CAMEvent m_EventComplete;
|
|
|
|
DWORD m_dwParam;
|
|
DWORD m_dwReturnVal;
|
|
|
|
protected:
|
|
HANDLE m_hThread;
|
|
|
|
// thread will run this function on startup
|
|
// must be supplied by derived class
|
|
virtual DWORD ThreadProc() = 0;
|
|
|
|
public:
|
|
CAMThread(__inout_opt HRESULT *phr = NULL);
|
|
virtual ~CAMThread();
|
|
|
|
CCritSec m_AccessLock; // locks access by client threads
|
|
CCritSec m_WorkerLock; // locks access to shared objects
|
|
|
|
// thread initially runs this. param is actually 'this'. function
|
|
// just gets this and calls ThreadProc
|
|
static DWORD WINAPI InitialThreadProc(__inout LPVOID pv);
|
|
|
|
// start thread running - error if already running
|
|
BOOL Create();
|
|
|
|
// signal the thread, and block for a response
|
|
//
|
|
DWORD CallWorker(DWORD);
|
|
|
|
// accessor thread calls this when done with thread (having told thread
|
|
// to exit)
|
|
void Close() {
|
|
|
|
// Disable warning: Conversion from LONG to PVOID of greater size
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4312)
|
|
HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0);
|
|
#pragma warning(pop)
|
|
|
|
if (hThread) {
|
|
WaitForSingleObject(hThread, INFINITE);
|
|
CloseHandle(hThread);
|
|
}
|
|
};
|
|
|
|
// ThreadExists
|
|
// Return TRUE if the thread exists. FALSE otherwise
|
|
BOOL ThreadExists(void) const
|
|
{
|
|
if (m_hThread == 0) {
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// wait for the next request
|
|
DWORD GetRequest();
|
|
|
|
// is there a request?
|
|
BOOL CheckRequest(__out_opt DWORD * pParam);
|
|
|
|
// reply to the request
|
|
void Reply(DWORD);
|
|
|
|
// If you want to do WaitForMultipleObjects you'll need to include
|
|
// this handle in your wait list or you won't be responsive
|
|
HANDLE GetRequestHandle() const { return m_EventSend; };
|
|
|
|
// Find out what the request was
|
|
DWORD GetRequestParam() const { return m_dwParam; };
|
|
|
|
// call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if
|
|
// available. S_FALSE means it's not available.
|
|
static HRESULT CoInitializeHelper();
|
|
};
|
|
#endif // AM_NOVTABLE
|
|
|
|
|
|
// CQueue
|
|
//
|
|
// Implements a simple Queue ADT. The queue contains a finite number of
|
|
// objects, access to which is controlled by a semaphore. The semaphore
|
|
// is created with an initial count (N). Each time an object is added
|
|
// a call to WaitForSingleObject is made on the semaphore's handle. When
|
|
// this function returns a slot has been reserved in the queue for the new
|
|
// object. If no slots are available the function blocks until one becomes
|
|
// available. Each time an object is removed from the queue ReleaseSemaphore
|
|
// is called on the semaphore's handle, thus freeing a slot in the queue.
|
|
// If no objects are present in the queue the function blocks until an
|
|
// object has been added.
|
|
|
|
#define DEFAULT_QUEUESIZE 2
|
|
|
|
template <class T> class CQueue {
|
|
private:
|
|
HANDLE hSemPut; // Semaphore controlling queue "putting"
|
|
HANDLE hSemGet; // Semaphore controlling queue "getting"
|
|
CRITICAL_SECTION CritSect; // Thread seriallization
|
|
int nMax; // Max objects allowed in queue
|
|
int iNextPut; // Array index of next "PutMsg"
|
|
int iNextGet; // Array index of next "GetMsg"
|
|
T *QueueObjects; // Array of objects (ptr's to void)
|
|
|
|
void Initialize(int n) {
|
|
iNextPut = iNextGet = 0;
|
|
nMax = n;
|
|
InitializeCriticalSection(&CritSect);
|
|
hSemPut = CreateSemaphore(NULL, n, n, NULL);
|
|
hSemGet = CreateSemaphore(NULL, 0, n, NULL);
|
|
QueueObjects = new T[n];
|
|
}
|
|
|
|
|
|
public:
|
|
CQueue(int n) {
|
|
Initialize(n);
|
|
}
|
|
|
|
CQueue() {
|
|
Initialize(DEFAULT_QUEUESIZE);
|
|
}
|
|
|
|
~CQueue() {
|
|
delete [] QueueObjects;
|
|
DeleteCriticalSection(&CritSect);
|
|
CloseHandle(hSemPut);
|
|
CloseHandle(hSemGet);
|
|
}
|
|
|
|
T GetQueueObject() {
|
|
int iSlot;
|
|
T Object;
|
|
LONG lPrevious;
|
|
|
|
// Wait for someone to put something on our queue, returns straight
|
|
// away is there is already an object on the queue.
|
|
//
|
|
WaitForSingleObject(hSemGet, INFINITE);
|
|
|
|
EnterCriticalSection(&CritSect);
|
|
iSlot = iNextGet++ % nMax;
|
|
Object = QueueObjects[iSlot];
|
|
LeaveCriticalSection(&CritSect);
|
|
|
|
// Release anyone waiting to put an object onto our queue as there
|
|
// is now space available in the queue.
|
|
//
|
|
ReleaseSemaphore(hSemPut, 1L, &lPrevious);
|
|
return Object;
|
|
}
|
|
|
|
void PutQueueObject(T Object) {
|
|
int iSlot;
|
|
LONG lPrevious;
|
|
|
|
// Wait for someone to get something from our queue, returns straight
|
|
// away is there is already an empty slot on the queue.
|
|
//
|
|
WaitForSingleObject(hSemPut, INFINITE);
|
|
|
|
EnterCriticalSection(&CritSect);
|
|
iSlot = iNextPut++ % nMax;
|
|
QueueObjects[iSlot] = Object;
|
|
LeaveCriticalSection(&CritSect);
|
|
|
|
// Release anyone waiting to remove an object from our queue as there
|
|
// is now an object available to be removed.
|
|
//
|
|
ReleaseSemaphore(hSemGet, 1L, &lPrevious);
|
|
}
|
|
};
|
|
|
|
// Ensures that memory is not read past the length source buffer
|
|
// and that memory is not written past the length of the dst buffer
|
|
// dst - buffer to copy to
|
|
// dst_size - total size of destination buffer
|
|
// cb_dst_offset - offset, first byte copied to dst+cb_dst_offset
|
|
// src - buffer to copy from
|
|
// src_size - total size of source buffer
|
|
// cb_src_offset - offset, first byte copied from src+cb_src_offset
|
|
// count - number of bytes to copy
|
|
//
|
|
// Returns:
|
|
// S_OK - no error
|
|
// E_INVALIDARG - values passed would lead to overrun
|
|
HRESULT AMSafeMemMoveOffset(
|
|
__in_bcount(dst_size) void * dst,
|
|
__in size_t dst_size,
|
|
__in DWORD cb_dst_offset,
|
|
__in_bcount(src_size) const void * src,
|
|
__in size_t src_size,
|
|
__in DWORD cb_src_offset,
|
|
__in size_t count);
|
|
|
|
extern "C"
|
|
void * __stdcall memmoveInternal(void *, const void *, size_t);
|
|
|
|
inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt)
|
|
{
|
|
#ifdef _X86_
|
|
void *pRet = NULL;
|
|
|
|
_asm {
|
|
cld // make sure we get the direction right
|
|
mov ecx, cnt // num of bytes to scan
|
|
mov edi, buf // pointer byte stream
|
|
mov eax, chr // byte to scan for
|
|
repne scasb // look for the byte in the byte stream
|
|
jnz exit_memchr // Z flag set if byte found
|
|
dec edi // scasb always increments edi even when it
|
|
// finds the required byte
|
|
mov pRet, edi
|
|
exit_memchr:
|
|
}
|
|
return pRet;
|
|
|
|
#else
|
|
while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) {
|
|
buf = (unsigned char *)buf + 1;
|
|
cnt--;
|
|
}
|
|
|
|
return(cnt ? (void *)buf : NULL);
|
|
#endif
|
|
}
|
|
|
|
void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr);
|
|
|
|
#define WstrToInt(sz) _wtoi(sz)
|
|
#define atoiW(sz) _wtoi(sz)
|
|
#define atoiA(sz) atoi(sz)
|
|
|
|
// These are available to help managing bitmap VIDEOINFOHEADER media structures
|
|
|
|
extern const DWORD bits555[3];
|
|
extern const DWORD bits565[3];
|
|
extern const DWORD bits888[3];
|
|
|
|
// These help convert between VIDEOINFOHEADER and BITMAPINFO structures
|
|
|
|
STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader);
|
|
STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader);
|
|
STDAPI_(WORD) GetBitCount(const GUID *pSubtype);
|
|
|
|
// strmbase.lib implements this for compatibility with people who
|
|
// managed to link to this directly. we don't want to advertise it.
|
|
//
|
|
// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype);
|
|
|
|
STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype);
|
|
STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype);
|
|
|
|
#ifdef UNICODE
|
|
#define GetSubtypeName GetSubtypeNameW
|
|
#else
|
|
#define GetSubtypeName GetSubtypeNameA
|
|
#endif
|
|
|
|
STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader);
|
|
STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader);
|
|
|
|
#ifdef __AMVIDEO__
|
|
STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo);
|
|
STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo);
|
|
#endif // __AMVIDEO__
|
|
|
|
|
|
// Compares two interfaces and returns TRUE if they are on the same object
|
|
BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond);
|
|
|
|
// This is for comparing pins
|
|
#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2)
|
|
|
|
|
|
// Arithmetic helper functions
|
|
|
|
// Compute (a * b + rnd) / c
|
|
LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd);
|
|
LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd);
|
|
|
|
|
|
// Avoids us dyna-linking to SysAllocString to copy BSTR strings
|
|
STDAPI WriteBSTR(__deref_out BSTR * pstrDest, LPCWSTR szSrc);
|
|
STDAPI FreeBSTR(__deref_in BSTR* pstr);
|
|
|
|
// Return a wide string - allocating memory for it
|
|
// Returns:
|
|
// S_OK - no error
|
|
// E_POINTER - ppszReturn == NULL
|
|
// E_OUTOFMEMORY - can't allocate memory for returned string
|
|
STDAPI AMGetWideString(LPCWSTR pszString, __deref_out LPWSTR *ppszReturn);
|
|
|
|
// Special wait for objects owning windows
|
|
DWORD WINAPI WaitDispatchingMessages(
|
|
HANDLE hObject,
|
|
DWORD dwWait,
|
|
HWND hwnd = NULL,
|
|
UINT uMsg = 0,
|
|
HANDLE hEvent = NULL);
|
|
|
|
// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in
|
|
// our use of HRESULT_FROM_WIN32, it typically means a function failed
|
|
// to call SetLastError(), and we still want a failure code.
|
|
//
|
|
#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x))
|
|
|
|
// call GetLastError and return an HRESULT value that will fail the
|
|
// SUCCEEDED() macro.
|
|
HRESULT AmGetLastErrorToHResult(void);
|
|
|
|
// duplicate of ATL's CComPtr to avoid linker conflicts.
|
|
|
|
IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp);
|
|
|
|
template <class T>
|
|
class QzCComPtr
|
|
{
|
|
public:
|
|
typedef T _PtrClass;
|
|
QzCComPtr() {p=NULL;}
|
|
QzCComPtr(T* lp)
|
|
{
|
|
if ((p = lp) != NULL)
|
|
p->AddRef();
|
|
}
|
|
QzCComPtr(const QzCComPtr<T>& lp)
|
|
{
|
|
if ((p = lp.p) != NULL)
|
|
p->AddRef();
|
|
}
|
|
~QzCComPtr() {if (p) p->Release();}
|
|
void Release() {if (p) p->Release(); p=NULL;}
|
|
operator T*() {return (T*)p;}
|
|
T& operator*() {ASSERT(p!=NULL); return *p; }
|
|
//The assert on operator& usually indicates a bug. If this is really
|
|
//what is needed, however, take the address of the p member explicitly.
|
|
T** operator&() { ASSERT(p==NULL); return &p; }
|
|
T* operator->() { ASSERT(p!=NULL); return p; }
|
|
T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);}
|
|
T* operator=(const QzCComPtr<T>& lp)
|
|
{
|
|
return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p);
|
|
}
|
|
#if _MSC_VER>1020
|
|
bool operator!(){return (p == NULL);}
|
|
#else
|
|
BOOL operator!(){return (p == NULL) ? TRUE : FALSE;}
|
|
#endif
|
|
T* p;
|
|
};
|
|
|
|
MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent );
|
|
bool TimeKillSynchronousFlagAvailable( void );
|
|
|
|
// Helper to replace lstrcpmi
|
|
__inline int lstrcmpiLocaleIndependentW(LPCWSTR lpsz1, LPCWSTR lpsz2)
|
|
{
|
|
return CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL;
|
|
}
|
|
__inline int lstrcmpiLocaleIndependentA(LPCSTR lpsz1, LPCSTR lpsz2)
|
|
{
|
|
return CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL;
|
|
}
|
|
|
|
#endif /* __WXUTIL__ */
|