无临时文件播放内存中的Flash(*.swf)文件

 

播放内存中的 Flash(*.swf) 文件
 
作者:Sunline                [email protected]
日期:2007年4月
下载例示代码:
SDK示例 :http://www.websamba.com/dust-fly/src/MemSwfDemo.rar
MFC示例 :http://www.websamba.com/dust-fly/src/MemSwfDemoMFC.rar
(放置文件的是一个免费空间 ,若不能下载,请从本人上传到CSDN的资源中下载.)
  http://download.csdn.net/source/179509
摘要
某些情况下希望直接从内存中播放 swf文件,而MecraMedia的ShockwaveFlash插件没有提供直接从内存中播放swf文件的功能,本文解决了直接从内存中播放swf文件的问题.
 
关键字
 播放 swf文件, flash播放, 播放内存中的flash文件, 无临时文件播放资源中的swf文件,无临时文件播放内存中的swf文件
        Load swf from memory, play flash from memory, play flash
 
简介
平时喜欢自己动手写几个小程序,利用 ShockwaveFlash插件实现Flash界面,效果很好,只是有个缺陷,那就是ShockwaveFlash只能用磁盘文件形式的Flash(*.swf)文件,在分发一个简单的应用程序时都至少有一个程序(.exe)文件和一个Flash(.swf)文件,这样非常不便,后来想到把Flash(.swf)文件放到程序文件内,需要的时候在内存中播放Flash,首先想到的便是有没有这样的解决方案,但是查了n多的资料,没有满意的解决方案(在ShockwaveFlash控件中有个SetMovieData()方法很像用来播放内存Flash,但MacroMedia的文档中没有这个方法的详细具体说明,对这个方法用了各种途径试了多次,没有任何有意义的反馈;另外在网上也有关于播放内存Flash的解决方案,但得收取¥或$,而我是个业余爱好者,口袋空空,而且也没有必要购买商业库。)。于是就自己动手写一个可以播放内存Flash的类。
 
实现原理
       Shockwave Flash object支持本地Flash(.swf)文件播放,比如用“file://c:/UI.swf”或“c:// UI.swf”都可以播放C盘下的UI.swf文件。那么它一定调用了文件操作的各种API,因此可以通过API Hook技术来实现播放内存中的Flash文件。而主要的文件操作函数有CreateFile(…), ReadFile(…), GetFileSize(…), GetFileAttributes (…) ...,使用API Hook后,我们就可以欺骗ShockwaveFlash,在其读文件时返回实际的内存中的swf文件内容。
这样,我们就可以让自己的程序潇洒地使用Flash文件了。
实现方法:
 
//MemoryFile.h
// 通过Hook文件操作函数,把读取磁盘文件的操作转向自己的实现
// 说明:虚拟文件名mlpFileName字符串由CMemoryFile类内部拷贝一份,而内存文件的内存块则使用传入
// 的内存块(重新拷贝一份太浪费内存了)。
#pragma once
//
class CMemoryFile
{
protected :    //struck members
     struct MFHANDLE{ ……};
     struct MFFINDHANDLE    { ……};
     static MFFINDHANDLE *spFindHandleHead;
     MFHANDLE *mpHandleHead;
     static CMemoryFile *spHead;//a inversion link head, actually, it’s a trail.
     LPCWSTR mlpFileName;
     LPBYTE mlpFileBuffer;
     DWORD mdwFileSizeLow;
     DWORD mdwFileSizeHigh;
     DWORD mdwFileAttributes;
     CMemoryFile *mpNext;
protected :
     // 静态数据成员
     //tCreateFileW record the Ture entrypoint to CreateFileW
     static HANDLE (__stdcall *tCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
static BOOL  (__stdcall *tReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
     ……
     // 静态方法
     static HANDLE __stdcall mfCreateFileW(
         LPCWSTR lpFileName,          // pointer to name of the file
         DWORD dwDesiredAccess,       // access (read-write) mode
         DWORD dwShareMode,           // share mode
         LPSECURITY_ATTRIBUTES lpSecurityAttributes,    // pointer to security attributes
         DWORD dwCreationDisposition,  // how to create
         DWORD dwFlagsAndAttributes,  // file attributes
         HANDLE hTemplateFile         // handle to file with attributes to copy
         );
     static BOOL __stdcall mfReadFile(
         HANDLE hFile,                // handle of file to read
         LPVOID lpBuffer,             // pointer to buffer that receives data
         DWORD nNumberOfBytesToRead, // number of bytes to read
         LPDWORD lpNumberOfBytesRead, // pointer to number of bytes read
         LPOVERLAPPED lpOverlapped    // pointer to structure for data
         );
……
public :
     CMemoryFile( LPCSTR    pFileName, LPVOID lpFileBuffer, int nFileSize, DWORD dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY);
     CMemoryFile( LPCWSTR pFileName, LPVOID lpFileBuffer, int nFileSize, DWORD dwFileAttributes = FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY);
……
     virtual ~CMemoryFile(void);
……
};
//MemoryFile.cpp
#include "MemoryFile.h"
#include "detours.h"
HANDLE (__stdcall *CMemoryFile::tCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) = &::CreateFileW;
……
CMemoryFile::MFFINDHANDLE* CMemoryFile::spFindHandleHead = NULL;
CMemoryFile* CMemoryFile::spHead = NULL;
HANDLE CMemoryFile::mfCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, /
                                       LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, /
                                       DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
     HANDLE hRet;
     CMemoryFile *pMemFile;
     if(pMemFile = IsMemoryFile(lpFileName))
     {
         EnterCriticalSection(&sCSHandle);
         MFHANDLE *pHandle = new MFHANDLE;
         pHandle->pCurPointer = pMemFile->mlpFileBuffer;
         pHandle->pNext = pMemFile->mpHandleHead;
         if(pMemFile->mpHandleHead == NULL)
         {
              pHandle->hHandle = (HANDLE)(~size_t(pMemFile->mlpFileBuffer)&(~WORD(0)<<((sizeof(HANDLE) - sizeof(WORD))*8)));
         }
         else
         {
              pHandle->hHandle = (HANDLE)((LPBYTE)pMemFile->mpHandleHead->hHandle + 1);
         }
         LONG lRet = InterlockedExchange(&(LONG&)pMemFile->mpHandleHead, (LONG&)pHandle);
         hRet = pHandle->hHandle;
         LeaveCriticalSection(&sCSHandle);
     }
     else
     {
         hRet = tCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
     }
     return hRet;
}
 
BOOL CMemoryFile::mfReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, /
                                  LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
     BOOL bRet;
     MFHANDLE *pMfHandle;
     CMemoryFile *pMemFile;
     if(pMemFile = IsMemoryFile(hFile, &pMfHandle))
     {//is MemSwf Handle
         LPBYTE lpFileEnd = LPBYTE(pMemFile->mlpFileBuffer + pMemFile->mdwFileSizeLow);
         DWORD dwNumOfByteRead = 0;
         if(pMfHandle->pCurPointer >= lpFileEnd)
         {
              *lpNumberOfBytesRead = 0;
         }
         else if((pMfHandle->pCurPointer + nNumberOfBytesToRead) < lpFileEnd)
         {
              dwNumOfByteRead = nNumberOfBytesToRead;
         }
         else
         {
              dwNumOfByteRead = (DWORD)(lpFileEnd - pMfHandle->pCurPointer);
         }
         memcpy(lpBuffer, pMfHandle->pCurPointer, dwNumOfByteRead);
         pMfHandle->pCurPointer = pMfHandle->pCurPointer + dwNumOfByteRead;
         *lpNumberOfBytesRead = dwNumOfByteRead;
         bRet = TRUE;
     }
     else
     {
         bRet = tReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
     }
     return bRet;
}
……
CMemoryFile::CMemoryFile(  LPCSTR pFileName, LPVOID lpFileBuffer,int nFileSize, DWORD dwFileAttributes)
{
     if( (lstrlenA(pFileName) == 0) || (lpFileBuffer == NULL ))
         throw -1;
     if(::IsBadReadPtr(lpFileBuffer, nFileSize))
     {
         throw -2;
     }
     int nRet;
     LONG lRet;
     int nLen = (int)(2 * lstrlenA(pFileName));
     LPWSTR lpwFileName = new WCHAR[nLen];
     nRet = MultiByteToWideChar(CP_THREAD_ACP, MB_ERR_INVALID_CHARS, pFileName, -1, lpwFileName, nLen);
     if(!nRet)
     {
         delete[] lpwFileName;
         throw GetLastError();
     }
     if(IsMemoryFile(lpwFileName))
     {
         delete[] lpwFileName;
         throw -2;
     }
     mdwFileAttributes = dwFileAttributes;
     mdwFileSizeHigh = 0;
     mdwFileSizeLow = nFileSize;
     mlpFileBuffer = (LPBYTE)lpFileBuffer;
     mlpFileName = lpwFileName;
     mpHandleHead = NULL;
     CMemoryFile *tp = this;
     // 使用TryEnterCriticalSection是为了兼容编译为静态库时,在用new方法初次创建CMemoryFile对象时
     // 静态初始化成员memfileInit还没有初始化sCSFile,此构造函数执行完毕后才构造memfileInit,完成初始化
     if(TryEnterCriticalSection(&sCSFile))
     {
         mpNext = spHead;
         lRet = InterlockedExchange(&(LONG&)spHead, (LONG&)tp);
         LeaveCriticalSection(&sCSFile);
     }
     else
     {
         if(spHead == NULL)
         {
              mpNext = spHead;
              lRet = InterlockedExchange(&(LONG&)spHead, (LONG&)tp);
         }
         else
         {
              throw -1;
         }
     }
}
 
