努力したWiki

推敲の足りないメモ書き多数

ユーザ用ツール

サイト用ツール


documents:windows:windows-023

VOICEROID+EXをコマンドラインからしゃべらせる

2016/09/17
音声の保存に対応しました! だけどWindows10での確認しかできてない。

2016/09/14
自分の理解用に作成。色々な方が公開しているソフトウエアのソースを参考に、自分なりの理解をしつつ作ったもの。
デフォルトは VOICEROID+ 京町セイカEX です。

ダウンロード

VOICEROID+をコマンドラインからしゃべらせるコマンド Windows 10 Pro 64bit版 + .NET Framework 4.0環境でコンパイル。 .NET Framework 4.5.2とかでも動くと思う。Windows XPだと動作しないかも。

プログラムの説明

コマンドプロンプトから、テキストをVOICEROIDL/VOICEROID+EXに送り、音声再生/音声保存させるプログラム(コマンド)です。

使用に際しては、先に使いたいVOICEROID+を起動しておく必要があります。

なお、現時点で Windows10 64bit版での確認しかできていませんし、京町セイカ(SEIKA)、民安ともえ(TAMMY)、結月ゆかり(YUKARI)、東北ずん子(ZUNKO)、鷹の爪 吉田くん(YOSHIDA)、の5製品でしか確認が取れていません。

VOICEROID 起動方法(起動例) 備考
VOICEROID+ 京町セイカ EX echoseika.exe おはようございます。涼しい朝ですね。 動作確認した
VOICEROID+ 民安ともえ echoseika.exe -cv TAMMY おはようございます。涼しい朝ですね。 動作確認した
VOICEROID+ 結月ゆかり echoseika.exe -cv YUKARI おはようございます。涼しい朝ですね。 動作確認した
VOICEROID+ 東北ずん子 echoseika.exe -cv ZUNKO おはようございます。涼しい朝ですね。 動作確認した
VOICEROID+ 鷹の爪吉田くん echoseika.exe -cv YOSHIDA おはようございます。涼しい朝ですね。 動作確認した
VOICEROID+ 民安ともえ EX echoseika.exe -cv TAMMY_EX おはようございます。涼しい朝ですね。 製品を持ってないので試していない
VOICEROID+ 結月ゆかり EX echoseika.exe -cv YUKARI_EX おはようございます。涼しい朝ですね。 製品を持ってないので試していない
VOICEROID+ 東北ずん子 EX echoseika.exe -cv ZUNKO_EX おはようございます。涼しい朝ですね。 製品を持ってないので試していない
VOICEROID+ 琴葉 茜・葵 echoseika.exe -cv AKANE おはようございます。涼しい朝ですね。 製品を持ってないので試していない
echoseika.exe -cv AOI おはようございます。涼しい朝ですね。

音声再生

例えば VOICEROID+ 京町セイカ EX を起動してから、コマンドプロンプトを開き echoseika.exe を実行します。

H:\echosaika>echoseika おはようございます。涼しい朝ですね。

音声が再生されたと思います。

すでにVOICEROIDが音声再生中だった場合、プログラムは最大3分待ちます。

音声保存

-wav オプションを指定する事で音声データ(Waveファイル)を保存できます。

H:\echoseika>echoseika -wav goodmorning おはようございます。希望の朝です!

H:\echoseika>DIR GOOD*
 H:\echoseika のディレクトリ

2016/09/17  22:17                34 goodmorning.txt
2016/09/17  22:17           127,682 goodmorning.wav
               2 個のファイル             127,716 バイト
               0 個のディレクトリ  1,768,407,678,976 バイトの空き領域

H:\echoseika>

オプション -wav goodmorning を指定した結果、音声ファイル goodmorning.wav、発声したテキストが goodmorning.txt、に保存されます。

なお、ファイル上書きはサポートしておらず、既にファイルが存在する場合はエラーとなります。同じ名前で保存する場合は、面倒ですが必ずファイルを消してください。

使用するVOICEROIDの指定

例えば、VOICEROID+ 民安ともえを使う場合は -cv tammy オプションで指定します。

H:\echosaika>echoseika -cv tammy おはようございます。涼しい朝ですね。

ヘルプを内蔵したので -h オプションでVOICEROID指定方法を確認できます。

H:\echoseika>echoseika
no speech text.

