Skip to content

Instantly share code, notes, and snippets.

@lniwn
Forked from t-mat/flash-activex.cpp
Created July 25, 2020 08:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lniwn/60a193a3008a8381dbecce227bf3d580 to your computer and use it in GitHub Desktop.
Save lniwn/60a193a3008a8381dbecce227bf3d580 to your computer and use it in GitHub Desktop.
Windows: ActiveXを利用して、Flashをウィンドウ内に表示する
// flash-to-directx : Library to embed Adobe Flash movies to DirectX-based applications.
// https://code.google.com/p/flash-to-directx/
//
// swfui : Adobe Flash User Interface
// https://code.google.com/p/swfui/
//
// C++ and Flash: Send or get data from/to a SWF using C++ and ActiveX in Win32
// http://www.codeproject.com/Articles/269829/Communicate-with-Flash-Send-or-Get-data-from-to-a
//
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <shlwapi.h>
#include <vector>
#import "PROGID:ShockwaveFlash.ShockwaveFlash" named_guids exclude("IServiceProvider")
#pragma comment(lib, "shlwapi.lib")
#define uuidof_ptr(p) __uuidof(decltype(*p))
/////////////////////////////////////////////////////////////////////////////
template<typename OwnerClass>
class CFlashSink
: public ShockwaveFlashObjects::_IShockwaveFlashEvents
{
public:
CFlashSink()
: dwCookie(0)
, pConnectionPoint(nullptr)
, refCnt(0)
, owner(nullptr)
{
}
virtual ~CFlashSink() {
}
HRESULT init(
OwnerClass* ownerClass
, ShockwaveFlashObjects::IShockwaveFlash* flashInterface
) {
owner = ownerClass;
HRESULT hr = NOERROR;
IConnectionPointContainer* cpc = nullptr;
hr = flashInterface->QueryInterface(uuidof_ptr(cpc)
, (void**)&cpc);
if(SUCCEEDED(hr)) {
hr = cpc->FindConnectionPoint(
__uuidof(_IShockwaveFlashEvents), &pConnectionPoint
);
if(SUCCEEDED(hr)) {
IDispatch* d = nullptr;
hr = QueryInterface(__uuidof(IDispatch), (void**) &d);
if(SUCCEEDED(hr)) {
hr = pConnectionPoint->Advise((IUnknown*)d, &dwCookie);
}
if(d) {
d->Release();
}
}
}
if(cpc) {
cpc->Release();
}
AddRef();
return hr;
}
HRESULT cleanup() {
HRESULT hr = S_OK;
Release();
if(pConnectionPoint) {
if(dwCookie) {
hr = pConnectionPoint->Unadvise(dwCookie);
dwCookie = 0;
}
pConnectionPoint->Release();
pConnectionPoint = NULL;
}
return hr;
}
protected:
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) {
void* p = nullptr;
if(IsEqualGUID(riid, IID_IUnknown)) {
p = (void*) this;
} else if(IsEqualGUID(riid, IID_IDispatch)) {
p = (void*) dynamic_cast<IDispatch*>(this);
} else if(IsEqualGUID(riid, __uuidof(_IShockwaveFlashEvents))) {
p = (void*) dynamic_cast<_IShockwaveFlashEvents*>(this);
}
*ppvObject = p;
if(p) {
AddRef();
return S_OK;
} else {
return E_NOINTERFACE;
}
}
ULONG STDMETHODCALLTYPE AddRef() {
return ++refCnt;
}
ULONG STDMETHODCALLTYPE Release() {
return --refCnt;
}
// IDispatch
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT*) {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT, LCID, ITypeInfo**) {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID, LPOLESTR*, UINT, LCID, DISPID*) {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE
Invoke(DISPID dispIdMember, REFIID, LCID, WORD, DISPPARAMS* pDispParams
, VARIANT*, EXCEPINFO*, UINT*
) {
switch(dispIdMember) {
case 0xc5:
if( pDispParams->cArgs != 1
|| pDispParams->rgvarg[0].vt != VT_BSTR
) {
return E_INVALIDARG;
}
return owner->invoke_FlashCall(pDispParams->rgvarg[0].bstrVal);
case 0x96:
if( pDispParams->cArgs != 2
|| pDispParams->rgvarg[0].vt != VT_BSTR
|| pDispParams->rgvarg[1].vt != VT_BSTR
) {
return E_INVALIDARG;
}
return owner->invoke_FSCommand(pDispParams->rgvarg[1].bstrVal
, pDispParams->rgvarg[0].bstrVal);
case 0x7a6:
return owner->invoke_OnProgress(pDispParams->rgvarg[0].intVal);
case DISPID_READYSTATECHANGE:
return E_NOTIMPL;
default:
return E_NOTIMPL;
}
}
IConnectionPoint* pConnectionPoint;
DWORD dwCookie;
ULONG refCnt;
OwnerClass* owner;
};
/////////////////////////////////////////////////////////////////////////////
template<typename OwnerClass>
class CControlSite
: public IOleInPlaceSiteWindowless
, public IOleClientSite
{
public:
CControlSite()
: owner(nullptr)
, refCnt(0)
{
}
virtual ~CControlSite() {
}
void init(OwnerClass* ownerClass) {
owner = ownerClass;
AddRef();
}
void cleanup() {
Release();
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppvObject) {
void* p = nullptr;
if(IsEqualGUID(riid, IID_IUnknown)) {
p = (void*) this;
} else if(IsEqualGUID(riid, IID_IOleWindow)) {
p = dynamic_cast<IOleWindow*>(this);
} else if(IsEqualGUID(riid, IID_IOleInPlaceSite)) {
p = dynamic_cast<IOleInPlaceSite*>(this);
} else if(IsEqualGUID(riid, IID_IOleInPlaceSiteEx)) {
p = dynamic_cast<IOleInPlaceSiteEx*>(this);
} else if(IsEqualGUID(riid, IID_IOleInPlaceSiteWindowless)) {
p = dynamic_cast<IOleInPlaceSiteWindowless*>(this);
} else if(IsEqualGUID(riid, IID_IOleClientSite)) {
p = dynamic_cast<IOleClientSite*>(this);
}
if(ppvObject) {
*ppvObject = p;
}
if(p) {
AddRef();
return S_OK;
} else {
return E_NOINTERFACE;
}
}
protected:
ULONG STDMETHODCALLTYPE AddRef() {
return ++refCnt;
}
ULONG STDMETHODCALLTYPE Release() {
return --refCnt;
}
HRESULT STDMETHODCALLTYPE SaveObject() {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetMoniker(DWORD, DWORD, IMoniker**) {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE GetContainer(IOleContainer** ppContainer) {
*ppContainer = 0;
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE ShowObject() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnShowWindow(BOOL) {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE RequestNewObjectLayout() {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL) {
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetWindow(HWND* lpHwnd) {
HWND h = owner->getHwnd();
*lpHwnd = h;
if(h) {
return S_OK;
} else {
return E_FAIL;
}
}
HRESULT STDMETHODCALLTYPE CanInPlaceActivate() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnInPlaceActivate() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnUIActivate() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetWindowContext(
IOleInPlaceFrame** ppFrame
, IOleInPlaceUIWindow** ppDoc
, RECT* lprcPosRect
, RECT* lprcClipRect
, OLEINPLACEFRAMEINFO* lpFrameInfo
) {
RECT r = { 0, 0, owner->getWidth(), owner->getHeight() };
*ppFrame = NULL;
QueryInterface(__uuidof(IOleInPlaceFrame), (void**) ppFrame);
*ppDoc = NULL;
lpFrameInfo->fMDIApp = FALSE;
lpFrameInfo->hwndFrame = NULL;
lpFrameInfo->haccel = NULL;
lpFrameInfo->cAccelEntries = 0;
*lprcPosRect = r;
*lprcClipRect = r;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Scroll(SIZE) {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL) {
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE DiscardUndoState() {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DeactivateAndUndo() {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT) {
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnInPlaceActivateEx(BOOL* pfNoRedraw, DWORD) {
*pfNoRedraw = FALSE;
return S_OK;
}
HRESULT STDMETHODCALLTYPE OnInPlaceDeactivateEx(BOOL) {
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE RequestUIActivate() {
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE CanWindowlessActivate() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetCapture() {
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE SetCapture(BOOL) {
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE GetFocus() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE SetFocus(BOOL) {
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetDC(LPCRECT, DWORD, HDC*) {
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE ReleaseDC(HDC) {
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE InvalidateRect(LPCRECT pRect, BOOL fErase) {
owner->addDirtyRect(pRect, fErase);
return S_OK;
}
HRESULT STDMETHODCALLTYPE InvalidateRgn(HRGN, BOOL fErase) {
owner->addDirtyRect(NULL, fErase);
return S_OK;
}
HRESULT STDMETHODCALLTYPE ScrollRect(INT, INT, LPCRECT, LPCRECT) {
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE AdjustRect(LPRECT) {
return S_FALSE;
}
HRESULT STDMETHODCALLTYPE OnDefWindowMessage(UINT, WPARAM, LPARAM, LRESULT*) {
return S_FALSE;
}
OwnerClass* owner;
ULONG refCnt;
};
/////////////////////////////////////////////////////////////////////////////
class CFlashDXPlayer {
public:
typedef CFlashDXPlayer ThisClass;
CFlashDXPlayer(unsigned int width, unsigned int height, HWND hWnd = nullptr)
: hWnd(nullptr)
, width(0)
, height(0)
, pShockwaveFlash(nullptr)
, pOleObject(nullptr)
, pOleInPlaceObjectWindowless(nullptr)
, dirtyFlag(false)
, backDc(nullptr)
, backBitmap(nullptr)
, backBits(nullptr)
, backBpp(0)
{
this->hWnd = hWnd;
this->width = width;
this->height = height;
controlSite.init(this);
HRESULT hr;
hr = CoCreateInstance(ShockwaveFlashObjects::CLSID_ShockwaveFlash
, NULL, CLSCTX_INPROC_SERVER, IID_IOleObject
, (void**)&pOleObject);
if(FAILED(hr)) {
return;
}
IOleClientSite* pcs = nullptr;
hr = controlSite.QueryInterface(uuidof_ptr(pcs)
, (void**)&pcs);
if(FAILED(hr)) {
return;
}
hr = pOleObject->SetClientSite(pcs);
hr = pOleObject->QueryInterface(uuidof_ptr(pShockwaveFlash)
, (void**)&pShockwaveFlash);
if(pShockwaveFlash) {
pShockwaveFlash->DisableLocalSecurity();
pShockwaveFlash->PutEmbedMovie(FALSE);
pShockwaveFlash->PutAllowScriptAccess(L"always");
// "opaque", "transparent"
pShockwaveFlash->PutWMode(_bstr_t("opaque"));
// L"Low", L"Medium", L"High", L"Best", L"AutoLow", L"AutoHigh"
pShockwaveFlash->PutQuality2(_bstr_t(L"High"));
pShockwaveFlash->PutBackgroundColor(0x000000);
pShockwaveFlash->QueryInterface(uuidof_ptr(pViewObject)
, (void**)&pViewObject);
}
hr = pOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, pcs, 0, NULL, NULL);
pcs->Release();
hr = pOleObject->QueryInterface(uuidof_ptr(pOleInPlaceObjectWindowless)
, (void**)&pOleInPlaceObjectWindowless);
flashSink.init(this, pShockwaveFlash);
resizePlayer(width, height);
}
virtual ~CFlashDXPlayer() {
if(backDc) {
DeleteDC(backDc);
DeleteObject(backBitmap);
}
if(pOleInPlaceObjectWindowless) {
pOleInPlaceObjectWindowless->Release();
}
if(pViewObject) {
pViewObject->Release();
}
if(pShockwaveFlash) {
pShockwaveFlash->Release();
}
flashSink.cleanup();
if(pOleObject) {
pOleObject->Close(OLECLOSE_NOSAVE);
pOleObject->Release();
}
controlSite.cleanup();
}
HWND getHwnd() const {
return hWnd;
}
int getWidth() const {
return width;
}
int getHeight() const {
return height;
}
HDC getBackDc() const {
return backDc;
}
void addDirtyRect(const RECT* pRect, BOOL) {
if(pRect == nullptr || !IsRectEmpty(pRect)) {
dirtyFlag = true;
}
}
void resizePlayer(unsigned int newWidth, unsigned int newHeight) {
IOleInPlaceObject* pip = nullptr;
pOleObject->QueryInterface(uuidof_ptr(pip)
, (void**)&pip);
if(pip) {
RECT rect = { 0, 0, newWidth, newHeight };
pip->SetObjectRects(&rect, &rect);
pip->Release();
width = newWidth;
height = newHeight;
addDirtyRect(NULL, FALSE);
}
if(backDc) {
DeleteDC(backDc);
DeleteObject(backBitmap);
backDc = NULL;
backBitmap = NULL;
}
}
bool isDirty() const {
return dirtyFlag;
}
void DrawFrame(HDC dc = nullptr) {
if(dirtyFlag && pShockwaveFlash && pViewObject) {
dirtyFlag = false;
int w = getWidth();
int h = getHeight();
if(!backDc) {
backDc = CreateCompatibleDC(dc);
BITMAPINFOHEADER bih = { 0 };
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biBitCount = 32;
bih.biCompression = BI_RGB;
bih.biPlanes = 1;
bih.biWidth = w;
bih.biHeight = -h;
backBitmap = CreateDIBSection(
dc, (BITMAPINFO*)&bih, DIB_RGB_COLORS
, (void **)&backBits, 0, 0);
SelectObject(backDc, backBitmap);
backBpp = GetDeviceCaps(backDc, BITSPIXEL);
}
RECTL r = { 0, 0, w, h };
memset(backBits, 0, w * h * 4);
pViewObject->Draw(DVASPECT_TRANSPARENT, 1, 0, 0, 0, backDc, &r, &r, 0, 0);
}
}
std::wstring CallFunction(const wchar_t* request) {
BSTR response = nullptr;
pShockwaveFlash->raw_CallFunction(_bstr_t(request), &response);
if(response) {
return std::wstring(response);
} else {
return std::wstring();
}
}
HRESULT invoke_FlashCall(const wchar_t* request) {
//@TODO implement
OutputDebugStringW(request);
return E_NOTIMPL;
}
HRESULT invoke_FSCommand(const wchar_t* command, const wchar_t* args) {
//@TODO implement
OutputDebugStringW(command);
OutputDebugStringW(args);
return E_NOTIMPL;
}
HRESULT invoke_OnProgress(long percentDone) {
//@TODO implement
percentDone;
return S_OK;
}
ShockwaveFlashObjects::IShockwaveFlash* getFlashInterface() const {
return pShockwaveFlash;
}
LRESULT DefaultMessageProc(UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
default:
{
LRESULT lr;
pOleInPlaceObjectWindowless->OnWindowMessage(uMsg, wParam, lParam, &lr);
return lr;
}
break;
case WM_SIZE:
resizePlayer(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
}
}
protected:
HWND hWnd;
unsigned int width;
unsigned int height;
ShockwaveFlashObjects::IShockwaveFlash* pShockwaveFlash;
IOleObject* pOleObject;
IOleInPlaceObjectWindowless* pOleInPlaceObjectWindowless;
IViewObject* pViewObject;
bool dirtyFlag;
HDC backDc;
HBITMAP backBitmap;
BYTE* backBits;
int backBpp;
CControlSite<ThisClass> controlSite;
CFlashSink<ThisClass> flashSink;
};
/////////////////////////////////////////////////////////////////////////////
#define APPNAME _T("SwfPlayer")
static CFlashDXPlayer* g_flashPlayer = NULL;
static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
case WM_DESTROY:
case WM_CLOSE:
PostQuitMessage(0);
return 0;
case WM_PAINT:
if(g_flashPlayer) {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
if(g_flashPlayer) {
if(g_flashPlayer->isDirty()) {
g_flashPlayer->DrawFrame();
BitBlt(hdc, 0, 0
, g_flashPlayer->getWidth()
, g_flashPlayer->getHeight()
, g_flashPlayer->getBackDc()
, 0, 0, SRCCOPY);
}
}
EndPaint(hWnd, &ps);
return 0;
}
break;
case WM_SIZE:
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_RBUTTONDBLCLK:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
case WM_XBUTTONDBLCLK:
case WM_MOUSEWHEEL:
case WM_CANCELMODE:
case WM_CHAR:
case WM_DEADCHAR:
case WM_HELP:
case WM_IME_CHAR:
case WM_IME_COMPOSITION:
case WM_IME_COMPOSITIONFULL:
case WM_IME_CONTROL:
case WM_IME_ENDCOMPOSITION:
case WM_IME_KEYDOWN:
case WM_IME_KEYUP:
case WM_IME_NOTIFY:
case WM_IME_REQUEST:
case WM_IME_SELECT:
case WM_IME_SETCONTEXT:
case WM_IME_STARTCOMPOSITION:
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSDEADCHAR:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
if(g_flashPlayer) {
return g_flashPlayer->DefaultMessageProc(uMsg, wParam, lParam);
}
break;
case WM_SETCURSOR:
if(g_flashPlayer) {
static bool restoreCursor = true;
if(LOWORD(lParam) != HTCLIENT) {
restoreCursor = true;
}
if(restoreCursor) {
restoreCursor = false;
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 1;
}
break;
default:
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int iCmdShow) {
CoInitialize(NULL);
int width = 700;
int height = 350;
const wchar_t* movie_path = L"test.swf";
wchar_t movieFullpath[MAX_PATH];
_wfullpath(movieFullpath, movie_path, MAX_PATH);
if(!PathFileExists(movieFullpath)) {
return MessageBox(0, movieFullpath, L"File not exist", MB_ICONEXCLAMATION);
}
WNDCLASS wc = { 0 };
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(0);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
wc.lpszClassName = APPNAME;
RegisterClass(&wc);
RECT rc = { 0, 0, width, height };
DWORD ws = WS_OVERLAPPEDWINDOW;
DWORD es = 0;
BOOL bMenu = FALSE;
AdjustWindowRectEx(&rc, ws, bMenu, es);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
HWND hWnd = CreateWindowEx(es, wc.lpszClassName, APPNAME, ws
, 0, 0, w, h, NULL, NULL, wc.hInstance, NULL);
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
g_flashPlayer = new CFlashDXPlayer(width, height, hWnd);
g_flashPlayer->getFlashInterface()->put_Movie(_bstr_t(movieFullpath));
g_flashPlayer->getFlashInterface()->Play();
MSG msg = { 0 };
for(bool bLoop = true; bLoop; ) {
while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if(WM_QUIT == msg.message) {
bLoop = false;
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if(g_flashPlayer->isDirty()) {
InvalidateRect(hWnd, 0, 0);
}
}
g_flashPlayer->getFlashInterface()->StopPlay();
CoUninitialize();
return (int) msg.wParam;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment