C# コンテキストメニューにサブメニュー表示していろいろしたい
目次
VSCodeのRainbow CSVっていう幸せな拡張機能を見つけて喜んでいたところ、タブ区切りのくせして拡張子が「txt」のやつを扱う必要があった。 手動でtsvに変換するの面倒なので「C#でツール作ろ」となった。 挙動は以下のとおり。 今回の主な実装は二つ。 圧倒的に1がメイン。(コピーして開くなんてすぐだし…) インストールしたらコンテキストメニューにサブメニューを表示しなくちゃならない。 ここで、サブメニューの表示にむちゃ苦戦した。記事が少ないうえに日本語と英語のサイトだとやり方違って、英語のほうでやってもできないという…何が正しいがわからなくなったが、とりあえず日本語のサイトを参考にしたらできた。 インストール時のレジストリ構造は下の画像のとおり(こうしないとサブメニューができない…)。Installerクラスを継承してInstallメソッドをオーバーライドしてもいいけど、今回はGUIつかってがちがちと…。
それぞれの文字列値とかは以下のとおり。「""」は空文字。下の設定以外はなんも値を入れてない。 「(Default)」のところは設定時に空欄でEnterすれば勝手にいれてくれる。インストールするフォルダはユーザごとで違うので[TARGETDIR]を使用する。 あとは「-csv」、「-tsv」を見てわかるように、オプションとしてファイルパスと「-tsv」とか受け取ったら拡張子変更コピーしてVSCodeで開くツールを作る。 自分用なのでサクッとつくる。VSCodeのexeなんて絶対パスそのまんま。レジストリから探すのは面倒(というか知らない、調べてない←) うまくいった。
はじめに
実装
開発環境
ツール:インストーラ
ツール:本体
using System;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
namespace ExtensionConvert
{
#region 列挙
/// <summary>
/// 変換先の列挙
/// </summary>
enum Extension
{
TSV,
CSV
}
#endregion
class Program
{
#region プライベートメンバ
static string path;
static Extension convertExt;
const string c_VsCodePath = @"VSCodeの絶対パス";
#endregion
#region Main
static void Main(string[] args)
{
commandParser(args);
var newPath = getCopyPath();
File.Copy(args[0], newPath, true);
var psi = new ProcessStartInfo(c_VsCodePath)
{
UseShellExecute = false,
CreateNoWindow = true,
Arguments = newPath
};
Process.Start(psi);
}
#endregion
#region コマンドラインパーサー
/// <summary>
/// コマンドパーサー(これいる?)
/// </summary>
/// <param name="args">引数</param>
static void commandParser(string[] args)
{
path = args[0];
convertExt = args[1] switch
{
"-tsv" => Extension.TSV,
"-csv" => Extension.CSV,
_ => throw new InvalidOperationException()
};
}
#endregion
#region コピー先のファイルパス
/// <summary>
/// 新しいコピー先のパスを取得
/// </summary>
/// <returns>新しいコピー先のファイルパス</returns>
static string getCopyPath()
{
var regNum = new Regex($@"{Path.GetFileNameWithoutExtension(path)}_copy[\d]*\.(csv|tsv)$");
var name = Path.GetFileNameWithoutExtension(path);
var retPath = convertExt switch
{
Extension.TSV => searchPath($"{Path.Combine(Path.GetDirectoryName(path), name)}_copy.tsv"),
Extension.CSV => searchPath($"{Path.Combine(Path.GetDirectoryName(path), name)}_copy.csv"),
_ => throw new InvalidOperationException()
};
return retPath;
#region (ローカル関数) コピー可能なファイル名探索
string searchPath(string path)
{
for (int i = 1; File.Exists(path); i++)
{
path = regNum.Replace(path, $"{name}_copy{i}.tsv");
}
return path;
}
#endregion
}
#endregion
}
}
実行結果
参考