mieki256's diary



2026/01/11() [n年前の日記]

#2 [csharp] C#から外部プログラムを呼び出すところでハマった

C#から外部プログラムを呼び出す処理でちょっとハマった。ググった感じでは、Process.Start() を使えば呼び出せるということは分かったのだけど…。

_C#でProcessを使って別アプリを実行(起動)する方法 #C# - Qiita
_外部アプリケーションを起動する、ファイルを関連付けられたソフトで開く - .NET Tips (VB.NET,C#...)
_プロセス | C# プログラミング解説
_C#で別EXEをパラメータ渡しで実行する #.NET - Qiita

単に、1つの .exe を呼び出すだけなら動作してくれた。

しかし、"python.exe C:/hoge/fuga/piyo.pyw" のような形で呼び出そうとすると「ソレ、実行できないよ」とエラーが出てしまう。

おそらくだけど、プログラムと引数をちゃんと分けて指定してやらないと実行できないっぽい。前述の事例の場合、プログラム名は "python.exe"、引数は "C:/hoge/fuga/piyo.pyw" に分解しないと…。

Google Gemini に尋ねてみたら、以下のような処理を提示された。Windowsには、CommandLineToArgvW() というAPI?があるので、それを利用すれば分解できるっぽい。

Form1.cs
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace CsProcessStartSample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = ofd.FileName;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // textBox に入っている文字列で外部プログラムを実行する
            string cmdline = textBox1.Text;
            if (cmdline == "")
            {
                MessageBox.Show("Empty file path.");
                return;
            }

            // プログラム名と引数に分ける
            string filename;
            string arguments;
            (filename, arguments) = ParseCommandLine(cmdline);

            if (filename == null || filename == "")
            {
                MessageBox.Show("Not found .exe", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            label2.Text = "0: [" + filename + "]";
            label3.Text = "1: [" + arguments + "]";

            ProcessStartInfo psi = new ProcessStartInfo
            {
                FileName = filename,
                Arguments = arguments,
                UseShellExecute = true
            };

            // 外部プログラムを実行
            Process.Start(psi);
        }

        public static (string fileName, string arguments) ParseCommandLine(string commandLine)
        {
            // Windows APIを使用して引数を配列に分解
            string[] args = Win32CommandLineParser.SplitArgs(commandLine);

            if (args.Length > 0)
            {
                string fileName = args[0];
                // 2番目以降の要素をスペースで結合して引数文字列を作る
                string arguments = string.Join(" ", args.Skip(1).Select(a => a.Contains(" ") ? $"\"{a}\"" : a));
                return (fileName, arguments);
            }
            return ("", "");
        }

        public static class Win32CommandLineParser
        {
            [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            private static extern IntPtr CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, out int pNumArgs);

            public static string[] SplitArgs(string commandLine)
            {
                IntPtr ptr = CommandLineToArgvW(commandLine, out int numArgs);
                if (ptr == IntPtr.Zero) return Array.Empty<string>();
                try
                {
                    string[] args = new string[numArgs];
                    for (int i = 0; i < numArgs; i++)
                    {
                        IntPtr p = Marshal.ReadIntPtr(ptr, i * IntPtr.Size);
                        args[i] = Marshal.PtrToStringUni(p);
                    }
                    return args;
                }
                finally { Marshal.FreeHGlobal(ptr); }
            }
        }

    }
}


_CommandLineToArgvW - 車輪のx発明 - B.G's Blog
_コマンドライン文字列の解析 - Qiita

たしかに動作してくれた。

動作してくれたけど…。考えてみたら、プログラム名と引数を別々に指定してもらうほうが確実なのかなと思えてきた。結局、設定ダイアログ上で、テキストボックスを2つ用意して対処することにしてしまった…。

以上です。

過去ログ表示

Prev - 2026/01 - Next
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project