]> git.saurik.com Git - wxWidgets.git/blob - samples/flash/flash.cpp
Don't generate any events from wxSpinCtrl and wxSpinCtrlDouble methods.
[wxWidgets.git] / samples / flash / flash.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: flash.cpp
3 // Purpose: Sample showing integration of Flash ActiveX control
4 // Author: Vadim Zeitlin
5 // Created: 2009-01-13
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 // ----------------------------------------------------------------------------
23
24 #include "wx/wxprec.h"
25
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
41 #ifndef wxHAS_IMAGES_IN_RESOURCES
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
61 using namespace ShockwaveFlashObjects;
62
63 const CLSID CLSID_ShockwaveFlash = __uuidof(ShockwaveFlash);
64 const IID IID_IShockwaveFlash = __uuidof(IShockwaveFlash);
65
66 inline wxString bstr2wx(const _bstr_t& bstr)
67 {
68 return wxString(static_cast<const wchar_t *>(bstr));
69 }
70
71 inline _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
81 namespace
82 {
83
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;
88
89 enum 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
107 class FlashApp : public wxApp
108 {
109 public:
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
119 private:
120 wxString m_swf;
121
122 wxDECLARE_NO_COPY_CLASS(FlashApp);
123 };
124
125 // Define a new frame type: this is going to be our main frame
126 class FlashFrame : public wxFrame
127 {
128 public:
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
139 private:
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()
189 wxDECLARE_NO_COPY_CLASS(FlashFrame);
190 };
191
192 // ----------------------------------------------------------------------------
193 // event tables and other macros for wxWidgets
194 // ----------------------------------------------------------------------------
195
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)
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)
213 END_EVENT_TABLE()
214
215 IMPLEMENT_APP(FlashApp)
216
217 // ============================================================================
218 // implementation
219 // ============================================================================
220
221 // ----------------------------------------------------------------------------
222 // the application class
223 // ----------------------------------------------------------------------------
224
225 void 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
233 bool FlashApp::OnCmdLineParsed(wxCmdLineParser& parser)
234 {
235 if ( parser.GetParamCount() )
236 m_swf = parser.GetParam(0);
237
238 return wxApp::OnCmdLineParsed(parser);
239 }
240
241 bool 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
266 bool 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
289 FlashFrame::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
392 FlashFrame::~FlashFrame()
393 {
394 delete wxLog::SetActiveTarget(m_oldLog);
395 }
396
397 // ----------------------------------------------------------------------------
398 // Flash API wrappers
399 // ----------------------------------------------------------------------------
400
401 void 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
409 void 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
437 wxString 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
450 void 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
466 void FlashFrame::Play()
467 {
468 CheckFlashCall(m_flash->Play(), "Play");
469 }
470
471 void FlashFrame::Stop()
472 {
473 CheckFlashCall(m_flash->Stop(), "Stop");
474 }
475
476 // ----------------------------------------------------------------------------
477 // event handlers
478 // ----------------------------------------------------------------------------
479
480 void 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
489 void FlashFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
490 {
491 // true is to force the frame to close
492 Close(true);
493 }
494
495 void 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
505 void 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
545 void FlashFrame::OnBack(wxCommandEvent& WXUNUSED(event))
546 {
547 CheckFlashCall(m_flash->Back(), "Back");
548 }
549
550 void FlashFrame::OnForward(wxCommandEvent& WXUNUSED(event))
551 {
552 CheckFlashCall(m_flash->Forward(), "Forward");
553 }
554
555 void 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
573 void FlashFrame::OnVarGet(wxCommandEvent& WXUNUSED(event))
574 {
575 m_varvalue->SetValue(bstr2wx(
576 m_flash->GetVariable(wx2bstr(m_varname->GetValue()))));
577 }
578
579 void FlashFrame::OnVarSet(wxCommandEvent& WXUNUSED(event))
580 {
581 m_flash->SetVariable(wx2bstr(m_varname->GetValue()),
582 wx2bstr(m_varvalue->GetValue()));
583 }
584
585 void FlashFrame::OnCall(wxCommandEvent& WXUNUSED(event))
586 {
587 CallFlashFunc("", m_funcname->GetValue());
588 }
589
590 void FlashFrame::OnCallWithArg(wxCommandEvent& WXUNUSED(event))
591 {
592 CallFlashFunc("string", m_funcname->GetValue(), m_funcarg->GetValue());
593 }
594
595
596