CMemoryFile::CMemoryFile( LPCWSTR pFileName, LPVOID lpFileBuffer, int nFileSize, DWORD dwFileAttributes)
{   
……
}
……
CMemoryFile::~CMemoryFile(void)
{
     EnterCriticalSection(&sCSHandle);
     if(mpHandleHead == NULL)
     {
          delete[] mlpFileName;
         mlpFileName = NULL;
     }
     LeaveCriticalSection(&sCSHandle);
     CMemoryFile *pMemFile, *pPreMemFile;
     EnterCriticalSection(&sCSFile);
     for(pPreMemFile = NULL, pMemFile = spHead; pMemFile != NULL; pPreMemFile = pMemFile, pMemFile = pMemFile->mpNext)
     {
         if(pPreMemFile != NULL)
         {
              //pPreMemFile->pNext = pMemFile->pNext;
              ::InterlockedExchange(&(LONG&)pPreMemFile->mpNext, (LONG&)pMemFile->mpNext);
         }
         else
         {
              //spHead = NULL;
              ::InterlockedExchange(&(LONG&)spHead, (LONG&)pMemFile->mpNext);
         }
     }
     LeaveCriticalSection(&sCSFile);
}
……  
  
具体的源代码很长,这里没有办法全部帖出,为了简化使用,我用CMemSwf类作了封装,并生成为静态库,大家可以在ShockwaveFlash控件的PutMovie方法前实例化一个CMemFlash对象,然后就可以播放指定的内存Flash文件了。
使用 CMemFlash 示例:
步骤1:新建一个 WIN32工程
新建一个名为MemSwfDemo的Win32 Aplication
 
  无临时文件播放内存中的Flash(*.swf)文件_第1张图片
选择A typical “Hello Word” application
 
  无临时文件播放内存中的Flash(*.swf)文件_第2张图片
步骤2 添加 Shockwave flash object控件
 
在VC自动生成的代码中添加如下的代码来实现Flash控件
 
……                                   
#include "stdafx.h"
#include "resource.h"
#include   <atlbase.h>
CComModule   _Module;
#include   <atlcom.h>  
#include   <atlwin.h>  
#pragma   comment(lib,"atl")
// flash.ocx 一般位于 C:/WINDOWS/system32/Macromed/Flash/
#import   "flash.ocx"  // 你可以把 flash.ocx 拷贝到项目文件夹中,就可以使用相对路径了。
using   namespace   ShockwaveFlashObjects;
 
