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

来源:互联网 发布:碘伏 碘酒 知乎 编辑:程序博客网 时间:2024/04/30 00:58

 

播放内存中的Flash(*.swf)文件
 
作者:Sunline               lisunlin0@yahoo.com.cn
日期: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
 
 
选择A typical “Hello Word” application
 
 
步骤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”
 
 
 
弹出的添加资源对话框中单击“ImPort...”
 
 
在弹出的文件浏览对话框中选择需要的swf文件,然后会要你填入自定义资源的类型,我在这里填的是“SWF”
 
现在资源管理器中就有了SWF型的“IDR_SWF1”的资源
 
步骤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):
 
样就可以播放实际上在内存中的pig.swf文件了。
 
MFC中使用类似。
Write By SunLine     
lisunlin0@yahoo.com.cn
2007/04/20
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 旺旺卖家拒收我的消息怎么办 淘宝清空购物车大奖到上限了怎么办 游戏无响应除了退出还能怎么办 淘宝给差评了卖家一直打电话怎么办 电脑说带宽问题无法观看视频怎么办 手机淘宝上的购买信息删除了怎么办 为什么支付宝有钱淘宝付不了怎么办 苹果平板电脑上的淘宝点不开怎么办 淘宝付了两次款只有一个订单怎么办 淘宝付款显示支付宝账号异常怎么办 手机老卡换新卡淘宝付不了款怎么办 淘宝买东西退款卖家拒绝退款怎么办 淘宝店铺收藏图片怎么点不了怎么办 手机淘宝显示用户被限制登录怎么办 淘宝设置登录密码原密码忘了怎么办 斑马智行淘宝号换没法登录了怎么办 淘宝卖家手机版显示宝贝不全怎么办 在电脑上登的淘宝账号退不了怎么办 淘宝买家退款不退货写假货怎么办 淘宝卖家已发布商品没货了怎么办 京东换货附近没有京东自提点怎么办 一直显示手机淘宝已停止运行怎么办 唯品会买了不可以退货的衣服怎么办 淘宝店卖东西邮费太贵怎么办 支付宝登录上去必须手机验证怎么办 支付宝里的钱被盗了怎么办 淘宝绑定的支付宝账号忘记了怎么办 支付宝绑定的微博账号忘记了怎么办 怎么知道自己的淘宝密码忘了怎么办 更换扣扣头像图片太大放不下怎么办 每次登入淘宝都要手机验证码怎么办 手机停机收不到唯品会验证码怎么办 魅蓝手机账户密码忘了怎么办 支付宝登录失败请稍后再试怎么办 万王之王3d限制注册了怎么办 绑定手机号无法登陆以前微信怎么办 手机号注册了淘宝如果不用了怎么办 淘宝网登陆要手机验证码怎么办 手机清理了微信图片打不开了怎么办 到淘宝网买东西卖家拒绝退货怎么办 淘宝店铺检测出他人认证图片怎么办