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