wxutil.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. //------------------------------------------------------------------------------
  2. // File: WXUtil.cpp
  3. //
  4. // Desc: DirectShow base classes - implements helper classes for building
  5. // multimedia filters.
  6. //
  7. // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
  8. //------------------------------------------------------------------------------
  9. #include <pjmedia-videodev/config.h>
  10. #if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
  11. #include <streams.h>
  12. #define STRSAFE_NO_DEPRECATE
  13. #include <strsafe.h>
  14. // --- CAMEvent -----------------------
  15. CAMEvent::CAMEvent(BOOL fManualReset, __inout_opt HRESULT *phr)
  16. {
  17. m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL);
  18. if (NULL == m_hEvent) {
  19. if (NULL != phr && SUCCEEDED(*phr)) {
  20. *phr = E_OUTOFMEMORY;
  21. }
  22. }
  23. }
  24. CAMEvent::CAMEvent(__inout_opt HRESULT *phr)
  25. {
  26. m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  27. if (NULL == m_hEvent) {
  28. if (NULL != phr && SUCCEEDED(*phr)) {
  29. *phr = E_OUTOFMEMORY;
  30. }
  31. }
  32. }
  33. CAMEvent::~CAMEvent()
  34. {
  35. if (m_hEvent) {
  36. EXECUTE_ASSERT(CloseHandle(m_hEvent));
  37. }
  38. }
  39. // --- CAMMsgEvent -----------------------
  40. // One routine. The rest is handled in CAMEvent
  41. CAMMsgEvent::CAMMsgEvent(__inout_opt HRESULT *phr) : CAMEvent(FALSE, phr)
  42. {
  43. }
  44. BOOL CAMMsgEvent::WaitMsg(DWORD dwTimeout)
  45. {
  46. // wait for the event to be signalled, or for the
  47. // timeout (in MS) to expire. allow SENT messages
  48. // to be processed while we wait
  49. DWORD dwWait;
  50. DWORD dwStartTime = 0;
  51. // set the waiting period.
  52. DWORD dwWaitTime = dwTimeout;
  53. // the timeout will eventually run down as we iterate
  54. // processing messages. grab the start time so that
  55. // we can calculate elapsed times.
  56. if (dwWaitTime != INFINITE) {
  57. dwStartTime = timeGetTime();
  58. }
  59. do {
  60. dwWait = MsgWaitForMultipleObjects(1,&m_hEvent,FALSE, dwWaitTime, QS_SENDMESSAGE);
  61. if (dwWait == WAIT_OBJECT_0 + 1) {
  62. MSG Message;
  63. PeekMessage(&Message,NULL,0,0,PM_NOREMOVE);
  64. // If we have an explicit length of time to wait calculate
  65. // the next wake up point - which might be now.
  66. // If dwTimeout is INFINITE, it stays INFINITE
  67. if (dwWaitTime != INFINITE) {
  68. DWORD dwElapsed = timeGetTime()-dwStartTime;
  69. dwWaitTime =
  70. (dwElapsed >= dwTimeout)
  71. ? 0 // wake up with WAIT_TIMEOUT
  72. : dwTimeout-dwElapsed;
  73. }
  74. }
  75. } while (dwWait == WAIT_OBJECT_0 + 1);
  76. // return TRUE if we woke on the event handle,
  77. // FALSE if we timed out.
  78. return (dwWait == WAIT_OBJECT_0);
  79. }
  80. // --- CAMThread ----------------------
  81. CAMThread::CAMThread(__inout_opt HRESULT *phr)
  82. : m_EventSend(TRUE, phr), // must be manual-reset for CheckRequest()
  83. m_EventComplete(FALSE, phr)
  84. {
  85. m_hThread = NULL;
  86. }
  87. CAMThread::~CAMThread() {
  88. Close();
  89. }
  90. // when the thread starts, it calls this function. We unwrap the 'this'
  91. //pointer and call ThreadProc.
  92. DWORD WINAPI
  93. CAMThread::InitialThreadProc(__inout LPVOID pv)
  94. {
  95. HRESULT hrCoInit = CAMThread::CoInitializeHelper();
  96. if(FAILED(hrCoInit)) {
  97. DbgLog((LOG_ERROR, 1, TEXT("CoInitializeEx failed.")));
  98. }
  99. CAMThread * pThread = (CAMThread *) pv;
  100. HRESULT hr = pThread->ThreadProc();
  101. if(SUCCEEDED(hrCoInit)) {
  102. CoUninitialize();
  103. }
  104. return hr;
  105. }
  106. BOOL
  107. CAMThread::Create()
  108. {
  109. DWORD threadid;
  110. CAutoLock lock(&m_AccessLock);
  111. if (ThreadExists()) {
  112. return FALSE;
  113. }
  114. m_hThread = CreateThread(
  115. NULL,
  116. 0,
  117. CAMThread::InitialThreadProc,
  118. this,
  119. 0,
  120. &threadid);
  121. if (!m_hThread) {
  122. return FALSE;
  123. }
  124. return TRUE;
  125. }
  126. DWORD
  127. CAMThread::CallWorker(DWORD dwParam)
  128. {
  129. // lock access to the worker thread for scope of this object
  130. CAutoLock lock(&m_AccessLock);
  131. if (!ThreadExists()) {
  132. return (DWORD) E_FAIL;
  133. }
  134. // set the parameter
  135. m_dwParam = dwParam;
  136. // signal the worker thread
  137. m_EventSend.Set();
  138. // wait for the completion to be signalled
  139. m_EventComplete.Wait();
  140. // done - this is the thread's return value
  141. return m_dwReturnVal;
  142. }
  143. // Wait for a request from the client
  144. DWORD
  145. CAMThread::GetRequest()
  146. {
  147. m_EventSend.Wait();
  148. return m_dwParam;
  149. }
  150. // is there a request?
  151. BOOL
  152. CAMThread::CheckRequest(__out_opt DWORD * pParam)
  153. {
  154. if (!m_EventSend.Check()) {
  155. return FALSE;
  156. } else {
  157. if (pParam) {
  158. *pParam = m_dwParam;
  159. }
  160. return TRUE;
  161. }
  162. }
  163. // reply to the request
  164. void
  165. CAMThread::Reply(DWORD dw)
  166. {
  167. m_dwReturnVal = dw;
  168. // The request is now complete so CheckRequest should fail from
  169. // now on
  170. //
  171. // This event should be reset BEFORE we signal the client or
  172. // the client may Set it before we reset it and we'll then
  173. // reset it (!)
  174. m_EventSend.Reset();
  175. // Tell the client we're finished
  176. m_EventComplete.Set();
  177. }
  178. HRESULT CAMThread::CoInitializeHelper()
  179. {
  180. // call CoInitializeEx and tell OLE not to create a window (this
  181. // thread probably won't dispatch messages and will hang on
  182. // broadcast msgs o/w).
  183. //
  184. // If CoInitEx is not available, threads that don't call CoCreate
  185. // aren't affected. Threads that do will have to handle the
  186. // failure. Perhaps we should fall back to CoInitialize and risk
  187. // hanging?
  188. //
  189. // older versions of ole32.dll don't have CoInitializeEx
  190. HRESULT hr = E_FAIL;
  191. HINSTANCE hOle = GetModuleHandle(TEXT("ole32.dll"));
  192. if(hOle)
  193. {
  194. typedef HRESULT (STDAPICALLTYPE *PCoInitializeEx)(
  195. LPVOID pvReserved, DWORD dwCoInit);
  196. PCoInitializeEx pCoInitializeEx =
  197. (PCoInitializeEx)(GetProcAddress(hOle, "CoInitializeEx"));
  198. if(pCoInitializeEx)
  199. {
  200. hr = (*pCoInitializeEx)(0, COINIT_DISABLE_OLE1DDE );
  201. }
  202. }
  203. else
  204. {
  205. // caller must load ole32.dll
  206. DbgBreak("couldn't locate ole32.dll");
  207. }
  208. return hr;
  209. }
  210. // destructor for CMsgThread - cleans up any messages left in the
  211. // queue when the thread exited
  212. CMsgThread::~CMsgThread()
  213. {
  214. if (m_hThread != NULL) {
  215. WaitForSingleObject(m_hThread, INFINITE);
  216. EXECUTE_ASSERT(CloseHandle(m_hThread));
  217. }
  218. POSITION pos = m_ThreadQueue.GetHeadPosition();
  219. while (pos) {
  220. CMsg * pMsg = m_ThreadQueue.GetNext(pos);
  221. delete pMsg;
  222. }
  223. m_ThreadQueue.RemoveAll();
  224. if (m_hSem != NULL) {
  225. EXECUTE_ASSERT(CloseHandle(m_hSem));
  226. }
  227. }
  228. BOOL
  229. CMsgThread::CreateThread(
  230. )
  231. {
  232. m_hSem = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
  233. if (m_hSem == NULL) {
  234. return FALSE;
  235. }
  236. m_hThread = ::CreateThread(NULL, 0, DefaultThreadProc,
  237. (LPVOID)this, 0, &m_ThreadId);
  238. return m_hThread != NULL;
  239. }
  240. // This is the threads message pump. Here we get and dispatch messages to
  241. // clients thread proc until the client refuses to process a message.
  242. // The client returns a non-zero value to stop the message pump, this
  243. // value becomes the threads exit code.
  244. DWORD WINAPI
  245. CMsgThread::DefaultThreadProc(
  246. __inout LPVOID lpParam
  247. )
  248. {
  249. CMsgThread *lpThis = (CMsgThread *)lpParam;
  250. CMsg msg;
  251. LRESULT lResult;
  252. // !!!
  253. CoInitialize(NULL);
  254. // allow a derived class to handle thread startup
  255. lpThis->OnThreadInit();
  256. do {
  257. lpThis->GetThreadMsg(&msg);
  258. lResult = lpThis->ThreadMessageProc(msg.uMsg,msg.dwFlags,
  259. msg.lpParam, msg.pEvent);
  260. } while (lResult == 0L);
  261. // !!!
  262. CoUninitialize();
  263. return (DWORD)lResult;
  264. }
  265. // Block until the next message is placed on the list m_ThreadQueue.
  266. // copies the message to the message pointed to by *pmsg
  267. void
  268. CMsgThread::GetThreadMsg(__out CMsg *msg)
  269. {
  270. CMsg * pmsg = NULL;
  271. // keep trying until a message appears
  272. while (TRUE) {
  273. {
  274. CAutoLock lck(&m_Lock);
  275. pmsg = m_ThreadQueue.RemoveHead();
  276. if (pmsg == NULL) {
  277. m_lWaiting++;
  278. } else {
  279. break;
  280. }
  281. }
  282. // the semaphore will be signalled when it is non-empty
  283. WaitForSingleObject(m_hSem, INFINITE);
  284. }
  285. // copy fields to caller's CMsg
  286. *msg = *pmsg;
  287. // this CMsg was allocated by the 'new' in PutThreadMsg
  288. delete pmsg;
  289. }
  290. // Helper function - convert int to WSTR
  291. void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr)
  292. {
  293. #ifdef UNICODE
  294. if (FAILED(StringCchPrintf(wstr, 12, L"%d", i))) {
  295. wstr[0] = 0;
  296. }
  297. #else
  298. TCHAR temp[12];
  299. if (FAILED(StringCchPrintf(temp, NUMELMS(temp), "%d", i))) {
  300. wstr[0] = 0;
  301. } else {
  302. MultiByteToWideChar(CP_ACP, 0, temp, -1, wstr, 12);
  303. }
  304. #endif
  305. } // IntToWstr
  306. #define MEMORY_ALIGNMENT 4
  307. #define MEMORY_ALIGNMENT_LOG2 2
  308. #define MEMORY_ALIGNMENT_MASK MEMORY_ALIGNMENT - 1
  309. void * __stdcall memmoveInternal(void * dst, const void * src, size_t count)
  310. {
  311. void * ret = dst;
  312. #if defined(_X86_) && defined(_MSC_VER)
  313. if (dst <= src || (char *)dst >= ((char *)src + count)) {
  314. /*
  315. * Non-Overlapping Buffers
  316. * copy from lower addresses to higher addresses
  317. */
  318. _asm {
  319. mov esi,src
  320. mov edi,dst
  321. mov ecx,count
  322. cld
  323. mov edx,ecx
  324. and edx,MEMORY_ALIGNMENT_MASK
  325. shr ecx,MEMORY_ALIGNMENT_LOG2
  326. rep movsd
  327. or ecx,edx
  328. jz memmove_done
  329. rep movsb
  330. memmove_done:
  331. }
  332. }
  333. else {
  334. /*
  335. * Overlapping Buffers
  336. * copy from higher addresses to lower addresses
  337. */
  338. _asm {
  339. mov esi,src
  340. mov edi,dst
  341. mov ecx,count
  342. std
  343. add esi,ecx
  344. add edi,ecx
  345. dec esi
  346. dec edi
  347. rep movsb
  348. cld
  349. }
  350. }
  351. #else
  352. MoveMemory(dst, src, count);
  353. #endif
  354. return ret;
  355. }
  356. #ifdef _MSC_VER
  357. HRESULT AMSafeMemMoveOffset(
  358. __in_bcount(dst_size) void * dst,
  359. __in size_t dst_size,
  360. __in DWORD cb_dst_offset,
  361. __in_bcount(src_size) const void * src,
  362. __in size_t src_size,
  363. __in DWORD cb_src_offset,
  364. __in size_t count)
  365. {
  366. // prevent read overruns
  367. if( count + cb_src_offset < count || // prevent integer overflow
  368. count + cb_src_offset > src_size) // prevent read overrun
  369. {
  370. return E_INVALIDARG;
  371. }
  372. // prevent write overruns
  373. if( count + cb_dst_offset < count || // prevent integer overflow
  374. count + cb_dst_offset > dst_size) // prevent write overrun
  375. {
  376. return E_INVALIDARG;
  377. }
  378. memmoveInternal( (BYTE *)dst+cb_dst_offset, (BYTE *)src+cb_src_offset, count);
  379. return S_OK;
  380. }
  381. #endif
  382. #ifdef DEBUG
  383. /******************************Public*Routine******************************\
  384. * Debug CCritSec helpers
  385. *
  386. * We provide debug versions of the Constructor, destructor, Lock and Unlock
  387. * routines. The debug code tracks who owns each critical section by
  388. * maintaining a depth count.
  389. *
  390. * History:
  391. *
  392. \**************************************************************************/
  393. CCritSec::CCritSec()
  394. {
  395. InitializeCriticalSection(&m_CritSec);
  396. m_currentOwner = m_lockCount = 0;
  397. m_fTrace = FALSE;
  398. }
  399. CCritSec::~CCritSec()
  400. {
  401. DeleteCriticalSection(&m_CritSec);
  402. }
  403. void CCritSec::Lock()
  404. {
  405. UINT tracelevel=3;
  406. DWORD us = GetCurrentThreadId();
  407. DWORD currentOwner = m_currentOwner;
  408. if (currentOwner && (currentOwner != us)) {
  409. // already owned, but not by us
  410. if (m_fTrace) {
  411. DbgLog((LOG_LOCKING, 2, TEXT("Thread %d about to wait for lock %x owned by %d"),
  412. GetCurrentThreadId(), &m_CritSec, currentOwner));
  413. tracelevel=2;
  414. // if we saw the message about waiting for the critical
  415. // section we ensure we see the message when we get the
  416. // critical section
  417. }
  418. }
  419. EnterCriticalSection(&m_CritSec);
  420. if (0 == m_lockCount++) {
  421. // we now own it for the first time. Set owner information
  422. m_currentOwner = us;
  423. if (m_fTrace) {
  424. DbgLog((LOG_LOCKING, tracelevel, TEXT("Thread %d now owns lock %x"), m_currentOwner, &m_CritSec));
  425. }
  426. }
  427. }
  428. void CCritSec::Unlock() {
  429. if (0 == --m_lockCount) {
  430. // about to be unowned
  431. if (m_fTrace) {
  432. DbgLog((LOG_LOCKING, 3, TEXT("Thread %d releasing lock %x"), m_currentOwner, &m_CritSec));
  433. }
  434. m_currentOwner = 0;
  435. }
  436. LeaveCriticalSection(&m_CritSec);
  437. }
  438. void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace)
  439. {
  440. pcCrit->m_fTrace = fTrace;
  441. }
  442. BOOL WINAPI CritCheckIn(CCritSec * pcCrit)
  443. {
  444. return (GetCurrentThreadId() == pcCrit->m_currentOwner);
  445. }
  446. BOOL WINAPI CritCheckIn(const CCritSec * pcCrit)
  447. {
  448. return (GetCurrentThreadId() == pcCrit->m_currentOwner);
  449. }
  450. BOOL WINAPI CritCheckOut(CCritSec * pcCrit)
  451. {
  452. return (GetCurrentThreadId() != pcCrit->m_currentOwner);
  453. }
  454. BOOL WINAPI CritCheckOut(const CCritSec * pcCrit)
  455. {
  456. return (GetCurrentThreadId() != pcCrit->m_currentOwner);
  457. }
  458. #endif
  459. STDAPI WriteBSTR(__deref_out BSTR *pstrDest, LPCWSTR szSrc)
  460. {
  461. *pstrDest = SysAllocString( szSrc );
  462. if( !(*pstrDest) ) return E_OUTOFMEMORY;
  463. return NOERROR;
  464. }
  465. STDAPI FreeBSTR(__deref_in BSTR* pstr)
  466. {
  467. if( (PVOID)*pstr == NULL ) return S_FALSE;
  468. SysFreeString( *pstr );
  469. return NOERROR;
  470. }
  471. // Return a wide string - allocating memory for it
  472. // Returns:
  473. // S_OK - no error
  474. // E_POINTER - ppszReturn == NULL
  475. // E_OUTOFMEMORY - can't allocate memory for returned string
  476. STDAPI AMGetWideString(LPCWSTR psz, __deref_out LPWSTR *ppszReturn)
  477. {
  478. CheckPointer(ppszReturn, E_POINTER);
  479. ValidateReadWritePtr(ppszReturn, sizeof(LPWSTR));
  480. *ppszReturn = NULL;
  481. size_t nameLen;
  482. HRESULT hr = StringCbLengthW(psz, 100000, &nameLen);
  483. if (FAILED(hr)) {
  484. return hr;
  485. }
  486. *ppszReturn = (LPWSTR)CoTaskMemAlloc(nameLen + sizeof(WCHAR));
  487. if (*ppszReturn == NULL) {
  488. return E_OUTOFMEMORY;
  489. }
  490. CopyMemory(*ppszReturn, psz, nameLen + sizeof(WCHAR));
  491. return NOERROR;
  492. }
  493. // Waits for the HANDLE hObject. While waiting messages sent
  494. // to windows on our thread by SendMessage will be processed.
  495. // Using this function to do waits and mutual exclusion
  496. // avoids some deadlocks in objects with windows.
  497. // Return codes are the same as for WaitForSingleObject
  498. DWORD WINAPI WaitDispatchingMessages(
  499. HANDLE hObject,
  500. DWORD dwWait,
  501. HWND hwnd,
  502. UINT uMsg,
  503. HANDLE hEvent)
  504. {
  505. BOOL bPeeked = FALSE;
  506. DWORD dwResult;
  507. DWORD dwStart = 0;
  508. DWORD dwThreadPriority = THREAD_PRIORITY_HIGHEST;
  509. static UINT uMsgId = 0;
  510. HANDLE hObjects[2] = { hObject, hEvent };
  511. if (dwWait != INFINITE && dwWait != 0) {
  512. dwStart = GetTickCount();
  513. }
  514. for (; ; ) {
  515. DWORD nCount = NULL != hEvent ? 2 : 1;
  516. // Minimize the chance of actually dispatching any messages
  517. // by seeing if we can lock immediately.
  518. dwResult = WaitForMultipleObjects(nCount, hObjects, FALSE, 0);
  519. if (dwResult < WAIT_OBJECT_0 + nCount) {
  520. break;
  521. }
  522. DWORD dwTimeOut = dwWait;
  523. if (dwTimeOut > 10) {
  524. dwTimeOut = 10;
  525. }
  526. dwResult = MsgWaitForMultipleObjects(
  527. nCount,
  528. hObjects,
  529. FALSE,
  530. dwTimeOut,
  531. hwnd == NULL ? QS_SENDMESSAGE :
  532. QS_SENDMESSAGE + QS_POSTMESSAGE);
  533. if (dwResult == WAIT_OBJECT_0 + nCount ||
  534. dwResult == WAIT_TIMEOUT && dwTimeOut != dwWait) {
  535. MSG msg;
  536. if (hwnd != NULL) {
  537. while (PeekMessage(&msg, hwnd, uMsg, uMsg, PM_REMOVE)) {
  538. DispatchMessage(&msg);
  539. }
  540. }
  541. // Do this anyway - the previous peek doesn't flush out the
  542. // messages
  543. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  544. if (dwWait != INFINITE && dwWait != 0) {
  545. DWORD dwNow = GetTickCount();
  546. // Working with differences handles wrap-around
  547. DWORD dwDiff = dwNow - dwStart;
  548. if (dwDiff > dwWait) {
  549. dwWait = 0;
  550. } else {
  551. dwWait -= dwDiff;
  552. }
  553. dwStart = dwNow;
  554. }
  555. if (!bPeeked) {
  556. // Raise our priority to prevent our message queue
  557. // building up
  558. dwThreadPriority = GetThreadPriority(GetCurrentThread());
  559. if (dwThreadPriority < THREAD_PRIORITY_HIGHEST) {
  560. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  561. }
  562. bPeeked = TRUE;
  563. }
  564. } else {
  565. break;
  566. }
  567. }
  568. if (bPeeked) {
  569. SetThreadPriority(GetCurrentThread(), dwThreadPriority);
  570. if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE) {
  571. if (uMsgId == 0) {
  572. uMsgId = RegisterWindowMessage(TEXT("AMUnblock"));
  573. }
  574. if (uMsgId != 0) {
  575. MSG msg;
  576. // Remove old ones
  577. while (PeekMessage(&msg, (HWND)-1, uMsgId, uMsgId, PM_REMOVE)) {
  578. }
  579. }
  580. PostThreadMessage(GetCurrentThreadId(), uMsgId, 0, 0);
  581. }
  582. }
  583. return dwResult;
  584. }
  585. HRESULT AmGetLastErrorToHResult()
  586. {
  587. DWORD dwLastError = GetLastError();
  588. if(dwLastError != 0)
  589. {
  590. return HRESULT_FROM_WIN32(dwLastError);
  591. }
  592. else
  593. {
  594. return E_FAIL;
  595. }
  596. }
  597. IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp)
  598. {
  599. if (lp != NULL)
  600. lp->AddRef();
  601. if (*pp)
  602. (*pp)->Release();
  603. *pp = lp;
  604. return lp;
  605. }
  606. /******************************************************************************
  607. CompatibleTimeSetEvent
  608. CompatibleTimeSetEvent() sets the TIME_KILL_SYNCHRONOUS flag before calling
  609. timeSetEvent() if the current operating system supports it. TIME_KILL_SYNCHRONOUS
  610. is supported on Windows XP and later operating systems.
  611. Parameters:
  612. - The same parameters as timeSetEvent(). See timeSetEvent()'s documentation in
  613. the Platform SDK for more information.
  614. Return Value:
  615. - The same return value as timeSetEvent(). See timeSetEvent()'s documentation in
  616. the Platform SDK for more information.
  617. ******************************************************************************/
  618. MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent )
  619. {
  620. #if WINVER >= 0x0501
  621. {
  622. static bool fCheckedVersion = false;
  623. static bool fTimeKillSynchronousFlagAvailable = false;
  624. if( !fCheckedVersion ) {
  625. fTimeKillSynchronousFlagAvailable = TimeKillSynchronousFlagAvailable();
  626. fCheckedVersion = true;
  627. }
  628. if( fTimeKillSynchronousFlagAvailable ) {
  629. fuEvent = fuEvent | TIME_KILL_SYNCHRONOUS;
  630. }
  631. }
  632. #endif // WINVER >= 0x0501
  633. return timeSetEvent( uDelay, uResolution, lpTimeProc, dwUser, fuEvent );
  634. }
  635. bool TimeKillSynchronousFlagAvailable( void )
  636. {
  637. OSVERSIONINFO osverinfo;
  638. osverinfo.dwOSVersionInfoSize = sizeof(osverinfo);
  639. if( GetVersionEx( &osverinfo ) ) {
  640. // Windows XP's major version is 5 and its' minor version is 1.
  641. // timeSetEvent() started supporting the TIME_KILL_SYNCHRONOUS flag
  642. // in Windows XP.
  643. if( (osverinfo.dwMajorVersion > 5) ||
  644. ( (osverinfo.dwMajorVersion == 5) && (osverinfo.dwMinorVersion >= 1) ) ) {
  645. return true;
  646. }
  647. }
  648. return false;
  649. }
  650. #endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */