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

 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/302428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Linux程序设计][调试][ElectricFence]

gcc –o test test.c –lefence 提前发现动态内存的错误 转载于:https://blog.51cto.com/honglei/934379

薄如冈本,37°恒温发热超薄保暖内衣,既要风度也要温度

问君能有几多愁恰似没穿秋裤遇寒流俗话说的好你在北方的暖气里穿着短袖我在南方的艳阳里瑟瑟发抖为了暖和一点大家都穿得里三层外三层的什么大衣棉袄厚外套都搬出来了但谁都不愿意在冬天穿的像个200斤的胖子好吗&#xff01;&#xff1f;可是为了风度连狗命都不要了吗&#xff…

Blazor Day

关注我们Blazor 是一个 Web UI 框架&#xff0c;Blazor 旨在简化快速的单页面 .Net 浏览器应用的构建过程&#xff0c;它虽然使用了诸如 CSS 和 HTML 之类的 Web 技术&#xff0c;但它使用 C&#xff03;语言和 Razor 语法代替 JavaScript 来构建可组合的 Web UI 。通过提供用于…

学会了Python之后,我的职业生涯突飞猛进

全世界只有3.14 % 的人关注了数据与算法之美身为职场人&#xff0c;收集上万条表格数据做商业分析&#xff0c;裁剪上千张图片&#xff0c;发送数百封邮件...这些都是经常会遇到的场景。我一直期待能有个工具解放我&#xff0c;直到我遇到了Python。Python的魅力很多小伙伴入坑…

Android网络编程

2019独角兽企业重金招聘Python工程师标准>>> Android平台有三种网络接口可以使用&#xff0c;他们分别是&#xff1a;java.net.*(标准Java接口)、Org.apache接口和Android.net.*(Android网络接口)。下面分别介绍这些接口的功能和作用。 1.标准Java接口 java.net.*提…

mac 启动mysql多实例_实践:mysql单机多实例部署(mac)

背景&#xff1a;在自己电脑搭建或测试分布式服务框架时&#xff0c;经常会用多个数据库实例模拟多个环境的情况&#xff0c;因此我把搭建多实例mysql的过程记录下来&#xff0c;方便互相学习和沟通。1.搭建环境1) mac 电脑&#xff0c;版本 10.15.62) mysql版本 8.0.202.搭建…

毫无疑问的是.NET 在信创常用软件适配清单之中

2020年8月份写了一篇文章《.NET Core也是国产化信息系统开发的重要选项》&#xff0c; 这又过去了大半年了&#xff0c;在信创领域发生了很大的变化&#xff0c;今天写这篇文章主要是想从信创常用软件适配清单 看一看.NET 在信创里面的情况。信创常用软件适配清单 是由中国电子…

学习Python编程的19个资源

全世界只有3.14 % 的人关注了数据与算法之美用Python编写代码一点都不难&#xff0c;事实上它一直被赞誉为最容易学的编程语言。如果你准备学习web开发&#xff0c; Python是一个不错的开始&#xff0c;甚至想做游戏的话&#xff0c;用Python来开发游戏的资源也有很多。这是快速…

读《精益商业思维》

五一假期读了程浩的《精益商业思维》&#xff0c;程浩是迅雷的联合创始人之一&#xff0c;现在是职业投资人&#xff0c; 全篇从创业者的角度&#xff0c;也从投资人的角度解析了创业的方法论。书中有大量的互联网公司的案例&#xff0c;都是我们耳熟能详的一些互联网企业&…

mysql中两根竖线什么意思_五线谱中两根竖线是什么意思?

五线谱中的竖线叫做终止线&#xff0c;写在乐曲结束处的右边一条略粗的双纵线。音乐总是由强拍和弱拍交替进行的&#xff0c;这种交替不能杂乱无章、任意安排&#xff0c;而是按照一定的规律构成最小的节拍组织一小节&#xff0c;然后以此为基础循环往复。比如&#xff0c;当两…

三张图读懂机器学习 :基本概念、五大流派与九种常见算法

