VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > VB.net教程 >
  • 【VB.NET】提取PPT中的SWF

学坏了~先贴图~~~~~~~~~~~~~~~~~

'这几天在网上看到了一些提取PPT内SWF的方法,于是编程实现了一下。其他的几种OFFICE文件内嵌后基本都可以用另存网页的方式解决。。。。。
'思路是这样的:
'1、通过PPT的COM对象,遍历幻灯片内容并把找到的内嵌SWF控件复制到剪贴板
'2、访问剪贴板对象,提取其中的嵌入对象内容得到一个流
'3、处理这个流前面的多余部分,并保存为文件
'还存在一些问题:
'1、如果只有控件,而没有SWF被嵌入,不知道代码会得到怎么样的结果

经过协商,得到了一个比较满意的结果。。。公开部分代码和软件。但请遵循程序的协议~~~~~~

请注意,这里所提到的“内嵌”,指将SWF文件内置于OFFICE文件中,即在设计文档时将FLASH AX控件的Embed Move属性设置为True。



然后保存文件。若要在Excel中观看到动画,请退出设计模式(点那个三角板、铅笔、直尺组成的图标使之处于非选中状态)。

而后是编码了,首先是一个总体的调用方式:

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim file As New OpenFileDialog
        file.Filter = "*.XLS|*.XLS"
        file.ShowDialog()
        If file.FileName <> "" Then
            AddHandler MSExcel.Progress, AddressOf Progress
            MSExcel.GetSWFFile(file.FileName)
            RemoveHandler MSExcel.Progress, AddressOf Progress
        End If
    End Sub

    Private Sub Progress(ByVal Msg As String)
        lstMsg.Items.Add(Msg)
    End Sub


在按钮点击事件,调用一个打开文件对话框,以打开要提取SWF文件的XLS文档,而后为了显示进度消息,添加事件处理函数句柄到Progress函数,当使用完毕后,该句柄被移除。而Progress函数是非常简单的,仅仅在一个名为lstMsg的ListBox里面添加得到的消息。
接下来实现GetSWFFile函数,这个函数被设定在一个仅有共享成员的类(MSExcel)中,该类将有一个共享成员:
Public Shared Event Progress(ByVal Msg As String)
而为了以后扩展的需要,把进程和文档引用都放在了这里:
    Private Shared app As Excel.Application
    Private Shared book As Excel.Workbook
当然,为了使用这些代码,需要在类文件开头导入一个名空间,在这里使用了指定别名的方式:
Imports Excel = Microsoft.Office.Interop.Excel
(请在引用对话框添加Microsoft.Office.Interop.Excel.XX及相应版本OFFICE的.NET引用,在这里笔者使用的是OFFICE2003,所以添加的版本都为11,OFFICE的引用当中会包含一些名空间,而对于我们的程序来讲只使用了其中包含一些常量的名空间,所以你完全可以用相应的数字来代替这些常量而不引用名空间,这样做的好处后面还将叙述)
而后,编写一个实现复制FLASH内嵌对象的函数、一个将剪贴板内容保存为SWF文件的函数(将这个功能分离是因为它可以重用:在其他OFFICE文件格式处理时也用这个函数)。首先描述第一个函数,这个函数要实现的功能就是把XLS文件中的FLASH OLE内容复制出来,简单的做法是利用EXCEL:
1、打开文档:
        app = New Excel.Application()
        app.Visible = Microsoft.Office.Core.MsoTriState.msoTrue(在VBA、VB6、VB.NET的IDE中这个msoTrue实际上为-1,对于VB.NET的布尔型在IDE和CLR中的关系等等不想赘述。有疑问的可以参考VB.NET核心编程或.NET FRAMEWORK详解等。在我们的程序里“最终”应使用-1来代替这些常量,后面将给予说明)
        book = app.Workbooks.Open(file)
2、遍历并复制FLASH OLE内容
这里的叙述可能有些小问题,不深究了。实际上我们的操作是复制了FLASH的控件,其他操作由OFFICE自动完成了。
A、我们都知道,在EXCEL里,工作簿里面有N个(默认3个)工作表,而我们要的FLASH在某个工作表里面,所以我们先遍历book这个工作簿的Sheets集合,而后遍历每个Sheet的Shapes集合,从而达到遍历Shape的目的。
For i As Integer = 1 To book.Sheets.Count
            For j As Integer = 1 To book.Sheets(i).Shapes.count
                  ‘这里进行识别
            Next
Next
B、当得到Shape引用之后,我们就要识别它是否包含了FLASH的OLE内容。这个内容如何识别呢,我们知道OLE对象都有一个OLEFormat属性,它包含了OLE信息,其中ProgID属性是一个很有用的字符串,包括了OLE对象的类型,我们使用这个属性来识别:
                    If InStr(1, book.Sheets(i).Shapes(j).OLEFormat.ProgID, "ShockwaveFlash.ShockwaveFlash", vbTextCompare) = 1 Then
                        ’这里执行复制代码
                    End If
C、当我们得到了含有FLASH OLE的Shape对象引用之后,就可以复制它,在不同的OFFICE工具中,复制方法可能有些差异,但在EXCEL中我们的对象是Shape,它支持COPY方法,于是我们直接复制:
                        '是FLASH内嵌文件,则复制到剪贴板
                        book.Sheets(i).Shapes(j).copy()
