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