播放内存中的
Flash(*.swf)
文件
日期: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”
弹出的添加资源对话框中单击“I
mPort...”
在弹出的文件浏览对话框中选择需要的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
2007/04/20