H:\echoseika>echoseika -h
usage: echoseika [-cv voiceroid] [-wav wavfile] TalkText

-cv voiceroid   : use voiceroid name. default is SEIKA
       SEIKA      VOICEROID+ 京町セイカ EX
       TAMMY      VOICEROID+ 民安ともえ
       TAMMY_EX   VOICEROID+ 民安ともえ EX
       YUKARI     VOICEROID+ 結月ゆかり
       YUKARI_EX  VOICEROID+ 結月ゆかり EX
       ZUNKO      VOICEROID+ 東北ずん子
       ZUNKO_EX   VOICEROID+ 東北ずん子 EX
       AKANE      VOICEROID+ 琴葉茜
       AOI        VOICEROID+ 琴葉葵
       YOSHIDA    VOICEROID+ 鷹の爪 吉田くん
-wav wavefile   : save the voice data to wavefile.wav
TalkText        : send the "TalkText" to VOICEROID

H:\echoseika>

琴葉姉妹を使用する際には目的のキャラクターへ切り替えておく必要があります。

例えば、琴葉姉妹の姉(茜)が選択されている状態で

H:\echosaika>echoseika -cv aoi おはようございます。涼しい朝ですね。

を実行しても、VOICEROIDが見つからない、と言われて終了します。

茜ちゃんが出ている時に葵ちゃんを指定してもしゃべってはくれません。

技術的な話

  • 民安ともえ、鷹の爪吉田くん、の2製品については、テキストボックスの内容を消去する方法が思いつかないでいます。
    なので、この2製品を使う時は、テキストボックスに何も入力されていない初期状態が必要です。
  • 結月ゆかり、は編集メニューに「すべて選択(CTRL+A)」が追加されたので、メニューからCTRL+A,CTRL+Vでクリップボード経由でテキストを置き換えすることができますので、民安ともえ、鷹の爪吉田くん、のような制限がなくなります。
  • 東北ずん子、京町セイカ、はテキストボックスを直接制御できるため、編集メニューを通さず操作できます。とても楽です。
  • 東北ずん子、京町セイカは音声再生中、「再生ボタン」が「一時停止ボタン」になるため、連続してコマンドを実行しようとすると一時停止状態になってしまいます。
    再生ボタンのキャプションを見て、‟再生”以外の時は最大3分間、元の‟再生”に戻るまで待ちます。3分を超えてまだ再生中だった場合、一時停止ボタンが押されてしまいます。仕様です。
  • VOICEROID+ のウインドウタイトルを見てVOICEROIDのプログラムを特定しています。
    なので、琴葉姉妹はキャラクターを切り替えておく必要があります。
  • -wav オプション指定時、「音声再生後に音声保存」を行うVOICEROIDと「音声保存後に音声再生」を行うVOICEROIDがあります。
    何故かは判らないのですが、この順番が逆になると途中でVOICEROIDに送りつけているWindowメッセージが無効になってしまいます。そのため、この機能は実際うごかしてみないと利用可能なのかどうかが分かりません。
  • 他のVOICEROID+(琴葉姉妹)やVOICEROID+EXは、公開されている画面の画像を見ると京町セイカ、東北ずん子、と同じUIの様にみえます。制御方法は京町セイカ方式で行けるんじゃないかと思います。※もし私が持っている5製品以外のもので試された場合はその結果を教えてもらえると修正が可能になるかもしれません。

ソース

エラー処理などはほぼ入れてません。自分の理解のためのソースコードとなっています。
色々な方がVOICEROIDを操作するための製品とそのソースを公開してくれているので、そちらも参照してください。色々考慮すべき点があることがわかります。

1ソースにまとめていますが、そろそろ理解できる限界かな。

echoseika.cs
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
 
namespace echoseika
{
    class echoseika
    {
 
