forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			771 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			771 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | //------------------------------------------------------------------------------
 | ||
|  | // File: WXUtil.cpp
 | ||
|  | //
 | ||
|  | // Desc: DirectShow base classes - implements helper classes for building
 | ||
|  | //       multimedia filters.
 | ||
|  | //
 | ||
|  | // Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
 | ||
|  | //------------------------------------------------------------------------------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #include <streams.h>
 | ||
|  | #define STRSAFE_NO_DEPRECATE
 | ||
|  | #include <strsafe.h>
 | ||
|  | 
 | ||
|  | #pragma warning(disable: 4996)
 | ||
|  | 
 | ||
|  | // --- CAMEvent -----------------------
 | ||
|  | CAMEvent::CAMEvent(BOOL fManualReset, __inout_opt HRESULT *phr) | ||
|  | { | ||
|  |     m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL); | ||
|  |     if (NULL == m_hEvent) { | ||
|  |         if (NULL != phr && SUCCEEDED(*phr)) { | ||
|  |             *phr = E_OUTOFMEMORY; | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | CAMEvent::CAMEvent(__inout_opt HRESULT *phr) | ||
|  | { | ||
|  |     m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | ||
|  |     if (NULL == m_hEvent) { | ||
|  |         if (NULL != phr && SUCCEEDED(*phr)) { | ||
|  |             *phr = E_OUTOFMEMORY; | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | CAMEvent::~CAMEvent() | ||
|  | { | ||
|  |     if (m_hEvent) { | ||
|  | 	EXECUTE_ASSERT(CloseHandle(m_hEvent)); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // --- CAMMsgEvent -----------------------
 | ||
|  | // One routine.  The rest is handled in CAMEvent
 | ||
|  | 
 | ||
|  | CAMMsgEvent::CAMMsgEvent(__inout_opt HRESULT *phr) : CAMEvent(FALSE, phr) | ||
|  | { | ||
|  | } | ||
|  | 
 | ||
|  | BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout) | ||
|  | { | ||
|  |     // wait for the event to be signalled, or for the
 | ||
|  |     // timeout (in MS) to expire.  allow SENT messages
 | ||
|  |     // to be processed while we wait
 | ||
|  |     DWORD dwWait; | ||
|  |     DWORD dwStartTime; | ||
|  | 
 | ||
|  |     // set the waiting period.
 | ||
|  |     DWORD dwWaitTime = dwTimeout; | ||
|  | 
 | ||
|  |     // the timeout will eventually run down as we iterate
 | ||
|  |     // processing messages.  grab the start time so that
 | ||
|  |     // we can calculate elapsed times.
 | ||
|  |     if (dwWaitTime != INFINITE) { | ||
|  |         dwStartTime = timeGetTime(); | ||
|  |     } | ||
|  | 
 | ||
|  |     do { | ||
|  |         dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE); | ||
|  |         if (dwWait == WAIT_OBJECT_0 + 1) { | ||
|  | 	    MSG Message; | ||
|  |             PeekMessage(&Message,NULL,0,0,PM_NOREMOVE); | ||
|  | 
 | ||
|  | 	    // If we have an explicit length of time to wait calculate
 | ||
|  | 	    // the next wake up point - which might be now.
 | ||
|  | 	    // If dwTimeout is INFINITE, it stays INFINITE
 | ||
|  | 	    if (dwWaitTime != INFINITE) { | ||
|  | 
 | ||
|  | 		DWORD dwElapsed = timeGetTime()-dwStartTime; | ||
|  | 
 | ||
|  | 		dwWaitTime = | ||
|  | 		    (dwElapsed >= dwTimeout) | ||
|  | 			? 0  // wake up with WAIT_TIMEOUT
 | ||
|  | 			: dwTimeout-dwElapsed; | ||
|  | 	    } | ||
|  |         } | ||
|  |     } while (dwWait == WAIT_OBJECT_0 + 1); | ||
|  | 
 | ||
|  |     // return TRUE if we woke on the event handle,
 | ||
|  |     //        FALSE if we timed out.
 | ||
|  |     return (dwWait == WAIT_OBJECT_0); | ||
|  | } | ||
|  | 
 | ||
|  | // --- CAMThread ----------------------
 | ||
|  | 
 | ||
|  | 
 | ||
|  | CAMThread::CAMThread(__inout_opt HRESULT *phr) | ||
|  |     : m_EventSend(TRUE, phr),     // must be manual-reset for CheckRequest()
 | ||
|  |       m_EventComplete(FALSE, phr) | ||
|  | { | ||
|  |     m_hThread = NULL; | ||
|  | } | ||
|  | 
 | ||
|  | CAMThread::~CAMThread() { | ||
|  |     Close(); | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // when the thread starts, it calls this function. We unwrap the 'this'
 | ||
|  | //pointer and call ThreadProc.
 | ||
|  | DWORD WINAPI | ||
|  | CAMThread::InitialThreadProc(__inout LPVOID pv) | ||
|  | { | ||
|  |     HRESULT hrCoInit = CAMThread::CoInitializeHelper(); | ||
|  |     if(FAILED(hrCoInit)) { | ||
|  |         DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed."))); | ||
|  |     } | ||
|  | 
 | ||
|  |     CAMThread * pThread = (CAMThread *) pv; | ||
|  | 
 | ||
|  |     HRESULT hr = pThread->ThreadProc(); | ||
|  | 
 | ||
|  |     if(SUCCEEDED(hrCoInit)) { | ||
|  |         CoUninitialize(); | ||
|  |     } | ||
|  | 
 | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL | ||
|  | CAMThread::Create() | ||
|  | { | ||
|  |     DWORD threadid; | ||
|  | 
 | ||
|  |     CAutoLock lock(&m_AccessLock); | ||
|  | 
 | ||
|  |     if (ThreadExists()) { | ||
|  | 	return FALSE; | ||
|  |     } | ||
|  | 
 | ||
|  |     m_hThread = CreateThread( | ||
|  | 		    NULL, | ||
|  | 		    0, | ||
|  | 		    CAMThread::InitialThreadProc, | ||
|  | 		    this, | ||
|  | 		    0, | ||
|  | 		    &threadid); | ||
|  | 
 | ||
|  |     if (!m_hThread) { | ||
|  | 	return FALSE; | ||
|  |     } | ||
|  | 
 | ||
|  |     return TRUE; | ||
|  | } | ||
|  | 
 | ||
|  | DWORD | ||
|  | CAMThread::CallWorker(DWORD dwParam) | ||
|  | { | ||
|  |     // lock access to the worker thread for scope of this object
 | ||
|  |     CAutoLock lock(&m_AccessLock); | ||
|  | 
 | ||
|  |     if (!ThreadExists()) { | ||
|  | 	return (DWORD) E_FAIL; | ||
|  |     } | ||
|  | 
 | ||
|  |     // set the parameter
 | ||
|  |     m_dwParam = dwParam; | ||
|  | 
 | ||
|  |     // signal the worker thread
 | ||
|  |     m_EventSend.Set(); | ||
|  | 
 | ||
|  |     // wait for the completion to be signalled
 | ||
|  |     m_EventComplete.Wait(); | ||
|  | 
 | ||
|  |     // done - this is the thread's return value
 | ||
|  |     return m_dwReturnVal; | ||
|  | } | ||
|  | 
 | ||
|  | // Wait for a request from the client
 | ||
|  | DWORD | ||
|  | CAMThread::GetRequest() | ||
|  | { | ||
|  |     m_EventSend.Wait(); | ||
|  |     return m_dwParam; | ||
|  | } | ||
|  | 
 | ||
|  | // is there a request?
 | ||
|  | BOOL | ||
|  | CAMThread::CheckRequest(__out_opt DWORD * pParam) | ||
|  | { | ||
|  |     if (!m_EventSend.Check()) { | ||
|  | 	return FALSE; | ||
|  |     } else { | ||
|  | 	if (pParam) { | ||
|  | 	    *pParam = m_dwParam; | ||
|  | 	} | ||
|  | 	return TRUE; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | // reply to the request
 | ||
|  | void | ||
|  | CAMThread::Reply(DWORD dw) | ||
|  | { | ||
|  |     m_dwReturnVal = dw; | ||
|  | 
 | ||
|  |     // The request is now complete so CheckRequest should fail from
 | ||
|  |     // now on
 | ||
|  |     //
 | ||
|  |     // This event should be reset BEFORE we signal the client or
 | ||
|  |     // the client may Set it before we reset it and we'll then
 | ||
|  |     // reset it (!)
 | ||
|  | 
 | ||
|  |     m_EventSend.Reset(); | ||
|  | 
 | ||
|  |     // Tell the client we're finished
 | ||
|  | 
 | ||
|  |     m_EventComplete.Set(); | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT CAMThread::CoInitializeHelper() | ||
|  | { | ||
|  |     // call CoInitializeEx and tell OLE not to create a window (this
 | ||
|  |     // thread probably won't dispatch messages and will hang on
 | ||
|  |     // broadcast msgs o/w).
 | ||
|  |     //
 | ||
|  |     // If CoInitEx is not available, threads that don't call CoCreate
 | ||
|  |     // aren't affected. Threads that do will have to handle the
 | ||
|  |     // failure. Perhaps we should fall back to CoInitialize and risk
 | ||
|  |     // hanging?
 | ||
|  |     //
 | ||
|  | 
 | ||
|  |     // older versions of ole32.dll don't have CoInitializeEx
 | ||
|  | 
 | ||
|  |     HRESULT hr = E_FAIL; | ||
|  |     HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll")); | ||
|  |     if(hOle) | ||
|  |     { | ||
|  |         typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)( | ||
|  |             LPVOID pvReserved, DWORD dwCoInit); | ||
|  |         PCoInitializeEx pCoInitializeEx = | ||
|  |             (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx")); | ||
|  |         if(pCoInitializeEx) | ||
|  |         { | ||
|  |             hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE ); | ||
|  |         } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         // caller must load ole32.dll
 | ||
|  |         DbgBreak("couldn't locate ole32.dll"); | ||
|  |     } | ||
|  | 
 | ||
|  |     return hr; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // destructor for CMsgThread  - cleans up any messages left in the
 | ||
|  | // queue when the thread exited
 | ||
|  | CMsgThread::~CMsgThread() | ||
|  | { | ||
|  |     if (m_hThread != NULL) { | ||
|  |         WaitForSingleObject(m_hThread, INFINITE); | ||
|  |         EXECUTE_ASSERT(CloseHandle(m_hThread)); | ||
|  |     } | ||
|  | 
 | ||
|  |     POSITION pos = m_ThreadQueue.GetHeadPosition(); | ||
|  |     while (pos) { | ||
|  |         CMsg * pMsg = m_ThreadQueue.GetNext(pos); | ||
|  |         delete pMsg; | ||
|  |     } | ||
|  |     m_ThreadQueue.RemoveAll(); | ||
|  | 
 | ||
|  |     if (m_hSem != NULL) { | ||
|  |         EXECUTE_ASSERT(CloseHandle(m_hSem)); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | BOOL | ||
|  | CMsgThread::CreateThread( | ||
|  |     ) | ||
|  | { | ||
|  |     m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL); | ||
|  |     if (m_hSem == NULL) { | ||
|  |         return FALSE; | ||
|  |     } | ||
|  | 
 | ||
|  |     m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc, | ||
|  | 			       (LPVOID)this, 0, &m_ThreadId); | ||
|  |     return m_hThread != NULL; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // This is the threads message pump.  Here we get and dispatch messages to
 | ||
|  | // clients thread proc until the client refuses to process a message.
 | ||
|  | // The client returns a non-zero value to stop the message pump, this
 | ||
|  | // value becomes the threads exit code.
 | ||
|  | 
 | ||
|  | DWORD WINAPI | ||
|  | CMsgThread::DefaultThreadProc( | ||
|  |     __inout LPVOID lpParam | ||
|  |     ) | ||
|  | { | ||
|  |     CMsgThread *lpThis = (CMsgThread *)lpParam; | ||
|  |     CMsg msg; | ||
|  |     LRESULT lResult; | ||
|  | 
 | ||
|  |     // !!!
 | ||
|  |     CoInitialize(NULL); | ||
|  | 
 | ||
|  |     // allow a derived class to handle thread startup
 | ||
|  |     lpThis->OnThreadInit(); | ||
|  | 
 | ||
|  |     do { | ||
|  | 	lpThis->GetThreadMsg(&msg); | ||
|  | 	lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags, | ||
|  | 					    msg.lpParam, msg.pEvent); | ||
|  |     } while (lResult == 0L); | ||
|  | 
 | ||
|  |     // !!!
 | ||
|  |     CoUninitialize(); | ||
|  | 
 | ||
|  |     return (DWORD)lResult; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // Block until the next message is placed on the list m_ThreadQueue.
 | ||
|  | // copies the message to the message pointed to by *pmsg
 | ||
|  | void | ||
|  | CMsgThread::GetThreadMsg(__out CMsg *msg) | ||
|  | { | ||
|  |     CMsg * pmsg = NULL; | ||
|  | 
 | ||
|  |     // keep trying until a message appears
 | ||
|  |     while (TRUE) { | ||
|  |         { | ||
|  |             CAutoLock lck(&m_Lock); | ||
|  |             pmsg = m_ThreadQueue.RemoveHead(); | ||
|  |             if (pmsg == NULL) { | ||
|  |                 m_lWaiting++; | ||
|  |             } else { | ||
|  |                 break; | ||
|  |             } | ||
|  |         } | ||
|  |         // the semaphore will be signalled when it is non-empty
 | ||
|  |         WaitForSingleObject(m_hSem, INFINITE); | ||
|  |     } | ||
|  |     // copy fields to caller's CMsg
 | ||
|  |     *msg = *pmsg; | ||
|  | 
 | ||
|  |     // this CMsg was allocated by the 'new' in PutThreadMsg
 | ||
|  |     delete pmsg; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | // Helper function - convert int to WSTR
 | ||
|  | void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr) | ||
|  | { | ||
|  | #ifdef UNICODE
 | ||
|  |     if (FAILED(StringCchPrintf(wstr, 12, L"%d", i))) { | ||
|  |         wstr[0] = 0; | ||
|  |     } | ||
|  | #else
 | ||
|  |     TCHAR temp[12]; | ||
|  |     if (FAILED(StringCchPrintf(temp, NUMELMS(temp), "%d", i))) { | ||
|  |         wstr[0] = 0; | ||
|  |     } else { | ||
|  |         MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, 12); | ||
|  |     } | ||
|  | #endif
 | ||
|  | } // IntToWstr
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #define MEMORY_ALIGNMENT        4
 | ||
|  | #define MEMORY_ALIGNMENT_LOG2   2
 | ||
|  | #define MEMORY_ALIGNMENT_MASK   MEMORY_ALIGNMENT - 1
 | ||
|  | 
 | ||
|  | void * __stdcall memmoveInternal(void * dst, const void * src, size_t count) | ||
|  | { | ||
|  |     void * ret = dst; | ||
|  | 
 | ||
|  | #ifdef _X86_
 | ||
|  |     if (dst <= src || (char *)dst >= ((char *)src + count)) { | ||
|  | 
 | ||
|  |         /*
 | ||
|  |          * Non-Overlapping Buffers | ||
|  |          * copy from lower addresses to higher addresses | ||
|  |          */ | ||
|  |         _asm { | ||
|  |             mov     esi,src | ||
|  |             mov     edi,dst | ||
|  |             mov     ecx,count | ||
|  |             cld | ||
|  |             mov     edx,ecx | ||
|  |             and     edx,MEMORY_ALIGNMENT_MASK | ||
|  |             shr     ecx,MEMORY_ALIGNMENT_LOG2 | ||
|  |             rep     movsd | ||
|  |             or      ecx,edx | ||
|  |             jz      memmove_done | ||
|  |             rep     movsb | ||
|  | memmove_done: | ||
|  |         } | ||
|  |     } | ||
|  |     else { | ||
|  | 
 | ||
|  |         /*
 | ||
|  |          * Overlapping Buffers | ||
|  |          * copy from higher addresses to lower addresses | ||
|  |          */ | ||
|  |         _asm { | ||
|  |             mov     esi,src | ||
|  |             mov     edi,dst | ||
|  |             mov     ecx,count | ||
|  |             std | ||
|  |             add     esi,ecx | ||
|  |             add     edi,ecx | ||
|  |             dec     esi | ||
|  |             dec     edi | ||
|  |             rep     movsb | ||
|  |             cld | ||
|  |         } | ||
|  |     } | ||
|  | #else
 | ||
|  |     MoveMemory(dst, src, count); | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     return ret; | ||
|  | } | ||
|  | 
 | ||
|  | 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) | ||
|  | { | ||
|  |     // prevent read overruns
 | ||
|  |     if( count + cb_src_offset < count ||   // prevent integer overflow
 | ||
|  |         count + cb_src_offset > src_size)  // prevent read overrun
 | ||
|  |     { | ||
|  |         return E_INVALIDARG; | ||
|  |     } | ||
|  | 
 | ||
|  |     // prevent write overruns
 | ||
|  |     if( count + cb_dst_offset < count ||   // prevent integer overflow
 | ||
|  |         count + cb_dst_offset > dst_size)  // prevent write overrun
 | ||
|  |     { | ||
|  |         return E_INVALIDARG; | ||
|  |     } | ||
|  | 
 | ||
|  |     memmoveInternal( (BYTE *)dst+cb_dst_offset, (BYTE *)src+cb_src_offset, count); | ||
|  |     return S_OK; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifdef DEBUG
 | ||
|  | /******************************Public*Routine******************************\
 | ||
|  | * Debug CCritSec helpers | ||
|  | * | ||
|  | * We provide debug versions of the Constructor, destructor, Lock and Unlock | ||
|  | * routines.  The debug code tracks who owns each critical section by | ||
|  | * maintaining a depth count. | ||
|  | * | ||
|  | * History: | ||
|  | * | ||
|  | \**************************************************************************/ | ||
|  | 
 | ||
|  | CCritSec::CCritSec() | ||
|  | { | ||
|  |     InitializeCriticalSection(&m_CritSec); | ||
|  |     m_currentOwner = m_lockCount = 0; | ||
|  |     m_fTrace = FALSE; | ||
|  | } | ||
|  | 
 | ||
|  | CCritSec::~CCritSec() | ||
|  | { | ||
|  |     DeleteCriticalSection(&m_CritSec); | ||
|  | } | ||
|  | 
 | ||
|  | void CCritSec::Lock() | ||
|  | { | ||
|  |     UINT tracelevel=3; | ||
|  |     DWORD us = GetCurrentThreadId(); | ||
|  |     DWORD currentOwner = m_currentOwner; | ||
|  |     if (currentOwner && (currentOwner != us)) { | ||
|  |         // already owned, but not by us
 | ||
|  |         if (m_fTrace) { | ||
|  |             DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"), | ||
|  |                 GetCurrentThreadId(), &m_CritSec, currentOwner)); | ||
|  |             tracelevel=2; | ||
|  | 	        // if we saw the message about waiting for the critical
 | ||
|  | 	        // section we ensure we see the message when we get the
 | ||
|  | 	        // critical section
 | ||
|  |         } | ||
|  |     } | ||
|  |     EnterCriticalSection(&m_CritSec); | ||
|  |     if (0 == m_lockCount++) { | ||
|  |         // we now own it for the first time.  Set owner information
 | ||
|  |         m_currentOwner = us; | ||
|  | 
 | ||
|  |         if (m_fTrace) { | ||
|  |             DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec)); | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | void CCritSec::Unlock() { | ||
|  |     if (0 == --m_lockCount) { | ||
|  |         // about to be unowned
 | ||
|  |         if (m_fTrace) { | ||
|  |             DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec)); | ||
|  |         } | ||
|  | 
 | ||
|  |         m_currentOwner = 0; | ||
|  |     } | ||
|  |     LeaveCriticalSection(&m_CritSec); | ||
|  | } | ||
|  | 
 | ||
|  | void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace) | ||
|  | { | ||
|  |     pcCrit->m_fTrace = fTrace; | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI CritCheckIn(CCritSec * pcCrit) | ||
|  | { | ||
|  |     return (GetCurrentThreadId() == pcCrit->m_currentOwner); | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI CritCheckIn(const CCritSec * pcCrit) | ||
|  | { | ||
|  |     return (GetCurrentThreadId() == pcCrit->m_currentOwner); | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI CritCheckOut(CCritSec * pcCrit) | ||
|  | { | ||
|  |     return (GetCurrentThreadId() != pcCrit->m_currentOwner); | ||
|  | } | ||
|  | 
 | ||
|  | BOOL WINAPI CritCheckOut(const CCritSec * pcCrit) | ||
|  | { | ||
|  |     return (GetCurrentThreadId() != pcCrit->m_currentOwner); | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 | ||
|  | 
 | ||
|  | STDAPI WriteBSTR(__deref_out BSTR *pstrDest, LPCWSTR szSrc) | ||
|  | { | ||
|  |     *pstrDest = SysAllocString( szSrc ); | ||
|  |     if( !(*pstrDest) ) return E_OUTOFMEMORY; | ||
|  |     return NOERROR; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | STDAPI FreeBSTR(__deref_in BSTR* pstr) | ||
|  | { | ||
|  |     if( (PVOID)*pstr == NULL ) return S_FALSE; | ||
|  |     SysFreeString( *pstr ); | ||
|  |     return NOERROR; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | // 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 psz, __deref_out LPWSTR *ppszReturn) | ||
|  | { | ||
|  |     CheckPointer(ppszReturn, E_POINTER); | ||
|  |     ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR)); | ||
|  |     *ppszReturn = NULL; | ||
|  |     size_t nameLen; | ||
|  |     HRESULT hr = StringCbLengthW(psz, 100000, &nameLen); | ||
|  |     if (FAILED(hr)) { | ||
|  |         return hr; | ||
|  |     } | ||
|  |     *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen + sizeof(WCHAR)); | ||
|  |     if (*ppszReturn == NULL) { | ||
|  |        return E_OUTOFMEMORY; | ||
|  |     } | ||
|  |     CopyMemory(*ppszReturn, psz, nameLen + sizeof(WCHAR)); | ||
|  |     return NOERROR; | ||
|  | } | ||
|  | 
 | ||
|  | // Waits for the HANDLE hObject.  While waiting messages sent
 | ||
|  | // to windows on our thread by SendMessage will be processed.
 | ||
|  | // Using this function to do waits and mutual exclusion
 | ||
|  | // avoids some deadlocks in objects with windows.
 | ||
|  | // Return codes are the same as for WaitForSingleObject
 | ||
|  | DWORD WINAPI WaitDispatchingMessages( | ||
|  |     HANDLE hObject, | ||
|  |     DWORD dwWait, | ||
|  |     HWND hwnd, | ||
|  |     UINT uMsg, | ||
|  |     HANDLE hEvent) | ||
|  | { | ||
|  |     BOOL bPeeked = FALSE; | ||
|  |     DWORD dwResult; | ||
|  |     DWORD dwStart; | ||
|  |     DWORD dwThreadPriority; | ||
|  | 
 | ||
|  |     static UINT uMsgId = 0; | ||
|  | 
 | ||
|  |     HANDLE hObjects[2] = { hObject, hEvent }; | ||
|  |     if (dwWait != INFINITE && dwWait != 0) { | ||
|  |         dwStart = GetTickCount(); | ||
|  |     } | ||
|  |     for (; ; ) { | ||
|  |         DWORD nCount = NULL != hEvent ? 2 : 1; | ||
|  | 
 | ||
|  |         //  Minimize the chance of actually dispatching any messages
 | ||
|  |         //  by seeing if we can lock immediately.
 | ||
|  |         dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0); | ||
|  |         if (dwResult < WAIT_OBJECT_0 + nCount) { | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         DWORD dwTimeOut = dwWait; | ||
|  |         if (dwTimeOut > 10) { | ||
|  |             dwTimeOut = 10; | ||
|  |         } | ||
|  |         dwResult = MsgWaitForMultipleObjects( | ||
|  |                              nCount, | ||
|  |                              hObjects, | ||
|  |                              FALSE, | ||
|  |                              dwTimeOut, | ||
|  |                              hwnd == NULL ? QS_SENDMESSAGE : | ||
|  |                                             QS_SENDMESSAGE + QS_POSTMESSAGE); | ||
|  |         if (dwResult == WAIT_OBJECT_0 + nCount || | ||
|  |             dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) { | ||
|  |             MSG msg; | ||
|  |             if (hwnd != NULL) { | ||
|  |                 while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) { | ||
|  |                     DispatchMessage(&msg); | ||
|  |                 } | ||
|  |             } | ||
|  |             // Do this anyway - the previous peek doesn't flush out the
 | ||
|  |             // messages
 | ||
|  |             PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); | ||
|  | 
 | ||
|  |             if (dwWait != INFINITE && dwWait != 0) { | ||
|  |                 DWORD dwNow = GetTickCount(); | ||
|  | 
 | ||
|  |                 // Working with differences handles wrap-around
 | ||
|  |                 DWORD dwDiff = dwNow - dwStart; | ||
|  |                 if (dwDiff > dwWait) { | ||
|  |                     dwWait = 0; | ||
|  |                 } else { | ||
|  |                     dwWait -= dwDiff; | ||
|  |                 } | ||
|  |                 dwStart = dwNow; | ||
|  |             } | ||
|  |             if (!bPeeked) { | ||
|  |                 //  Raise our priority to prevent our message queue
 | ||
|  |                 //  building up
 | ||
|  |                 dwThreadPriority = GetThreadPriority(GetCurrentThread()); | ||
|  |                 if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) { | ||
|  |                     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); | ||
|  |                 } | ||
|  |                 bPeeked = TRUE; | ||
|  |             } | ||
|  |         } else { | ||
|  |             break; | ||
|  |         } | ||
|  |     } | ||
|  |     if (bPeeked) { | ||
|  |         SetThreadPriority(GetCurrentThread(), dwThreadPriority); | ||
|  |         if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) { | ||
|  |             if (uMsgId == 0) { | ||
|  |                 uMsgId = RegisterWindowMessage(TEXT("AMUnblock")); | ||
|  |             } | ||
|  |             if (uMsgId != 0) { | ||
|  |                 MSG msg; | ||
|  |                 //  Remove old ones
 | ||
|  |                 while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) { | ||
|  |                 } | ||
|  |             } | ||
|  |             PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0); | ||
|  |         } | ||
|  |     } | ||
|  |     return dwResult; | ||
|  | } | ||
|  | 
 | ||
|  | HRESULT AmGetLastErrorToHResult() | ||
|  | { | ||
|  |     DWORD dwLastError = GetLastError(); | ||
|  |     if(dwLastError != 0) | ||
|  |     { | ||
|  |         return HRESULT_FROM_WIN32(dwLastError); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         return E_FAIL; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp) | ||
|  | { | ||
|  |     if (lp != NULL) | ||
|  |         lp->AddRef(); | ||
|  |     if (*pp) | ||
|  |         (*pp)->Release(); | ||
|  |     *pp = lp; | ||
|  |     return lp; | ||
|  | } | ||
|  | 
 | ||
|  | /******************************************************************************
 | ||
|  | 
 | ||
|  | CompatibleTimeSetEvent | ||
|  | 
 | ||
|  |     CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling | ||
|  | timeSetEvent() if the current operating system supports it.  TIME_KILL_SYNCHRONOUS | ||
|  | is supported on Windows XP and later operating systems. | ||
|  | 
 | ||
|  | Parameters: | ||
|  | - The same parameters as timeSetEvent().  See timeSetEvent()'s documentation in  | ||
|  | the Platform SDK for more information. | ||
|  | 
 | ||
|  | Return Value: | ||
|  | - The same return value as timeSetEvent().  See timeSetEvent()'s documentation in  | ||
|  | the Platform SDK for more information. | ||
|  | 
 | ||
|  | ******************************************************************************/ | ||
|  | MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent ) | ||
|  | { | ||
|  |     #if WINVER >= 0x0501
 | ||
|  |     { | ||
|  |         static bool fCheckedVersion = false; | ||
|  |         static bool fTimeKillSynchronousFlagAvailable = false;  | ||
|  | 
 | ||
|  |         if( !fCheckedVersion ) { | ||
|  |             fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable(); | ||
|  |             fCheckedVersion = true; | ||
|  |         } | ||
|  | 
 | ||
|  |         if( fTimeKillSynchronousFlagAvailable ) { | ||
|  |             fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS; | ||
|  |         } | ||
|  |     } | ||
|  |     #endif // WINVER >= 0x0501
 | ||
|  | 
 | ||
|  |     return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent ); | ||
|  | } | ||
|  | 
 | ||
|  | bool TimeKillSynchronousFlagAvailable( void ) | ||
|  | { | ||
|  |     OSVERSIONINFO osverinfo; | ||
|  | 
 | ||
|  |     osverinfo.dwOSVersionInfoSize = sizeof(osverinfo); | ||
|  | 
 | ||
|  |     if( GetVersionEx( &osverinfo ) ) { | ||
|  |          | ||
|  |         // Windows XP's major version is 5 and its' minor version is 1.
 | ||
|  |         // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag
 | ||
|  |         // in Windows XP.
 | ||
|  |         if( (osverinfo.dwMajorVersion > 5) ||  | ||
|  |             ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) { | ||
|  |             return true; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return false; | ||
|  | } | ||
|  | 
 | ||
|  | 
 |