]> git.sesse.net Git - casparcg/blob - modules/flash/producer/FlashAxContainer.cpp
1b2de24587413617f96d8b1fe7050009f36c5df2
[casparcg] / modules / flash / producer / FlashAxContainer.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Nicklas P Andersson
20 */
21
22 #include "../stdafx.h"
23
24 #include "FlashAxContainer.h"
25 #include "../interop/TimerHelper.h"
26
27 #include <common/log.h>
28 #include <common/os/general_protection_fault.h>
29
30 #if defined(_MSC_VER)
31 #pragma warning (push, 2) // TODO
32 #endif
33
34 using namespace ATL;
35
36 namespace caspar { namespace flash {
37
38 CComBSTR FlashAxContainer::flashGUID_(_T("{D27CDB6E-AE6D-11CF-96B8-444553540000}"));
39
40 _ATL_FUNC_INFO fnInfoFlashCallEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_BSTR } };
41 _ATL_FUNC_INFO fnInfoReadyStateChangeEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_I4 } };
42
43 FlashAxContainer::FlashAxContainer() : bInPlaceActive_(FALSE), pTimerHelper(0), bInvalidRect_(false), bReadyToRender_(false), bHasNewTiming_(false), m_lpDD4(0), timerCount_(0), bIsEmpty_(true)
44 {
45 }
46 FlashAxContainer::~FlashAxContainer()
47 {       
48         if(m_lpDD4)
49         {
50                 m_lpDD4->Release();
51                 delete m_lpDD4;
52         }
53
54         if(pTimerHelper != 0)
55                 delete pTimerHelper;
56 }
57
58
59 /////////
60 // IObjectWithSite
61 /////////
62 HRESULT STDMETHODCALLTYPE FlashAxContainer::SetSite(IUnknown* pUnkSite)
63 {
64         ATLTRACE(_T("IObjectWithSite::SetSite\n"));
65         HRESULT hr = IObjectWithSiteImpl<FlashAxContainer>::SetSite(pUnkSite);
66
67         if (SUCCEEDED(hr) && m_spUnkSite)
68         {
69                 // Look for "outer" IServiceProvider
70                 hr = m_spUnkSite->QueryInterface(__uuidof(IServiceProvider), (void**)&m_spServices);
71                 ATLASSERT( !hr && _T("No ServiceProvider!") );
72         }
73
74         if (pUnkSite == NULL)
75                 m_spServices.Release();
76
77         return hr;
78 }
79
80 /////////
81 // IOleClientSite
82 /////////
83 HRESULT STDMETHODCALLTYPE FlashAxContainer::SaveObject()
84 {
85         ATLTRACENOTIMPL(_T("IOleClientSite::SaveObject"));
86 }
87
88 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker** ppmk)
89 {
90 /*      if(*ppmk != NULL) {
91                 if(m_spMyMoniker == NULL) {
92                         ATL::CComObject<MyMoniker>* pMoniker = NULL;
93                         HRESULT hr = ATL::CComObject<MyMoniker>::CreateInstance(&pMoniker);
94                         if(SUCCEEDED(hr))
95                                 m_spMyMoniker = pMoniker;
96                 }
97
98                 if(m_spMyMoniker != NULL) {
99                         *ppmk = m_spMyMoniker;
100                         (*ppmk)->AddRef();
101                         return S_OK;
102                 }
103         }
104 */      if(ppmk != NULL)
105                 *ppmk = NULL;
106         return E_FAIL;
107 }
108
109 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetContainer(IOleContainer** ppContainer)
110 {
111         ATLTRACE(_T("IOleClientSite::GetContainer\n"));
112         (*ppContainer) = NULL;
113         return E_NOINTERFACE;
114 }
115
116 HRESULT STDMETHODCALLTYPE FlashAxContainer::ShowObject()
117 {
118         ATLTRACE(_T("IOleClientSite::ShowObject\n"));
119         return S_OK;
120 }
121
122 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnShowWindow(BOOL fShow)
123 {
124         ATLTRACE(_T("IOleClientSite::OnShowWindow"));
125         return S_OK;
126 }
127
128 HRESULT STDMETHODCALLTYPE FlashAxContainer::RequestNewObjectLayout()
129 {
130         ATLTRACE(_T("IOleClientSite::RequestNewObjectLayout"));
131         return S_OK;
132 }
133
134 /////////
135 // IOleInPlaceSite
136 /////////
137 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetWindow(HWND* pHwnd)
138 {
139         ATLTRACE(_T("IOleInPlaceSite::GetWindow\n"));
140         (*pHwnd) = NULL;//GetApplication()->GetMainWindow()->getHwnd();
141         return E_FAIL;
142 }
143 HRESULT STDMETHODCALLTYPE FlashAxContainer::ContextSensitiveHelp(BOOL fEnterMode)
144 {
145         ATLTRACE(_T("IOleInPlaceSite::ContextSensitiveHelp"));
146         return S_OK;
147 }
148
149 HRESULT STDMETHODCALLTYPE FlashAxContainer::CanInPlaceActivate()
150 {
151         ATLTRACE(_T("IOleInPlaceSite::CanInPlaceActivate\n"));
152         return S_OK;
153 }
154
155 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceActivate()
156 {
157         ATLTRACE(_T("IOleInPlaceSite::OnInPlaceActivate"));
158         return S_OK;
159 }
160
161 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnUIActivate()
162 {
163         ATLTRACE(_T("IOleInPlaceSite::OnUIActivate\n"));
164         bUIActive_ = TRUE;
165         return S_OK;
166 }
167
168 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetWindowContext(IOleInPlaceFrame** ppFrame, IOleInPlaceUIWindow** ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO pFrameInfo)
169 {
170         ATLTRACE(_T("IOleInPlaceSite::GetWindowContext\n"));
171         if (ppFrame != NULL)
172                 *ppFrame = NULL;
173         if (ppDoc != NULL)
174                 *ppDoc = NULL;
175
176         if (ppFrame == NULL || ppDoc == NULL || lprcPosRect == NULL || lprcClipRect == NULL)
177                 return E_POINTER;
178
179         pFrameInfo->fMDIApp = FALSE;
180         pFrameInfo->haccel = NULL;
181         pFrameInfo->cAccelEntries = 0;
182         pFrameInfo->hwndFrame = NULL;
183
184         lprcPosRect->top = m_rcPos.top;
185         lprcPosRect->left = m_rcPos.left;
186         lprcPosRect->right = m_rcPos.right;
187         lprcPosRect->bottom = m_rcPos.bottom;
188
189         lprcClipRect->top = m_rcPos.top;
190         lprcClipRect->left = m_rcPos.left;
191         lprcClipRect->right = m_rcPos.right;
192         lprcClipRect->bottom = m_rcPos.bottom;
193
194         return S_OK;
195 }
196
197 HRESULT STDMETHODCALLTYPE FlashAxContainer::Scroll(SIZE scrollExtant)
198 {
199         ATLTRACE(_T("IOleInPlaceSite::Scroll"));
200         return S_OK;
201 }
202
203 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnUIDeactivate(BOOL fUndoable)
204 {
205         ATLTRACE(_T("IOleInPlaceSite::OnUIDeactivate\n"));
206         bUIActive_ = FALSE;
207         return S_OK;
208 }
209
210 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceDeactivate()
211 {
212         ATLTRACE(_T("IOleInPlaceSite::OnInPlaceDeactivate\n"));
213         bInPlaceActive_ = FALSE;
214         m_spInPlaceObjectWindowless.Release();
215         return S_OK;
216 }
217
218 HRESULT STDMETHODCALLTYPE FlashAxContainer::DiscardUndoState()
219 {
220         ATLTRACE(_T("IOleInPlaceSite::DiscardUndoState"));
221         return S_OK;
222 }
223
224 HRESULT STDMETHODCALLTYPE FlashAxContainer::DeactivateAndUndo()
225 {
226         ATLTRACE(_T("IOleInPlaceSite::DeactivateAndUndo"));
227         return S_OK;
228 }
229
230 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnPosRectChange(LPCRECT lprcPosRect)
231 {
232         ATLTRACE(_T("IOleInPlaceSite::OnPosRectChange"));
233         return S_OK;
234 }
235
236
237 //////////
238 // IOleInPlaceSiteEx
239 //////////
240 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceActivateEx(BOOL* pfNoRedraw, DWORD dwFlags)
241 {
242         // should only be called once the first time control is inplace-activated
243         ATLTRACE(_T("IOleInPlaceSiteEx::OnInPlaceActivateEx\n"));
244         ATLASSERT(bInPlaceActive_ == FALSE);
245         ATLASSERT(m_spInPlaceObjectWindowless == NULL);
246
247         bInPlaceActive_ = TRUE;
248         OleLockRunning(m_spOleObject, TRUE, FALSE);
249         HRESULT hr = E_FAIL;
250         if (dwFlags & ACTIVATE_WINDOWLESS)
251         {
252                 hr = m_spOleObject->QueryInterface(__uuidof(IOleInPlaceObjectWindowless), (void**) &m_spInPlaceObjectWindowless);
253
254                 if (m_spInPlaceObjectWindowless != NULL)
255                         m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);
256         }
257
258         return (m_spInPlaceObjectWindowless != NULL) ? S_OK : E_FAIL;
259 }
260
261 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnInPlaceDeactivateEx(BOOL fNoRedraw)
262 {
263         ATLTRACE(_T("IOleInPlaceSiteEx::OnInPlaceDeactivateEx\n"));
264         bInPlaceActive_ = FALSE;
265         m_spInPlaceObjectWindowless.Release();
266         return S_OK;
267 }
268
269 HRESULT STDMETHODCALLTYPE FlashAxContainer::RequestUIActivate()
270 {
271         ATLTRACE(_T("IOleInPlaceSiteEx::RequestUIActivate\n"));
272         return S_OK;
273 }
274
275
276 //////////////
277 // IOleInPlaceSiteWindowless
278 //////////////
279 HRESULT STDMETHODCALLTYPE FlashAxContainer::CanWindowlessActivate()
280 {
281         ATLTRACE(_T("IOleInPlaceSiteWindowless::CanWindowlessActivate\n"));
282         return S_OK;
283 //      return S_FALSE;
284 }
285
286 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetCapture()
287 {
288         ATLTRACE(_T("IOleInPlaceSiteWindowless::GetCapture\n"));
289         return bCapture_ ? S_OK : S_FALSE;
290 }
291
292 HRESULT STDMETHODCALLTYPE FlashAxContainer::SetCapture(BOOL fCapture)
293 {
294         ATLTRACE(_T("IOleInPlaceSiteWindowless::SetCapture\n"));
295         bCapture_ = fCapture;
296         return S_OK;
297 }
298
299 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetFocus()
300 {
301         ATLTRACE(_T("IOleInPlaceSiteWindowless::GetFocus\n"));
302         return bHaveFocus_ ? S_OK : S_FALSE;
303 }
304
305 HRESULT STDMETHODCALLTYPE FlashAxContainer::SetFocus(BOOL fGotFocus)
306 {
307         ATLTRACE(_T("IOleInPlaceSiteWindowless::SetFocus\n"));
308         bHaveFocus_ = fGotFocus;
309         return S_OK;
310 }
311
312 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetDC(LPCRECT pRect, DWORD grfFlags, HDC* phDC)
313 {
314         ATLTRACE(_T("IOleInPlaceSiteWindowless::GetDC"));
315         return S_OK;
316 }
317
318 HRESULT STDMETHODCALLTYPE FlashAxContainer::ReleaseDC(HDC hDC)
319 {
320         ATLTRACE(_T("IOleInPlaceSiteWindowless::ReleaseDC"));
321         return S_OK;
322 }
323
324 HRESULT STDMETHODCALLTYPE FlashAxContainer::InvalidateRect(LPCRECT pRect, BOOL fErase)
325 {
326 //      ATLTRACE(_T("IOleInPlaceSiteWindowless::InvalidateRect\n"));
327         
328         bInvalidRect_ = true;
329
330 /*      //Keep a list of dirty rectangles in order to be able to redraw only them
331         if(pRect != NULL) {
332                 bDirtyRects_.push_back(DirtyRect(*pRect, fErase != 0));
333         }
334         else {
335                 bDirtyRects_.push_back(DirtyRect(true));
336         }
337 */      return S_OK;
338 }
339
340 HRESULT STDMETHODCALLTYPE FlashAxContainer::InvalidateRgn(HRGN hRGN, BOOL fErase)
341 {
342         ATLTRACE(_T("IOleInPlaceSiteWindowless::InvalidateRng\n"));
343         return S_OK;
344 }
345
346 HRESULT STDMETHODCALLTYPE FlashAxContainer::ScrollRect(INT dx, INT dy, LPCRECT pRectScroll, LPCRECT pRectClip)
347 {
348         ATLTRACE(_T("IOleInPlaceSiteWindowless::ScrollRect"));
349         return S_OK;
350 }
351
352 HRESULT STDMETHODCALLTYPE FlashAxContainer::AdjustRect(LPRECT prc)
353 {
354         ATLTRACE(_T("IOleInPlaceSiteWindowless::AdjustRect"));
355         return S_OK;
356 }
357
358 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnDefWindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* plResult)
359 {
360         ATLTRACE(_T("IOleInPlaceSiteWindowless::OnDefWindowMessage"));
361         return S_OK;
362 }
363
364 /////////
365 // IOleControlSite
366 /////////
367 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnControlInfoChanged()
368 {
369         ATLTRACE(_T("IOleControlSite::OnControlInfoChanged"));
370         return S_OK;
371 }
372
373 HRESULT STDMETHODCALLTYPE FlashAxContainer::LockInPlaceActive(BOOL fLock)
374 {
375         ATLTRACE(_T("IOleControlSite::LockInPlaceActive"));
376         return S_OK;
377 }
378
379 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetExtendedControl(IDispatch** ppDisp)
380 {
381         ATLTRACE(_T("IOleControlSite::GetExtendedControl"));
382
383         if (ppDisp == NULL)
384                 return E_POINTER;
385         return m_spOleObject.QueryInterface(ppDisp);
386 }
387
388 HRESULT STDMETHODCALLTYPE FlashAxContainer::TransformCoords(POINTL* pPtlHimetric, POINTF* pPtfContainer, DWORD dwFlags)
389 {
390         ATLTRACE(_T("IOleControlSite::TransformCoords"));
391         return S_OK;
392 }
393
394 HRESULT STDMETHODCALLTYPE FlashAxContainer::TranslateAccelerator(LPMSG lpMsg, DWORD grfModifiers)
395 {
396         ATLTRACE(_T("IOleControlSite::TranslateAccelerator"));
397         return S_FALSE;
398 }
399
400 HRESULT STDMETHODCALLTYPE FlashAxContainer::OnFocus(BOOL fGotFocus)
401 {
402         bHaveFocus_ = fGotFocus;
403         return S_OK;
404 }
405
406 HRESULT STDMETHODCALLTYPE FlashAxContainer::ShowPropertyFrame()
407 {
408         ATLTRACE(_T("IOleControlSite::ShowPropertyFrame"));
409         return S_OK;
410 }
411
412
413 /////////
414 // IAdviseSink
415 /////////
416 void STDMETHODCALLTYPE FlashAxContainer::OnDataChange(FORMATETC* pFormatetc, STGMEDIUM* pStgmed)
417 {
418         ATLTRACE(_T("IAdviseSink::OnDataChange\n"));
419 }
420
421 void STDMETHODCALLTYPE FlashAxContainer::OnViewChange(DWORD dwAspect, LONG lindex)
422 {
423         ATLTRACE(_T("IAdviseSink::OnViewChange\n"));
424 }
425
426 void STDMETHODCALLTYPE FlashAxContainer::OnRename(IMoniker* pmk)
427 {
428         ATLTRACE(_T("IAdviseSink::OnRename\n"));
429 }
430
431 void STDMETHODCALLTYPE FlashAxContainer::OnSave()
432 {
433         ATLTRACE(_T("IAdviseSink::OnSave\n"));
434 }
435
436 void STDMETHODCALLTYPE FlashAxContainer::OnClose()
437 {
438         ATLTRACE(_T("IAdviseSink::OnClose\n"));
439 }
440
441
442 //DirectDraw GUIDS
443
444 DEFINE_GUID2(CLSID_DirectDraw,0xD7B70EE0,0x4340,0x11CF,0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35);
445 DEFINE_GUID2(CLSID_DirectDraw7,0x3c305196,0x50db,0x11d3,0x9c,0xfe,0x00,0xc0,0x4f,0xd9,0x30,0xc5);
446
447 DEFINE_GUID2(IID_IDirectDraw,0x6C14DB80,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60);
448 DEFINE_GUID2(IID_IDirectDraw3,0x618f8ad4,0x8b7a,0x11d0,0x8f,0xcc,0x0,0xc0,0x4f,0xd9,0x18,0x9d);
449 DEFINE_GUID2(IID_IDirectDraw4,0x9c59509a,0x39bd,0x11d1,0x8c,0x4a,0x00,0xc0,0x4f,0xd9,0x30,0xc5);
450 DEFINE_GUID2(IID_IDirectDraw7,0x15e65ec0,0x3b9c,0x11d2,0xb9,0x2f,0x00,0x60,0x97,0x97,0xea,0x5b);
451
452 /////////
453 // IServiceProvider
454 /////////
455 HRESULT STDMETHODCALLTYPE FlashAxContainer::QueryService( REFGUID rsid, REFIID riid, void** ppvObj) 
456 {
457         ensure_gpf_handler_installed_for_thread("flash-player-thread");
458 //      ATLTRACE(_T("IServiceProvider::QueryService\n"));
459         //the flashcontrol asks for an interface {618F8AD4-8B7A-11D0-8FCC-00C04FD9189D}, this is IID for a DirectDraw3 object
460
461         ATLASSERT(ppvObj != NULL);
462         if (ppvObj == NULL)
463                 return E_POINTER;
464         *ppvObj = NULL;
465         
466         HRESULT hr;
467         // Author: Makarov Igor
468         // Transparent Flash Control in Plain C++ 
469         // http://www.codeproject.com/KB/COM/flashcontrol.aspx 
470         if (IsEqualGUID(rsid, IID_IDirectDraw3))
471         {
472                 if (!m_lpDD4)
473                 {
474                         m_lpDD4 = new IDirectDraw4Ptr;
475                         hr = m_lpDD4->CreateInstance(CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER); 
476                         if (FAILED(hr))
477                         {
478                                 delete m_lpDD4;
479                                 m_lpDD4 = NULL;
480                                 CASPAR_LOG(info) << print_() << " DirectDraw not installed. Running without DirectDraw.";
481                                 return E_NOINTERFACE;
482                         }
483                 }
484                 if (m_lpDD4 && m_lpDD4->GetInterfacePtr())
485                 {
486                         *ppvObj = m_lpDD4->GetInterfacePtr();
487                         m_lpDD4->AddRef();
488                         return S_OK;
489                 }
490         }
491
492         //TODO: The fullscreen-consumer requires that ths does NOT return an ITimerService
493         hr = QueryInterface(riid, ppvObj);//E_NOINTERFACE;
494
495         return hr;
496 }
497
498
499 /////////
500 // ITimerService
501 /////////
502 HRESULT STDMETHODCALLTYPE FlashAxContainer::CreateTimer(ITimer *pReferenceTimer, ITimer **ppNewTimer)
503 {
504         ATLTRACE(_T("ITimerService::CreateTimer\n"));
505         if(pTimerHelper != 0)
506         {
507                 delete pTimerHelper;
508                 pTimerHelper = 0;
509         }
510         pTimerHelper = new TimerHelper();
511         return QueryInterface(__uuidof(ITimer), (void**) ppNewTimer);
512 }
513
514 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetNamedTimer(REFGUID rguidName, ITimer **ppTimer)
515 {
516         ATLTRACE(_T("ITimerService::GetNamedTimer"));
517         if(ppTimer == NULL)
518                 return E_POINTER;
519         else
520                 *ppTimer = NULL;
521
522         return E_FAIL;
523 }
524
525 HRESULT STDMETHODCALLTYPE FlashAxContainer::SetNamedTimerReference(REFGUID rguidName, ITimer *pReferenceTimer)
526 {
527         ATLTRACE(_T("ITimerService::SetNamedTimerReference"));
528         return S_OK;
529 }
530
531 //////
532 // ITimer
533 //////
534 HRESULT STDMETHODCALLTYPE FlashAxContainer::Advise(VARIANT vtimeMin, VARIANT vtimeMax, VARIANT vtimeInterval, DWORD dwFlags, ITimerSink *pTimerSink, DWORD *pdwCookie)
535 {
536         ATLTRACE(_T("Timer::Advise\n"));
537
538         if(pdwCookie == 0)
539                 return E_POINTER;
540
541         if(pTimerHelper != 0)
542         {
543                 pTimerHelper->Setup(vtimeMin.ulVal, vtimeInterval.ulVal, pTimerSink);
544                 *pdwCookie = pTimerHelper->ID;
545                 bHasNewTiming_ = true;
546
547                 return S_OK;
548         }
549         else
550                 return E_OUTOFMEMORY;
551 }
552
553 HRESULT STDMETHODCALLTYPE FlashAxContainer::Unadvise(/* [in] */ DWORD dwCookie)
554 {
555         ATLTRACE(_T("Timer::Unadvice\n"));
556         if(pTimerHelper != 0)
557         {
558                 pTimerHelper->pTimerSink = 0;
559                 return S_OK;
560         }
561         else
562                 return E_FAIL;
563 }
564
565 HRESULT STDMETHODCALLTYPE FlashAxContainer::Freeze(/* [in] */ BOOL fFreeze)
566 {
567         ATLTRACE(_T("Timer::Freeze\n"));
568         return S_OK;
569 }
570
571 HRESULT STDMETHODCALLTYPE FlashAxContainer::GetTime(/* [out] */ VARIANT *pvtime)
572 {
573         ATLTRACE(_T("Timer::GetTime\n"));
574         if(pvtime == 0)
575                 return E_POINTER;
576
577 //      return E_NOTIMPL;
578         pvtime->lVal = 0;
579         return S_OK;
580 }
581
582 double FlashAxContainer::GetFPS() {
583         if(pTimerHelper != 0 && pTimerHelper->interval > 0)
584                 return (1000.0 / static_cast<double>(pTimerHelper->interval));
585         
586         return 0.0;
587 }
588
589 bool FlashAxContainer::IsReadyToRender() const {
590         return bReadyToRender_;
591 }
592
593 void FlashAxContainer::EnterFullscreen()
594 {
595         if(m_spInPlaceObjectWindowless != 0)
596         {
597                 LRESULT result;
598                 m_spInPlaceObjectWindowless->OnWindowMessage(WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1), &result);
599                 m_spInPlaceObjectWindowless->OnWindowMessage(WM_LBUTTONUP, 0, MAKELPARAM(1, 1), &result);
600         }
601 }
602
603 void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
604 {
605         ensure_gpf_handler_installed_for_thread("flash-player-thread");
606         std::wstring str(request);
607         if(str.find(L"DisplayedTemplate") != std::wstring::npos)
608         {
609                 ATLTRACE(_T("ShockwaveFlash::DisplayedTemplate\n"));
610                 bReadyToRender_ = true;
611         }
612         else if(str.find(L"OnCommand") != std::wstring::npos) {
613                 //this is how templatehost 1.8 reports that a command has been received
614                 CASPAR_LOG(debug)  << print_()  << L" [command]      " << str;
615                 bCallSuccessful_ = true;
616         }
617         else if(str.find(L"Activity") != std::wstring::npos)
618         {
619                 CASPAR_LOG(debug) << print_() << L" [activity]     " << str;
620
621                 //this is how templatehost 1.7 reports that a command has been received
622                 if(str.find(L"Command recieved") != std::wstring::npos)
623                         bCallSuccessful_ = true;
624
625                 /*if(pFlashProducer_ != 0 && pFlashProducer_->pMonitor_) {
626                         std::wstring::size_type pos = str.find(TEXT('@'));
627                         if(pos != std::wstring::npos)
628                                 pFlashProducer_->pMonitor_->Inform(str.substr(pos, str.find(TEXT('<'), pos)-pos));
629                 }*/
630         }
631         else if(str.find(L"OnNotify") != std::wstring::npos)
632         {
633                 CASPAR_LOG(info) << print_() << L" [notification] " << str;
634
635                 //if(pFlashProducer_ != 0 && pFlashProducer_->pMonitor_) {
636                 //      std::wstring::size_type pos = str.find(TEXT('@'));
637                 //      if(pos != std::wstring::npos)
638                 //              pFlashProducer_->pMonitor_->Inform(str.substr(pos, str.find(TEXT('<'), pos)-pos));
639                 //}
640         }
641         else if(str.find(L"IsEmpty") != std::wstring::npos)
642         {
643                 CASPAR_LOG(debug) << print_() << L" Empty.";
644                 ATLTRACE(_T("ShockwaveFlash::IsEmpty\n"));
645                 bIsEmpty_ = true;
646         }
647         else if(str.find(L"OnError") != std::wstring::npos)
648         {
649                 if (str.find(L"No template playing on layer") != std::wstring::npos)
650                         CASPAR_LOG(info) << print_() << L" [info]        " << str;
651                 else
652                         CASPAR_LOG(error) << print_() << L" [error]        " << str;
653         }
654         else if(str.find(L"OnDebug") != std::wstring::npos)
655         {
656                 CASPAR_LOG(debug) << print_() << L" [debug]        " << str;
657         }
658         //else if(str.find(TEXT("OnTemplateDescription")) != std::wstring::npos)
659         //{
660         //      CASPAR_LOG(error) << print_() << L" TemplateDescription: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";
661         //}
662         //else if(str.find(TEXT("OnGetInfo")) != std::wstring::npos)
663         //{
664         //      CASPAR_LOG(error) << print_() << L" Info: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";
665         //}
666         //else
667         //{
668         //      CASPAR_LOG(error) << print_() << L" Unknown: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";
669         //}
670
671         CComPtr<IShockwaveFlash> spFlash;
672         HRESULT hr = m_spOleObject->QueryInterface(__uuidof(IShockwaveFlash), (void**) &spFlash);
673         if(hr == S_OK && spFlash)
674         {
675                 hr = spFlash->SetReturnValue(L"<null/>");
676         }
677 }
678
679 void STDMETHODCALLTYPE FlashAxContainer::OnReadyStateChange(long newState)
680 {
681         if(newState == 4)
682                 bReadyToRender_ = true;
683 }
684
685 void FlashAxContainer::DestroyAxControl()
686 {
687         GetControllingUnknown()->AddRef();
688
689         if ((!m_spViewObject) == false)
690                 m_spViewObject->SetAdvise(DVASPECT_CONTENT, 0, NULL);
691
692         if ((!m_spOleObject) == false)
693         {
694                 DispEventUnadvise(m_spOleObject, &DIID__IShockwaveFlashEvents);
695                 m_spOleObject->Unadvise(m_dwOleObject);
696                 m_spOleObject->Close(OLECLOSE_NOSAVE);
697                 m_spOleObject->SetClientSite(NULL);
698         }
699
700         if ((!m_spUnknown) == false)
701         {
702                 CComPtr<IObjectWithSite> spSite;
703                 m_spUnknown->QueryInterface(__uuidof(IObjectWithSite), (void**)&spSite);
704                 if (spSite != NULL)
705                         spSite->SetSite(NULL);
706         }
707
708         if ((!m_spViewObject) == false)
709                 m_spViewObject.Release();
710
711         if ((!m_spInPlaceObjectWindowless) == false)
712                 m_spInPlaceObjectWindowless.Release();
713
714         if ((!m_spOleObject) == false)
715                 m_spOleObject.Release();
716
717         if ((!m_spUnknown) == false)
718                 m_spUnknown.Release();
719 }
720
721 bool FlashAxContainer::CheckForFlashSupport()
722 {
723         CLSID clsid;
724         return SUCCEEDED(CLSIDFromString((LPOLESTR)flashGUID_, &clsid));
725 }
726
727 HRESULT FlashAxContainer::CreateAxControl()
728 {
729         CLSID clsid;
730         HRESULT hr = CLSIDFromString((LPOLESTR)flashGUID_, &clsid); 
731         if(SUCCEEDED(hr))
732                 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(IUnknown), (void**)&m_spUnknown);
733
734 //Start ActivateAx
735         if(SUCCEEDED(hr))
736         {
737                 m_spUnknown->QueryInterface(__uuidof(IOleObject), (void**)&m_spOleObject);
738                 if(m_spOleObject)
739                 {
740                         m_spOleObject->GetMiscStatus(DVASPECT_CONTENT, &m_dwMiscStatus);
741                         if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
742                         {
743                                 CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
744                                 m_spOleObject->SetClientSite(spClientSite);
745                         }
746
747                         //Initialize control
748                         CComQIPtr<IPersistStreamInit> spPSI(m_spOleObject);
749                         if (spPSI)
750                                 hr = spPSI->InitNew();
751
752                         if (FAILED(hr)) // If the initialization of the control failed...
753                         {
754                                 // Clean up and return
755                                 if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
756                                         m_spOleObject->SetClientSite(NULL);
757
758                                 m_dwMiscStatus = 0;
759                                 m_spOleObject.Release();
760                                 m_spUnknown.Release();
761
762                                 return hr;
763                         }
764                         //end Initialize object
765
766                         if (0 == (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
767                         {
768                                 CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
769                                 m_spOleObject->SetClientSite(spClientSite);
770                         }
771
772                         CComPtr<IShockwaveFlash> spFlash;
773                         HRESULT hResultQuality;
774                         HRESULT hr2 = m_spOleObject->QueryInterface(__uuidof(IShockwaveFlash), (void**) &spFlash);
775                         if(hr2 == S_OK && spFlash)
776                         {
777                                 if(FAILED(spFlash->put_WMode(L"Transparent")))
778                                         CASPAR_LOG(warning) << print_() << L" Failed to set flash container to transparent mode.";
779                                 //spFlash->put_WMode(TEXT("ogl"));
780                                 hResultQuality = spFlash->put_Quality2(L"Best");
781                         }
782                         if(SUCCEEDED(DispEventAdvise(spFlash, &DIID__IShockwaveFlashEvents)))
783                         {
784                         }
785
786                         HRESULT hrView = m_spOleObject->QueryInterface(__uuidof(IViewObjectEx), (void**) &m_spViewObject);
787
788                         CComQIPtr<IAdviseSink> spAdviseSink(GetControllingUnknown());
789                         m_spOleObject->Advise(spAdviseSink, &m_dwOleObject);
790                         if (m_spViewObject)
791                                 m_spViewObject->SetAdvise(DVASPECT_CONTENT, 0, spAdviseSink);
792
793                         if ((m_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME) == 0)
794                         {
795                                 //Initialize window to some dummy size
796                                 m_rcPos.top = 0;
797                                 m_rcPos.left = 0;
798                                 m_rcPos.right = 720;
799                                 m_rcPos.bottom = 576;
800
801                                 m_pxSize.cx = m_rcPos.right - m_rcPos.left;
802                                 m_pxSize.cy = m_rcPos.bottom - m_rcPos.top;
803                                 AtlPixelToHiMetric(&m_pxSize, &m_hmSize);
804                                 m_spOleObject->SetExtent(DVASPECT_CONTENT, &m_hmSize);
805                                 m_spOleObject->GetExtent(DVASPECT_CONTENT, &m_hmSize);
806                                 AtlHiMetricToPixel(&m_hmSize, &m_pxSize);
807                                 m_rcPos.right = m_rcPos.left + m_pxSize.cx;
808                                 m_rcPos.bottom = m_rcPos.top + m_pxSize.cy;
809
810                                 CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
811                                 hr = m_spOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, spClientSite, 0, NULL, &m_rcPos);
812                         }
813                 }
814                 CComPtr<IObjectWithSite> spSite;
815                 m_spUnknown->QueryInterface(__uuidof(IObjectWithSite), (void**)&spSite);
816                 if (spSite != NULL)
817                         spSite->SetSite(GetControllingUnknown());
818         }
819 //End ActivateAx
820
821 //      hr = E_FAIL;
822         if (FAILED(hr) || m_spUnknown == NULL)
823         {
824                 return E_FAIL;
825                 // We don't have a control or something failed so release
826 //              ReleaseAll();
827         }
828
829         return S_OK;
830 }
831
832 void FlashAxContainer::SetSize(size_t width, size_t height) {
833         if(m_spInPlaceObjectWindowless != 0)
834         {
835                 m_rcPos.top = 0;
836                 m_rcPos.left = 0;
837                 m_rcPos.right = width;
838                 m_rcPos.bottom = height;
839
840                 m_pxSize.cx = m_rcPos.right - m_rcPos.left;
841                 m_pxSize.cy = m_rcPos.bottom - m_rcPos.top;
842                 AtlPixelToHiMetric(&m_pxSize, &m_hmSize);
843                 m_spOleObject->SetExtent(DVASPECT_CONTENT, &m_hmSize);
844                 m_spOleObject->GetExtent(DVASPECT_CONTENT, &m_hmSize);
845                 AtlHiMetricToPixel(&m_hmSize, &m_pxSize);
846                 m_rcPos.right = m_rcPos.left + m_pxSize.cx;
847                 m_rcPos.bottom = m_rcPos.top + m_pxSize.cy;
848
849                 m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);
850                 bInvalidRect_ = true;
851         }
852 }
853
854 HRESULT FlashAxContainer::QueryControl(REFIID iid, void** ppUnk)
855 {
856         ATLASSERT(ppUnk != NULL);
857         if (ppUnk == NULL)
858                 return E_POINTER;
859         HRESULT hr;
860         hr = m_spOleObject->QueryInterface(iid, ppUnk);
861         return hr;
862 }
863
864 bool FlashAxContainer::DrawControl(HDC targetDC)
865 {
866 //      ATLTRACE(_T("FlashAxContainer::DrawControl\n"));
867         DVASPECTINFO aspectInfo = {sizeof(DVASPECTINFO), DVASPECTINFOFLAG_CANOPTIMIZE};
868         HRESULT hr = m_spViewObject->Draw(DVASPECT_CONTENT, -1, &aspectInfo, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); 
869         bInvalidRect_ = false;
870 /*      const video_format_desc& fmtDesc = video_format_desc::FormatDescriptions[format_];
871
872         //Trying to redraw just the dirty rectangles. Doesn't seem to work when the movie uses "filters", such as glow, dropshadow etc.
873         std::vector<flash::DirtyRect>::iterator it = bDirtyRects_.begin();
874         std::vector<flash::DirtyRect>::iterator end = bDirtyRects_.end();
875         for(; it != end; ++it) {
876                 flash::DirtyRect& dirtyRect = (*it);
877                 if(dirtyRect.bWhole || dirtyRect.rect.right >= fmtDesc.width || dirtyRect.rect.bottom >= fmtDesc.height) {
878                         m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &m_rcPos);
879                         hr = m_spViewObject->Draw(DVASPECT_OPAQUE, -1, NULL, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); 
880                         break;
881                 }
882                 else {
883                         m_spInPlaceObjectWindowless->SetObjectRects(&m_rcPos, &(dirtyRect.rect));
884                         hr = m_spViewObject->Draw(DVASPECT_OPAQUE, -1, NULL, NULL, NULL, targetDC, NULL, NULL, NULL, NULL); 
885                 }
886         }
887         bDirtyRects_.clear();
888 */
889
890         return (hr == S_OK);
891 }
892
893 void FlashAxContainer::Tick()
894 {
895         if(pTimerHelper)
896         {
897                 DWORD time = pTimerHelper->Invoke(); // Tick flash
898                 if(time - timerCount_ >= 400)
899                 {
900                         timerCount_ = time;
901                         LRESULT hr;
902                         m_spInPlaceObjectWindowless->OnWindowMessage(WM_TIMER, 3, 0, &hr);
903                 }
904         }
905 }
906
907 bool FlashAxContainer::FlashCall(const std::wstring& str, std::wstring& result2)
908 {
909         CComBSTR result;
910         CComPtr<IShockwaveFlash> spFlash;
911         QueryControl(&spFlash);
912         CComBSTR request(str.c_str());
913         
914         bIsEmpty_ = false;
915         bCallSuccessful_ = false;
916         for(size_t retries = 0; !bCallSuccessful_ && retries < 4; ++retries)
917                 spFlash->CallFunction(request, &result);
918
919         if(bCallSuccessful_)
920                 result2 = result;
921
922         return bCallSuccessful_;
923 }
924
925 }       //namespace flash
926 }       //namespace caspar