        static void Main(string[] args)
        {
            getopt opts = new getopt(args);
 
            if (!opts.usable) return;
 
            if (opts.talkText.Length == 0)
            {
                Console.WriteLine("no speech text.");
                return;
            }
            if ("" != opts.wavFilePath)
            {
                string folder = Path.GetDirectoryName(opts.wavFilePath);
                string wavfile = Path.GetFileName(opts.wavFilePath + ".wav");
                string txtfile = Path.GetFileName(opts.wavFilePath + ".txt");
 
                if (("" != folder) && (!Directory.Exists(folder)))
                {
                    Console.WriteLine("error. folder not found. please create a folder {0} first.", folder);
                    return;
                }
                if (File.Exists(folder + @"\" + wavfile))
                {
                    Console.WriteLine("error. file {0} found. please delete a this file first.", wavfile);
                    return;
                }
                if (File.Exists(folder + @"\" + txtfile))
                {
                    Console.WriteLine("error. file {0} found. please delete a this file first.", txtfile);
                    return;
                }
            }
 
            vRoidController voiceroid = new vRoidController(opts.cv);
 
            if (voiceroid.isUsable)
            {
 
                if (opts.talkText.Length == 0)
                {
                    Console.WriteLine("no speech text.");
                }
                else
                {
                    voiceroid.play(opts.talkText, opts.wavFilePath);
                }
            }
            else
            {
                Console.WriteLine("VOICEROID not found.");
            }
            return;
        }
    }
 
    /// <summary>
    /// ターゲットのVOICEROID
    /// </summary>
    public enum vRoidAvator
    {
        SEIKA,
        TAMMY,
        TAMMY_EX,
        YUKARI,
        YUKARI_EX,
        ZUNKO,
        ZUNKO_EX,
        AKANE,
        AOI,
        YOSHIDA
    }
    public static class vRoidAvatorEx
    {
        public static string ProdName(this vRoidAvator value)
        {
            string[] values =
            {
                "VOICEROID+ 京町セイカ EX",
                "VOICEROID+ 民安ともえ",
                "VOICEROID+ 民安ともえ EX",
                "VOICEROID+ 結月ゆかり",
                "VOICEROID+ 結月ゆかり EX",
                "VOICEROID+ 東北ずん子",
                "VOICEROID+ 東北ずん子 EX",
                "VOICEROID+ 琴葉茜",
                "VOICEROID+ 琴葉葵",
                "VOICEROID+ 鷹の爪 吉田くん"
            };
 
            return values[(int)value];
        }
    }
 
    /// <summary>
    /// やっつけオプション解析
    /// </summary>
    class getopt
    {
        public vRoidAvator cv { get; }
        public string talkText { get; }
        public string wavFilePath { get; }
        public bool wavSave { get; }
        public bool usable { get; }
 
        public getopt(string[] args)
        {
            int i = 0;
 
            cv = vRoidAvator.SEIKA;
            talkText = "";
            wavFilePath = "";
            usable = true;
 
            while (i < args.Length)
            {
                if (args[i].Substring(0,1)=="-")
                {
                    switch (args[i])
                    {
                        case "-cv":
                            if ((i+1)<args.Length)
                            {
                                try
                                {
                                    cv = (vRoidAvator)Enum.Parse(typeof(vRoidAvator), args[i + 1].ToUpper());
                                }
                                catch (Exception e)
                                {
                                    Console.WriteLine(e.Message);
                                    Console.WriteLine("error found. option changed to {0} {1} .", args[i], cv.ToString());
                                }
                                i++;
                            }
                            else
                            {
                                usable = false;
                                Console.WriteLine("error. not enough options.", args[i], cv.ToString());
                            }
                            break;
 
                        case "-wav":
                            if ((i + 1) < args.Length)
                            {
                                wavFilePath = Path.GetFullPath(args[i + 1]);
                                wavSave = true;
                                i++;
                            }
                            else
                            {
                                usable = false;
                                Console.WriteLine("error. finename not found.");
                            }
                            break;
 
                        case "-h":
                            i = args.Length;
                            usable = false;
 
                            Console.WriteLine("usage: echoseika [-cv voiceroid] [-wav wavfile] TalkText");
                            Console.WriteLine("");
                            Console.WriteLine("-cv voiceroid   : use voiceroid name. default is {0}", vRoidAvator.SEIKA.ToString());
                            foreach (vRoidAvator avator in Enum.GetValues(typeof(vRoidAvator)))
                            {
                                Console.WriteLine("       {0,-10} {1}", avator.ToString(), avator.ProdName());
                            }
                            Console.WriteLine("-wav wavefile   : save the voice data to wavefile.wav");
                            Console.WriteLine("TalkText        : send the \"TalkText\" to VOICEROID");
 
                            break;
                    }
                }
                else
                {
                    talkText = args[i];
                    break;
                }
 
                i++;
            }
        }
    }
 
    /// <summary>
    /// VOICEROID制御
    /// </summary>
    class vRoidController
    {
        [DllImport("user32.dll")]
        private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
 
        [DllImport("user32.dll")]
        private static extern IntPtr GetParent(IntPtr hWnd);
 
        [DllImport("user32.dll")]
        private static extern int PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
 
        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int GetWindowTextLength(IntPtr hWnd);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpString);
 
        /// <summary>
        /// VOIVEROIDのUIウインドウハンドル種別
        /// </summary>
        private enum UIhWnds
        {
            voiceroid_mainwindow,
            voiceroid_textbox,
            voiceroid_playbutton,
            voiceroid_savebutton,
            savedlg_mainwindow,
            savedlg_editbox,
            savedlg_savebutton
        };
 
        const uint WM_NULL = 0x0000;
        const uint GW_HWNDNEXT = 0x0002;
        const uint GW_CHILD = 0x0005;
        const uint WM_SETTEXT = 0x000C;
        const uint EM_SETSEL = 0x00B1;
        const uint BM_CLICK = 0x00F5;
        const uint WM_COMMAND = 0x0111;
        const uint WM_PASTE = 0x0302;
 
        private Dictionary<UIhWnds, IntPtr> hMainWnds;
        private Dictionary<UIhWnds, IntPtr> hDlgWnds;
        private vRoidAvator selectedAvator;
 
        // コンストラクタ
        public vRoidController( vRoidAvator cv)
        {
            selectedAvator = cv;
 
            switch(cv)
            {
                case vRoidAvator.SEIKA:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus_Ex(vRoidAvator.SEIKA.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.TAMMY:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus(vRoidAvator.TAMMY.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.YUKARI:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus(vRoidAvator.YUKARI.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.ZUNKO:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus_2(vRoidAvator.ZUNKO.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.TAMMY_EX:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus_Ex(vRoidAvator.TAMMY_EX.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.YUKARI_EX:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus_Ex(vRoidAvator.YUKARI_EX.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.ZUNKO_EX:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus_Ex(vRoidAvator.ZUNKO_EX.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.YOSHIDA:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus(vRoidAvator.YOSHIDA.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.AKANE:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus_Ex(vRoidAvator.AKANE.ProdName(), 3, 1000);
                    break;
                case vRoidAvator.AOI:
                    hMainWnds = GetTargethWnds_Voiceroid_Plus_Ex(vRoidAvator.AOI.ProdName(), 3, 1000);
                    break;
            }
        }
 
        // 使える?
        public bool isUsable
        {
            get
            {
                IntPtr ans = hMainWnds[UIhWnds.voiceroid_mainwindow];
                return ans.Equals(IntPtr.Zero) ? false : true;
            }
        }
 
        // テキスト再生、音声保存
        public void play(string text, string wavFilePath)
        {
            switch (selectedAvator)
            {
                case vRoidAvator.TAMMY_EX:
                case vRoidAvator.YUKARI_EX:
                case vRoidAvator.ZUNKO_EX:
                case vRoidAvator.AKANE:
                case vRoidAvator.AOI:
 
                case vRoidAvator.SEIKA:
                    if (""!=wavFilePath) save_Plus_Ex(text, wavFilePath);
                    play_Plus_Ex(text);
                    break;
 
                case vRoidAvator.ZUNKO:
                    play_Plus_Ex(text);
                    if ("" != wavFilePath) save_Plus_Ex(text, wavFilePath);
                    break;
 
                case vRoidAvator.YUKARI:
                    if ("" != wavFilePath) save_Plus2(text, wavFilePath);
                    play_Plus2(text);
                    break;
 
                case vRoidAvator.TAMMY:
                case vRoidAvator.YOSHIDA:
                    play_Plus(text);
                    if ("" != wavFilePath) save_Plus(wavFilePath);
                    break;
            }
        }
 
        // 再生シーケンス
        private void play_Plus_Ex(string text)
        {
            // 多分+EXで有効な方法
            waitPlaying();
            SendMessage(hMainWnds[UIhWnds.voiceroid_textbox],    EM_SETSEL,   0,-1); // 全テキストを選択
            setClipboard(text);
            SendMessage(hMainWnds[UIhWnds.voiceroid_textbox],    WM_PASTE,    0, 0); // クリップボードの内容をペースト
            SendMessage(hMainWnds[UIhWnds.voiceroid_playbutton], BM_CLICK,    0, 0); // 再生ボタンクリック
        }
        private void play_Plus2(string text)
        {
            // 多分+の新しい方で有効
            SendMessage(hMainWnds[UIhWnds.voiceroid_mainwindow], WM_COMMAND, 60, 0); // メニューの全て選択
            SendMessage(hMainWnds[UIhWnds.voiceroid_mainwindow], WM_COMMAND, 52, 0); // メニューの削除
            setClipboard(text);
            SendMessage(hMainWnds[UIhWnds.voiceroid_mainwindow], WM_COMMAND, 56, 0); // メニューの貼り付け
            SendMessage(hMainWnds[UIhWnds.voiceroid_playbutton], WM_NULL,     0, 0); // 再生ボタンクリック
        }
        private void play_Plus(string text)
        {
            // 多分+の初期型で有効
            SendMessage(hMainWnds[UIhWnds.voiceroid_mainwindow], WM_COMMAND, 46, 0); // メニューの元に戻す
            setClipboard(text);
            SendMessage(hMainWnds[UIhWnds.voiceroid_mainwindow], WM_COMMAND, 56, 0); // メニューの貼り付け
            SendMessage(hMainWnds[UIhWnds.voiceroid_playbutton], WM_NULL,     0, 0); // 再生ボタンクリック
        }
 
        // 保存シーケンス
        private void save_Plus_Ex(string text, string filenamePath)
        {
            waitPlaying();
 
            Thread.Sleep(1000);
 
            SendMessage(hMainWnds[UIhWnds.voiceroid_textbox],    EM_SETSEL, 0, -1); // 全テキストを選択
            setClipboard(text);
            SendMessage(hMainWnds[UIhWnds.voiceroid_textbox],    WM_PASTE, 0, 0); // クリップボードの内容をペースト
            PostMessage(hMainWnds[UIhWnds.voiceroid_savebutton], BM_CLICK, 0, 0); // 音声保存ボタンクリック
 
            //dump1();
            hDlgWnds = GetTargethWnds_saveDlg("音声ファイルの保存", 300, 100);
            //dump2();
 
            if (!hDlgWnds[UIhWnds.savedlg_mainwindow].Equals(IntPtr.Zero))
            {
                StringBuilder sb = new StringBuilder(filenamePath);
 
                SendMessage(hDlgWnds[UIhWnds.savedlg_editbox],    WM_SETTEXT,   0, sb);
                SendMessage(hDlgWnds[UIhWnds.savedlg_savebutton], BM_CLICK,     0, 0 );
            }
        }
        private void save_Plus2(string text, string filenamePath)
        {
            Thread.Sleep(1000);
 
            SendMessage(hMainWnds[UIhWnds.voiceroid_mainwindow], WM_COMMAND, 60, 0); // メニューの全て選択
            SendMessage(hMainWnds[UIhWnds.voiceroid_mainwindow], WM_COMMAND, 52, 0); // メニューの削除
            setClipboard(text);
            SendMessage(hMainWnds[UIhWnds.voiceroid_mainwindow], WM_COMMAND, 56, 0); // メニューの貼り付け
            PostMessage(hMainWnds[UIhWnds.voiceroid_savebutton], WM_NULL, 0, 0); // 音声保存ボタンクリック
 
            //dump1();
            hDlgWnds = GetTargethWnds_saveDlg("音声ファイルの保存", 300, 100);
            //dump2();
 
            if (!hDlgWnds[UIhWnds.savedlg_mainwindow].Equals(IntPtr.Zero))
            {
                StringBuilder sb = new StringBuilder(filenamePath);
 
                SendMessage(hDlgWnds[UIhWnds.savedlg_editbox], WM_SETTEXT, 0, sb);
                SendMessage(hDlgWnds[UIhWnds.savedlg_savebutton], BM_CLICK, 0, 0);
            }
        }
        private void save_Plus(string filenamePath)
        {
            Thread.Sleep(1000);
 
            PostMessage(hMainWnds[UIhWnds.voiceroid_savebutton], WM_NULL, 0, 0); // 音声保存ボタンクリック
 
            //dump1();
            hDlgWnds = GetTargethWnds_saveDlg("音声ファイルの保存", 300, 100);
            //dump2();
 
            if (!hDlgWnds[UIhWnds.savedlg_mainwindow].Equals(IntPtr.Zero))
            {
                StringBuilder sb = new StringBuilder(filenamePath);
 
                SendMessage(hDlgWnds[UIhWnds.savedlg_editbox], WM_SETTEXT, 0, sb);
                SendMessage(hDlgWnds[UIhWnds.savedlg_savebutton], BM_CLICK, 0, 0);
            }
        }
 
        // 再生ボタンのキャプションが変化する製品用
        private void waitPlaying()
        {
            int winTextLen = 0;
            int count = 0;
 
            while(true)
            {
                winTextLen = GetWindowTextLength(hMainWnds[UIhWnds.voiceroid_playbutton]);
 
                if (0 < winTextLen)
                {
                    StringBuilder sb = new StringBuilder(winTextLen + 1);
                    GetWindowText(hMainWnds[UIhWnds.voiceroid_playbutton], sb, sb.Capacity);
 
                    if (sb.ToString() == " 再生")  // 文字列先頭が空白なので注意
                    {
                        break;
                    }
                    else
                    {
                        count++;
                        Thread.Sleep(100);
                        if (1800 < count) break; // 3分待ったら待つの止めるよ!
                    }
                }
            }
        }
 
        // クリップボードにテキスト設定
        private void setClipboard(string text)
        {
            Thread t = new Thread(() => {
                Clipboard.SetText(text, TextDataFormat.Text);
            });
            t.SetApartmentState(ApartmentState.STA);
            t.Start();
            t.Join();
        }
 
        // 音声ファイルの保存ダイアログのウインドウハンドル取得
        private IntPtr GetSaveDialogWindowHandle(string winTitle, int retryCount, int retryWaitms)
        {
            IntPtr hWnd = IntPtr.Zero;
            IntPtr hWndDaddy = IntPtr.Zero;
            IntPtr hParentWnd = hMainWnds[UIhWnds.voiceroid_mainwindow];
 
            for (int i = 0; i < retryCount; i++)
            {
                hWnd = FindWindow("#32770", winTitle); // "#32770 (ダイアログ)" はダイアログのクラス名?
 
                if (hWnd != IntPtr.Zero)
                {
                    while( !hWnd.Equals(IntPtr.Zero))
                    {
                        hWndDaddy = GetParent(hWnd);
                        if (hParentWnd.Equals(hWndDaddy))
                        {
                            break;
                        }
                        else
                        {
                            hWnd = GetWindow(hWnd, GW_HWNDNEXT);
                        }
                    }
                }
 
                if (hParentWnd.Equals(hWndDaddy)) break;
                if (i < (retryCount - 1)) Thread.Sleep(retryWaitms);
            }
 
            return hWnd;
        }
 
        // 音声ファイルの保存ダイアログの各種ウインドウハンドル取得
        private Dictionary<UIhWnds, IntPtr> GetTargethWnds_saveDlg(string dlgtitle, int retryCount, int retryWaitms)
        {
            IntPtr hWndWorkPtr = IntPtr.Zero;
            IntPtr hWndDlgWinPtr = GetSaveDialogWindowHandle(dlgtitle, retryCount, retryWaitms);
 
            Dictionary<UIhWnds, IntPtr> hWnds = new Dictionary<UIhWnds, IntPtr>();
 
            // ダイアログウインドウハンドル
            hWnds.Add(UIhWnds.savedlg_mainwindow, hWndDlgWinPtr);
 
            if (hWndDlgWinPtr == IntPtr.Zero)
            {
                hWnds.Add(UIhWnds.savedlg_editbox, IntPtr.Zero);
                hWnds.Add(UIhWnds.savedlg_savebutton, IntPtr.Zero);
                return hWnds;
            }
            Thread.Sleep(1000);
            // テキストボックス
            hWndWorkPtr = hWndDlgWinPtr;
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 第1層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 第2層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 第3層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 第4層ウインドウ(コンボボックス)
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD); // 第5層ウインドウ(テキストボックス)
            hWnds.Add(UIhWnds.savedlg_editbox, hWndWorkPtr);
 
            // 保存ボタン
            hWndWorkPtr = FindWindowEx(hWndDlgWinPtr, IntPtr.Zero, "Button", "保存(&S)"); // 配下の保存ボタン
            hWnds.Add(UIhWnds.savedlg_savebutton, hWndWorkPtr);
 
            return hWnds;
        }
 
        // VOICEROIDメインウインドウハンドル取得
        private IntPtr GetMainWindowHandle(string winTitle, int retryCount, int retryWaitms)
        {
            IntPtr hWnd = IntPtr.Zero;
            string winTitle2 = winTitle + "*";
            Process[] ps = Process.GetProcesses();
 
            for (int i = 0; i < retryCount; i++)
            {
                foreach (Process pitem in ps)
                {
                    if ((pitem.MainWindowHandle != IntPtr.Zero) &&
                           ((pitem.MainWindowTitle.Equals(winTitle)) || (pitem.MainWindowTitle.Equals(winTitle2))))
                    {
                        hWnd = pitem.MainWindowHandle;
                    }
                }
                if (hWnd != IntPtr.Zero) break;
                if (i < (retryCount - 1)) Thread.Sleep(retryWaitms);
            }
            return hWnd;
        }
 
        // VOICEROID+EXの各種ウインドウハンドル取得
        private Dictionary<UIhWnds, IntPtr> GetTargethWnds_Voiceroid_Plus_Ex(string wintitle, int retryCount, int retryWaitms)
        {
            Dictionary<UIhWnds, IntPtr> hWnds = new Dictionary<UIhWnds, IntPtr>();
            IntPtr hWndMainWinPtr = GetMainWindowHandle(wintitle, retryCount, retryWaitms);
            IntPtr hWndWorkPtr = IntPtr.Zero;
 
            // ウインドウハンドル
            hWnds.Add(UIhWnds.voiceroid_mainwindow, hWndMainWinPtr);
 
            if (hWndMainWinPtr == IntPtr.Zero)
            {
                hWnds.Add(UIhWnds.voiceroid_textbox, IntPtr.Zero);
                hWnds.Add(UIhWnds.voiceroid_playbutton, IntPtr.Zero);
                hWnds.Add(UIhWnds.voiceroid_savebutton, IntPtr.Zero);
                return hWnds;
            }
 
            // テキストボックス
            hWndWorkPtr = hWndMainWinPtr;
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第1層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第2層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第2層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第3層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第4層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第5層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第6層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第7層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第8層ウインドウ(テキストボックス) 
            hWnds.Add(UIhWnds.voiceroid_textbox, hWndWorkPtr);
 
            // 再生ボタン
            hWndWorkPtr = hWndMainWinPtr;
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第1層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第2層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第2層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第3層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第4層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第5層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第6層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第7層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第7層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第8層ウインドウ(再生ボタン)
            hWnds.Add(UIhWnds.voiceroid_playbutton, hWndWorkPtr);
 
            // 音声保存ボタン
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT);    // 第8層2番目ウインドウ(停止ボタン)
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT);    // 第8層3番目ウインドウ(音声保存ボタン)
            hWnds.Add(UIhWnds.voiceroid_savebutton, hWndWorkPtr);
 
            return hWnds;
        }
 
        // VOICEROID+の各種ウインドウハンドル取得
        private Dictionary<UIhWnds, IntPtr> GetTargethWnds_Voiceroid_Plus(string wintitle, int retryCount, int retryWaitms)
        {
            Dictionary<UIhWnds, IntPtr> hWnds = new Dictionary<UIhWnds, IntPtr>();
            IntPtr hWndMainWinPtr = GetMainWindowHandle(wintitle, retryCount, retryWaitms);
            IntPtr hWndWorkPtr = IntPtr.Zero;
 
            //ウインドウハンドル
            hWnds.Add(UIhWnds.voiceroid_mainwindow, hWndMainWinPtr);
 
            if (hWndMainWinPtr == IntPtr.Zero)
            {
                hWnds.Add(UIhWnds.voiceroid_textbox, IntPtr.Zero);
                hWnds.Add(UIhWnds.voiceroid_playbutton, IntPtr.Zero);
                hWnds.Add(UIhWnds.voiceroid_savebutton, IntPtr.Zero);
                return hWnds;
            }
 
            //テキストボックス
            hWndWorkPtr = hWndMainWinPtr;
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第1層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第2層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第2層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第2層3番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第3層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第3層2番目ウインドウ(テキストボックス) 
            hWnds.Add(UIhWnds.voiceroid_textbox, hWndWorkPtr);
 
            //保存ボタン
            hWndWorkPtr = hWndMainWinPtr;
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第1層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第2層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第2層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第3層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第3層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第3層3番目ウインドウ(保存ボタン)
            hWnds.Add(UIhWnds.voiceroid_savebutton, hWndWorkPtr);
 
            //再生ボタン
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第3層4番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第3層5番目ウインドウ(再生ボタン)
            hWnds.Add(UIhWnds.voiceroid_playbutton, hWndWorkPtr);
 
            return hWnds;
        }
 
        // VOICEROID+の各種ウインドウハンドル取得(東北ずん子)
        private Dictionary<UIhWnds, IntPtr> GetTargethWnds_Voiceroid_Plus_2(string wintitle, int retryCount, int retryWaitms)
        {
            Dictionary<UIhWnds, IntPtr> hWnds = new Dictionary<UIhWnds, IntPtr>();
            IntPtr hWndMainWinPtr = GetMainWindowHandle(wintitle, retryCount, retryWaitms);
            IntPtr hWndWorkPtr = IntPtr.Zero;
 
            //ウインドウハンドル
            hWnds.Add(UIhWnds.voiceroid_mainwindow, hWndMainWinPtr);
 
            if (hWndMainWinPtr == IntPtr.Zero)
            {
                hWnds.Add(UIhWnds.voiceroid_textbox, IntPtr.Zero);
                hWnds.Add(UIhWnds.voiceroid_playbutton, IntPtr.Zero);
                hWnds.Add(UIhWnds.voiceroid_savebutton, IntPtr.Zero);
                return hWnds;
            }
 
            //テキストボックス
            hWndWorkPtr = hWndMainWinPtr;
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第1層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第2層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第2層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第3層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第4層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第5層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第6層ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第7層ウインドウ(テキストボックス) 
            hWnds.Add(UIhWnds.voiceroid_textbox, hWndWorkPtr);
 
            //再生ボタン
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第7層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_CHILD);    // 第8層ウインドウ(再生ボタン)
            hWnds.Add(UIhWnds.voiceroid_playbutton, hWndWorkPtr);
 
            //保存ボタン
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第8層2番目ウインドウ
            hWndWorkPtr = GetWindow(hWndWorkPtr, GW_HWNDNEXT); // 第8層3番目ウインドウ(音声保存ボタン)
            hWnds.Add(UIhWnds.voiceroid_savebutton, hWndWorkPtr);
 
            return hWnds;
        }
 
        private void dump1()
        {
            Console.WriteLine("{0,20}:{1}", UIhWnds.voiceroid_mainwindow.ToString(), hMainWnds[UIhWnds.voiceroid_mainwindow].ToString("X8"));
            Console.WriteLine("{0,20}:{1}", UIhWnds.voiceroid_textbox.ToString(), hMainWnds[UIhWnds.voiceroid_textbox].ToString("X8"));
            Console.WriteLine("{0,20}:{1}", UIhWnds.voiceroid_playbutton.ToString(), hMainWnds[UIhWnds.voiceroid_playbutton].ToString("X8"));
            Console.WriteLine("{0,20}:{1}", UIhWnds.voiceroid_savebutton.ToString(), hMainWnds[UIhWnds.voiceroid_savebutton].ToString("X8"));
        }
        private void dump2()
        {
            Console.WriteLine("{0,20}:{1}", UIhWnds.savedlg_mainwindow.ToString(), hDlgWnds[UIhWnds.savedlg_mainwindow].ToString("X8"));
            Console.WriteLine("{0,20}:{1}", UIhWnds.savedlg_editbox.ToString(), hDlgWnds[UIhWnds.savedlg_editbox].ToString("X8"));
            Console.WriteLine("{0,20}:{1}", UIhWnds.savedlg_savebutton.ToString(), hDlgWnds[UIhWnds.savedlg_savebutton].ToString("X8"));
        }
    }
}

コメント

コメントを入力. Wiki文法が有効です:
画像の文字が読めなければ、文字を読んだ.wavファイルをダウンロードして下さい。
 
documents/windows/windows-023.txt · 最終更新: 2016/09/18 01:37 by k896951