Question

I'm embedding a Flash ActiveX control in my C++ app (Flash.ocx, Flash10a.ocx, etc depending on your Flash version).

I can load an SWF file by calling LoadMovie(0, filename), but the file needs to physically reside in the disk. How to load the SWF from memory (or resource, or stream)? I'm sure there must be a way, because commercial solutions like f-in-box's feature Load flash movies from memory directly also uses Flash ActiveX control.

Was it helpful?

Solution

Appearantly I a going to need to supply details for a vote 'up'.. OK.

The internal flash buffer when first initiailized indicates if a movie is loaded or if the buffer hold properties in the buffer fisrt four bytes.

gUfU -- no movie loaded. properties to follow ....

fUfU -- .. [4bytes] size as integer.

then the UNCOMPRESSED movie or SWF as it were. Write a IStream class. fill with above. save as szFile

TFlashStream *fStream = new TFlashStream(szFile);
// QI flash player

IPersistStreamInit * psStreamInit = 0;
shock->QueryInterface(::IID_IPersistStreamInit,  
                     (LPVOID*)&psStreamInit);
if(psStreamInit)
{
    psStreamInit->InitNew();
    psStreamInit->Load(fStream);
    psStreamInit->Release();
}
delete fStream;

Things to note : When psStreamInit->Load(fStream); will call IStream::Read looking for the header 'fUfU'.

if the return is correct psStreamInit then calls IStream::Read for the buffer size.

If everthing looks good so far, psStreamInit then reads in 1024 byte chunks until the read is exhausted. However. for the header and file size.

STDMETHOD(Read)(void *pv, ULONG cb, ULONG *pcbRead)

pcbRead is invalid. you may want to use something like IsBadReadPtr

--

Michael

OTHER TIPS

To spare you some typing. It works for me in this way (just works not extensively tested):

void flash_load_memory(FlashWidget* w, void* data, ULONG size) {
        FlashMemoryStream fStream = FlashMemoryStream(data, size);
        IPersistStreamInit* psStreamInit = NULL;
        w->mFlashInterface->QueryInterface(IID_IPersistStreamInit,(LPVOID*) &psStreamInit);
        if(psStreamInit) {
            psStreamInit->InitNew();
            psStreamInit->Load((LPSTREAM)&fStream);
            psStreamInit->Release();
        }
    }

class FlashMemoryStream : IStream {
    public:
        FlashMemoryStream(void* data,ULONG size) {
            this->data = data;
            this->size = size;
            this->pos = 0;
        }

        HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, LPVOID* ppv) {
            return E_NOTIMPL;
        }

        ULONG STDMETHODCALLTYPE AddRef() {  
            return E_NOTIMPL;
        }

        ULONG STDMETHODCALLTYPE Release() {  
            return E_NOTIMPL;
        }

        // IStream methods
        STDMETHOD(Read) (void *pv,ULONG cb,ULONG *pcbRead) {
            if(pos == 0 && cb == 4) {
                memcpy(pv,"fUfU",4);
                pos += 4;
                return S_OK;
            }
            else if(pos == 4 && cb == 4) {
                memcpy(pv,&size,4);
                size += 8;
                pos += 4;
                return S_OK;
            }
            else {
                if(pos + cb > size) cb = size - pos;
                if(cb == 0) return S_FALSE;
                memcpy(pv,(char*)data + pos - 8,cb);
                if(pcbRead) (*pcbRead) = cb;
                pos += cb;
                return S_OK;
            }
        }

        STDMETHOD(Write) (void const *pv,ULONG cb,ULONG *pcbWritten) { return E_NOTIMPL; }
        STDMETHOD(Seek) (LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition) { return E_NOTIMPL; }
        STDMETHOD(SetSize) (ULARGE_INTEGER libNewSize) { return E_NOTIMPL; }
        STDMETHOD(CopyTo) (IStream *pstm,ULARGE_INTEGER cb,ULARGE_INTEGER *pcbRead,ULARGE_INTEGER *pcbWritten) { return E_NOTIMPL; }
        STDMETHOD(Commit) (DWORD grfCommitFlags) { return E_NOTIMPL; }
        STDMETHOD(Revert) (void) { return E_NOTIMPL; }
        STDMETHOD(LockRegion) (ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType) { return E_NOTIMPL; }
        STDMETHOD(UnlockRegion) (ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType) { return E_NOTIMPL; }
        STDMETHOD(Stat) (STATSTG *pstatstg,DWORD grfStatFlag) { return E_NOTIMPL; }
        STDMETHOD(Clone) (IStream **ppstm) { return E_NOTIMPL; }

        void* data;
        ULONG size;
        ULONG pos;
    };

