From: Vadim Zeitlin Date: Thu, 15 Jan 2009 12:17:22 +0000 (+0000) Subject: added a (Windows-only) Flash sample X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/3707ff679972e0428cb693c788d1645a8c1cf9c9 added a (Windows-only) Flash sample git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58114 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/doxygen/mainpages/samples.h b/docs/doxygen/mainpages/samples.h index 90f8776afb..bfec6ec988 100644 --- a/docs/doxygen/mainpages/samples.h +++ b/docs/doxygen/mainpages/samples.h @@ -78,6 +78,7 @@ TODO: Organize them in a more human-readable way. @li @sample{event} @li @sample{except} @li @sample{exec} +@li @sample{flash} @li @sample{font} @li @sample{grid} @@ -407,6 +408,23 @@ wxProcess::Exists(). @sampledir{exec} +@section page_samples_flash Flash Sample + +The flash sample demonstrates embedding of Adobe Flash into a wxWidgets +program. Currently it only works under Windows as it uses the Flash ActiveX +control to achieve this but we hope to be able to extend it to also work under +other platforms in the future. The sample also currently requires Microsoft +Visual C++ compiler as it uses COM support extensions specific to this +compiler. + +The sample comes with 2 Flash files (SWF), showing a simple Flash animation +which can be controlled using the "Play", "Stop" and "Back"/"Forward" buttons +in the sample as well as a Flash form which shows how Flash and wxWidgets +program can exchange data: calling "GetText" function without arguments returns +the text of the text control defined inside Flash and calling "SetText" with an +argument sets the control contents to the given string. Finally clicking on the +button generates an event which is caught by the C++ program. + @section page_samples_font Font Sample The font sample demonstrates wxFont, diff --git a/samples/flash/animation.swf b/samples/flash/animation.swf new file mode 100644 index 0000000000..acb578f63e Binary files /dev/null and b/samples/flash/animation.swf differ diff --git a/samples/flash/flash.bkl b/samples/flash/flash.bkl new file mode 100644 index 0000000000..f059b18c74 --- /dev/null +++ b/samples/flash/flash.bkl @@ -0,0 +1,14 @@ + + + + + + + + flash.cpp + media + core + base + wx06 + + diff --git a/samples/flash/flash.cpp b/samples/flash/flash.cpp new file mode 100644 index 0000000000..e0467ef5b9 --- /dev/null +++ b/samples/flash/flash.cpp @@ -0,0 +1,597 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: flash.cpp +// Purpose: Sample showing integration of Flash ActiveX control +// Author: Vadim Zeitlin +// Created: 2009-01-13 +// RCS-ID: $Id$ +// Copyright: (c) 2009 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + Documentation for embedding Flash into anything other than a web browser is + not easy to find, here is the tech note which provided most of the + information used here: http://www.adobe.com/go/tn_12059 + */ + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef __WXMSW__ + #error "ActiveX controls are MSW-only" +#endif + +#ifndef WX_PRECOMP + #include "wx/wx.h" +#endif + +#include "wx/cmdline.h" +#include "wx/filename.h" + +#if !defined(__WXMSW__) && !defined(__WXPM__) + #include "../sample.xpm" +#endif + +#include "wx/msw/ole/activex.h" + +// we currently use VC-specific extensions in this sample, it could be +// rewritten to avoid them if there is real interest in doing it but compiler +// COM support in MSVC makes the code much simpler to understand +#ifndef __VISUALC__ + #error "This sample requires Microsoft Visual C++ compiler COM extensions" +#endif + +// import Flash ActiveX control by using its (standard) type library UUID +// +// no_auto_exclude is needed to import IServiceProvider interface defined in +// this type library even though its name conflicts with a standard Windows +// interface with the same name +#import "libid:D27CDB6B-AE6D-11CF-96B8-444553540000" no_auto_exclude + +using namespace ShockwaveFlashObjects; + +const CLSID CLSID_ShockwaveFlash = __uuidof(ShockwaveFlash); +const IID IID_IShockwaveFlash = __uuidof(IShockwaveFlash); + +inline wxString bstr2wx(const _bstr_t& bstr) +{ + return wxString(static_cast(bstr)); +} + +inline _bstr_t wx2bstr(const wxString& str) +{ + return _bstr_t(str.wc_str()); +} + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// taken from type library +namespace +{ + +const int FLASH_DISPID_ONREADYSTATECHANGE = -609; // DISPID_ONREADYSTATECHANGE +const int FLASH_DISPID_ONPROGRESS = 0x7a6; +const int FLASH_DISPID_FSCOMMAND = 0x96; +const int FLASH_DISPID_FLASHCALL = 0xc5; + +enum FlashState +{ + FlashState_Unknown = -1, + FlashState_Loading, + FlashState_Uninitialized, + FlashState_Loaded, + FlashState_Interactive, + FlashState_Complete, + FlashState_Max +}; + +} // anonymous namespace + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// Define a new application type, each program should derive a class from wxApp +class FlashApp : public wxApp +{ +public: + FlashApp() { } + + virtual bool OnInit(); + + virtual void OnInitCmdLine(wxCmdLineParser& parser); + virtual bool OnCmdLineParsed(wxCmdLineParser& parser); + + virtual bool OnExceptionInMainLoop(); + +private: + wxString m_swf; + + DECLARE_NO_COPY_CLASS(FlashApp) +}; + +// Define a new frame type: this is going to be our main frame +class FlashFrame : public wxFrame +{ +public: + // ctor takes ownership of the pointer which must be non-NULL and opens the + // given SWF file if it's non-empty + FlashFrame(IShockwaveFlash *flash, const wxString& swf); + virtual ~FlashFrame(); + + void SetMovie(const wxString& movie); + + void Play(); + void Stop(); + +private: + enum + { + Flash_Play = 100, + Flash_Get, + Flash_Set, + Flash_Call, + Flash_CallWithArg + }; + + void OnOpen(wxCommandEvent& event); + void OnQuit(wxCommandEvent& event); + void OnAbout(wxCommandEvent& event); + + void OnPlay(wxCommandEvent&) { Play(); } + void OnStop(wxCommandEvent&) { Stop(); } + void OnBack(wxCommandEvent& event); + void OnForward(wxCommandEvent& event); + void OnInfo(wxCommandEvent& event); + void OnVarGet(wxCommandEvent& event); + void OnVarSet(wxCommandEvent& event); + void OnCall(wxCommandEvent& event); + void OnCallWithArg(wxCommandEvent& event); + + void OnActiveXEvent(wxActiveXEvent& event); + + // give an error message if hr is not S_OK + void CheckFlashCall(HRESULT hr, const char *func); + + // return the name of the Flash control state + wxString GetFlashStateString(int state); + + // call CallFunction() with a single argument of the type specified by + // argtype or without any arguments if it is empty + void CallFlashFunc(const wxString& argtype, + const wxString& func, + const wxString& arg = wxString()); + + + const IShockwaveFlashPtr m_flash; + wxLog *m_oldLog; + wxString m_swf; + FlashState m_state; + + wxTextCtrl *m_varname, + *m_varvalue, + *m_funcname, + *m_funcarg; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(FlashFrame) +}; + +// ---------------------------------------------------------------------------- +// event tables and other macros for wxWidgets +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(FlashFrame, wxFrame) + EVT_MENU(wxID_OPEN, FlashFrame::OnOpen) + EVT_MENU(wxID_EXIT, FlashFrame::OnQuit) + EVT_MENU(wxID_ABOUT, FlashFrame::OnAbout) + + EVT_BUTTON(Flash_Play, FlashFrame::OnPlay) + EVT_BUTTON(wxID_STOP, FlashFrame::OnStop) + EVT_BUTTON(wxID_BACKWARD, FlashFrame::OnBack) + EVT_BUTTON(wxID_FORWARD, FlashFrame::OnForward) + + EVT_BUTTON(wxID_INFO, FlashFrame::OnInfo) + EVT_BUTTON(Flash_Get, FlashFrame::OnVarGet) + EVT_BUTTON(Flash_Set, FlashFrame::OnVarSet) + EVT_BUTTON(Flash_Call, FlashFrame::OnCall) + EVT_BUTTON(Flash_CallWithArg, FlashFrame::OnCallWithArg) + + EVT_ACTIVEX(wxID_ANY, FlashFrame::OnActiveXEvent) +END_EVENT_TABLE() + +IMPLEMENT_APP(FlashApp) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// the application class +// ---------------------------------------------------------------------------- + +void FlashApp::OnInitCmdLine(wxCmdLineParser& parser) +{ + wxApp::OnInitCmdLine(parser); + + parser.AddParam("SWF file to play", + wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); +} + +bool FlashApp::OnCmdLineParsed(wxCmdLineParser& parser) +{ + if ( parser.GetParamCount() ) + m_swf = parser.GetParam(0); + + return wxApp::OnCmdLineParsed(parser); +} + +bool FlashApp::OnInit() +{ + if ( !wxApp::OnInit() ) + return false; + + IShockwaveFlash *flash = NULL; + HRESULT hr = ::CoCreateInstance + ( + CLSID_ShockwaveFlash, + NULL, + CLSCTX_INPROC_SERVER, + IID_IShockwaveFlash, + (void **)&flash + ); + if ( FAILED(hr) ) + { + wxLogSysError(hr, "Failed to create Flash ActiveX control"); + return false; + } + + new FlashFrame(flash, m_swf); + + return true; +} + +bool FlashApp::OnExceptionInMainLoop() +{ + try + { + throw; + } + catch ( _com_error& ce ) + { + wxLogMessage("COM exception: %s", ce.ErrorMessage()); + + return true; + } + catch ( ... ) + { + throw; + } +} + +// ---------------------------------------------------------------------------- +// main frame creation +// ---------------------------------------------------------------------------- + +// frame constructor +FlashFrame::FlashFrame(IShockwaveFlash *flash, const wxString& swf) + : wxFrame(NULL, wxID_ANY, "wxWidgets Flash sample"), + m_flash(flash, false /* take ownership */), + m_swf(swf), + m_state(FlashState_Unknown) +{ + // set the frame icon + SetIcon(wxICON(sample)); + + // create the new log target before doing anything with the Flash that + // could result in log messages + wxTextCtrl * const log = new wxTextCtrl(this, wxID_ANY, "", + wxDefaultPosition, wxSize(-1, 100), + wxTE_MULTILINE); + m_oldLog = wxLog::SetActiveTarget(new wxLogTextCtrl(log)); + +#if wxUSE_MENUS + // create a menu bar + wxMenu *fileMenu = new wxMenu; + fileMenu->Append(wxID_OPEN); + fileMenu->AppendSeparator(); + fileMenu->Append(wxID_EXIT); + + wxMenu *helpMenu = new wxMenu; + helpMenu->Append(wxID_ABOUT); + + wxMenuBar *menuBar = new wxMenuBar(); + menuBar->Append(fileMenu, "&File"); + menuBar->Append(helpMenu, "&Help"); + SetMenuBar(menuBar); +#endif // wxUSE_MENUS + +#if wxUSE_STATUSBAR + CreateStatusBar(2); + SetStatusText("Welcome to wxWidgets Flash embedding sample"); + SetStatusText("No loaded file", 1); +#endif // wxUSE_STATUSBAR + + wxPanel * const panel = new wxPanel(this); + wxSizer * const sizerPanel = new wxBoxSizer(wxVERTICAL); + wxWindow * const activeXParent = new wxWindow(panel, wxID_ANY, + wxDefaultPosition, + wxSize(300, 200)); + new wxActiveXContainer(activeXParent, IID_IShockwaveFlash, flash); + if ( !swf.empty() ) + SetMovie(swf); + + sizerPanel->Add(activeXParent, + wxSizerFlags(1).Expand().Border()); + + const wxSizerFlags flagsHorz(wxSizerFlags().Centre().HorzBorder()); + + wxSizer * const sizerBtns = new wxBoxSizer(wxHORIZONTAL); + sizerBtns->Add(new wxButton(panel, wxID_BACKWARD), flagsHorz); + sizerBtns->Add(new wxButton(panel, Flash_Play, "&Play"), flagsHorz); + sizerBtns->Add(new wxButton(panel, wxID_STOP), flagsHorz); + sizerBtns->Add(new wxButton(panel, wxID_FORWARD), flagsHorz); + sizerBtns->AddSpacer(20); + sizerBtns->Add(new wxButton(panel, wxID_INFO), flagsHorz); + sizerPanel->Add(sizerBtns, wxSizerFlags().Center().Border()); + + wxSizer * const sizerVar = new wxBoxSizer(wxHORIZONTAL); + sizerVar->Add(new wxStaticText(panel, wxID_ANY, "Variable &name:"), + flagsHorz); + m_varname = new wxTextCtrl(panel, wxID_ANY); + sizerVar->Add(m_varname, flagsHorz); + sizerVar->Add(new wxStaticText(panel, wxID_ANY, "&value:"), + flagsHorz); + m_varvalue = new wxTextCtrl(panel, wxID_ANY); + sizerVar->Add(m_varvalue, flagsHorz); + sizerVar->AddSpacer(10); + sizerVar->Add(new wxButton(panel, Flash_Get, "&Get"), flagsHorz); + sizerVar->Add(new wxButton(panel, Flash_Set, "&Set"), flagsHorz); + sizerPanel->Add(sizerVar, wxSizerFlags().Center().Border()); + + wxSizer * const sizerCall = new wxBoxSizer(wxHORIZONTAL); + sizerCall->Add(new wxStaticText(panel, wxID_ANY, "&Function name:"), + flagsHorz); + m_funcname = new wxTextCtrl(panel, wxID_ANY); + sizerCall->Add(m_funcname, flagsHorz); + sizerCall->Add(new wxButton(panel, Flash_Call, "&Call"), flagsHorz); + sizerCall->Add(new wxStaticText(panel, wxID_ANY, "&argument:"), + flagsHorz); + m_funcarg = new wxTextCtrl(panel, wxID_ANY); + sizerCall->Add(m_funcarg, flagsHorz); + sizerCall->Add(new wxButton(panel, Flash_CallWithArg, "Call &with arg"), + flagsHorz); + sizerPanel->Add(sizerCall, wxSizerFlags().Center().Border()); + + panel->SetSizer(sizerPanel); + + wxSizer * const sizerFrame = new wxBoxSizer(wxVERTICAL); + sizerFrame->Add(panel, wxSizerFlags(2).Expand()); + sizerFrame->Add(log, wxSizerFlags(1).Expand()); + SetSizerAndFit(sizerFrame); + + Show(); + + m_flash->PutAllowScriptAccess(L"always"); + wxLogMessage("Script access changed to \"%s\"", + bstr2wx(m_flash->GetAllowScriptAccess())); +} + +FlashFrame::~FlashFrame() +{ + delete wxLog::SetActiveTarget(m_oldLog); +} + +// ---------------------------------------------------------------------------- +// Flash API wrappers +// ---------------------------------------------------------------------------- + +void FlashFrame::CheckFlashCall(HRESULT hr, const char *func) +{ + if ( FAILED(hr) ) + { + wxLogSysError(hr, "Call to IShockwaveFlash::%s() failed", func); + } +} + +void FlashFrame::CallFlashFunc(const wxString& argtype, + const wxString& func, + const wxString& arg) +{ + wxString args; + if ( !argtype.empty() ) + { + args = wxString::Format("<%s>%s", argtype, arg, argtype); + } + + // take care with XML formatting: there should be no spaces in it or the + // call would fail! + wxString request = wxString::Format + ( + "" + "" + "%s" + "" + "", + func, + args + ); + + wxLogMessage("%s(%s) returned \"%s\"", + func, args, + bstr2wx(m_flash->CallFunction(wx2bstr(request)))); +} + +wxString FlashFrame::GetFlashStateString(int state) +{ + static const char *knownStates[] = + { + "Loading", "Uninitialized", "Loaded", "Interactive", "Complete", + }; + + if ( state >= 0 && state < WXSIZEOF(knownStates) ) + return knownStates[state]; + + return wxString::Format("unknown state (%d)", state); +} + +void FlashFrame::SetMovie(const wxString& movie) +{ + // Flash doesn't like relative file names + wxFileName fn(movie); + fn.MakeAbsolute(); + const wxString swf = fn.GetFullPath(); + if ( swf == m_swf ) + m_flash->PutMovie(L""); + else + m_swf = swf; + + m_flash->PutMovie(m_swf.wc_str()); + + SetStatusText("Loaded \"" + m_swf + '"', 1); +} + +void FlashFrame::Play() +{ + CheckFlashCall(m_flash->Play(), "Play"); +} + +void FlashFrame::Stop() +{ + CheckFlashCall(m_flash->Stop(), "Stop"); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void FlashFrame::OnOpen(wxCommandEvent& WXUNUSED(event)) +{ + wxString swf = wxLoadFileSelector("Flash movie", ".swf", m_swf, this); + if ( swf.empty() ) + return; + + SetMovie(swf); +} + +void FlashFrame::OnQuit(wxCommandEvent& WXUNUSED(event)) +{ + // true is to force the frame to close + Close(true); +} + +void FlashFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) +{ + wxMessageBox("Flash ActiveX control embedding sample\n" + "\n" + "(c) 2009 Vadim Zeitlin", + "About " + GetTitle(), + wxOK | wxICON_INFORMATION, + this); +} + +void FlashFrame::OnActiveXEvent(wxActiveXEvent& event) +{ + switch ( event.GetDispatchId() ) + { + case FLASH_DISPID_ONREADYSTATECHANGE: + { + const int state = event[0].GetInteger(); + if ( state != m_state ) + { + wxLogMessage("State changed to %s", + GetFlashStateString(state)); + + if ( state >= 0 && state < FlashState_Max ) + m_state = static_cast(state); + else + m_state = FlashState_Unknown; + } + } + break; + + case FLASH_DISPID_ONPROGRESS: + wxLogMessage("Progress: %d%%", event[0].GetInteger()); + break; + + case FLASH_DISPID_FSCOMMAND: + wxLogMessage("Flash command %s(%s)", + event[0].GetString(), event[1].GetString()); + break; + + case FLASH_DISPID_FLASHCALL: + wxLogMessage("Flash request \"%s\"", event[0].GetString()); + break; + + default: + wxLogMessage("Unknown event %ld", event.GetDispatchId()); + } + + event.Skip(); +} + +void FlashFrame::OnBack(wxCommandEvent& WXUNUSED(event)) +{ + CheckFlashCall(m_flash->Back(), "Back"); +} + +void FlashFrame::OnForward(wxCommandEvent& WXUNUSED(event)) +{ + CheckFlashCall(m_flash->Forward(), "Forward"); +} + +void FlashFrame::OnInfo(wxCommandEvent& WXUNUSED(event)) +{ + const int state = m_flash->GetReadyState(); + wxString msg = "State: " + GetFlashStateString(state); + + if ( state == FlashState_Complete ) + { + msg += wxString::Format(", frame: %ld/%ld", + m_flash->GetFrameNum() + 1, + m_flash->GetTotalFrames()); + } + + if ( m_flash->IsPlaying() ) + msg += ", playing"; + + wxLogMessage("%s", msg); +} + +void FlashFrame::OnVarGet(wxCommandEvent& WXUNUSED(event)) +{ + m_varvalue->SetValue(bstr2wx( + m_flash->GetVariable(wx2bstr(m_varname->GetValue())))); +} + +void FlashFrame::OnVarSet(wxCommandEvent& WXUNUSED(event)) +{ + m_flash->SetVariable(wx2bstr(m_varname->GetValue()), + wx2bstr(m_varvalue->GetValue())); +} + +void FlashFrame::OnCall(wxCommandEvent& WXUNUSED(event)) +{ + CallFlashFunc("", m_funcname->GetValue()); +} + +void FlashFrame::OnCallWithArg(wxCommandEvent& WXUNUSED(event)) +{ + CallFlashFunc("string", m_funcname->GetValue(), m_funcarg->GetValue()); +} + + + diff --git a/samples/flash/flash_vc7.vcproj b/samples/flash/flash_vc7.vcproj new file mode 100644 index 0000000000..a5047ddd95 --- /dev/null +++ b/samples/flash/flash_vc7.vcproj @@ -0,0 +1,545 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/flash/flash_vc8.vcproj b/samples/flash/flash_vc8.vcproj new file mode 100644 index 0000000000..ddabcf2a04 --- /dev/null +++ b/samples/flash/flash_vc8.vcproj @@ -0,0 +1,810 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/flash/flash_vc9.vcproj b/samples/flash/flash_vc9.vcproj new file mode 100644 index 0000000000..11b6f5b536 --- /dev/null +++ b/samples/flash/flash_vc9.vcproj @@ -0,0 +1,782 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/flash/form.mxml b/samples/flash/form.mxml new file mode 100644 index 0000000000..567ff1d89a --- /dev/null +++ b/samples/flash/form.mxml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/samples/flash/form.swf b/samples/flash/form.swf new file mode 100644 index 0000000000..7bd9d7ab2d Binary files /dev/null and b/samples/flash/form.swf differ diff --git a/samples/samples.bkl b/samples/samples.bkl index 558f1feb4e..306651b15c 100644 --- a/samples/samples.bkl +++ b/samples/samples.bkl @@ -86,6 +86,7 @@ +