说明
本项目参考了 https://github.com/yangzhongke/phoneasprompter 项目来完成实现,并对其进行了一些修改完善。
完整代码可以到 https://github.com/puzhiweizuishuai/ppt-remote-control 与 https://gitee.com/puzhiweizuishuai/ppt-remote-control 查看。
软件下载地址: https://gitee.com/puzhiweizuishuai/ppt-remote-control/releases/v1.0.0
另外,由于程序启动后会创建一个web服务器,用来显示ppt的操控界面,所以某些安全软件可能会报毒。但是程序本身是没有问题的。
截图
具体实现
通过在win form项目中内嵌一个kestrel web服务器,我们就可以通过浏览器向web服务器发送请求来接收远程操作指令。之后通过late binding的方式去操作ppt。
1、在 win form项目中内嵌http服务器
在form窗口启动时,我们新建一个kestrel服务器
this.webhost = new webhostbuilder() .usekestrel() .configure(configurewebapp) .useurls("http://*:" + port) .build(); // 异步运行服务器 this.webhost.runasync();
然后对其进行配置
private void configurewebapp(iapplicationbuilder app) { app.usedefaultfiles(); app.usestaticfiles(); app.run(async (context) => { // 处理非静态请求 var request = context.request; var response = context.response; string path = request.path.value; response.contenttype = "application/json; charset=utf-8"; bool hasrun = true; if (path == "/report") { string value = request.query["value"]; this.begininvoke(new action(() => { this.pagelabel.text = value; })); response.statuscode = 200; await response.writeasync("ok"); } else { response.statuscode = 404; } }); }
操作ppt
首先,由于涉及到了com编程,我们需要注意内存回收与释放,所以需要用到comreferencetracker
类进行应用管理。
每一步用到com的地方,都要用t方法进行资源回收。
private dynamic t(dynamic comobj) { return this.comreference.t(comobj); }
以下操作使用dynamic
进行操作,所有操作需要去查询vba文档了解具体用法,以下仅演示部分操作
打开一个ppt的操作实现
private void button1_click(object sender, eventargs e) { // 文件选择框 openfiledialog.filter = "ppt文件|*.ppt;*.pptx;*.pptm"; if (openfiledialog.showdialog() != dialogresult.ok) { return; } string filename = openfiledialog.filename; this.clearcomrefs(); // 创建 ppt 对象 dynamic pptapp = t(powerpointhelper.createpowerpointapplication()); // 显示 ppt pptapp.visible = true; dynamic presentations = t(pptapp.presentations); // 打开 ppt this.presentation = t(presentations.open(filename)); // 全屏显示 t(this.presentation.slideshowsettings).run(); }
ppt上一个动画操作实现
t(t(presentation.slideshowwindow).view).previous();
下一步,与上一个操作类似,只需更换previous()
方法为next()
即可。
获取注释
首先我们需要一个方法去解析注释
private string getinnertext(dynamic part) { stringbuilder sb = new stringbuilder(); dynamic shapes = t(t(part).shapes); int shapescount = shapes.count; for (int i = 0; i < shapescount; i++) { dynamic shape = t(shapes[i + 1]); var textframe = t(shape.textframe); // msotristate.msotrue==-1 if (textframe.hastext == -1) { string text = t(textframe.textrange).text; sb.appendline(text); } sb.appendline(); } return sb.tostring(); }
之后通过
dynamic notespage = t(t(t(t(presentation.slideshowwindow).view).slide).notespage); string notestext = getinnertext(notespage);
我们就可以获取具体每页的注释信息。
完善服务器
了解了以上的ppt操作之后,我们就需要去完善我们的web服务器端配置。
用户访问相应的地址,然后去执行上面ppt操作部分的代码即可。
else if (path == "/getnote") { string notestext = null; this.invoke(new action(() => { if (this.presentation == null) { return; } try { dynamic notespage = t(t(t(t(presentation.slideshowwindow).view).slide).notespage); notestext = getinnertext(notespage); } catch (comexception ex) { notestext = ""; } })); await response.writeasync(notestext); } else if (path == "/next") { response.statuscode = 200; this.invoke(new action(() => { if (this.presentation == null) { return; } try { t(t(this.presentation.slideshowwindow).view).next(); hasrun = true; } catch (comexception e) { hasrun = false; } })); if (hasrun) { await response.writeasync("ok"); } else { await response.writeasync("no"); } } else if (path == "/previous") { response.statuscode = 200; this.invoke(new action(() => { if (this.presentation == null) { return; } try { t(t(this.presentation.slideshowwindow).view).previous(); hasrun = true; } catch (comexception e) { hasrun = false; } })); if (hasrun) { await response.writeasync("ok"); } else { await response.writeasync("no"); }
完成前端
通过轮询的方式,不断的向服务端发送请求,获取最新的消息,这样我们就可以实现通过浏览器去操作ppt了。
<!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8" /> <meta http-equiv="x-ua-compatible" content="ie=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="renderer" content="webkit" /> <title>操作你的ppt</title> <link rel="icon" href="/logo.ico" rel="external nofollow" > <style> div { font-size: 25px } </style> </head> <body> <div id="main" style="width:100vw;height:100vh;"> <p id="note"></p> </div> <script src="hammer.min.js"></script> <script> function httpget(url, cb) { fetch(url, { headers: { 'content-type': 'application/json; charset=utf-8' }, method: 'get' }).then(response => response.text()) .then(text => { cb(text) }) .catch(e => { return null }) } const note = document.queryselector("#note"); let hasrun = true let getnotes = setinterval(() => { httpget('/getnote', (text) => { note.innertext = text }) }, 500) function nextpage() { httpget('/next', (text) => { if (text == 'no') { clearinterval(getnotes) note.innertext = "幻灯片播放完毕!" hasrun = false } else { if (!hasrun) { getnotes = setinterval(() => { httpget('/getnote', (text) => { note.innertext = text }) }, 500) hasrun = true } } }) } function previouspage() { httpget('/previous', (text) => { if (text == 'no') { clearinterval(getnotes) note.innertext = "幻灯片播放完毕!" hasrun = false } else { if (!hasrun) { getnotes = setinterval(() => { httpget('/getnote', (text) => { note.innertext = text }) }, 500) hasrun = true } } }) } var hammer = new hammer(document.queryselector("#main")); hammer.on("swipeleft", function () { nextpage(); }); hammer.on("swiperight", function () { previouspage(); }); </script> </body> </html>
到此这篇关于使用c#实现一个ppt遥控器的文章就介绍到这了,更多相关c#实现ppt遥控器内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!