1 //------------------------------------------------------------------------------
2 // File: WXUtil.h
3 //
4 // Desc: DirectShow base classes - defines helper classes and functions for
5 //       building multimedia filters.
6 //
7 // Copyright (c) 1992-2002 Microsoft Corporation.  All rights reserved.
8 //------------------------------------------------------------------------------
9 
10 
11 #ifndef __WXUTIL__
12 #define __WXUTIL__
13 
14 // eliminate spurious "statement has no effect" warnings.
15 #pragma warning(disable: 4705)
16 
17 // wrapper for whatever critical section we have
18 class CCritSec {
19 
20     // make copy constructor and assignment operator inaccessible
21 
22     CCritSec(const CCritSec &refCritSec);
23     CCritSec &operator=(const CCritSec &refCritSec);
24 
25     CRITICAL_SECTION m_CritSec;
26 
27 #ifdef DEBUG
28 public:
29     DWORD   m_currentOwner;
30     DWORD   m_lockCount;
31     BOOL    m_fTrace;        // Trace this one
32 public:
33     CCritSec();
34     ~CCritSec();
35     void Lock();
36     void Unlock();
37 #else
38 
39 public:
CCritSec()40     CCritSec() {
41         InitializeCriticalSection(&m_CritSec);
42     };
43 
~CCritSec()44     ~CCritSec() {
45         DeleteCriticalSection(&m_CritSec);
46     };
47 
Lock()48     void Lock() {
49         EnterCriticalSection(&m_CritSec);
50     };
51 
Unlock()52     void Unlock() {
53         LeaveCriticalSection(&m_CritSec);
54     };
55 #endif
56 };
57 
58 //
59 // To make deadlocks easier to track it is useful to insert in the
60 // code an assertion that says whether we own a critical section or
61 // not.  We make the routines that do the checking globals to avoid
62 // having different numbers of member functions in the debug and
63 // retail class implementations of CCritSec.  In addition we provide
64 // a routine that allows usage of specific critical sections to be
65 // traced.  This is NOT on by default - there are far too many.
66 //
67 
68 #ifdef DEBUG
69     BOOL WINAPI CritCheckIn(CCritSec * pcCrit);
70     BOOL WINAPI CritCheckIn(const CCritSec * pcCrit);
71     BOOL WINAPI CritCheckOut(CCritSec * pcCrit);
72     BOOL WINAPI CritCheckOut(const CCritSec * pcCrit);
73     void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace);
74 #else
75     #define CritCheckIn(x) TRUE
76     #define CritCheckOut(x) TRUE
77     #define DbgLockTrace(pc, fT)
78 #endif
79 
80 
81 // locks a critical section, and unlocks it automatically
82 // when the lock goes out of scope
83 class CAutoLock {
84 
85     // make copy constructor and assignment operator inaccessible
86 
87     CAutoLock(const CAutoLock &refAutoLock);
88     CAutoLock &operator=(const CAutoLock &refAutoLock);
89 
90 protected:
91     CCritSec * m_pLock;
92 
93 public:
CAutoLock(CCritSec * plock)94     CAutoLock(CCritSec * plock)
95     {
96         m_pLock = plock;
97         m_pLock->Lock();
98     };
99 
~CAutoLock()100     ~CAutoLock() {
101         m_pLock->Unlock();
102     };
103 };
104 
105 
106 
107 // wrapper for event objects
108 class CAMEvent
109 {
110 
111     // make copy constructor and assignment operator inaccessible
112 
113     CAMEvent(const CAMEvent &refEvent);
114     CAMEvent &operator=(const CAMEvent &refEvent);
115 
116 protected:
117     HANDLE m_hEvent;
118 public:
119     CAMEvent(BOOL fManualReset = FALSE);
120     ~CAMEvent();
121 
122     // Cast to HANDLE - we don't support this as an lvalue
HANDLE()123     operator HANDLE () const { return m_hEvent; };
124 
Set()125     void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));};
126     BOOL Wait(DWORD dwTimeout = INFINITE) {
127 	return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0);
128     };
Reset()129     void Reset() { ResetEvent(m_hEvent); };
Check()130     BOOL Check() { return Wait(0); };
131 };
132 
133 
134 // wrapper for event objects that do message processing
135 // This adds ONE method to the CAMEvent object to allow sent
136 // messages to be processed while waiting
137 
138 class CAMMsgEvent : public CAMEvent
139 {
140 
141 public:
142 
143     // Allow SEND messages to be processed while waiting
144     BOOL WaitMsg(DWORD dwTimeout = INFINITE);
145 };
146 
147 // old name supported for the time being
148 #define CTimeoutEvent CAMEvent
149 
150 // support for a worker thread
151 
152 // simple thread class supports creation of worker thread, synchronization
153 // and communication. Can be derived to simplify parameter passing
154 class AM_NOVTABLE CAMThread {
155 
156     // make copy constructor and assignment operator inaccessible
157 
158     CAMThread(const CAMThread &refThread);
159     CAMThread &operator=(const CAMThread &refThread);
160 
161     CAMEvent m_EventSend;
162     CAMEvent m_EventComplete;
163 
164     DWORD m_dwParam;
165     DWORD m_dwReturnVal;
166 
167 protected:
168     HANDLE m_hThread;
169 
170     // thread will run this function on startup
171     // must be supplied by derived class
172     virtual DWORD ThreadProc() = 0;
173 
174 public:
175     CAMThread();
176     virtual ~CAMThread();
177 
178     CCritSec m_AccessLock;	// locks access by client threads
179     CCritSec m_WorkerLock;	// locks access to shared objects
180 
181     // thread initially runs this. param is actually 'this'. function
182     // just gets this and calls ThreadProc
183     static DWORD WINAPI InitialThreadProc(LPVOID pv);
184 
185     // start thread running  - error if already running
186     BOOL Create();
187 
188     // signal the thread, and block for a response
189     //
190     DWORD CallWorker(DWORD);
191 
192     // accessor thread calls this when done with thread (having told thread
193     // to exit)
Close()194     void Close() {
195         HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0);
196         if (hThread) {
197             WaitForSingleObject(hThread, INFINITE);
198             CloseHandle(hThread);
199         }
200     };
201 
202     // ThreadExists
203     // Return TRUE if the thread exists. FALSE otherwise
ThreadExists(void)204     BOOL ThreadExists(void) const
205     {
206         if (m_hThread == 0) {
207             return FALSE;
208         } else {
209             return TRUE;
210         }
211     }
212 
213     // wait for the next request
214     DWORD GetRequest();
215 
216     // is there a request?
217     BOOL CheckRequest(DWORD * pParam);
218 
219     // reply to the request
220     void Reply(DWORD);
221 
222     // If you want to do WaitForMultipleObjects you'll need to include
223     // this handle in your wait list or you won't be responsive
GetRequestHandle()224     HANDLE GetRequestHandle() const { return m_EventSend; };
225 
226     // Find out what the request was
GetRequestParam()227     DWORD GetRequestParam() const { return m_dwParam; };
228 
229     // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if
230     // available. S_FALSE means it's not available.
231     static HRESULT CoInitializeHelper();
232 };
233 
234 
235 // CQueue
236 //
237 // Implements a simple Queue ADT.  The queue contains a finite number of
238 // objects, access to which is controlled by a semaphore.  The semaphore
239 // is created with an initial count (N).  Each time an object is added
240 // a call to WaitForSingleObject is made on the semaphore's handle.  When
241 // this function returns a slot has been reserved in the queue for the new
242 // object.  If no slots are available the function blocks until one becomes
243 // available.  Each time an object is removed from the queue ReleaseSemaphore
244 // is called on the semaphore's handle, thus freeing a slot in the queue.
245 // If no objects are present in the queue the function blocks until an
246 // object has been added.
247 
248 #define DEFAULT_QUEUESIZE   2
249 
250 template <class T> class CQueue {
251 private:
252     HANDLE          hSemPut;        // Semaphore controlling queue "putting"
253     HANDLE          hSemGet;        // Semaphore controlling queue "getting"
254     CRITICAL_SECTION CritSect;      // Thread seriallization
255     int             nMax;           // Max objects allowed in queue
256     int             iNextPut;       // Array index of next "PutMsg"
257     int             iNextGet;       // Array index of next "GetMsg"
258     T              *QueueObjects;   // Array of objects (ptr's to void)
259 
Initialize(int n)260     void Initialize(int n) {
261         iNextPut = iNextGet = 0;
262         nMax = n;
263         InitializeCriticalSection(&CritSect);
264         hSemPut = CreateSemaphore(NULL, n, n, NULL);
265         hSemGet = CreateSemaphore(NULL, 0, n, NULL);
266         QueueObjects = new T[n];
267     }
268 
269 
270 public:
CQueue(int n)271     CQueue(int n) {
272         Initialize(n);
273     }
274 
CQueue()275     CQueue() {
276         Initialize(DEFAULT_QUEUESIZE);
277     }
278 
~CQueue()279     ~CQueue() {
280         delete [] QueueObjects;
281         DeleteCriticalSection(&CritSect);
282         CloseHandle(hSemPut);
283         CloseHandle(hSemGet);
284     }
285 
GetQueueObject()286     T GetQueueObject() {
287         int iSlot;
288         T Object;
289         LONG lPrevious;
290 
291         // Wait for someone to put something on our queue, returns straight
292         // away is there is already an object on the queue.
293         //
294         WaitForSingleObject(hSemGet, INFINITE);
295 
296         EnterCriticalSection(&CritSect);
297         iSlot = iNextGet++ % nMax;
298         Object = QueueObjects[iSlot];
299         LeaveCriticalSection(&CritSect);
300 
301         // Release anyone waiting to put an object onto our queue as there
302         // is now space available in the queue.
303         //
304         ReleaseSemaphore(hSemPut, 1L, &lPrevious);
305         return Object;
306     }
307 
PutQueueObject(T Object)308     void PutQueueObject(T Object) {
309         int iSlot;
310         LONG lPrevious;
311 
312         // Wait for someone to get something from our queue, returns straight
313         // away is there is already an empty slot on the queue.
314         //
315         WaitForSingleObject(hSemPut, INFINITE);
316 
317         EnterCriticalSection(&CritSect);
318         iSlot = iNextPut++ % nMax;
319         QueueObjects[iSlot] = Object;
320         LeaveCriticalSection(&CritSect);
321 
322         // Release anyone waiting to remove an object from our queue as there
323         // is now an object available to be removed.
324         //
325         ReleaseSemaphore(hSemGet, 1L, &lPrevious);
326     }
327 };
328 
329 // miscellaneous string conversion functions
330 // NOTE: as we need to use the same binaries on Win95 as on NT this code should
331 // be compiled WITHOUT unicode being defined.  Otherwise we will not pick up
332 // these internal routines and the binary will not run on Win95.
333 
334 int WINAPIV wsprintfWInternal(LPWSTR, LPCWSTR, ...);
335 
336 LPWSTR
337 WINAPI
338 lstrcpyWInternal(
339     LPWSTR lpString1,
340     LPCWSTR lpString2
341     );
342 LPWSTR
343 WINAPI
344 lstrcpynWInternal(
345     LPWSTR lpString1,
346     LPCWSTR lpString2,
347     int     iMaxLength
348     );
349 int
350 WINAPI
351 lstrcmpWInternal(
352     LPCWSTR lpString1,
353     LPCWSTR lpString2
354     );
355 int
356 WINAPI
357 lstrcmpiWInternal(
358     LPCWSTR lpString1,
359     LPCWSTR lpString2
360     );
361 int
362 WINAPI
363 lstrlenWInternal(
364     LPCWSTR lpString
365     );
366 
367 #ifndef UNICODE
368 #define wsprintfW wsprintfWInternal
369 #define lstrcpyW lstrcpyWInternal
370 #define lstrcpynW lstrcpynWInternal
371 #define lstrcmpW lstrcmpWInternal
372 #define lstrcmpiW lstrcmpiWInternal
373 #define lstrlenW lstrlenWInternal
374 #endif
375 
376 extern "C"
377 void * __stdcall memmoveInternal(void *, const void *, size_t);
378 
memchrInternal(const void * buf,int chr,size_t cnt)379 inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt)
380 {
381 #ifdef _X86_
382     void *pRet = NULL;
383 
384     _asm {
385         cld                 // make sure we get the direction right
386         mov     ecx, cnt    // num of bytes to scan
387         mov     edi, buf    // pointer byte stream
388         mov     eax, chr    // byte to scan for
389         repne   scasb       // look for the byte in the byte stream
390         jnz     exit_memchr // Z flag set if byte found
391         dec     edi         // scasb always increments edi even when it
392                             // finds the required byte
393         mov     pRet, edi
394 exit_memchr:
395     }
396     return pRet;
397 
398 #else
399     while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) {
400         buf = (unsigned char *)buf + 1;
401         cnt--;
402     }
403 
404     return(cnt ? (void *)buf : NULL);
405 #endif
406 }
407 
408 void WINAPI IntToWstr(int i, LPWSTR wstr);
409 
410 #define WstrToInt(sz) _wtoi(sz)
411 #define atoiW(sz) _wtoi(sz)
412 #define atoiA(sz) atoi(sz)
413 
414 // These are available to help managing bitmap VIDEOINFOHEADER media structures
415 
416 extern const DWORD bits555[3];
417 extern const DWORD bits565[3];
418 extern const DWORD bits888[3];
419 
420 // These help convert between VIDEOINFOHEADER and BITMAPINFO structures
421 
422 STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader);
423 STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader);
424 STDAPI_(WORD) GetBitCount(const GUID *pSubtype);
425 
426 // strmbase.lib implements this for compatibility with people who
427 // managed to link to this directly.  we don't want to advertise it.
428 //
429 // STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype);
430 
431 STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype);
432 STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype);
433 
434 #ifdef UNICODE
435 #define GetSubtypeName GetSubtypeNameW
436 #else
437 #define GetSubtypeName GetSubtypeNameA
438 #endif
439 
440 STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader);
441 STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader);
442 STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo);
443 STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo);
444 
445 
446 // Compares two interfaces and returns TRUE if they are on the same object
447 BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond);
448 
449 // This is for comparing pins
450 #define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2)
451 
452 
453 // Arithmetic helper functions
454 
455 // Compute (a * b + rnd) / c
456 LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd);
457 LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd);
458 
459 
460 // Avoids us dyna-linking to SysAllocString to copy BSTR strings
461 STDAPI WriteBSTR(BSTR * pstrDest, LPCWSTR szSrc);
462 STDAPI FreeBSTR(BSTR* pstr);
463 
464 // Return a wide string - allocating memory for it
465 // Returns:
466 //    S_OK          - no error
467 //    E_POINTER     - ppszReturn == NULL
468 //    E_OUTOFMEMORY - can't allocate memory for returned string
469 STDAPI AMGetWideString(LPCWSTR pszString, LPWSTR *ppszReturn);
470 
471 // Special wait for objects owning windows
472 DWORD WINAPI WaitDispatchingMessages(
473     HANDLE hObject,
474     DWORD dwWait,
475     HWND hwnd = NULL,
476     UINT uMsg = 0,
477     HANDLE hEvent = NULL);
478 
479 // HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in
480 // our use of HRESULT_FROM_WIN32, it typically means a function failed
481 // to call SetLastError(), and we still want a failure code.
482 //
483 #define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x))
484 
485 // call GetLastError and return an HRESULT value that will fail the
486 // SUCCEEDED() macro.
487 HRESULT AmGetLastErrorToHResult(void);
488 
489 // duplicate of ATL's CComPtr to avoid linker conflicts.
490 
491 IUnknown* QzAtlComPtrAssign(IUnknown** pp, IUnknown* lp);
492 
493 template <class T>
494 class QzCComPtr
495 {
496 public:
497 	typedef T _PtrClass;
QzCComPtr()498 	QzCComPtr() {p=NULL;}
QzCComPtr(T * lp)499 	QzCComPtr(T* lp)
500 	{
501 		if ((p = lp) != NULL)
502 			p->AddRef();
503 	}
QzCComPtr(const QzCComPtr<T> & lp)504 	QzCComPtr(const QzCComPtr<T>& lp)
505 	{
506 		if ((p = lp.p) != NULL)
507 			p->AddRef();
508 	}
~QzCComPtr()509 	~QzCComPtr() {if (p) p->Release();}
Release()510 	void Release() {if (p) p->Release(); p=NULL;}
511 	operator T*() {return (T*)p;}
512 	T& operator*() {ASSERT(p!=NULL); return *p; }
513 	//The assert on operator& usually indicates a bug.  If this is really
514 	//what is needed, however, take the address of the p member explicitly.
515 	T** operator&() { ASSERT(p==NULL); return &p; }
516 	T* operator->() { ASSERT(p!=NULL); return p; }
517 	T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);}
518 	T* operator=(const QzCComPtr<T>& lp)
519 	{
520 		return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p);
521 	}
522 #if _MSC_VER>1020
523 	bool operator!(){return (p == NULL);}
524 #else
525 	BOOL operator!(){return (p == NULL) ? TRUE : FALSE;}
526 #endif
527 	T* p;
528 };
529 
530 MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent );
531 bool TimeKillSynchronousFlagAvailable( void );
532 
533 #endif /* __WXUTIL__ */
534