PowerPointファイルにC#で外から文字を埋め込むアプリのサンプルを作成

#概要
毎回同じような内容のPowerPointを作成するのが面倒なため
あらかじめテンプレートとなるPowerPointを作成しておき
テンプレートに設定したタグに設定内容を埋め込むアプリのサンプルを作成しました。

#使用方法
テンプレートとなるPowerPointに置換対象文字を設定
下記例では置換対象のShapeに「[replace_....]」置き換え対象の文字列を設定
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172093/9fe91452-5b02-c5f4-5eec-cdb6288edeb0.png">

置き換え文字列ペアを定義
左側に置き換え対象文字列、右側に置き換え後文字列を記述

```:
"replace_sample1","置き換えサンプル１"
"replace_sample2","置き換えサンプル２"
"replace_list_sample1","リスト内置き換えサンプル１"
"replace_list_sample2","リスト内置き換えサンプル２"
```

変換を実施すると、以下のように置き換えてくれます。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172093/b11756af-059d-eb13-1070-be7eee178792.png">

#アプリ生成手順

１．アプリダウンロード
以下からソースコードをダウンロードしVisual Studioでプロジェクトを開く
※Visual Studio 2019 .NET Framework C# で開発しています
https://github.com/ZumWalt22/PPTReplace

２．参照設定追加
プロジェクトの参照パスが通っていない場合、再設定
Microsoft.Office.Interop.PowerPoint
Microsoft.Office.Core

３．ビルド
Visual Studioからビルドを実行し、アプリを生成
「PPTAutoMakeTest.exe」が「bin」フォルダ配下に作成される

４．アプリの実行

１．テンプレートファイルを準備
文字埋め込み対象となる、PowerPointファイルを準備する
ビルド時に実行ファイルと同一フォルダに作成される「PowerpointReplaceSample.pptx」を参考に作成

２．変換規則の準備
ビルド時に実行ファイルと同一フォルダに作成される「temp.csv」ファイルに
左側に置き換え対象文字列、右側に置き換え後文字列を
ダブルクォーテーションで囲い、カンマ区切りで記述

設定例：

```temp.csv:
"replace_sample1","置き換えサンプル１"
"replace_sample2","置き換えサンプル２"
"replace_list_sample1","リスト内置き換えサンプル１"
"replace_list_sample2","リスト内置き換えサンプル２"
```

３．変換を実施
「PPTAutoMakeTest.exe」を実行し、変換アプリを起動する
「PPT File」ボタンを押下し、上記で１．作成したPowerPointファイルを指定
「Replace」ボタンを押下すると、変換処理が開始される
変換が完了すると、変換後PowerPointファイル（末尾が「_Replace」）が生成される

#アプリ処理概要
変換処理の主要ロジックのソースは以下の通りです
以下のみを参考にしても変換処理の作成は可能です

変換辞書「replaceKeyValDic」 に置換文字列情報を設定分追加

```PPTAutoMakeTest.cs:

//変換情報の辞書情報（再帰関数内で使用されるため面倒なのでGlobalで宣言）
Dictionary<String, String> replaceKeyValDic = new Dictionary<string, string>();

//置換文字列情報を設定分追加
replaceKeyValDic.Add("置き換え対象文字列","置き換え文字列");
```

以下のdoReplaceメソッドの引数にテンプレートとなるPowerPointファイルのバスと
置き換え後のPowerPointファイル名を渡し、実行する

