1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Sample showing integration of Flash ActiveX control
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2009 Vadim Zeitlin
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
12 Documentation for embedding Flash into anything other than a web browser is
13 not easy to find, here is the tech note which provided most of the
14 information used here: http://www.adobe.com/go/tn_12059
17 // ============================================================================
19 // ============================================================================
21 // ----------------------------------------------------------------------------
23 // ----------------------------------------------------------------------------
25 #include "wx/wxprec.h"
32 #error "ActiveX controls are MSW-only"
39 #include "wx/cmdline.h"
40 #include "wx/filename.h"
42 #if !defined(__WXMSW__) && !defined(__WXPM__)
43 #include "../sample.xpm"
46 #include "wx/msw/ole/activex.h"
48 // we currently use VC-specific extensions in this sample, it could be
49 // rewritten to avoid them if there is real interest in doing it but compiler
50 // COM support in MSVC makes the code much simpler to understand
52 #error "This sample requires Microsoft Visual C++ compiler COM extensions"
55 // import Flash ActiveX control by using its (standard) type library UUID
57 // no_auto_exclude is needed to import IServiceProvider interface defined in
58 // this type library even though its name conflicts with a standard Windows
59 // interface with the same name
60 #import "libid:D27CDB6B-AE6D-11CF-96B8-444553540000" no_auto_exclude
62 using namespace ShockwaveFlashObjects
;
64 const CLSID CLSID_ShockwaveFlash
= __uuidof(ShockwaveFlash
);
65 const IID IID_IShockwaveFlash
= __uuidof(IShockwaveFlash
);
67 inline wxString
bstr2wx(const _bstr_t
& bstr
)
69 return wxString(static_cast<const wchar_t *>(bstr
));
72 inline _bstr_t
wx2bstr(const wxString
& str
)
74 return _bstr_t(str
.wc_str());
77 // ----------------------------------------------------------------------------
79 // ----------------------------------------------------------------------------
81 // taken from type library
85 const int FLASH_DISPID_ONREADYSTATECHANGE
= -609; // DISPID_ONREADYSTATECHANGE
86 const int FLASH_DISPID_ONPROGRESS
= 0x7a6;
87 const int FLASH_DISPID_FSCOMMAND
= 0x96;
88 const int FLASH_DISPID_FLASHCALL
= 0xc5;
92 FlashState_Unknown
= -1,
94 FlashState_Uninitialized
,
96 FlashState_Interactive
,
101 } // anonymous namespace
103 // ----------------------------------------------------------------------------
105 // ----------------------------------------------------------------------------
107 // Define a new application type, each program should derive a class from wxApp
108 class FlashApp
: public wxApp
113 virtual bool OnInit();
115 virtual void OnInitCmdLine(wxCmdLineParser
& parser
);
116 virtual bool OnCmdLineParsed(wxCmdLineParser
& parser
);
118 virtual bool OnExceptionInMainLoop();
123 DECLARE_NO_COPY_CLASS(FlashApp
)
126 // Define a new frame type: this is going to be our main frame
127 class FlashFrame
: public wxFrame
130 // ctor takes ownership of the pointer which must be non-NULL and opens the
131 // given SWF file if it's non-empty
132 FlashFrame(IShockwaveFlash
*flash
, const wxString
& swf
);
133 virtual ~FlashFrame();
135 void SetMovie(const wxString
& movie
);
150 void OnOpen(wxCommandEvent
& event
);
151 void OnQuit(wxCommandEvent
& event
);
152 void OnAbout(wxCommandEvent
& event
);
154 void OnPlay(wxCommandEvent
&) { Play(); }
155 void OnStop(wxCommandEvent
&) { Stop(); }
156 void OnBack(wxCommandEvent
& event
);
157 void OnForward(wxCommandEvent
& event
);
158 void OnInfo(wxCommandEvent
& event
);
159 void OnVarGet(wxCommandEvent
& event
);
160 void OnVarSet(wxCommandEvent
& event
);
161 void OnCall(wxCommandEvent
& event
);
162 void OnCallWithArg(wxCommandEvent
& event
);
164 void OnActiveXEvent(wxActiveXEvent
& event
);
166 // give an error message if hr is not S_OK
167 void CheckFlashCall(HRESULT hr
, const char *func
);
169 // return the name of the Flash control state
170 wxString
GetFlashStateString(int state
);
172 // call CallFunction() with a single argument of the type specified by
173 // argtype or without any arguments if it is empty
174 void CallFlashFunc(const wxString
& argtype
,
175 const wxString
& func
,
176 const wxString
& arg
= wxString());
179 const IShockwaveFlashPtr m_flash
;
184 wxTextCtrl
*m_varname
,
189 DECLARE_EVENT_TABLE()
190 DECLARE_NO_COPY_CLASS(FlashFrame
)
193 // ----------------------------------------------------------------------------
194 // event tables and other macros for wxWidgets
195 // ----------------------------------------------------------------------------
197 BEGIN_EVENT_TABLE(FlashFrame
, wxFrame
)
198 EVT_MENU(wxID_OPEN
, FlashFrame::OnOpen
)
199 EVT_MENU(wxID_EXIT
, FlashFrame::OnQuit
)
200 EVT_MENU(wxID_ABOUT
, FlashFrame::OnAbout
)
202 EVT_BUTTON(Flash_Play
, FlashFrame::OnPlay
)
203 EVT_BUTTON(wxID_STOP
, FlashFrame::OnStop
)
204 EVT_BUTTON(wxID_BACKWARD
, FlashFrame::OnBack
)
205 EVT_BUTTON(wxID_FORWARD
, FlashFrame::OnForward
)
207 EVT_BUTTON(wxID_INFO
, FlashFrame::OnInfo
)
208 EVT_BUTTON(Flash_Get
, FlashFrame::OnVarGet
)
209 EVT_BUTTON(Flash_Set
, FlashFrame::OnVarSet
)
210 EVT_BUTTON(Flash_Call
, FlashFrame::OnCall
)
211 EVT_BUTTON(Flash_CallWithArg
, FlashFrame::OnCallWithArg
)
213 EVT_ACTIVEX(wxID_ANY
, FlashFrame::OnActiveXEvent
)
216 IMPLEMENT_APP(FlashApp
)
218 // ============================================================================
220 // ============================================================================
222 // ----------------------------------------------------------------------------
223 // the application class
224 // ----------------------------------------------------------------------------
226 void FlashApp::OnInitCmdLine(wxCmdLineParser
& parser
)
228 wxApp::OnInitCmdLine(parser
);
230 parser
.AddParam("SWF file to play",
231 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
);
234 bool FlashApp::OnCmdLineParsed(wxCmdLineParser
& parser
)
236 if ( parser
.GetParamCount() )
237 m_swf
= parser
.GetParam(0);
239 return wxApp::OnCmdLineParsed(parser
);
242 bool FlashApp::OnInit()
244 if ( !wxApp::OnInit() )
247 IShockwaveFlash
*flash
= NULL
;
248 HRESULT hr
= ::CoCreateInstance
250 CLSID_ShockwaveFlash
,
252 CLSCTX_INPROC_SERVER
,
258 wxLogSysError(hr
, "Failed to create Flash ActiveX control");
262 new FlashFrame(flash
, m_swf
);
267 bool FlashApp::OnExceptionInMainLoop()
273 catch ( _com_error
& ce
)
275 wxLogMessage("COM exception: %s", ce
.ErrorMessage());
285 // ----------------------------------------------------------------------------
286 // main frame creation
287 // ----------------------------------------------------------------------------
290 FlashFrame::FlashFrame(IShockwaveFlash
*flash
, const wxString
& swf
)
291 : wxFrame(NULL
, wxID_ANY
, "wxWidgets Flash sample"),
292 m_flash(flash
, false /* take ownership */),
294 m_state(FlashState_Unknown
)
296 // set the frame icon
297 SetIcon(wxICON(sample
));
299 // create the new log target before doing anything with the Flash that
300 // could result in log messages
301 wxTextCtrl
* const log
= new wxTextCtrl(this, wxID_ANY
, "",
302 wxDefaultPosition
, wxSize(-1, 100),
304 m_oldLog
= wxLog::SetActiveTarget(new wxLogTextCtrl(log
));
308 wxMenu
*fileMenu
= new wxMenu
;
309 fileMenu
->Append(wxID_OPEN
);
310 fileMenu
->AppendSeparator();
311 fileMenu
->Append(wxID_EXIT
);
313 wxMenu
*helpMenu
= new wxMenu
;
314 helpMenu
->Append(wxID_ABOUT
);
316 wxMenuBar
*menuBar
= new wxMenuBar();
317 menuBar
->Append(fileMenu
, "&File");
318 menuBar
->Append(helpMenu
, "&Help");
320 #endif // wxUSE_MENUS
324 SetStatusText("Welcome to wxWidgets Flash embedding sample");
325 SetStatusText("No loaded file", 1);
326 #endif // wxUSE_STATUSBAR
328 wxPanel
* const panel
= new wxPanel(this);
329 wxSizer
* const sizerPanel
= new wxBoxSizer(wxVERTICAL
);
330 wxWindow
* const activeXParent
= new wxWindow(panel
, wxID_ANY
,
333 new wxActiveXContainer(activeXParent
, IID_IShockwaveFlash
, flash
);
337 sizerPanel
->Add(activeXParent
,
338 wxSizerFlags(1).Expand().Border());
340 const wxSizerFlags
flagsHorz(wxSizerFlags().Centre().HorzBorder());
342 wxSizer
* const sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
343 sizerBtns
->Add(new wxButton(panel
, wxID_BACKWARD
), flagsHorz
);
344 sizerBtns
->Add(new wxButton(panel
, Flash_Play
, "&Play"), flagsHorz
);
345 sizerBtns
->Add(new wxButton(panel
, wxID_STOP
), flagsHorz
);
346 sizerBtns
->Add(new wxButton(panel
, wxID_FORWARD
), flagsHorz
);
347 sizerBtns
->AddSpacer(20);
348 sizerBtns
->Add(new wxButton(panel
, wxID_INFO
), flagsHorz
);
349 sizerPanel
->Add(sizerBtns
, wxSizerFlags().Center().Border());
351 wxSizer
* const sizerVar
= new wxBoxSizer(wxHORIZONTAL
);
352 sizerVar
->Add(new wxStaticText(panel
, wxID_ANY
, "Variable &name:"),
354 m_varname
= new wxTextCtrl(panel
, wxID_ANY
);
355 sizerVar
->Add(m_varname
, flagsHorz
);
356 sizerVar
->Add(new wxStaticText(panel
, wxID_ANY
, "&value:"),
358 m_varvalue
= new wxTextCtrl(panel
, wxID_ANY
);
359 sizerVar
->Add(m_varvalue
, flagsHorz
);
360 sizerVar
->AddSpacer(10);
361 sizerVar
->Add(new wxButton(panel
, Flash_Get
, "&Get"), flagsHorz
);
362 sizerVar
->Add(new wxButton(panel
, Flash_Set
, "&Set"), flagsHorz
);
363 sizerPanel
->Add(sizerVar
, wxSizerFlags().Center().Border());
365 wxSizer
* const sizerCall
= new wxBoxSizer(wxHORIZONTAL
);
366 sizerCall
->Add(new wxStaticText(panel
, wxID_ANY
, "&Function name:"),
368 m_funcname
= new wxTextCtrl(panel
, wxID_ANY
);
369 sizerCall
->Add(m_funcname
, flagsHorz
);
370 sizerCall
->Add(new wxButton(panel
, Flash_Call
, "&Call"), flagsHorz
);
371 sizerCall
->Add(new wxStaticText(panel
, wxID_ANY
, "&argument:"),
373 m_funcarg
= new wxTextCtrl(panel
, wxID_ANY
);
374 sizerCall
->Add(m_funcarg
, flagsHorz
);
375 sizerCall
->Add(new wxButton(panel
, Flash_CallWithArg
, "Call &with arg"),
377 sizerPanel
->Add(sizerCall
, wxSizerFlags().Center().Border());
379 panel
->SetSizer(sizerPanel
);
381 wxSizer
* const sizerFrame
= new wxBoxSizer(wxVERTICAL
);
382 sizerFrame
->Add(panel
, wxSizerFlags(2).Expand());
383 sizerFrame
->Add(log
, wxSizerFlags(1).Expand());
384 SetSizerAndFit(sizerFrame
);
388 m_flash
->PutAllowScriptAccess(L
"always");
389 wxLogMessage("Script access changed to \"%s\"",
390 bstr2wx(m_flash
->GetAllowScriptAccess()));
393 FlashFrame::~FlashFrame()
395 delete wxLog::SetActiveTarget(m_oldLog
);
398 // ----------------------------------------------------------------------------
399 // Flash API wrappers
400 // ----------------------------------------------------------------------------
402 void FlashFrame::CheckFlashCall(HRESULT hr
, const char *func
)
406 wxLogSysError(hr
, "Call to IShockwaveFlash::%s() failed", func
);
410 void FlashFrame::CallFlashFunc(const wxString
& argtype
,
411 const wxString
& func
,
415 if ( !argtype
.empty() )
417 args
= wxString::Format("<%s>%s</%s>", argtype
, arg
, argtype
);
420 // take care with XML formatting: there should be no spaces in it or the
422 wxString request
= wxString::Format
424 "<invoke name=\"%s\" returntype=\"xml\">"
433 wxLogMessage("%s(%s) returned \"%s\"",
435 bstr2wx(m_flash
->CallFunction(wx2bstr(request
))));
438 wxString
FlashFrame::GetFlashStateString(int state
)
440 static const char *knownStates
[] =
442 "Loading", "Uninitialized", "Loaded", "Interactive", "Complete",
445 if ( state
>= 0 && state
< WXSIZEOF(knownStates
) )
446 return knownStates
[state
];
448 return wxString::Format("unknown state (%d)", state
);
451 void FlashFrame::SetMovie(const wxString
& movie
)
453 // Flash doesn't like relative file names
454 wxFileName
fn(movie
);
456 const wxString swf
= fn
.GetFullPath();
458 m_flash
->PutMovie(L
"");
462 m_flash
->PutMovie(m_swf
.wc_str());
464 SetStatusText("Loaded \"" + m_swf
+ '"', 1);
467 void FlashFrame::Play()
469 CheckFlashCall(m_flash
->Play(), "Play");
472 void FlashFrame::Stop()
474 CheckFlashCall(m_flash
->Stop(), "Stop");
477 // ----------------------------------------------------------------------------
479 // ----------------------------------------------------------------------------
481 void FlashFrame::OnOpen(wxCommandEvent
& WXUNUSED(event
))
483 wxString swf
= wxLoadFileSelector("Flash movie", ".swf", m_swf
, this);
490 void FlashFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
492 // true is to force the frame to close
496 void FlashFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
498 wxMessageBox("Flash ActiveX control embedding sample\n"
500 "(c) 2009 Vadim Zeitlin",
501 "About " + GetTitle(),
502 wxOK
| wxICON_INFORMATION
,
506 void FlashFrame::OnActiveXEvent(wxActiveXEvent
& event
)
508 switch ( event
.GetDispatchId() )
510 case FLASH_DISPID_ONREADYSTATECHANGE
:
512 const int state
= event
[0].GetInteger();
513 if ( state
!= m_state
)
515 wxLogMessage("State changed to %s",
516 GetFlashStateString(state
));
518 if ( state
>= 0 && state
< FlashState_Max
)
519 m_state
= static_cast<FlashState
>(state
);
521 m_state
= FlashState_Unknown
;
526 case FLASH_DISPID_ONPROGRESS
:
527 wxLogMessage("Progress: %d%%", event
[0].GetInteger());
530 case FLASH_DISPID_FSCOMMAND
:
531 wxLogMessage("Flash command %s(%s)",
532 event
[0].GetString(), event
[1].GetString());
535 case FLASH_DISPID_FLASHCALL
:
536 wxLogMessage("Flash request \"%s\"", event
[0].GetString());
540 wxLogMessage("Unknown event %ld", event
.GetDispatchId());
546 void FlashFrame::OnBack(wxCommandEvent
& WXUNUSED(event
))
548 CheckFlashCall(m_flash
->Back(), "Back");
551 void FlashFrame::OnForward(wxCommandEvent
& WXUNUSED(event
))
553 CheckFlashCall(m_flash
->Forward(), "Forward");
556 void FlashFrame::OnInfo(wxCommandEvent
& WXUNUSED(event
))
558 const int state
= m_flash
->GetReadyState();
559 wxString msg
= "State: " + GetFlashStateString(state
);
561 if ( state
== FlashState_Complete
)
563 msg
+= wxString::Format(", frame: %ld/%ld",
564 m_flash
->GetFrameNum() + 1,
565 m_flash
->GetTotalFrames());
568 if ( m_flash
->IsPlaying() )
571 wxLogMessage("%s", msg
);
574 void FlashFrame::OnVarGet(wxCommandEvent
& WXUNUSED(event
))
576 m_varvalue
->SetValue(bstr2wx(
577 m_flash
->GetVariable(wx2bstr(m_varname
->GetValue()))));
580 void FlashFrame::OnVarSet(wxCommandEvent
& WXUNUSED(event
))
582 m_flash
->SetVariable(wx2bstr(m_varname
->GetValue()),
583 wx2bstr(m_varvalue
->GetValue()));
586 void FlashFrame::OnCall(wxCommandEvent
& WXUNUSED(event
))
588 CallFlashFunc("", m_funcname
->GetValue());
591 void FlashFrame::OnCallWithArg(wxCommandEvent
& WXUNUSED(event
))
593 CallFlashFunc("string", m_funcname
->GetValue(), m_funcarg
->GetValue());