前提: 被要求Flash必须加密,不能在硬盘上留下文件。
起点: Flash 播放器的属性Movie接受本地文件名 或者 HTTP URL。
首先当然是在网络上寻找解决方案了。找了半天,发现一个国内的,一个国外的。都在出售。 奇怪的是,他们不约而同的都是用了Delphi。 根据了解的人透露,它是利用了Flash一个未公开的属性MovieData, 该属性文档中没有记录,但是从名称可以看出应该是应该是接受数据片的。
其国内的那一版目前还不支持最新的flash播放器。这让人不能不有点担忧。 因此还是尽量照自己的思路来。
思路: 最开始考虑的就是建一个协议(类似于rtsp的样子)来代替http,并把请求转到本地守护进程。 后来又想到还不如直接建立一个简陋的http服务器,直接使用http url , 这样子肯定是可行的,于是就着手写http服务器了。 写了个简单的测试程序,监听了一些http包,发现即使建立个简陋的http服务器,也需要了解一下rfc2612的,考虑到flash不同版本可能识别的响应及其标签,响应头还是蛮复杂的。 看rfc2612的时候突然想到, 建立http服务器是虚拟一个url;如果能够虚拟一个本地文件名,是不是更简单些呢? 照着这个思路,找了个把小时,当然也走了不少的弯路。最终发现可以用管道来处理。
因为管道客户端也是用CreateFile, ReadFile来处理的, 与普通文件一样。这样子就可以用管道名称来代替文件名来欺骗一下flash乐^_^
被欺骗的Flash读文件的时候:CreateFile, ReadFile实际上是读的是管道,只是他自己不知道而已. 而我们可以向管道写入任何内容,这不就达到目的了么?
写了段代码验证了一下,确实可行。 而且还模拟了网络的流环境(每次读10字节,延迟3ms),发现效果不错,正如预料的一样。
下面贴出来的代码来资源是测试程序,比较零乱。如果你仔细看了上面的内容,并且对于提到的属于没什么不解的话,应该就不用看下面的代码了。 附上来仅仅是为了备忘。
代码是一个console程序, vs2003环境。 假设有个样例Flash为Blue.swf。 设定的管道名称为: \\.\pipe\egbpipe 验证时先运行本程序,并保证blue.swf存在。然后打开flash播放器,用她播放文件"\\.\pipe\egbpipe"。
代码开始: ------------- // PipeService.cpp : 定义控制台应用程序的入口点。 //
#include "stdafx.h"
#define BUFSIZE 1024 #define PIPE_TIMEOUT 1000
int __main(void); int MyErrExit(char*); int _tmain(int argc, _TCHAR* argv[]) { __main(); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> VOID InstanceThread(LPVOID); VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD); VOID GetAnswerToRequest(HANDLE hFile); int xx = 0;
/*
\\.\pipe\egbpipe
*/
int __main(void) { BOOL fConnected; DWORD dwThreadId; HANDLE hPipe, hThread; LPTSTR lpszPipename = "\\\\.\\pipe\\egbpipe"; // The main loop creates an instance of the named pipe and // then waits for a client to connect to it. When the client // connects, a thread is created to handle communications // with that client, and the loop is repeated. for (;;) { hPipe = CreateNamedPipe( lpszPipename, // pipe name PIPE_ACCESS_DUPLEX, // read/write access PIPE_TYPE_MESSAGE | // message type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_WAIT, // blocking mode PIPE_UNLIMITED_INSTANCES, // max. instances BUFSIZE, // output buffer size BUFSIZE, // input buffer size PIPE_TIMEOUT, // client time-out NULL); // no security attribute
if (hPipe == INVALID_HANDLE_VALUE) MyErrExit("CreatePipe"); // Wait for the client to connect; if it succeeds, // the function returns a nonzero value. If the function returns // zero, GetLastError returns ERROR_PIPE_CONNECTED. fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); if (fConnected) { // Create a thread for this client. hThread = CreateThread( NULL, // no security attribute 0, // default stack size (LPTHREAD_START_ROUTINE) InstanceThread, (LPVOID) hPipe, // thread parameter 0, // not suspended &dwThreadId); // returns thread ID
if (hThread == NULL) MyErrExit("CreateThread"); else CloseHandle(hThread); } else // The client could not connect, so close the pipe. CloseHandle(hPipe); } return 1; } VOID InstanceThread(LPVOID lpvParam) { CHAR chRequest[BUFSIZE]; CHAR chReply[BUFSIZE]; DWORD cbBytesRead, cbReplyBytes, cbWritten; BOOL fSuccess; HANDLE hPipe; // The thread's parameter is a handle to a pipe instance. hPipe = (HANDLE) lpvParam; // while (1) { // Read client requests from the pipe. /* fSuccess = ReadFile( hPipe, // handle to pipe chRequest, // buffer to receive data BUFSIZE, // size of buffer &cbBytesRead, // number of bytes read NULL); // not overlapped I/O
if (! fSuccess || cbBytesRead == 0) break; */ //GetAnswerToRequest(chRequest, chReply, &cbReplyBytes); GetAnswerToRequest(hPipe); /* // Write the reply to the pipe. fSuccess = WriteFile( hPipe, // handle to pipe chReply, // buffer to write from cbReplyBytes, // number of bytes to write &cbWritten, // number of bytes written NULL); // not overlapped I/O
// if (! fSuccess || cbReplyBytes != cbWritten) break; */ } // Flush the pipe to allow the client to read the pipe's contents // before disconnecting. Then disconnect the pipe, and close the // handle to this pipe instance. FlushFileBuffers(hPipe); DisconnectNamedPipe(hPipe); CloseHandle(hPipe); }
int MyErrExit(char* szInfo) { return MessageBox(0, szInfo, "Whoo", MB_OK); }
VOID GetAnswerToRequest(HANDLE hFile) { const int BuffLen = 10; byte buff[BuffLen] = {0};
FILE* f = fopen("blue.swf", "rb");
int iLen = BuffLen; while(iLen == BuffLen) { iLen = fread(buff, sizeof(byte), BuffLen, f);
Sleep(3); DWORD uLen = 0; WriteFile(hFile, buff, iLen, &uLen, NULL); } _fcloseall( ); }

|