はじめに
前回インストールをしたVisual Studio for MacでWindowsの壁紙を変更するイタズラアプリを作成してみたので、作成したアプリについてお伝えしたいと思う。
※Macのアプリでない理由については、気にしないでいただきたい。
注意事項
今回作成するアプリはイタズラアプリなので、実行する環境には十二分に注意して自己責任で実行すること。
今回作成するアプリについて
Windows上で実行可能なコンソールアプリ。
アプリを実行することで、UI上は何も表示されないが一定間隔(60秒)ごとに壁紙を変更される。
対象の環境でどのように実行させるかという課題はあるが、実行させてしまえば一定期間壁紙を変更し続けるため、設定する壁紙によっては面白い反応を得られるかもしれない。
また、イタズラアプリを通してアプリ作成を行ったことがないような方でもアプリ開発は面白いということを少しでも理解していただければ幸いである。
開発環境
- Mac Book Pro 2018 13インチ
- Visual Studio for Mac(導入手順はこちら)
※Windows版のVisual Studioでも同様のアプリは作成可。
プロジェクトの作成
1.Visual Studioを起動する。
2.新しいプロジェクト...を押す。
3.その他 -> .NET -> 全般 -> コンソール プロジェクトを選択し、次へを押す。
4.任意のプロジェクト名とソリューション名、場所を入力し作成を押す。
5.無事にプロジェクトが作成されたことを確認し、これでプロジェクトの作成は終了。
実装
作成したプロジェクトに対して、実装を始める。
コードの編集
program.csに対して、以下のコードを入力する。
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.IO; using System.Reflection; using System.Timers; namespace changeWall { public class program { /// <summary> /// タイマーの実行間隔(ミリ秒:指定した時間ごとに壁紙を変更する) /// </summary> static readonly int TIMER_INTERVAL = 60000; /// <summary> /// タイマー処理の繰り返し回数(今回の場合は60秒ごとに60回繰り返すため1時間程度動作することになる) /// </summary> static readonly int TIMER_INTERVAL_COUNT = 60; /// <summary> /// 壁紙変更関連定義 /// </summary> static readonly uint SPI_SETDESKWALLPAPER = 20; static readonly uint SPIF_UPDATEINIFILE = 1; static readonly uint SPIF_SENDWININICHANGE = 2; [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool SystemParametersInfo(uint uiAction, int uiParam, string pvParam, uint fWinIni); static void Main(string[] args) { // 埋め込みリソースの展開 var filePathList = new List<String>(); DeployEmbededJPGResources(filePathList); // 埋め込みリソースが1つもない場合は終了 if(filePathList.Count <= 0) { return; } // タイマーの処理 Timer timer = new Timer(TIMER_INTERVAL); int count = 0; bool result = true; timer.Elapsed += (sender, e) => { // 指定回数分繰りすか壁紙の変更に失敗した場合に終了 if (count >= TIMER_INTERVAL_COUNT || !result) { timer.Stop(); } else { // 壁紙を変更 count++; result = changeWall(filePathList, count); } }; // タイマーを開始する timer.Start(); // タイマー終了を待つ System.Threading.Thread.Sleep(TIMER_INTERVAL * TIMER_INTERVAL_COUNT); // 書き出したファイルを削除する foreach(var filePath in filePathList) { if (File.Exists(filePath)) { File.Delete(filePath); } } } /// <summary> /// 埋め込みリソース(拡張子がJPG)の展開 /// </summary> /// <param name="filePathList">展開した埋め込みリソースのパス</param> private static void DeployEmbededJPGResources(List<String> filePathList) { // 埋め込みリソース内のファイルを一時ファイルとして書き出す Assembly assembly = Assembly.GetExecutingAssembly(); string[] resourceNames = assembly.GetManifestResourceNames(); foreach (string resourceName in resourceNames) { // 拡張子がJPGのファイルのみを対象とする string extension = Path.GetExtension(resourceName); if(!extension.Equals(".jpg")) { continue; } // 一時フォルダへの書き出し Stream stream = assembly.GetManifestResourceStream(resourceName); string tmpFilePath = Path.GetTempFileName(); if (SaveFileStream(stream, tmpFilePath)) { filePathList.Add(tmpFilePath); } } } /// <summary> /// ストリーム情報を指定されたパスに書き出す /// </summary> /// <param name="stream"></param> /// <param name="path"></param> private static bool SaveFileStream(Stream stream, String path) { if(stream == null) { return false; } try { using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write)) { stream.CopyTo(fileStream); } } catch (Exception) { return false; } return true; } /// <summary> /// 壁紙の変更 /// </summary> /// <returns><c>true</c>, if wall was changed, <c>false</c> otherwise.</returns> /// <param name="filePathList">壁紙に適用するファイルパスのリスト</param> /// <param name="index">ファイルパスのリストに対するインデックス値</param> private static bool changeWall(List<string> filePathList, int index) { // 壁紙に適用するファイルが存在するかの確認 int targetFilePathIndex = index % filePathList.Count(); string targetFilePath = filePathList[targetFilePathIndex]; if(!File.Exists(targetFilePath)) { return false; } // 壁紙に適用 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, targetFilePath, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); return true; } } }
リソースファイルの埋め込み
1.プロジェクト -> 追加 -> ファイルを追加を選択する。
2.壁紙に設定する任意のファイル(拡張子がJPG)を追加する。
3.追加した画像に対して、プロパティを選択する。(この操作は追加した画像全てに必要)
4.ビルド アクションをEmbeddedResource(埋め込みリソース)に変更する。
UIの非表示設定
1.プロジェクト -> オプションを選択する。
2.ビルド -> 全般 -> コード生成 -> コンパイルのターゲットをGUI実行可能ファイルに変更して、OKボタンを押す。
以上で、実装は終了。
ビルド
1.ビルド構成をReleaseに変更する。
※開発環境以外で動作させるのであれば、必ずReleaseに変更すること。
逆に開発環境で実行する場合は、Debugでも問題なし。
2.ビルドを実行する。
3.プロジェクトフォルダ -> bin -> Releaseに拡張子がexeのファイルが出来上がるので、このファイルを実行対象の環境(Windows)にコピーしダブルクリック等で実行することで作成したアプリを動かすことができる。
補足事項
今回作成したアプリは、changeWall.exeになるため実行する側からすると何をするのかが推測しやすいので、あまり面白みがなくなってしまう。
詳しくは説明しないがRLOやらダミー動作を加えるともう少し面白くなるので、興味がある方はそちらのキーワードも調べてみるといいと思う。
※あまり怪しい動作を付け加えるとセキュリティソフトに誤検知される恐れがあるのでそこは注意してほしい。
(私も何度かこの手の誤検知にやられている。。。)