CAxWindow   g_container;
IShockwaveFlash*   g_pshwaveflash;
 
 ……
……
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
      ……
       MyRegisterClass(hInstance);
 
       CoInitialize(NULL); 
       AtlAxWinInit(); 
       // Perform application initialization:
       if (!InitInstance (hInstance, nCmdShow))
       {
              return FALSE;
       }
 
       hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_MEMFLASH);
 
       // Main message loop:
       while (GetMessage(&msg, NULL, 0, 0))
       {
              if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
              {
                     TranslateMessage(&msg);
                     DispatchMessage(&msg);
              }
       }
 
       return msg.wParam;
}
……
……
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
       int wmId, wmEvent;
       PAINTSTRUCT ps;
       HDC hdc;
       TCHAR szHello[MAX_LOADSTRING];
       LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);
     
       switch (message)
       {
              case WM_CREATE:
   RECT   rc;
                     GetClientRect(hWnd, &rc);  
                    //create a browser control  
                     g_container.Create(hWnd, rc, LPCTSTR("ShockwaveFlash.ShockwaveFlash.1"),   WS_CHILD | WS_VISIBLE);
                     g_container.QueryControl(__uuidof(IShockwaveFlash), reinterpret_cast<void**>(&g_pshwaveflash));  
                     g_pshwaveflash->put_Movie(_bstr_t("c://a.swf"));   //  the flash file path  
                     //g_pshwaveflash->Play();
                     break;
              case WM_COMMAND:
                    ……
               ……
              case WM_DESTROY:
                     g_pshwaveflash->Release();
                     g_container.DestroyWindow();
                     PostQuitMessage(0);
                     break;
              default:
                     return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}
……
 
  
添加了上面的代码后就可以播放C盘下的a.swf文件了。
步骤3:添加 swf文件到PE的资源
添加目标swf文件为资源文件:
菜单“Insert->Resourc...”, 弹出的添加资源对话框中单击“Resource”
 
  无临时文件播放内存中的Flash(*.swf)文件_第3张图片
 
弹出的添加资源对话框中单击“I mPort...”
 
  无临时文件播放内存中的Flash(*.swf)文件_第4张图片
在弹出的文件浏览对话框中选择需要的swf文件,然后会要你填入自定义资源的类型,我在这里填的是“SWF”
  无临时文件播放内存中的Flash(*.swf)文件_第5张图片
现在资源管理器中就有了SWF型的“IDR_SWF1”的资源
  无临时文件播放内存中的Flash(*.swf)文件_第6张图片
步骤 4:添加内存Flash文件支持:
 
IShockwaveFlash* g_pshwaveflash;

#include "MemFlash.h"
#pragma comment(lib, "MemSwf")
CMemSwf *g_pMemSwf = NULL;
PBYTE g_pSwf = NULL;
HRSRC g_hResInfo;
HGLOBAL g_hResData;
……

……
……
              case WM_CREATE:
                     g_hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_SWF1), "SWF");
          g_hResData = LoadResource(NULL, g_hResInfo);
          g_pSwf = (LPBYTE)LockResource(g_hResData);
          g_pMemSwf = (CMemSwf *)new CMemSwf("m://pig.swf", g_pSwf, SizeofResource(NULL, g_hResInfo), FILE_ATTRIBUTE_ARCHIVE);
          RECT rc;
                    GetClientRect(hWnd, &rc);  
……
                     g_pshwaveflash->put_Movie(_bstr_t(" m://pig.swf "));   //   you   have   to   change   the   path   here  
 
然后要设置项目的编译属性 use run-time library为多线程的(Project->Settings...或Alt+F7):
无临时文件播放内存中的Flash(*.swf)文件_第7张图片
 
样就可以播放实际上在内存中的pig.swf文件了。
 
MFC中使用类似。
Write By SunLine      
2007/04/20

你可能感兴趣的:(File,Flash,null,application,attributes,archive)