Flash ActiveX: comment charger un film à partir de la mémoire, d'une ressource ou d'un flux?

StackOverflow https://stackoverflow.com/questions/423166

Question

J'intègre un contrôle ActiveX Flash dans mon application C ++ (Flash.ocx, Flash10a.ocx, etc. selon la version de Flash).

Je peux charger un fichier SWF en appelant LoadMovie (0, nom de fichier), mais le fichier doit résider physiquement sur le disque. Comment charger le fichier SWF à partir de la mémoire (ou d'une ressource ou d'un flux)? Je suis sûr qu'il doit y avoir un moyen, car des solutions commerciales telles que la fonctionnalité de f-in-box Charger directement des animations flash à partir de la mémoire utilise également le contrôle Flash ActiveX.

Était-ce utile?

La solution

Apparemment, je vais avoir besoin de fournir des détails pour un vote "up" .. OK.

Le tampon flash interne lors de la première initialisation indique si une vidéo est chargée ou si le tampon contient les propriétés dans la mémoire tampon pour quatre octets seulement.

gUfU - aucun film chargé. propriétés à suivre ....

fUfU - .. [4 octets] taille sous forme d'entier.

puis le film ou le SWF UNCOMPRESSED pour ainsi dire. Ecrire une classe IStream. remplir avec ci-dessus. enregistrer sous 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;

Choses à noter: Lorsque psStreamInit- > Load (fStream); appellera IStream :: Read à la recherche de l'en-tête 'fUfU'.

si le retour est correct, psStreamInit appelle alors IStream :: Read pour connaître la taille du tampon.

Si tout semble bon jusqu'à présent, psStreamInit lit ensuite des fragments de 1024 octets jusqu'à ce que la lecture soit épuisée. Toutefois. pour l'en-tête et la taille du fichier.

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

pcbRead n'est pas valide. vous voudrez peut-être utiliser quelque chose comme IsBadReadPtr

-

Michael

Autres conseils

Pour vous épargner quelques fautes de frappe. Cela fonctionne pour moi de cette manière (fonctionne simplement, pas complètement testé):

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;
    };

Étant un gars de Flash, je ne connais aucun détail du côté C ++, mais si vous avez demandé un faux protocole du côté de Flash, vous pouvez du côté C intercepter cette demande et y répondre avec un flux de données ? Je veux dire quelque chose comme:

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

Tant que la réponse (à Flash) ressemble à un flux HTTP, cela devrait fonctionner. (Veuillez nous excuser par avance si "intercepter la demande et renvoyer un flux de données" est la partie sur laquelle vous demandez de l'aide.)

en plus .... Flash Player promeut IPersistStorage. flash.QI IPersistStorage pStorage.load (mystorage_as_stream)

.. en théorie.

Désolé pour ce qui précède .. Je voulais poster Flash player promeut IPersistStreamInit. flash.QI IPersistStreamInit pStream.load (my_stream)

Michael

Cette méthode ne fonctionne pas lorsque vous essayez de charger un film via MovieclipLoader ou LoadMovie à partir d'un autre film !!!

Le résultat est de remplacer le fichier SWF appelant !! ... donc cette méthode ne fonctionne que pour charger le fichier de base.

Quelqu'un connaît-il une meilleure méthode qui fonctionne également avec MovieClipLoader et LoadMovie? Merci.

Exemple MS VC ATL (construit avec VS 2010 SP1 + Windows SDK 7.1 et testé sur Windows 7 SP1 64 bits avec Flash64_11_3_300_257.ocx / Flash32_11_3_300_257.ocx et sur Windows XP SP3 32 bits avec 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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top