打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
.NET5 开发手机提词应用,基于内嵌Web服务器及PowerPoint自动化

今天

以下文章来源于杨中科 ,作者杨中科

  • 项目说明

我使用电脑录制视频教程的时候,会展示PPT给观众,同时也有一些提示性的文字给我自己看。这就类似于很多电视节目录制现场的“提词器”。

节目录制现场的提词器

       在PC环境下,PowerPoint也具有提词器功能,在编辑PPT的时候,把每一页的备注中写上提示词即可。投影到屏幕上的给观众看的画面没有提示词,而演讲者的电脑屏幕的画面中有提示词。但是这要求使用投影仪或者使用双屏幕。而我的视频录制环境是我和观众是看的同一块屏幕,因此无法使用PowerPoint的提词功能。所以我只能自己开发一个应用。

       既然我和观众是看的同一块屏幕,如果想达到“观众看不到提示词,而我能看到”的效果,就只能把提示词展示到额外的显示设备上。我们每个人都有智能手机,因此我就想到了把智能手机做为显示提示词的设备。基于这个想法,我开发出了一个桌面应用,这个应用提供了一个内嵌的Web服务器,提供了“获取当前PPT页面备注文字”以及“翻页”等功能的接口,并且提供了一个调用这些接口的网页;这样,只要在手机上访问这个网页,就可以通过手机来获取提示词,也可以通过手机来切换PPT的翻页。下图是我使用这个提词应用实际工作的场景:

我的提词器实际工作场景

       这个应用使用.NET 5/.NET Core开发,但是思路是不局限于语言的,其他编程语言的开发者也可以使用你习惯的语言来开发。

我的应用主要使用了两个技术,一个是在WinForm程序中内嵌Web服务器,另一个就是通过代码控制PowerPoint文档。我下面将对它们分别做讲解。

  • .NET 内嵌Web服务器技术

.NET中可以使用Kestrel实现内嵌Web服务器,而Kestrel就是ASP.NET Core项目默认的Web服务器。由于Kestrel只是一个NuGet包而已,因此可以把它装到任何.NET项目上,比如控制台、WinForm、WPF、Xamarin等。其实所谓的ASP.NETCore项目本质上也只是一个装了Kestrel等相关包的控制台程序而已。

这里演示在WinForm项目中的用法,其他类型项目操作步骤都差不多:

1、首先创建一个WinForm项目,然后在项目根目录下创建名字为wwwroot的文件夹,这个文件夹用来放html、js、css等静态文件。

2、在项目的csproj文件中增加如下配置:




<None Update="wwwroot\**">       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></None>

这段配置的作用是:项目构建的时候,会把wwwroot目录下所有的内容都复制到输出目录下。

3、在wwwroot目录下创建index.html文件。

4、通过Nuget安装:Microsoft.AspNetCore.Owin


Install-Package Microsoft.AspNetCore.Owin

5、在主窗口中声明


private IWebHost host;

在窗口的构造函数中添加如下内容:







host = new WebHostBuilder()  .UseKestrel()  .UseUrls("http://*:80")  .Configure(Configure)  .Build();host.RunAsync();

其中"http://*:80" 表示网站监听所有网卡(这样就可以通过其他设备访问内嵌的网站了),并且通过80端口提供服务。要确保计算机中的防火墙中开启了对应端口的访问权限。

在需要关闭服务器或者窗口关闭的时候执行如下代码,否则程序不会正常退出:



host.StopAsync();host.WaitForShutdown();

然后声明如下方法:





















public void Configure(IApplicationBuilderapp){       app.UseDefaultFiles();       app.UseStaticFiles();       app.Run(async(context) =>       {              varrequest = context.Request;              varresponse = context.Response;              stringpath = request.Path.Value;              if(path == "/report")              {                     response.StatusCode= 200;                     awaitresponse.WriteAsync("OK");              }              else              {                     response.StatusCode= 404;              }       });}

其中app.UseDefaultFiles()表示启用对于index.html等默认文档的支持;app.UseStaticFiles()表示把wwwroot提供为静态文件夹。app.Run()中的代码意思为:如果用户访问了/report这个路径,则输出OK,否则就响应码为404。

  • 代码控制PowerPoint文档

代码需要实现读取PowerPoint页面的备注文字以及翻页等功能,这需要使用Office Automation技术,也就是通过代码调用Office的COM接口,当前前提条件就是计算机上必须安装PowerPoint软件。

微软官方推荐的在.NET中访问Office的方法就是在Visual Studio中通过COM引用生成Office的Interop程序集,也就是所谓的“Early Binding”。这种方式的优点就是一切对象都是强类型的,所以代码编写比较方便。而缺点就是和特定Office版本绑定,必须注意开发的时候的Office绑定,必须用尽可能低的版本的Office进行开发。不知道是我本地环境的原因还是.NET 5对于这种方式支持不成熟,我在.NET 5项目通过COM引用方式使用的时候,一直出现“MsoTriState在未被引用的程序集中定义。必须添加对程序集office的引用”的编译错误,如下图:

Figure3编译错误

       也可以使用Late Binding方式操作,也就是通过dynamic这种方式进行COM接口的访问。这种方式的优点是不依赖于特性Office版本,缺点就是全都是弱类型调用,因此需要查询文档,开发效率比较低。

       我发现一个开源项目NetOffice(https://netoffice.io/),它仍然是强类型的,但是不依赖于特定的Office版本。最大的遗憾就是它目前的.NET Standard版本的开发正在进行,所以目前的版本仍然不支持.NET Core。

       经过比较,我只能选择Late Binding这种方式来进行了。

由于Com的复杂性,特别是“引用计数”这种比较古老的资源管理技术的复杂性,导致晚绑定的对象回收要十分注意,否则会导致Office无法退出。我封装了一个简单的库Zack.ComObjectHelpers,可以简化Com对象资源的回收。

这个库的Nuget安装命令是:


Install-PackageZack.ComObjectHelpers

       然后使用其中的COMReferenceTracker类进行COM引用的管理:打开文档创建一个COMReferenceTracker对象,在每一步可能返回Com对象的地方,都用T方法进行资源回收,操作完成后调用Dispose。

       如下的代码就是打开一个PPT文档,然后进入演示模式的代码:























private dynamic presentation;private COMReferenceTracker comRefTracker =new COMReferenceTracker(); private void Form1_Closed(object sender,EventArgs e){       this.comRefTracker.Dispose();} private dynamic T(dynamic comObj){       returnthis.comRefTracker.T(comObj);} private void MiOpen_Click(object sender,System.EventArgs e){       stringfilename = "d:/1.pptx";       dynamicpptApp = T(PowerPointHelper.CreatePowerPointApplication());       pptApp.Visible= true;       dynamicpresentations = T(pptApp.Presentations);       this.presentation= T(presentations.Open(filename));       T(this.presentation.SlideShowSettings).Run();}

       C#操作Office Automation的文档、资料比较少,不过由于COM对象本身是跨语言的,而VBA操作Office Automation的资料非常多,因此完全参考VBA操作的资料即可。比如下面的代码就是我仿照网上搜索“VBA 读取PowerPoint备注”的代码改造成C#语法而成的“读取当前PowerPoint页面的备注”代码:






















dynamic notesPage =T(T(T(T(presentation.SlideShowWindow).View).Slide).NotesPage);notesText = GetInnerText(notesPage); private string GetInnerText(dynamic part){       StringBuildersb = new StringBuilder();       dynamicshapes = T(T(part).Shapes);       intshapesCount = shapes.Count;       for(int i = 0; i < shapesCount; i++)       {              dynamicshape = T(shapes[i + 1]);              vartextFrame = T(shape.TextFrame);              if(textFrame.HasText == -1)//MsoTriState.msoTrue==-1              {                     stringtext = T(textFrame.TextRange).Text;                     sb.AppendLine(text);              }              sb.AppendLine();       }       returnsb.ToString();}
  • 手机提词器应用代码

上面已经把整个应用的最核心代码介绍了,想了解整个项目的代码请访问项目的github页面https://github.com/yangzhongke/PhoneAsPrompter

  • 手机控制电脑中视频播放

用“应用中内嵌Web服务器”技术,我还实现了一个“手机控制电脑中视频播放”的应用,可以通过手机控制电脑中的视频播放器进行暂停、播放、调节音量、快进快退等功能,甚至可以进一步开发完成切换直播电视频道等功能。代码也放到了上面github页面的VideoRemoteController项目中。

  • 视频教程

    除了这篇文章,我还录制了大约2个小时的视频教程来更详细的讲解代码,视频都是免费的,可以访问我推送的这条公众号消息中的其他视频。也可以访问我的哔哩哔哩、头条、微博等平台中同步发布的账号中的视频,账号名都是“杨中科”。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
PPT声音处理剖析
把声音文件嵌入到powerpoint中自动播放的几种办法
快速在PPT里插入多张图片
学习office办公软件后的心得体会
VBA还能活多久?——完美Excel第169周小结
解决在PowerPoint 2007/2010中打字慢的问题
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服