• 项目说明

我使用电脑录制视频教程的时候,会展示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个小时的视频教程来更详细的讲解代码,视频都是免费的,可以访问我推送的这条公众号消息中的其他视频。也可以访问我的哔哩哔哩、头条、微博等平台中同步发布的账号中的视频,账号名都是“杨中科”。

点击阅读原文访问开源项目

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

  1. 内嵌WEB服务器加载原理

    内嵌WEB服务器加载原理 理解里面的tomcat是如何启动的 Startup.bat Server.start() 1,概述 我们在使用springboot项目的时候并没有使用外部的tomcat,那么 ...

  2. 手机屏幕提词器软件哪个好用?快来看看这几个手机提词器

    你们在刷视频的时候是不是会看到一些主播十分流畅地播报着视频的内容,没有出现卡顿和忘词的情况.其实很简单,只需要一个手机屏幕提词器即可流利的播报视频的内容了.那你们知道手机屏幕提词器软件有哪些吗?别急, ...

  3. IDRLnet: 基于内嵌物理知识神经网络的开源求解框架

    " 点击蓝字 / 关注我们 " 编者按 为解决飞行器设计优化过程中物理场快速仿真问题和运行监测阶段物理场精确反演问题,国防科技创新研究院无人系统技术研究中心智能设计与鲁棒学习团队推 ...

  4. 三维视频融合 开放源代码 混合模式 内嵌web容器 c++ js 混合开发 时空克隆引擎 数字孪生 点卯 系列 魔镜系列

    元宇宙的兴起,让以三维视频融合与三维投影融合为核心.以倾斜摄影和三维地图构筑的CIM作为托底的时空克隆引擎,成为时代的主流技术,以此打造了混合架构的魔镜平台 济南用魔镜打造元宇宙城市,难道是真的? 开 ...

  5. 基于Linux的web的中期报告,基于Linux的Web服务器设计论文中期检查.doc

    附件3: 长沙师范学院 届毕业论文(设计)课题任务书 课题题目基于Linux的Web服务器设计指导教师李列文职 称副教授学生姓名叶润凯系(部)/专业信工系/计应学 号2014541930121课题主要 ...

  6. 【转载】设置端口映射或DMZ主机---将内网web服务器映射入公网

    设置端口映射或DMZ主机---将内网web服务器映射入公网 原链接 https://blog.csdn.net/qq_31739317/article/details/75008375 总的来说,原理 ...

  7. 浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包

    浅谈:Spring Boot原理分析(更多细节解释在代码注释中) 通过@EnableAutoConfiguration注解加载Springboot内置的自动初始化类(加载什么类是配置在spring.f ...

  8. linux对web后端重要吗,基于Linux的Web服务器性能测试

    摘要:Linux作为一种免费的开源操作系统,正越来越受到人们的重视.随着稳定的Linux2.4内核发布日期的临近和IntelIA-64构架的推出,Linux在服务器操作系统市场所占的份额会继续扩大,那 ...

  9. goahead内嵌web——用户登录

    goahead设备内嵌web--环境搭建 基于前一章节环境搭建的基础上,goahead用户登录操作流程. 在web资源目录下创建一个用户登录的HTML文件,login.html文件代码内容如下 < ...

最新文章

  1. zookeeper伪分布式集群搭建
  2. Redis学习笔记之二 :在Java项目中使用Redis
  3. Java 自动转换和强制转换
  4. Java中9大内置基本数据类型Class实例和数组的Class实例
  5. u盘怎么重装系统win11教程
  6. vue中使用kindeditor编辑器_vue中使用kindeditor富文本编辑器
  7. 01数组寻找通路c语言,迷宫算法 之 迷宫生成和迷宫寻路
  8. fake-useragent User Agent 伪装
  9. LaTex中让页码从正文开始编号
  10. python wx包_今天玩点啥:python真香系列之利用wxpy包写一个微信消息自动回复插件...
  11. 浅说ksm的适用范围
  12. 红旗桌面4.0正式版最新使用方法和问题解答100例
  13. Linux命令之复制文件或目录cp
  14. 新西兰计算机科学专业方向,2020年新西兰计算机科学专业哪个大学好
  15. Java通过JFreeChart实现(饼图、柱状图、层叠柱状图、折线图、散点图、雷达图、环形图、仪表盘图、XY图)生成图片和下载
  16. jquery语法三ajax+echarts插件的使用
  17. HDU 6333 Problem B. Harvest of Apples(莫队离线)
  18. linux函数表,libnet 函数列表
  19. Android图片选择器 图片裁剪
  20. 如何清除cookies?

热门文章

  1. 奇迹暖暖服务器不稳定,闪耀暖暖用土豆当服务器?开服仅半小时就崩溃,无数玩家疯狂吐槽...
  2. python画枫叶_python-文件的操作
  3. Sql Server设置用户只能查看并访问特定数据库
  4. VMware Tools安装和卸载
  5. 上传jar包到nexus私服
  6. 将字符串分割为指定长度的子字符串
  7. Git中的日常使用 码云
  8. 原型继承+原型链 + 对象继承发展
  9. 基于visual Studio2013解决C语言竞赛题之0710排序函数
  10. System.getProperty()参数