1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Sample showing integration of Flash ActiveX control
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2009 Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 Documentation for embedding Flash into anything other than a web browser is
12 not easy to find, here is the tech note which provided most of the
13 information used here: http://www.adobe.com/go/tn_12059
16 // ============================================================================
18 // ============================================================================
20 // ----------------------------------------------------------------------------
22 // ----------------------------------------------------------------------------
24 #include "wx/wxprec.h"
31 #error "ActiveX controls are MSW-only"
38 #include "wx/cmdline.h"
39 #include "wx/filename.h"
41 #ifndef wxHAS_IMAGES_IN_RESOURCES
42 #include "../sample.xpm"
45 #include "wx/msw/ole/activex.h"
47 // we currently use VC-specific extensions in this sample, it could be
48 // rewritten to avoid them if there is real interest in doing it but compiler
49 // COM support in MSVC makes the code much simpler to understand
51 #error "This sample requires Microsoft Visual C++ compiler COM extensions"
54 // import Flash ActiveX control by using its (standard) type library UUID
56 // no_auto_exclude is needed to import IServiceProvider interface defined in
57 // this type library even though its name conflicts with a standard Windows
58 // interface with the same name
59 #import "libid:D27CDB6B-AE6D-11CF-96B8-444553540000" no_auto_exclude
61 using namespace ShockwaveFlashObjects
;
63 const CLSID CLSID_ShockwaveFlash
= __uuidof(ShockwaveFlash
);
64 const IID IID_IShockwaveFlash
= __uuidof(IShockwaveFlash
);
66 inline wxString
bstr2wx(const _bstr_t
& bstr
)
68 return wxString(static_cast<const wchar_t *>(bstr
));
71 inline _bstr_t
wx2bstr(const wxString
& str
)
73 return _bstr_t(str
.wc_str());
76 // ----------------------------------------------------------------------------
78 // ----------------------------------------------------------------------------
80 // taken from type library
84 const int FLASH_DISPID_ONREADYSTATECHANGE
= -609; // DISPID_ONREADYSTATECHANGE
85 const int FLASH_DISPID_ONPROGRESS
= 0x7a6;
86 const int FLASH_DISPID_FSCOMMAND
= 0x96;
87 const int FLASH_DISPID_FLASHCALL
= 0xc5;
91 FlashState_Unknown
= -1,
93 FlashState_Uninitialized
,
95 FlashState_Interactive
,
100 } // anonymous namespace
102 // ----------------------------------------------------------------------------
104 // ----------------------------------------------------------------------------
106 // Define a new application type, each program should derive a class from wxApp
107 class FlashApp
: public wxApp
112 virtual bool OnInit();
114 virtual void OnInitCmdLine(wxCmdLineParser
& parser
);
115 virtual bool OnCmdLineParsed(wxCmdLineParser
& parser
);
117 virtual bool OnExceptionInMainLoop();
122 wxDECLARE_NO_COPY_CLASS(FlashApp
);
125 // Define a new frame type: this is going to be our main frame
126 class FlashFrame
: public wxFrame
129 // ctor takes ownership of the pointer which must be non-NULL and opens the
130 // given SWF file if it's non-empty
131 FlashFrame(IShockwaveFlash
*flash
, const wxString
& swf
);
132 virtual ~FlashFrame();
134 void SetMovie(const wxString
& movie
);
149 void OnOpen(wxCommandEvent
& event
);
150 void OnQuit(wxCommandEvent
& event
);
151 void OnAbout(wxCommandEvent
& event
);
153 void OnPlay(wxCommandEvent
&) { Play(); }
154 void OnStop(wxCommandEvent
&) { Stop(); }
155 void OnBack(wxCommandEvent
& event
);
156 void OnForward(wxCommandEvent
& event
);
157 void OnInfo(wxCommandEvent
& event
);
158 void OnVarGet(wxCommandEvent
& event
);
159 void OnVarSet(wxCommandEvent
& event
);
160 void OnCall(wxCommandEvent
& event
);
161 void OnCallWithArg(wxCommandEvent
& event
);
163 void OnActiveXEvent(wxActiveXEvent
& event
);
165 // give an error message if hr is not S_OK
166 void CheckFlashCall(HRESULT hr
, const char *func
);
168 // return the name of the Flash control state
169 wxString
GetFlashStateString(int state
);
171 // call CallFunction() with a single argument of the type specified by
172 // argtype or without any arguments if it is empty
173 void CallFlashFunc(const wxString
& argtype
,
174 const wxString
& func
,
175 const wxString
& arg
= wxString());
178 const IShockwaveFlashPtr m_flash
;
183 wxTextCtrl
*m_varname
,
188 DECLARE_EVENT_TABLE()
189 wxDECLARE_NO_COPY_CLASS(FlashFrame
);
192 // ----------------------------------------------------------------------------
193 // event tables and other macros for wxWidgets
194 // ----------------------------------------------------------------------------
196 BEGIN_EVENT_TABLE(FlashFrame
, wxFrame
)
197 EVT_MENU(wxID_OPEN
, FlashFrame::OnOpen
)
198 EVT_MENU(wxID_EXIT
, FlashFrame::OnQuit
)
199 EVT_MENU(wxID_ABOUT
, FlashFrame::OnAbout
)
201 EVT_BUTTON(Flash_Play
, FlashFrame::OnPlay
)
202 EVT_BUTTON(wxID_STOP
, FlashFrame::OnStop
)
203 EVT_BUTTON(wxID_BACKWARD
, FlashFrame::OnBack
)
204 EVT_BUTTON(wxID_FORWARD
, FlashFrame::OnForward
)
206 EVT_BUTTON(wxID_INFO
, FlashFrame::OnInfo
)
207 EVT_BUTTON(Flash_Get
, FlashFrame::OnVarGet
)
208 EVT_BUTTON(Flash_Set
, FlashFrame::OnVarSet
)
209 EVT_BUTTON(Flash_Call
, FlashFrame::OnCall
)
210 EVT_BUTTON(Flash_CallWithArg
, FlashFrame::OnCallWithArg
)
212 EVT_ACTIVEX(wxID_ANY
, FlashFrame::OnActiveXEvent
)
215 IMPLEMENT_APP(FlashApp
)
217 // ============================================================================
219 // ============================================================================
221 // ----------------------------------------------------------------------------
222 // the application class
223 // ----------------------------------------------------------------------------
225 void FlashApp::OnInitCmdLine(wxCmdLineParser
& parser
)
227 wxApp::OnInitCmdLine(parser
);
229 parser
.AddParam("SWF file to play",
230 wxCMD_LINE_VAL_STRING
, wxCMD_LINE_PARAM_OPTIONAL
);
233 bool FlashApp::OnCmdLineParsed(wxCmdLineParser
& parser
)
235 if ( parser
.GetParamCount() )
236 m_swf
= parser
.GetParam(0);
238 return wxApp::OnCmdLineParsed(parser
);
241 bool FlashApp::OnInit()
243 if ( !wxApp::OnInit() )
246 IShockwaveFlash
*flash
= NULL
;
247 HRESULT hr
= ::CoCreateInstance
249 CLSID_ShockwaveFlash
,
251 CLSCTX_INPROC_SERVER
,
257 wxLogSysError(hr
, "Failed to create Flash ActiveX control");
261 new FlashFrame(flash
, m_swf
);
266 bool FlashApp::OnExceptionInMainLoop()
272 catch ( _com_error
& ce
)
274 wxLogMessage("COM exception: %s", ce
.ErrorMessage());
284 // ----------------------------------------------------------------------------
285 // main frame creation
286 // ----------------------------------------------------------------------------
289 FlashFrame::FlashFrame(IShockwaveFlash
*flash
, const wxString
& swf
)
290 : wxFrame(NULL
, wxID_ANY
, "wxWidgets Flash sample"),
291 m_flash(flash
, false /* take ownership */),
293 m_state(FlashState_Unknown
)
295 // set the frame icon
296 SetIcon(wxICON(sample
));
298 // create the new log target before doing anything with the Flash that
299 // could result in log messages
300 wxTextCtrl
* const log
= new wxTextCtrl(this, wxID_ANY
, "",
301 wxDefaultPosition
, wxSize(-1, 100),
303 m_oldLog
= wxLog::SetActiveTarget(new wxLogTextCtrl(log
));
307 wxMenu
*fileMenu
= new wxMenu
;
308 fileMenu
->Append(wxID_OPEN
);
309 fileMenu
->AppendSeparator();
310 fileMenu
->Append(wxID_EXIT
);
312 wxMenu
*helpMenu
= new wxMenu
;
313 helpMenu
->Append(wxID_ABOUT
);
315 wxMenuBar
*menuBar
= new wxMenuBar();
316 menuBar
->Append(fileMenu
, "&File");
317 menuBar
->Append(helpMenu
, "&Help");
319 #endif // wxUSE_MENUS
323 SetStatusText("Welcome to wxWidgets Flash embedding sample");
324 SetStatusText("No loaded file", 1);
325 #endif // wxUSE_STATUSBAR
327 wxPanel
* const panel
= new wxPanel(this);
328 wxSizer
* const sizerPanel
= new wxBoxSizer(wxVERTICAL
);
329 wxWindow
* const activeXParent
= new wxWindow(panel
, wxID_ANY
,
332 new wxActiveXContainer(activeXParent
, IID_IShockwaveFlash
, flash
);
336 sizerPanel
->Add(activeXParent
,
337 wxSizerFlags(1).Expand().Border());
339 const wxSizerFlags
flagsHorz(wxSizerFlags().Centre().HorzBorder());
341 wxSizer
* const sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
342 sizerBtns
->Add(new wxButton(panel
, wxID_BACKWARD
), flagsHorz
);
343 sizerBtns
->Add(new wxButton(panel
, Flash_Play
, "&Play"), flagsHorz
);
344 sizerBtns
->Add(new wxButton(panel
, wxID_STOP
), flagsHorz
);
345 sizerBtns
->Add(new wxButton(panel
, wxID_FORWARD
), flagsHorz
);
346 sizerBtns
->AddSpacer(20);
347 sizerBtns
->Add(new wxButton(panel
, wxID_INFO
), flagsHorz
);
348 sizerPanel
->Add(sizerBtns
, wxSizerFlags().Center().Border());
350 wxSizer
* const sizerVar
= new wxBoxSizer(wxHORIZONTAL
);
351 sizerVar
->Add(new wxStaticText(panel
, wxID_ANY
, "Variable &name:"),
353 m_varname
= new wxTextCtrl(panel
, wxID_ANY
);
354 sizerVar
->Add(m_varname
, flagsHorz
);
355 sizerVar
->Add(new wxStaticText(panel
, wxID_ANY
, "&value:"),
357 m_varvalue
= new wxTextCtrl(panel
, wxID_ANY
);
358 sizerVar
->Add(m_varvalue
, flagsHorz
);
359 sizerVar
->AddSpacer(10);
360 sizerVar
->Add(new wxButton(panel
, Flash_Get
, "&Get"), flagsHorz
);
361 sizerVar
->Add(new wxButton(panel
, Flash_Set
, "&Set"), flagsHorz
);
362 sizerPanel
->Add(sizerVar
, wxSizerFlags().Center().Border());
364 wxSizer
* const sizerCall
= new wxBoxSizer(wxHORIZONTAL
);
365 sizerCall
->Add(new wxStaticText(panel
, wxID_ANY
, "&Function name:"),
367 m_funcname
= new wxTextCtrl(panel
, wxID_ANY
);
368 sizerCall
->Add(m_funcname
, flagsHorz
);
369 sizerCall
->Add(new wxButton(panel
, Flash_Call
, "&Call"), flagsHorz
);
370 sizerCall
->Add(new wxStaticText(panel
, wxID_ANY
, "&argument:"),
372 m_funcarg
= new wxTextCtrl(panel
, wxID_ANY
);
373 sizerCall
->Add(m_funcarg
, flagsHorz
);
374 sizerCall
->Add(new wxButton(panel
, Flash_CallWithArg
, "Call &with arg"),
376 sizerPanel
->Add(sizerCall
, wxSizerFlags().Center().Border());
378 panel
->SetSizer(sizerPanel
);
380 wxSizer
* const sizerFrame
= new wxBoxSizer(wxVERTICAL
);
381 sizerFrame
->Add(panel
, wxSizerFlags(2).Expand());
382 sizerFrame
->Add(log
, wxSizerFlags(1).Expand());
383 SetSizerAndFit(sizerFrame
);
387 m_flash
->PutAllowScriptAccess(L
"always");
388 wxLogMessage("Script access changed to \"%s\"",
389 bstr2wx(m_flash
->GetAllowScriptAccess()));
392 FlashFrame::~FlashFrame()
394 delete wxLog::SetActiveTarget(m_oldLog
);
397 // ----------------------------------------------------------------------------
398 // Flash API wrappers
399 // ----------------------------------------------------------------------------
401 void FlashFrame::CheckFlashCall(HRESULT hr
, const char *func
)
405 wxLogSysError(hr
, "Call to IShockwaveFlash::%s() failed", func
);
409 void FlashFrame::CallFlashFunc(const wxString
& argtype
,
410 const wxString
& func
,
414 if ( !argtype
.empty() )
416 args
= wxString::Format("<%s>%s</%s>", argtype
, arg
, argtype
);
419 // take care with XML formatting: there should be no spaces in it or the
421 wxString request
= wxString::Format
423 "<invoke name=\"%s\" returntype=\"xml\">"
432 wxLogMessage("%s(%s) returned \"%s\"",
434 bstr2wx(m_flash
->CallFunction(wx2bstr(request
))));
437 wxString
FlashFrame::GetFlashStateString(int state
)
439 static const char *knownStates
[] =
441 "Loading", "Uninitialized", "Loaded", "Interactive", "Complete",
444 if ( state
>= 0 && state
< WXSIZEOF(knownStates
) )
445 return knownStates
[state
];
447 return wxString::Format("unknown state (%d)", state
);
450 void FlashFrame::SetMovie(const wxString
& movie
)
452 // Flash doesn't like relative file names
453 wxFileName
fn(movie
);
455 const wxString swf
= fn
.GetFullPath();
457 m_flash
->PutMovie(L
"");
461 m_flash
->PutMovie(m_swf
.wc_str());
463 SetStatusText("Loaded \"" + m_swf
+ '"', 1);
466 void FlashFrame::Play()
468 CheckFlashCall(m_flash
->Play(), "Play");
471 void FlashFrame::Stop()
473 CheckFlashCall(m_flash
->Stop(), "Stop");
476 // ----------------------------------------------------------------------------
478 // ----------------------------------------------------------------------------
480 void FlashFrame::OnOpen(wxCommandEvent
& WXUNUSED(event
))
482 wxString swf
= wxLoadFileSelector("Flash movie", ".swf", m_swf
, this);
489 void FlashFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
491 // true is to force the frame to close
495 void FlashFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
497 wxMessageBox("Flash ActiveX control embedding sample\n"
499 "(c) 2009 Vadim Zeitlin",
500 "About " + GetTitle(),
501 wxOK
| wxICON_INFORMATION
,
505 void FlashFrame::OnActiveXEvent(wxActiveXEvent
& event
)
507 switch ( event
.GetDispatchId() )
509 case FLASH_DISPID_ONREADYSTATECHANGE
:
511 const int state
= event
[0].GetInteger();
512 if ( state
!= m_state
)
514 wxLogMessage("State changed to %s",
515 GetFlashStateString(state
));
517 if ( state
>= 0 && state
< FlashState_Max
)
518 m_state
= static_cast<FlashState
>(state
);
520 m_state
= FlashState_Unknown
;
525 case FLASH_DISPID_ONPROGRESS
:
526 wxLogMessage("Progress: %d%%", event
[0].GetInteger());
529 case FLASH_DISPID_FSCOMMAND
:
530 wxLogMessage("Flash command %s(%s)",
531 event
[0].GetString(), event
[1].GetString());
534 case FLASH_DISPID_FLASHCALL
:
535 wxLogMessage("Flash request \"%s\"", event
[0].GetString());
539 wxLogMessage("Unknown event %ld", event
.GetDispatchId());
545 void FlashFrame::OnBack(wxCommandEvent
& WXUNUSED(event
))
547 CheckFlashCall(m_flash
->Back(), "Back");
550 void FlashFrame::OnForward(wxCommandEvent
& WXUNUSED(event
))
552 CheckFlashCall(m_flash
->Forward(), "Forward");
555 void FlashFrame::OnInfo(wxCommandEvent
& WXUNUSED(event
))
557 const int state
= m_flash
->GetReadyState();
558 wxString msg
= "State: " + GetFlashStateString(state
);
560 if ( state
== FlashState_Complete
)
562 msg
+= wxString::Format(", frame: %ld/%ld",
563 m_flash
->GetFrameNum() + 1,
564 m_flash
->GetTotalFrames());
567 if ( m_flash
->IsPlaying() )
570 wxLogMessage("%s", msg
);
573 void FlashFrame::OnVarGet(wxCommandEvent
& WXUNUSED(event
))
575 m_varvalue
->SetValue(bstr2wx(
576 m_flash
->GetVariable(wx2bstr(m_varname
->GetValue()))));
579 void FlashFrame::OnVarSet(wxCommandEvent
& WXUNUSED(event
))
581 m_flash
->SetVariable(wx2bstr(m_varname
->GetValue()),
582 wx2bstr(m_varvalue
->GetValue()));
585 void FlashFrame::OnCall(wxCommandEvent
& WXUNUSED(event
))
587 CallFlashFunc("", m_funcname
->GetValue());
590 void FlashFrame::OnCallWithArg(wxCommandEvent
& WXUNUSED(event
))
592 CallFlashFunc("string", m_funcname
->GetValue(), m_funcarg
->GetValue());