全世界只有3.14 % 的人关注了数据与算法之美机器学习正在进步&#xff0c;我们似乎正在不断接近我们心中的人工智能目标。语音识别、图像检测、机器翻译、风格迁移等技术已经在我们的实际生活中开始得到了应用&#xff0c;但机器学习的发展仍还在继续&#xff0c;甚至被认为有可…

go 切片取最后一个元素_深挖 Go 之 forrange 排坑指南

今年做个 Dig101 系列&#xff0c;挖一挖技术背后的故事。Dig101: dig more, simplified more and know moregolang 常用的遍历方式&#xff0c;有两种&#xff1a;for 和 for-range。而 for-range 使用中有些坑常会遇到&#xff0c;今天我们一起来捋一捋。文章目录0x01 遍历取…

SqlServer SqlParser 介绍及基本使用

SqlServer SqlParser 介绍及使用示例Intro最近发现在 Nuget 上有一个 SqlServer 的 SqlParser&#xff0c;利用 SqlParser 我们做到可以解析 SQL 的每一部分 &#xff0c;nuget 包是公开的&#xff0c;可以拿来即用&#xff0c;只是缺少使用示例&#xff0c;很多功能需要自己去…

如何使用TensorFlow玩转深度学习?

自 2015 年 11 月 9 号发布之后&#xff0c;TensorFlow 逐渐成为人工智能领域最广泛运用的深度学习框架。那么TensorFlow框架到底是什么&#xff1f;TensorFlow 是一个大规模机器学习的开源框架&#xff0c;提供了多种深度神经网络的支持。不仅 Google 在自己的产品线使用 Tens…

大学,我是怎么边学编程边赚钱的?

我是如何在大学时就靠编程赚钱的&#xff1f;大家好&#xff0c;我是鱼皮&#xff0c;前段时间看到一位朋友的问题&#xff1a;穷极客一枚&#xff0c;正值大学&#xff0c;很想自己解决生活问题&#xff0c;不再向父母要钱。计算机相关专业&#xff0c;喜欢编程&#xff0c;觉…

独占设备的分配与回收_灵魂拷问:Java对象的内存分配过程是如何保证线程安全的?...

点击上方“linkoffer”&#xff0c;选择关注公众号高薪职位第一时间送达作者 l HollisJVM内存结构&#xff0c;是很重要的知识&#xff0c;相信每一个静心准备过面试的程序员都可以清楚的把堆、栈、方法区等介绍的比较清楚。上图&#xff0c;是一张在作者根据《Java虚拟机规范(…

Wtm Blazor来了!

快点关注我们吧BlazorBlazor从诞生到现在也有一段时间了&#xff0c;之前一直在观望&#xff0c;从dotnet5中Blazor的进步以及即将到来的dotnet6中的规划来看&#xff0c;Blazor的前途还是光明的&#xff0c;所以WtmBlazor来了&#xff01;Blazor的优势后台代码的高复用率。不论…

[Netty实践] 简单WebSocket服务实现

目录 一、介绍 二、依赖导入 三、基础类准备 四、Handler实现 五、WebSocketChannelInitializer实现 六、WebSocketServer实现 七、前端实现 八、测试 九、参考链接 一、介绍 关于WebSocket此处不进行过多介绍&#xff0c;本章主要着重通过Netty实现WebSocket通信服务…

这个爱喝酒的酒鬼可真是让人操碎了心

全世界只有3.14 % 的人关注了数据与算法之美最近又有一道数学难题重现江湖&#xff0c;在数学的江湖上掀起了腥风血雨。为了这道题&#xff0c;武林中也衍生出了三个门派&#xff01;分别有75%派&#xff0c;90%派&#xff0c;50%派。打完这么多派字&#xff0c;怎么莫名有点饿…

这几家5月还在急招.NET,都是30k以上!

最近常看到鼓吹财务自由的文章&#xff0c;甚至将5月18号(谐音&#xff1a;我要发)都演变成了财务自由日&#xff0c;号称通过理财快速达到财务自由... 荒谬&#xff01;财务自由本身就是伪命题&#xff0c;更不提啥小白理财就变身财务自由了&#xff0c;完全收智商税&#xff…