Being a flash guy I don't know any details on the C++ side, but if you made a request on the Flash side to a fake protocol, on the C side can you intercept that request and answer it with a data stream? I mean something like:

var mc:MovieClip = createEmptyMovieClip( "mc", 0 );
mc.loadMovie( "fakeprotocol://"+filename )

As long as the response looks (to Flash) like an HTTP stream, that ought to work. (Apologies in advance if the "intercept the request and return a data stream" is the part you're asking for help with.)

in addition.... Flash player promotes IPersistStorage. flash.QI IPersistStorage pStorage.load (mystorage_as_stream)

.. in theory.

Sorry for the above.. I intended to post Flash player promotes IPersistStreamInit. flash.QI IPersistStreamInit pStream.load (my_stream)

Michael

This method don't work when you try to load a movie via the MovieclipLoader or LoadMovie from another movie!!!

The result is to replace the calling SWF file!! ...so this method work only for loading the base file.

Someone know a better method that work also with MovieClipLoader and LoadMovie? Thanks.

MS VC ATL sample (have built with VS 2010 SP1 + Windows SDK 7.1 and tested on Windows 7 SP1 64-bit with Flash64_11_3_300_257.ocx / Flash32_11_3_300_257.ocx and on Windows XP SP3 32-bit with Flash32_11_3_300_257.ocx):

#pragma pack(push, 1)

typedef struct _FLASH_STREAM_HEADER
{
    DWORD m_dwSignature;
    DWORD m_dwDataSize;
} FLASH_STREAM_HEADER, *PFLASH_STREAM_HEADER;

#pragma pack(pop)

static HRESULT LoadFlashMovieFromResource(ATL::CComPtr<IShockwaveFlash>& spShockwaveFlash,
    UINT nResourceID, LPCTSTR pszResourceType = RT_RCDATA)
{
    HMODULE hModule = ATL::_AtlBaseModule.GetModuleInstance();
    ATLASSUME(hModule != NULL);

    //HINSTANCE hResourceInstance = ATL::AtlFindResourceInstance(nResourceID, pszResourceType);
    //HRSRC hResource = ::FindResource(hResourceInstance, MAKEINTRESOURCE(nResourceID),
    //  pszResourceType);

    HRSRC hResource = ::FindResource(hModule, MAKEINTRESOURCE(nResourceID), pszResourceType);

    if (hResource == NULL)
        return HRESULT_FROM_WIN32(::GetLastError());

    DWORD dwResourceDataSize = ::SizeofResource(hModule, hResource);

    if (dwResourceDataSize == 0)
        return HRESULT_FROM_WIN32(::GetLastError());

    HGLOBAL hResourceLoaded = ::LoadResource(hModule, hResource);

    if (hResourceLoaded == NULL)
        return HRESULT_FROM_WIN32(::GetLastError());

    ATL::CComPtr<IStream> spStream;

    HRESULT hResult = ::CreateStreamOnHGlobal(NULL, TRUE, &spStream);

    if (FAILED(hResult))
        return hResult;

    FLASH_STREAM_HEADER fsh = {0x55665566, dwResourceDataSize};

    ULARGE_INTEGER uli = {sizeof (fsh) + dwResourceDataSize};

    hResult = spStream->SetSize(uli);

    if (FAILED(hResult))
        return hResult;

    hResult = spStream->Write(&fsh, sizeof (fsh), NULL);

    if (FAILED(hResult))
        return hResult;

    hResult = spStream->Write(reinterpret_cast<void*>(hResourceLoaded), dwResourceDataSize, NULL);

    if (FAILED(hResult))
        return hResult;

    uli.QuadPart = 0;

    hResult = spStream->Seek(*reinterpret_cast<PLARGE_INTEGER>(&uli), STREAM_SEEK_SET, NULL);

    if (FAILED(hResult))
        return hResult;

    ATL::CComPtr<IPersistStreamInit> spPersistStreamInit;

    hResult = spShockwaveFlash.QueryInterface(&spPersistStreamInit);

    if (SUCCEEDED(hResult))
        hResult = spPersistStreamInit->Load(spStream);

    return hResult;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top