mieki256's diary



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

#1 [visualstudio][csharp] C#でスクリーンセーバのラッパーを作ってみた

C#を使って、Windows用スクリーンセーバのラッパーを作ってみた。

スクリーンセーバとしてインストールして、設定ダイアログからフルスクリーン表示をする何かしらのプログラムを指定しておけば、そのプログラムをスクリーンセーバとして利用できるようになる。

せっかくだから github にアップロードしておいた。

_mieki256/CsSSWrap: Windows用のフルスクリーン表示プログラムをスクリーンセーバ代わりにするラッパー

VisualStudio用のプロジェクトってこういう感じにアップロードしておけばいいのだろうか…。よく分かってない…。でもまあ、これでもソース(.cs)は見れるからなんとかなるんじゃないか。

もっとも、今時スクリーンセーバを動かす人も作る人も居ないやろという気もするけど…。まあ、自分にとってC#を勉強するためのお題ということで…。

注意点 :

フルスクリーン表示をするプログラム(.exe や .pyw等)は以下の条件を満たしていないといけない。
  • 多重起動禁止処理が入っていること。
  • フルスクリーン表示をすること。
  • キーボードやマウスに反応して終了すること。

制作の動機 :

Python + pygame でWindows用のスクリーンセーバを作成してみたものの、Nuitkaでexe化する際の仕組みの関係か、プレビュー画面モード時の表示が遅過ぎて、これはラッパーの類を通したほうがいいのかな、せっかくだから昔作ったラッパーをパワーアップしつつ、C#の勉強も兼ねて作ってみようかと思った次第。

ただ、出来上がったファイルのサイズが大き過ぎる…。100MBを越えてる…。.NET9のランタイムが同梱されているからだけど…。大き過ぎて、github にアップロード(プッシュ)しようとしたら「ファイルサイズが100MBを越えてるからプッシュに失敗した」と表示されて…。

もっと小さいサイズで作れないものか。そのためには別の言語を使うしかないのだろうけど。

アイコン画像で悩んだ :

スクリーンセーバのラッパーと分かりそうなアイコン画像ってどういうものを作ったらいいのか…。

Google Gemini に、どういうモチーフで作ったらええんやろと相談してみたら、「モニターを箱で囲んでみるとか、ギフトボックスにモニター入れてみるとかどうよ? 要は包む何かなわけだから」と言ってきた。なるほど…。ついでに画像生成もお願いしてみたら、アイコン画像とは程遠いリッチな画像ばかり出てきた。違うんだよなあ…。

結局 Inkscape でテキトーに作ってみたけど、なんというか、ショボい…。しかもラッパーの類とは分からない気がする…。

#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つ用意して対処することにしてしまった…。

#3 [csharp] C#でフォームのレイアウト

Visual Studio 2022 Community と C# を使ってGUIアプリのフォーム(ウインドウみたいなもの)をレイアウトしている際、いくつか疑問が湧いたのでそのあたりをメモ。

ウインドウサイズの変更にコントロールのサイズも追従させたい :

コントロールの Anchor プロパティを指定すればできる。

デフォルトでは、top, left が指定されているけれど、top, left, right を指定すれば、親のフォームの幅が変わった時に追従してコントロールの横幅が伸びてくれる。

top, left, bottom を指定すれば縦幅が追従してくれる。

また、left, bottom を指定すれば、フォームの左下のほうを基準にして位置決めができる。

right, bottom を指定すれば、フォームの右下のほうを基準にして位置決めができる。

テーブルレイアウトをしたい :

表を使ったようなレイアウトをしたい。TableLayoutPanel を使えばできる。

_TableLayoutPanelコントロールを使って、コントロールを表形式で整列させる - .NET Tips (VB.NET,C#...)

#4 [csharp] Native AOTってなんだろう

.NET関係についてググってる最中に、Native AOT なるワードを見かけた。

_【C#】コンパイルが必要な言語はダメらしいので「NativeAOT」について紹介
_.NET で Native AOT アプリケーションを開発する方法 | ハウツー記事
_.NET Native AOTとは

処理が速くなるうえに、ファイルサイズも小さくなるらしい…。しかしどうやったら使えるのかよく分からない…。Visual Studio 2022 上で、GUIで設定したりして使えるものではない…?

以上、1 日分です。

過去ログ表示

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