现在的位置: 首页 > 综合 > 正文

利用命名管道(Named Pipe)向Flash Player模拟Flash媒体文件

2012年09月05日 ⁄ 综合 ⁄ 共 5097字 ⁄ 字号 评论关闭

  多样、互动的WinForm UI设计与开发思路一文中,我提到过把Flash作为控件嵌入到WinForm程序中以提高软件的互动效果并降低开发难度这样一种思路。但这样一个系统,我们往往不希望随应用程序打包,或者让用户看到,很多很多的FLASH文件。其中一个办法就是把flash文件作为资源嵌入到系统中。但这样又出现一个问题,Flash Player只有一个Movie属性用于指定当前播放的媒体,而这个字符串属性只能是本地文件或者一个URL。我们可以在运行时把资源里的flash释放到一个临时目录,但这样一来失去了打包的意义,二来无法保护flash文件。

  我们希望最好的解决方案,就是Flash Player提供类似于DataSet.ReadXml()这样的方法,既可以从指定名字的Xml文件读取数据,又可以从一个数据流(Stream)读数据。但是找遍了Flash Player的所有参数,似乎只有MovieData这个属性有点接近,如果我们能直接把Flash文件的内容赋值给它就好了。不过目前我还没有找到关于这个属性的资料 -_-

  另外一个思路,就是在我们的程序运行的时候,动态建立一个自己的http服务器,可以直接从资源中读取内容。事实上,对于大部分要求文件或url形式的内容,都可以通过建立虚拟http服务器来模拟。但实现起来要费点功夫,而且http会在本机留下缓存,安全性不高。

  最后在whoo从内存播放Flash一文找到了另外一种方法,就是通过命名管道(Named Pipe)。

首先我们看看命名管道为什么能够解决这个问题。这要从它的运行机制讲起。当一个命名管道被建立起来后,它的服务端和客户端之间的数据交流,就完全是通过和操作文件一样的方式来进行,即CreateFile(),ReadFile()和WriteFile()三个函数。也就是说客户端可以像读取文件一样,来读取管道里的数据。

  我们通过调用Win32 API 既可创建管道。这里先简单讲一下服务器端的处理流程:

  1、通过CreateNamedPipe()函数创建一个命名管道,如果成功,会返回这个管道实例的句柄。

  2、管道创建成功后,调用ConnectNamedPipe()函数等到客户端连接。

  3、如果有客户端连接进来,可以通过对文件的操作来交换数据,例如ReadFile()和WriteFile()。

  在.NET里我们不必用这些Win32 API函数来读写文件,直接用System.IO命名空间下的类即可(将文件读写的内存指针指向管道句柄即可)。

  注:目前该方法只针对在Flash Player播放器打开 \\.\pipe\testPipe 才有效。如果您使用的是Flash Player 7.0,那么一定要用 \\?\pipe\testPipe才行。

  至于在html页面或WinForm里的Flash Player控件,指定其Movie属性为"\\.\pipe\testPipe",目前尚无效。

  以下是简单的例子:

using System;

using System.IO;


namespace PipeServer {

    
class Entry {

        
/// <summary>

        
/// 应用程序的主入口点。

        
/// </summary>


        [STAThread]

        
static void Main(string[] args) {

            CreatePipe();

        }



        
private const int BUFFER_SIZE = 1024;

        
private const int PIPE_TIMEOUT = 1000;

        
private const string PIPE_NAME = @"\\.\pipe\testPipe";


        
public static void CreatePipe(){

            

            API.SECURITY_ATTRIBUTES sec 
= new API.SECURITY_ATTRIBUTES();

            
int pipeHandle = API.CreateNamedPipe( PIPE_NAME, API.PIPE_ACCESS_DUPLEX

                , API.PIPE_WAIT, API.PIPE_UNLIMITED_INSTANCES, BUFFER_SIZE, BUFFER_SIZE

                , PIPE_TIMEOUT, 
ref sec);

            Console.WriteLine(pipeHandle);


            
if ( pipeHandle == API.INVALID_HANDLE_VALUE ){

                Console.WriteLine(
"Cannot create pipe.");

                
return;

            }
else{

                Console.WriteLine(
"Create pipe successful. Waiting for connection");

            }



            API.OVERLAPPED lapped 
= new API.OVERLAPPED();

            
int connected = API.ConnectNamedPipe( pipeHandle, ref lapped );


            
if ( connected > 0 ){

                
// 如果从资源文件读入swf文件,用下面这句

                
// using ( Stream swf = typeof(API).Assembly.GetManifestResourceStream("PipeServer.test.swf")) {

                using ( Stream swf = File.Open(@"test.swf", FileMode.Open)) {

                    
using (FileStream pipe = new FileStream( new IntPtr(pipeHandle), FileAccess.Write)) {

                        
int reads;

                        
byte[] buffer = new byte[BUFFER_SIZE];

                        
while ( (reads = swf.Read(buffer, 0, BUFFER_SIZE) ) > 0 ) {

                            pipe.Write(buffer, 
0, reads);

                        }


                        pipe.Flush();

                    }


                }


                

                Console.WriteLine(
"Someone arrived.");

                API.DisconnectNamedPipe(pipeHandle);

                API.CloseHandle( pipeHandle );

            }
else{

                API.CloseHandle( pipeHandle );

            }


        }


    }


}

using System;

using System.Runtime.InteropServices;


namespace PipeServer {


    
public class API {


        
public const int INVALID_HANDLE_VALUE = -1;

        
public const int PIPE_ACCESS_INBOUND = 0x1;

        
public const int PIPE_ACCESS_OUTBOUND = 0x2;

        
public const int PIPE_ACCESS_DUPLEX = 0x3;

        
public const int PIPE_WAIT = 0x0;

        
public const int PIPE_UNLIMITED_INSTANCES = 255;


        [DllImport(
"kernel32.dll", EntryPoint="CreateNamedPipe")]

        
public static extern int CreateNamedPipe (

            
string lpName,

            
int dwOpenMode,

            
int dwPipeMode,

            
int nMaxInstances,

            
int nOutBufferSize,

            
int nInBufferSize,

            
int nDefaultTimeOut,

            
ref SECURITY_ATTRIBUTES lpSecurityAttributes

        );


        [StructLayout(LayoutKind.Sequential)]

            
public struct SECURITY_ATTRIBUTES {

            
public int nLength;

            
public int lpSecurityDescriptor;

            
public int bInheritHandle;

        }



        [DllImport(
"kernel32.dll", EntryPoint="ConnectNamedPipe")]

        
public static extern int ConnectNamedPipe (

            
int hNamedPipe,

            
ref OVERLAPPED lpOverlapped

        );


        [StructLayout(LayoutKind.Sequential)]

            
public struct OVERLAPPED {

            
public int Internal;

            
public int InternalHigh;

            
public int offset;

            
public int OffsetHigh;

            
public int hEvent;

        }



        [DllImport(
"kernel32.dll", EntryPoint="CloseHandle")]

        
public static extern int CloseHandle (

            
int hObject

        );


        [DllImport(
"kernel32.dll", EntryPoint="DisconnectNamedPipe")]

        
public static extern int DisconnectNamedPipe (

            
int hNamedPipe

        );

    }


}

抱歉!评论已关闭.