D、将处理权交给剪贴板处理函数:
                        Clipboard2File(book.Name, i, j)
这个函数有三个参数:第一个是处理的文件名,第2、3个是我们遍历时用到的数据,其实这三个参数都是为了命名最终生成的文件而传入的,如果有必要,你可以把这个保存文件功能分离出来——也许这样更好,但是我没有这样做,理由就是……我懒

3、剪贴板处理:
就是我们上面的Clipboard2File函数了,我把它放在一个类(Clipboard2FileClass)里面,这个类仅有一个共享成员:我们的处理函数。
这里,我们使用的是Clipboard对象来读取剪贴板数据:
Dim iData As IDataObject = Clipboard.GetDataObject
这都是大家所熟知的东东了,用它就可以读回来我们要的内容,但是内容格式是什么呢?当然是“内嵌对象”了,呵呵
Dim ms As IO.MemoryStream = iData.GetData("Embedded Object")
于是我们就得到一个含有SWF文件内容的流——它是我们复制到内存中全部数据的一部分,也正是我们关心的SWF文件所在部分。到这里,有一种即将大功告成的希望了吧?也许没什么好高兴的,我们一共才写了几十行代码?
接下来处理这个流,如何提取SWF文件是当务之急,如果我们熟知SWF文件的结构该有多好……(……)(*(——&*%……¥%……¥)(()——(
确实,已经有同志付出了很多努力,给了我们一个母语版的SWF文件结构,对此表示敬意,对原作者表示感谢!
http://bbs.zhujiangroad.com/html/2008/6/250234.html
上面的地址,就是了~~~~~我们要用的信息就是前8字节:
1
2     FWS,CWS
3
4     版本
5
6     文件大小
7
8
OK,开始找文件头吧!这个内存流查找我还真不会,转化成数组,而后遍历
Dim bs As Byte() = ms.ToArray()                                 '将原始流转化为数组以对SWF文件头进行搜索
        Dim point As Integer                                            '文件头的位置
        For index As Integer = 0 To bs.Length - 3
            If bs(index) = CByte(&H46) OrElse bs(index) = CByte(&H43) Then  '有两种情况,可能是SWF,也可能是SWC,视FLASH生成文件时是否压缩
                If bs(index + 1) = CByte(&H57) AndAlso bs(index + 2) = CByte(&H53) Then
                    point = index
                    Exit For
                End If
            End If
        Next
这样,我们的point里面保存的就是SWF文件的开始位置了~~再得到文件长度,就可以把数组写入一个新流,而后保存
        Dim filesize As Integer = System.BitConverter.ToInt32(bs, point + 4)
        Dim by As New IO.MemoryStream(bs, point, filesize)
此时,by流中就是我们的SWF文件,保存它!
Dim filename As String = My.Application.Info.DirectoryPath & "\SWFFile\" & name & "-" & i & "-" & j & ".swf"
        If Not My.Computer.FileSystem.DirectoryExists(My.Application.Info.DirectoryPath & "\SWFFile\") Then My.Computer.FileSystem.CreateDirectory(My.Application.Info.DirectoryPath & "\SWFFile\")
        If My.Computer.FileSystem.FileExists(filename) Then My.Computer.FileSystem.DeleteFile(filename)
        '创建一个流以保存内存流到磁盘
        Dim dumpFile As IO.FileStream = New IO.FileStream(filename, IO.FileMode.OpenOrCreate, IO.FileAccess.ReadWrite)
        '保存内存流
        by.WriteTo(dumpFile)
上面的过程进行了文件夹和文件是否存在等判断和操作,以保证程序的“健壮”——不能因为一个文件操作搞得崩溃了啊。。。多丢人,呵呵,最后擦擦屁屁:
        '退出用过的流
        dumpFile.Close()
        ms.Close()
        by.Close()
        '清除剪贴板
        My.Computer.Clipboard.Clear()
好了,至此我们的EXCEL中提取SWF的工作告一段落,你可以测试你的代码了……感觉还不错吧?连注释都算进去,不到百行,解决了这个问题。。。
下面是一个测试文件和写好的主程序。。但使用时有一些限制,如果仔细阅读了上文,相信你已经知道怎么做~~~~

/Files/zcsor/提取SWF工具测试文件.xls

/Files/zcsor/复制OFFICE内嵌的SWF.7z


最后的最后,我们来讨论一下,这个代码存在的问题~~~适应性,为了让更多的OFFICE版本被我们支持,你可以进行以下工作~~~(当然我没做,懒啊)
0、复制一份解决方案目录,打开这个复制品
1、用鼠标指着每个OFFICE常量,它怕怕了就把实际数值告诉你,用数值替换这些常量
2、将APP和BOOK声明为OBJCET,并改用CreateObject 方法创建APP对象
3、在引用页扫描未使用引用,并删除它们
OK,你的更通用的版本诞生了~~~~可回到IDE修改代码时就没有那么多提示喽~~~~~~呵呵呵。。。并不是我们不知道怎么做更好怎么才能做到更好,是吧?

出处:https://www.cnblogs.com/zcsor/archive/2009/10/10/1580143.html


相关教程