使用C#實(shí)現(xiàn)一個(gè)PPT遙控器
說明
本項(xiàng)目參考了 https://github.com/yangzhongke/PhoneAsPrompter 項(xiàng)目來完成實(shí)現(xiàn),并對(duì)其進(jìn)行了一些修改完善。
完整代碼可以到 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
另外,由于程序啟動(dòng)后會(huì)創(chuàng)建一個(gè)WEB服務(wù)器,用來顯示PPT的操控界面,所以某些安全軟件可能會(huì)報(bào)毒。但是程序本身是沒有問題的。
截圖
具體實(shí)現(xiàn)
通過在Win Form項(xiàng)目中內(nèi)嵌一個(gè)Kestrel Web服務(wù)器,我們就可以通過瀏覽器向web服務(wù)器發(fā)送請求來接收遠(yuǎn)程操作指令。之后通過Late Binding的方式去操作PPT。
1、在 Win Form項(xiàng)目中內(nèi)嵌HTTP服務(wù)器
在Form窗口啟動(dòng)時(shí),我們新建一個(gè)Kestrel服務(wù)器
this.webHost = new WebHostBuilder() .UseKestrel() .Configure(ConfigureWebApp) .UseUrls("http://*:" + port) .Build(); // 異步運(yùn)行服務(wù)器 this.webHost.RunAsync();
然后對(duì)其進(jìn)行配置
private void ConfigureWebApp(IApplicationBuilder app) { app.UseDefaultFiles(); app.UseStaticFiles(); app.Run(async (context) => { // 處理非靜態(tài)請求 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編程,我們需要注意內(nèi)存回收與釋放,所以需要用到COMReferenceTracker
類進(jìn)行應(yīng)用管理。
每一步用到COM的地方,都要用T方法進(jìn)行資源回收。
private dynamic T(dynamic comObj) { return this.comReference.T(comObj); }
以下操作使用dynamic
進(jìn)行操作,所有操作需要去查詢VBA文檔了解具體用法,以下僅演示部分操作
打開一個(gè)PPT的操作實(shí)現(xiàn)
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(); // 創(chuàng)建 PPT 對(duì)象 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上一個(gè)動(dòng)畫操作實(shí)現(xiàn)
T(T(presentation.SlideShowWindow).View).Previous();
下一步,與上一個(gè)操作類似,只需更換Previous()
方法為Next()
即可。
獲取注釋
首先我們需要一個(gè)方法去解析注釋
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);
我們就可以獲取具體每頁的注釋信息。
完善服務(wù)器
了解了以上的PPT操作之后,我們就需要去完善我們的Web服務(wù)器端配置。
用戶訪問相應(yīng)的地址,然后去執(zhí)行上面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"); }
完成前端
通過輪詢的方式,不斷的向服務(wù)端發(fā)送請求,獲取最新的消息,這樣我們就可以實(shí)現(xiàn)通過瀏覽器去操作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>
到此這篇關(guān)于使用C#實(shí)現(xiàn)一個(gè)PPT遙控器的文章就介紹到這了,更多相關(guān)C#實(shí)現(xiàn)PPT遙控器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#實(shí)現(xiàn)排列組合算法完整實(shí)例
這篇文章主要介紹了C#實(shí)現(xiàn)排列組合算法的完整實(shí)例,文中實(shí)例主要展示了排列循環(huán)方法和排列堆棧方法,需要的朋友可以參考下2014-09-09C#實(shí)現(xiàn)用戶自定義控件中嵌入自己的圖標(biāo)
這篇文章主要介紹了C#實(shí)現(xiàn)用戶自定義控件中嵌入自己的圖標(biāo),較為詳細(xì)的分析了C#實(shí)現(xiàn)自定義控件中嵌入圖標(biāo)的具體步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-03-03C#通過標(biāo)簽軟件Bartender的ZPL命令打印條碼
這篇文章介紹了C#通過標(biāo)簽軟件Bartender的ZPL命令打印條碼,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01C#與C++?dll之間傳遞字符串string?wchar_t*?char*?IntPtr問題
C#與C++?dll之間傳遞字符串string?wchar_t*?char*?IntPtr問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11