```PPTAutoMakeTest.cs:

        /// <summary>
        /// 置き換え処理を実施
        /// </summary>
        /// <param name="pptFilePath">テンプレートPPTファイルパス</param>
        /// <param name="pptGenerateFilePath">生成PPT保存ファイルパス</param>
        private void doReplace(string pptFilePath,string pptGenerateFilePath)
        {
            List<string> notes = new List<string>();
            Microsoft.Office.Interop.PowerPoint.Application app = null;
            Microsoft.Office.Interop.PowerPoint.Presentation ppt = null;

            try
            {
                // PPTのインスタンス作成
                app = new Microsoft.Office.Interop.PowerPoint.Application();

                // PPTファイルオープン
                ppt = app.Presentations.Open(
                    pptFilePath,
                    Microsoft.Office.Core.MsoTriState.msoTrue,
                    Microsoft.Office.Core.MsoTriState.msoTrue,
                    Microsoft.Office.Core.MsoTriState.msoFalse
               );

                // スライドのインデックスは１から　順にループする
                for (int i = 1; i <= ppt.Slides.Count; i++)
                {
                    foreach (Microsoft.Office.Interop.PowerPoint.Shape shape in ppt.Slides[i].Shapes)
                    {
                        getShapeText(shape);
                    }
                }

                //生成PPTファイルの保存を実行
                ppt.SaveAs(pptGenerateFilePath,
                    PpSaveAsFileType.ppSaveAsDefault,
                    Microsoft.Office.Core.MsoTriState.msoFalse);
            }
            finally
            {
                // PPTファイルを閉じる
                if (ppt != null)
                {
                    ppt.Close();
                    ppt = null;
                }

                // PPTインスタンスを閉じる
                if (app != null)
                {
                    app.Quit();
                    app = null;
                }
            }
        }

        /// <summary>
        /// PPTオブジェクト内文字列を置き換え（再帰呼び出しでも使用）
        /// </summary>
        /// <param name="shape">PPTのShape</param>
        private void getShapeText(Microsoft.Office.Interop.PowerPoint.Shape shape)
        {
            if (shape.HasTextFrame == Microsoft.Office.Core.MsoTriState.msoTrue
                && shape.TextFrame.HasText == Microsoft.Office.Core.MsoTriState.msoTrue)
            {
                if (shape.TextFrame.TextRange.Text != "")
                {
                    //PPT内の文字列置き換えを実施
                    shape.TextFrame.TextRange.Text = replaceStr(shape.TextFrame.TextRange.Text);
                }
            }

            // 構造が入れ子になっている場合を考慮し、再帰検索を実施
            if (shape.Type == Microsoft.Office.Core.MsoShapeType.msoGroup)
            {
                foreach (Microsoft.Office.Interop.PowerPoint.Shape childShape in shape.GroupItems)
                {
                    //項目設定文字列を置き換え（再帰呼び出し）
                    getShapeText(childShape);
                }
            }

            //テーブル情報取得
            if (shape.Type == Microsoft.Office.Core.MsoShapeType.msoTable)
            {
                foreach (Row row in shape.Table.Rows)
                {
                    foreach (Cell cell in row.Cells)
                    {
                        getShapeTextForTable(cell.Shape);
                    }
                }
            }
        }

        /// <summary>
        /// テーブル用文字列置き換え
        /// </summary>
        /// <param name="shape">PPTのShape</param>
        private void getShapeTextForTable(Microsoft.Office.Interop.PowerPoint.Shape shape)
        {
            if (shape.HasTextFrame == Microsoft.Office.Core.MsoTriState.msoTrue
                && shape.TextFrame.HasText == Microsoft.Office.Core.MsoTriState.msoTrue)
            {
                if (shape.TextFrame.TextRange.Text != "")
                {
                    shape.TextFrame.TextRange.Text = replaceStr(shape.TextFrame.TextRange.Text);
                }
            }
        }

        /// <summary>
        /// 文字列置き換え
        /// </summary>
        /// <param name="targetStr">置き換え対象文字列</param>
        /// <returns>置き換え後文字列</returns>
        private String replaceStr(String targetStr)
        {
            foreach (string replaceKeyValKey in replaceKeyValDic.Keys)
            {
                //PPTテンプレートに「[置き換え対象文字列]」の書式で設定したものを変換
                targetStr = targetStr.Replace("[" + replaceKeyValKey + "]", replaceKeyValDic[replaceKeyValKey]);
            }

            return targetStr;
        }

```