WXUTIL.H

//==========================================================================; 
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;

//
// helper classes and functions for building multimedia filters
//

#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 CritCheckOut(CCritSec * pcCrit);
void WINAPI DbgLockTrace(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);
~CAMEvent();

// Cast to HANDLE - we don't support this as an lvalue
operator HANDLE () const { return m_hEvent; };

void Set() { 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:

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

// 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();
~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(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() {
HANDLE hThread = (HANDLE)InterlockedExchange((LONG *)&m_hThread, 0);
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(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; };
};


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

// miscellaneous string conversion functions
// NOTE: as we need to use the same binaries on Win95 as on NT this code should
// be compiled WITHOUT unicode being defined. Otherwise we will not pick up
// these internal routines and the binary will not run on Win95.

#ifndef UNICODE
#define wsprintfW wsprintfWInternal
int WINAPIV wsprintfWInternal(LPWSTR, LPCWSTR, ...);

#define lstrcpyW lstrcpyWInternal
LPWSTR
WINAPI
lstrcpyWInternal(
LPWSTR lpString1,
LPCWSTR lpString2
);
#define lstrcpynW lstrcpynWInternal
LPWSTR
WINAPI
lstrcpynWInternal(
LPWSTR lpString1,
LPCWSTR lpString2,
int iMaxLength
);
#define lstrcmpW lstrcmpWInternal
int
WINAPI
lstrcmpWInternal(
LPCWSTR lpString1,
LPCWSTR lpString2
);
#define lstrcmpiW lstrcmpiWInternal
int
WINAPI
lstrcmpiWInternal(
LPCWSTR lpString1,
LPCWSTR lpString2
);
#define lstrlenW lstrlenWInternal
int
WINAPI
lstrlenWInternal(
LPCWSTR lpString
);
#endif

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, LPWSTR wstr);

#define WstrToInt(sz) atoiW(sz)

inline int atoiW(const WCHAR *sz)
{
int i = 0;

while (*sz && *sz >= L'0' && *sz <= L'9')
i = i*10 + *sz++ - L'0';

return i;
}

inline int WINAPI atoiA(const CHAR *sz)
{
int i = 0;

while (*sz && *sz >= '0' && *sz <= '9')
i = i*10 + *sz++ - '0';

return i;
}

#ifdef UNICODE
#define atoi atoiW
#else
#define atoi atoiA
#endif



// 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);
STDAPI_(TCHAR *) GetSubtypeName(const GUID *pSubtype);
STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader);
STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader);
STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo);
STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo);


// 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(BSTR * pstrDest, LPCWSTR szSrc);
STDAPI FreeBSTR(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, LPWSTR *ppszReturn);

// Special wait for objects owning windows
DWORD WINAPI WaitDispatchingMessages(HANDLE hObject, DWORD dwWait, HWND hwnd = NULL, UINT uMsg = 0);
#endif /* __WXUTIL__ */