]> git.saurik.com Git - wxWidgets.git/blame - samples/flash/flash.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / samples / flash / flash.cpp
CommitLineData
3707ff67
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: flash.cpp
3// Purpose: Sample showing integration of Flash ActiveX control
4// Author: Vadim Zeitlin
5// Created: 2009-01-13
3707ff67
VZ
6// Copyright: (c) 2009 Vadim Zeitlin
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10/*
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
14 */
15
16// ============================================================================
17// declarations
18// ============================================================================
19
20// ----------------------------------------------------------------------------
21// headers
22// ----------------------------------------------------------------------------
ce00f59b 23
3707ff67 24#include "wx/wxprec.h"
ce00f59b 25
3707ff67
VZ
26#ifdef __BORLANDC__
27 #pragma hdrstop
28#endif
29
30#ifndef __WXMSW__
31 #error "ActiveX controls are MSW-only"
32#endif
33
34#ifndef WX_PRECOMP
35 #include "wx/wx.h"
36#endif
37
38#include "wx/cmdline.h"
39#include "wx/filename.h"
40
e7092398 41#ifndef wxHAS_IMAGES_IN_RESOURCES
3707ff67
VZ
42 #include "../sample.xpm"
43#endif
44
45#include "wx/msw/ole/activex.h"
46
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
50#ifndef __VISUALC__
51 #error "This sample requires Microsoft Visual C++ compiler COM extensions"
52#endif
53
54// import Flash ActiveX control by using its (standard) type library UUID
55//
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
60
61using namespace ShockwaveFlashObjects;
62
63const CLSID CLSID_ShockwaveFlash = __uuidof(ShockwaveFlash);
64const IID IID_IShockwaveFlash = __uuidof(IShockwaveFlash);
65
66inline wxString bstr2wx(const _bstr_t& bstr)
67{
68 return wxString(static_cast<const wchar_t *>(bstr));
69}
70
71inline _bstr_t wx2bstr(const wxString& str)
72{
73 return _bstr_t(str.wc_str());
74}
75
76// ----------------------------------------------------------------------------
77// constants
78// ----------------------------------------------------------------------------
79
80// taken from type library
81namespace
82{
83
84const int FLASH_DISPID_ONREADYSTATECHANGE = -609; // DISPID_ONREADYSTATECHANGE
85const int FLASH_DISPID_ONPROGRESS = 0x7a6;
86const int FLASH_DISPID_FSCOMMAND = 0x96;
87const int FLASH_DISPID_FLASHCALL = 0xc5;
88
89enum FlashState
90{
91 FlashState_Unknown = -1,
92 FlashState_Loading,
93 FlashState_Uninitialized,
94 FlashState_Loaded,
95 FlashState_Interactive,
96 FlashState_Complete,
97 FlashState_Max
98};
99
100} // anonymous namespace
101
102// ----------------------------------------------------------------------------
103// private classes
104// ----------------------------------------------------------------------------
105
106// Define a new application type, each program should derive a class from wxApp
107class FlashApp : public wxApp
108{
109public:
110 FlashApp() { }
111
112 virtual bool OnInit();
113
114 virtual void OnInitCmdLine(wxCmdLineParser& parser);
115 virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
116
117 virtual bool OnExceptionInMainLoop();
118
119private:
120 wxString m_swf;
121
c0c133e1 122 wxDECLARE_NO_COPY_CLASS(FlashApp);
3707ff67
VZ
123};
124
125// Define a new frame type: this is going to be our main frame
126class FlashFrame : public wxFrame
127{
128public:
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();
133
134 void SetMovie(const wxString& movie);
135
136 void Play();
137 void Stop();
138
139private:
140 enum
141 {
142 Flash_Play = 100,
143 Flash_Get,
144 Flash_Set,
145 Flash_Call,
146 Flash_CallWithArg
147 };
148
149 void OnOpen(wxCommandEvent& event);
150 void OnQuit(wxCommandEvent& event);
151 void OnAbout(wxCommandEvent& event);
152
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);
162
163 void OnActiveXEvent(wxActiveXEvent& event);
164
165 // give an error message if hr is not S_OK
166 void CheckFlashCall(HRESULT hr, const char *func);
167
168 // return the name of the Flash control state
169 wxString GetFlashStateString(int state);
170
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());
176
177
178 const IShockwaveFlashPtr m_flash;
179 wxLog *m_oldLog;
180 wxString m_swf;
181 FlashState m_state;
182
183 wxTextCtrl *m_varname,
184 *m_varvalue,
185 *m_funcname,
186 *m_funcarg;
187
188 DECLARE_EVENT_TABLE()
c0c133e1 189 wxDECLARE_NO_COPY_CLASS(FlashFrame);
3707ff67
VZ
190};
191
192// ----------------------------------------------------------------------------
193// event tables and other macros for wxWidgets
194// ----------------------------------------------------------------------------
195
196BEGIN_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)
200
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)
205
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)
211
212 EVT_ACTIVEX(wxID_ANY, FlashFrame::OnActiveXEvent)
213END_EVENT_TABLE()
214
215IMPLEMENT_APP(FlashApp)
216
217// ============================================================================
218// implementation
219// ============================================================================
220
221// ----------------------------------------------------------------------------
222// the application class
223// ----------------------------------------------------------------------------
224
225void FlashApp::OnInitCmdLine(wxCmdLineParser& parser)
226{
227 wxApp::OnInitCmdLine(parser);
228
229 parser.AddParam("SWF file to play",
230 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
231}
232
233bool FlashApp::OnCmdLineParsed(wxCmdLineParser& parser)
234{
235 if ( parser.GetParamCount() )
236 m_swf = parser.GetParam(0);
237
238 return wxApp::OnCmdLineParsed(parser);
239}
240
241bool FlashApp::OnInit()
242{
243 if ( !wxApp::OnInit() )
244 return false;
245
246 IShockwaveFlash *flash = NULL;
247 HRESULT hr = ::CoCreateInstance
248 (
249 CLSID_ShockwaveFlash,
250 NULL,
251 CLSCTX_INPROC_SERVER,
252 IID_IShockwaveFlash,
253 (void **)&flash
254 );
255 if ( FAILED(hr) )
256 {
257 wxLogSysError(hr, "Failed to create Flash ActiveX control");
258 return false;
259 }
260
261 new FlashFrame(flash, m_swf);
262
263 return true;
264}
265
266bool FlashApp::OnExceptionInMainLoop()
267{
268 try
269 {
270 throw;
271 }
272 catch ( _com_error& ce )
273 {
274 wxLogMessage("COM exception: %s", ce.ErrorMessage());
275
276 return true;
277 }
278 catch ( ... )
279 {
280 throw;
281 }
282}
283
284// ----------------------------------------------------------------------------
285// main frame creation
286// ----------------------------------------------------------------------------
287
288// frame constructor
289FlashFrame::FlashFrame(IShockwaveFlash *flash, const wxString& swf)
290 : wxFrame(NULL, wxID_ANY, "wxWidgets Flash sample"),
291 m_flash(flash, false /* take ownership */),
292 m_swf(swf),
293 m_state(FlashState_Unknown)
294{
295 // set the frame icon
296 SetIcon(wxICON(sample));
297
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),
302 wxTE_MULTILINE);
303 m_oldLog = wxLog::SetActiveTarget(new wxLogTextCtrl(log));
304
305#if wxUSE_MENUS
306 // create a menu bar
307 wxMenu *fileMenu = new wxMenu;
308 fileMenu->Append(wxID_OPEN);
309 fileMenu->AppendSeparator();
310 fileMenu->Append(wxID_EXIT);
311
312 wxMenu *helpMenu = new wxMenu;
313 helpMenu->Append(wxID_ABOUT);
314
315 wxMenuBar *menuBar = new wxMenuBar();
316 menuBar->Append(fileMenu, "&File");
317 menuBar->Append(helpMenu, "&Help");
318 SetMenuBar(menuBar);
319#endif // wxUSE_MENUS
320
321#if wxUSE_STATUSBAR
322 CreateStatusBar(2);
323 SetStatusText("Welcome to wxWidgets Flash embedding sample");
324 SetStatusText("No loaded file", 1);
325#endif // wxUSE_STATUSBAR
326
327 wxPanel * const panel = new wxPanel(this);
328 wxSizer * const sizerPanel = new wxBoxSizer(wxVERTICAL);
329 wxWindow * const activeXParent = new wxWindow(panel, wxID_ANY,
330 wxDefaultPosition,
331 wxSize(300, 200));
332 new wxActiveXContainer(activeXParent, IID_IShockwaveFlash, flash);
333 if ( !swf.empty() )
334 SetMovie(swf);
335
336 sizerPanel->Add(activeXParent,
337 wxSizerFlags(1).Expand().Border());
338
339 const wxSizerFlags flagsHorz(wxSizerFlags().Centre().HorzBorder());
340
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());
349
350 wxSizer * const sizerVar = new wxBoxSizer(wxHORIZONTAL);
351 sizerVar->Add(new wxStaticText(panel, wxID_ANY, "Variable &name:"),
352 flagsHorz);
353 m_varname = new wxTextCtrl(panel, wxID_ANY);
354 sizerVar->Add(m_varname, flagsHorz);
355 sizerVar->Add(new wxStaticText(panel, wxID_ANY, "&value:"),
356 flagsHorz);
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());
363
364 wxSizer * const sizerCall = new wxBoxSizer(wxHORIZONTAL);
365 sizerCall->Add(new wxStaticText(panel, wxID_ANY, "&Function name:"),
366 flagsHorz);
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:"),
371 flagsHorz);
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"),
375 flagsHorz);
376 sizerPanel->Add(sizerCall, wxSizerFlags().Center().Border());
377
378 panel->SetSizer(sizerPanel);
379
380 wxSizer * const sizerFrame = new wxBoxSizer(wxVERTICAL);
381 sizerFrame->Add(panel, wxSizerFlags(2).Expand());
382 sizerFrame->Add(log, wxSizerFlags(1).Expand());
383 SetSizerAndFit(sizerFrame);
384
385 Show();
386
387 m_flash->PutAllowScriptAccess(L"always");
388 wxLogMessage("Script access changed to \"%s\"",
389 bstr2wx(m_flash->GetAllowScriptAccess()));
390}
391
392FlashFrame::~FlashFrame()
393{
394 delete wxLog::SetActiveTarget(m_oldLog);
395}
396
397// ----------------------------------------------------------------------------
398// Flash API wrappers
399// ----------------------------------------------------------------------------
400
401void FlashFrame::CheckFlashCall(HRESULT hr, const char *func)
402{
403 if ( FAILED(hr) )
404 {
405 wxLogSysError(hr, "Call to IShockwaveFlash::%s() failed", func);
406 }
407}
408
409void FlashFrame::CallFlashFunc(const wxString& argtype,
410 const wxString& func,
411 const wxString& arg)
412{
413 wxString args;
414 if ( !argtype.empty() )
415 {
416 args = wxString::Format("<%s>%s</%s>", argtype, arg, argtype);
417 }
418
419 // take care with XML formatting: there should be no spaces in it or the
420 // call would fail!
421 wxString request = wxString::Format
422 (
423 "<invoke name=\"%s\" returntype=\"xml\">"
424 "<arguments>"
425 "%s"
426 "</arguments>"
427 "</invoke>",
428 func,
429 args
430 );
431
432 wxLogMessage("%s(%s) returned \"%s\"",
433 func, args,
434 bstr2wx(m_flash->CallFunction(wx2bstr(request))));
435}
436
437wxString FlashFrame::GetFlashStateString(int state)
438{
439 static const char *knownStates[] =
440 {
441 "Loading", "Uninitialized", "Loaded", "Interactive", "Complete",
442 };
443
444 if ( state >= 0 && state < WXSIZEOF(knownStates) )
445 return knownStates[state];
446
447 return wxString::Format("unknown state (%d)", state);
448}
449
450void FlashFrame::SetMovie(const wxString& movie)
451{
452 // Flash doesn't like relative file names
453 wxFileName fn(movie);
454 fn.MakeAbsolute();
455 const wxString swf = fn.GetFullPath();
456 if ( swf == m_swf )
457 m_flash->PutMovie(L"");
458 else
459 m_swf = swf;
460
461 m_flash->PutMovie(m_swf.wc_str());
462
463 SetStatusText("Loaded \"" + m_swf + '"', 1);
464}
465
466void FlashFrame::Play()
467{
468 CheckFlashCall(m_flash->Play(), "Play");
469}
470
471void FlashFrame::Stop()
472{
473 CheckFlashCall(m_flash->Stop(), "Stop");
474}
475
476// ----------------------------------------------------------------------------
477// event handlers
478// ----------------------------------------------------------------------------
479
480void FlashFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
481{
482 wxString swf = wxLoadFileSelector("Flash movie", ".swf", m_swf, this);
483 if ( swf.empty() )
484 return;
485
486 SetMovie(swf);
487}
488
489void FlashFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
490{
491 // true is to force the frame to close
492 Close(true);
493}
494
495void FlashFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
496{
497 wxMessageBox("Flash ActiveX control embedding sample\n"
498 "\n"
499 "(c) 2009 Vadim Zeitlin",
500 "About " + GetTitle(),
501 wxOK | wxICON_INFORMATION,
502 this);
503}
504
505void FlashFrame::OnActiveXEvent(wxActiveXEvent& event)
506{
507 switch ( event.GetDispatchId() )
508 {
509 case FLASH_DISPID_ONREADYSTATECHANGE:
510 {
511 const int state = event[0].GetInteger();
512 if ( state != m_state )
513 {
514 wxLogMessage("State changed to %s",
515 GetFlashStateString(state));
516
517 if ( state >= 0 && state < FlashState_Max )
518 m_state = static_cast<FlashState>(state);
519 else
520 m_state = FlashState_Unknown;
521 }
522 }
523 break;
524
525 case FLASH_DISPID_ONPROGRESS:
526 wxLogMessage("Progress: %d%%", event[0].GetInteger());
527 break;
528
529 case FLASH_DISPID_FSCOMMAND:
530 wxLogMessage("Flash command %s(%s)",
531 event[0].GetString(), event[1].GetString());
532 break;
533
534 case FLASH_DISPID_FLASHCALL:
535 wxLogMessage("Flash request \"%s\"", event[0].GetString());
536 break;
537
538 default:
539 wxLogMessage("Unknown event %ld", event.GetDispatchId());
540 }
541
542 event.Skip();
543}
544
545void FlashFrame::OnBack(wxCommandEvent& WXUNUSED(event))
546{
547 CheckFlashCall(m_flash->Back(), "Back");
548}
549
550void FlashFrame::OnForward(wxCommandEvent& WXUNUSED(event))
551{
552 CheckFlashCall(m_flash->Forward(), "Forward");
553}
554
555void FlashFrame::OnInfo(wxCommandEvent& WXUNUSED(event))
556{
557 const int state = m_flash->GetReadyState();
558 wxString msg = "State: " + GetFlashStateString(state);
559
560 if ( state == FlashState_Complete )
561 {
562 msg += wxString::Format(", frame: %ld/%ld",
563 m_flash->GetFrameNum() + 1,
564 m_flash->GetTotalFrames());
565 }
566
567 if ( m_flash->IsPlaying() )
568 msg += ", playing";
569
570 wxLogMessage("%s", msg);
571}
572
573void FlashFrame::OnVarGet(wxCommandEvent& WXUNUSED(event))
574{
575 m_varvalue->SetValue(bstr2wx(
576 m_flash->GetVariable(wx2bstr(m_varname->GetValue()))));
577}
578
579void FlashFrame::OnVarSet(wxCommandEvent& WXUNUSED(event))
580{
581 m_flash->SetVariable(wx2bstr(m_varname->GetValue()),
582 wx2bstr(m_varvalue->GetValue()));
583}
584
585void FlashFrame::OnCall(wxCommandEvent& WXUNUSED(event))
586{
587 CallFlashFunc("", m_funcname->GetValue());
588}
589
590void FlashFrame::OnCallWithArg(wxCommandEvent& WXUNUSED(event))
591{
592 CallFlashFunc("string", m_funcname->GetValue(), m_funcarg->GetValue());
593}
594
595
596