この間の無駄話で「現在開発中」

と書いたので、そろそろ始めないと不味いですよね?

 

という訳で、実際の開発速度に合わせて少しづつ描いてゆきましょう。

 

↑の無駄話で書いたように、プログラミングから大分ご無沙汰していたので「無理にでも書かなきゃ」「とはいえ、興味のないものは嫌だな」と思っていて、webをつらつらと見ていたら、

 

簡単なようで存外に奥が深そうな8パズル

に興味を覚えたので、

 

いつも通り、先ずはドンガラ

 

を先に開発し、解法や不可能配置の判定等実質的な機能付加は後でじっくりやりましょう、ということで始めました。

 

しかし、

 

↑のような1-8の数字だけが並んだようなパズルはいかにもやる気が起きません。

 

 

ということで、

 

(1)ウィンドウはダイアログベースの固定サイズ(サイズ変更を可能にしても、デメが多い割にメリットがほぼない為)

(2)数字ではなく、ユーザーが画像を選択し、それを3x3で切り分けで内部的に0-8の画像IDを振る。

(3)ゲームを開始する際に配置は0 - 8の配列のランダムな初期化で行う。

(4)操作はアクションゲームではなく、じっくり考えながら行うので、上下左右ボタンで空のピースを動かす。

(5)処理は、「画像選択(ボタン、ファイル投げ入れ起動、ドラッグアンドドロップのいずれも可)」→「開始」(但し、誤った画像選択もあり、この段階では「画像選択」を有効にする)→PCによる「終了判定」(不可配置、または完成)→「初期状態」の流れとする。

 

という

 

大雑把なイメージ

 

だけ決めて、先ずはドンガラを作り始めましたが、結構山あり谷ありでした。その理由は...

 

(1)ダイアログにボタンとピクチャーボックスを貼り付けるのは良いとして、どのように読み込んだ原画像をピクチャーボックスに合わせるのか?(サイズと縦横比)

(2)メンバーグラフィックオブジェクトの仕様問題・・・ピクチャーボックスはImageプロパティがあるので、それに仮想画面を貼り付けるが、これはImageクラスにすべきか、Bitmapクラスにすべきか?現画像は保持すべきか、分割画像はImageか、Bitmapか?(ここでトラブル発生!)

(3)分割画像をどう表示()するのか?8Puzzleの観掛けを出すために、分割画像をそれとわかるようにしたいが、どうすべきか?(ここでトラブル発生!)

:一旦仮想画面に描画して、それをピクチャーボックスに貼り付けるが、描画は変更部分のみか、全体か?変更部分のみであれば「空ピース」画像をどうする(取得?作成?)するか?

(4)画像選択ボタン(ファイル選択ダイアログ)、ドラッグアンドドロップは正常に画像が表示されるが、起動時にファイルをドロップしても画像が表示されない?(ここでトラブル発生!)

 

まっ、追い追い書いてゆきましょう。

 

ps. 実際のプログラミングは、ドンガラを作成しながら、現在初期画像(IDが0 - 8の分割画像配置)の為に「乱数を使い、0から8までの数を一つづつ(重複せずに)並べる」メソッドをコンソールでチェックし、結構驚くべき結果が出て面喰っています。

 

プログラミングをしていると、過去の自分のコードを見直すことが有り、

 

あれっ、これ(俺)ってすごいじゃん!

 

というように、若い頃のプログラムのスマートさに驚くことが有ります。

 

一方、

 

最近の私は大分(本ブログの本分である)プログラミングに億劫さを感じ始め、好奇心や創造の喜びを失いつつあることを認め、

 

諦めの境地

 

に入りかかっています。(実際最近プログラミングネタはご無沙汰ですよね?)

 

こんなことじゃいかんっ!

 

と自らを叱咤激励し、「なんでもいいから書こう!」ということで、お馴染みのパズル系ゲーム()でもと思い、webで物色して、所謂「8パズル」に決めました。

:C#では「ハノイの塔」(これはC++のBCCSkelton版-グラフィック版の方がかっこいいです))、「Othello」、「Maze」、「GhostLeg」(アミダクジ)、「Chinchirorin」(「麻雀放浪記」のオマージュ)、「Concentration」(神経衰弱)、「MoPai」(麻雀版の神経衰弱)等を作ってきました。

 

で、

 

やっと重い腰を上げて始めたのは良いのですが、大分C#の約束事や文法等を忘れてしまっていて、(自分で)WEBで調べる代わりに

 

あっちこっちに突っかかりながら、

 

そのたびに(自分でWeb調査する代わりにChat-GPT様に相談しながら(堕落したなぁ)

 

少しずつ組み上げている毎日です。

 

何れ、完成版とコードを公表できるといいなと思っています。

ps. 14年前(東関東大震災の年)に亡くなった愛犬(ポメラニアン-チャンピオン犬の娘という話でした)です。今もPCの待ち受け画面で私を慰めてくれています。

 

急性の胃腸炎でのたうち回った後、ビデオよりも読書に時間をかけてきました。そんな中でコメントに値すると思われる本について書きます。

 

1.騎士団長殺し

 

著者が大物すぎることと、往々にして長編で延々と続くので敬遠しがちになりますが、読めば望外に面白いので時々手頃そうなものを見繕って読みます。

このシリーズは、タイトルを知っている程度の知識でした。読み始めは、

 

とっつきにくいな。

 

というのが正直な感想でしたが、話が流れ始めてくると(所謂)"PAGE-TURNER"と化し、「もう止まらん、止まらん」ということで第1部「顕れるイデア編」を終了し、現在第2部の「還ろうメタファー編」を既に調達し、先行するキューに入った5冊を読んだら続きが読める状況です。ハッキリ言って、

 

楽しみっ!

 

という状況かな。

 

2.白日の鴉

 

著者の福沢徹三さんは存じ上げておらず、本屋で「厚さ」「タイトル」「概要」(そしてBookOffだったので「新しさ」)を見て買いましたが、

 

正直(정직)、得した気分!

 

四の五の言わず、展開やストーリー性、障害や伏線(及びその回収尾時期、方法)何れもよく楽しめるエンターテインメント性の高いドラマです。一方、刑事訴訟法や痴漢冤罪問題について結構勉強されて様で(特に男の人は切実な問題故)読んでいて損はないでしょう。

 

合格よっ‼

 

 

なんか、C#のクラス名のような題ですが、これには訳があります。

 

65歳でリタイアして(同時にコロナ禍)から、昔やったこと、昔出来なかったこと等をやり直してきましたが、昔苦手だったこと、避けていたこともこの際(無理して)再度学ぼうかと考えました。その意味で私が子供や学生の時に嫌いだったことは...

 

(1)地理、歴史等「社会科」(「じゃ、なんでお前が社会学部?」という突っ込みがありそうです。)

(2)法律(大学5年間~一年「麻雀学科」へ留学(留年)~で法律は2時間だけ授業に出ました-注)

(3)コンピューター

注:この時に出た科目は刑法各論でしたが、「男の髪を切っても暴行罪、女の髪を切ると傷害罪」という内容は今でも忘れていません!

 

(2)は保険屋に勤め始めてから、国内民法(特に契約法、不法行為法、親族編、会社法等)、英米法(New York、Singapore駐在)に長じることになりましたし、(3)に至ってはこのブログ等言わずもがなです。

 

が、

 

地理(「奥羽山脈を茶で、信濃川を水色で塗りなさい」は未だにトラウマ)、歴史(特に日本史)は未だに苦手意識があり、大学の入試では「年代記憶のマークシート」の学校は落ち、「自由論文形式」の学校に受かりました。

 

Nevertheless,

 

もう一度学習しなおそうということで(また、歳を取ってきて歴史にも興味が出てきたので)「自己学習」という形で(昔から)気になっていたことを学んでいこうと思っています。

 

ということで、

 

最近の学生がやるようにChat-GPT様に教えてもらいましょう。先ずは

 

世界史の中の欧州史

 

<私>

欧州のローマン、ノルマン、ゲルマン、ケルト等人種の流れを基に、言語、文化、国家の発展を解説してください。

 

<Chat-GPT様>

欧州の歴史的な言語、文化、国家の発展は、ローマン(ラテン系)ノルマン(ヴァイキング系)ゲルマンケルトなどの民族(あるいは文化的集団)の交流と衝突によって大きく形成されてきました。それぞれの民族は異なる言語や社会構造を持ち、相互に影響を与えながらヨーロッパ文明を築き上げてきました。以下に、それぞれの民族の特徴と、彼らが欧州に与えた影響を時代順に解説します。


1. ケルト(Celtic)

■ 時期:

先史時代~ローマ時代初期(紀元前1000年頃~紀元前1世紀)

■ 分布:

中央ヨーロッパからフランス(ガリア)、ブリテン諸島、イベリア北部、ガリシア地方まで広がった。

■ 言語・文化:

  • インド・ヨーロッパ語族ケルト語派

  • ドルイド僧による宗教・自然崇拝・口承文化

  • 金属細工や戦士文化に長けていた

■ 影響:

  • 現代でもアイルランド語、ウェールズ語、スコットランド・ゲール語に残る

  • フランスのブルターニュ地方やスペインのガリシアに文化的痕跡あり


2. ローマン(ラテン系・Roman)

■ 時期:

紀元前1世紀~5世紀(ローマ帝国時代)

■ 分布:

地中海世界全体、特に西ヨーロッパ(イタリア、フランス、スペインなど)

■ 言語・文化:

  • ラテン語(のちのロマンス諸語の基盤)

  • ローマ法、都市計画、道路網、建築、統治制度

  • キリスト教(ローマ帝政後期に国教化)

■ 影響:

  • ラテン語から派生したフランス語、スペイン語、イタリア語、ポルトガル語、ルーマニア語(ロマンス語派)

  • ヨーロッパの国家形成の制度的基盤を提供(法制度、行政)


3. ゲルマン(Germanic)

■ 時期:

紀元前数世紀~中世

■ 分布:

スカンジナビアからドイツ、オランダ、イングランド、フランス東部などに広がる

■ 言語・文化:

  • ゲルマン語派(古英語、古高ドイツ語、ゴート語など)

  • 戦士階級社会、氏族制

  • キリスト教受容後にラテン文化を取り込む

■ 影響:

  • ローマ崩壊後、西欧にゲルマン王国(フランク王国、ヴァンダル王国など)を建国

  • 現代のドイツ語、英語、オランダ語、スカンジナビア諸語の起源

  • 封建制度の原型(忠誠と封土の関係)


4. ノルマン(Norman/ヴァイキング系)

■ 時期:

8世紀~11世紀(ヴァイキング時代)

■ 分布:

スカンジナビア半島出身、イギリス、アイルランド、ノルマンディー(フランス北部)、南イタリア、シチリアまで展開

■ 言語・文化:

  • 古ノルド語(ゲルマン語派の一種)

  • 航海・略奪・交易に優れた海洋民族

  • ノルマン人はフランス語化(ノルマン・フレンチ)し、文化的融合を果たす

■ 影響:

  • 1066年のノルマン・コンクエストによってイングランド文化に大変革(英語に大量のフランス語語彙が流入)

  • ノルマンディー公国 → イングランド王国の一体化

  • シチリア王国など地中海世界でも多文化融合政権を形成


各文化の影響による国家形成の流れ

地域 古代 中世 国家形成・近世
イギリス ケルト → ローマ ゲルマン(アングロ・サクソン)、ノルマン イングランド王国 → イギリス帝国
フランス ケルト(ガリア)→ ローマ フランク王国(ゲルマン) フランス王国
ドイツ ケルト・ゲルマン混在 → ローマ一部 神聖ローマ帝国(ゲルマン) ドイツ諸邦 → ドイツ帝国
イタリア エトルリア・ローマ 諸侯国家分立、ノルマン進出(南部) イタリア統一運動
スペイン ケルト・イベリア → ローマ 西ゴート王国(ゲルマン) レコンキスタ後の統一王国

言語進化の概要図(単純化)

印欧語族 ├─ ケルト語派 → アイルランド語、ウェールズ語など

 ├─ ラテン語(ローマ)→ ロマンス語派(仏・西・伊など)

 ├─ ゲルマン語派 │

 │        ├─ 西ゲルマン語 → 英語、ドイツ語、オランダ語

 │        └─ 北ゲルマン語 → スウェーデン語、ノルウェー語など 

 └─ スラヴ語派(東欧、別途展開)


総合的な文化・国家発展への影響

  • ローマ帝国がインフラ(道路、法、都市)と共通言語(ラテン語)を広めた

  • ゲルマン民族の大移動によって西ローマ崩壊 → 中世封建制度と王国の発展

  • ノルマンの進出が言語的・文化的融合を促進(特に英語文化圏)

  • ケルト文化は支配的ではなかったが、地域文化の個性を今なお残す


 

矢張り、Chat-GPTは賢いなぁ。

 

ブログの引き出しは多い方が良いだろうと、私のanother「得意技」である、

 

お酒

 

の話をつらつらと書いてゆこうかと。

 

先ずは簡単な履歴から...

 

(1)最初にお酒を口に入れたのは、小学校低学年で隠れて「赤玉ポートワイン」をキャップに入れて飲んだ時。この手の盗みのみは枚挙にいとまがなく、叔母のカクテル用CINZANOやViolet(正式の名称はBols Parfait Amour)等もやってました。(まぁ、子供ですから甘いのが良かったのですね。)

 

(2)真面目にお酒を飲んで盛大に吐いたのは高2の時だったか。宝酒造の合成焼酎を仲間と友人の下宿で。土曜の昼から飲んで、夜までノックアウト。

 

(3)普通に飲むようになったのは大学に入ってからかな?普通に飲んで、普通に吐いた。大体、私はお酒に強くはなかったのですが、飲んでゆくうちに耐性が付いたのかもしれません。

 

(4)勤めるようになって毎晩飲むようになりましたね。その為に入社二年目にして赤い鼻で出社、「腎性糖尿」と診断され、原因は飲み過ぎ。翌年はとうとう痔瘻迄発病し入院。(女子社員のお見舞いに困惑しました。)

 

(5)爾来55年超、一年365日、12カ月、週7日、古日も照る日も病気でない限り(先日の急性胃腸炎の時は休みました)、毎晩飲み続けています。(神様は新婚の時、当時2-3,000円するオールド等が2-3日で空いてゆくので~外で飲んでから家でも飲んでいたので~狂ったように怒りました。)

 

(6)私は神に守られているのか、20代で酒の為に病になりましたが、その後肝臓、膵臓、腎臓等アルコール消化臓器の検査値は正常のまま現在(毎夕2~3合を晩酌)に至ります。(家庭医にも検診時に「また毎日飲んでいますか?」と訊かれます。昔は休肝日を設けろとか、肝臓を休ませろとか医者に言われましたが、余命が少なくなると好きに生きさせてくれるようです。)

 

(7)現在は、

 ①一番好きなDewars 12年もののハイボール(4-5杯)で、時々オンザロックを御猪口1杯

 ②缶ビールでスタートして日本酒1合(正月は燗、後は冷)

 ③缶ビールでスタートして赤|白ワイン1合

 ④夏場はウオッカベースでウオッカトニックやブラッディメァリー

 

のラインアップ。

 

 

少々マンネリ化

 

を嘆いていたのですが、突然神が下りてきて

 

そうだ、カクテルに挑もう!

 

ということで、発作的にAmazonで(ドライかスウィートか、で悩んだのですが...)ポチっと。

 

ベルモット(結局スウィートのCINZANOロッソにしました)

を買ってしまいました。そして、

 

Manhattan = Whiskey + Vermouth(甘いが、少量を舐めるなら秀逸!)

(Vodka) Martini = Vodka + Vermouth(ドライに未練があったが、スウィートでも結構いけます)

 

を楽しんでいます。

 

さて、次は何にしようかな?

 

ps. なお、このブログは神様は見ていません。

前々回前回でMSBild.exeを(スイッチ文付きで)実行するソフトウェアが出来ました。

 

ところがっ!

 

手元にあった一部のサンプルでエラーがでてしまいました。

 

エラー表示を見てみると、

状態ファイル "obj\Debug\contour.csproj.GenerateResource.Cache" を読み取ることができませんでした。この状態ファイルの形式は無効です。

とあり、更に

C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets(1682,9): error MSB3091: "resgen.exe" が見つからなかったため、または正し い Microsoft Windows SDK がインストールされていないため、タスクが失敗しました。

とされました。即ち「resgen.exe が無いので、contour.csproj.GenerateResource.Cache を読み取ることが出来ない」ということのようです。

 

念の為、バッチファイルでビルドしてみても矢張り(MSBuilderの所為ではなく)エラーになります。

 

そして↑に書いた通り、

その原因は、

error MSB3091: "resgen.exe" が見つからなかったため、または正しい Microsoft Windows SDK がインストールされていないため、タスクが失敗しました。

タスクは、レジストリ キー HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A\WinSDK-NetFx35Tools-x86 の値 InstallationFolder で指定された場所の下にある "bin" サブディレクトリで "Resgen.exe" を探しています。

次のいずれかを行うことによって問題を解決できる可能性があります。

1) Microsoft Windows SDK をインストールする。

2) Visual Studio 2010 をインストールする。

3) 上記のレジストリ キーを正しい場所に手動で設定する。

4) 正しい場所をタスクの "ToolPath" パラメーターに渡す。

 

対策にある1)2)は「現在のWindows 11環境をWindows 7時代に戻す」ことに等しく、3)の「レジストリーをマニュアルで弄る」のと同様に危険である為、4)の「(xamlファイルを弄って)現在のMSBuildを使って、現在のResGen.exeを使う」ことで対処できないか、色々と試し、またChat-GPT様にも相談しました。

:私の場合、"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools"ResGen.exeがあります。

 

(益のない)長い話になるので、"To tell you a long story short"、xamlファイル(*.csproj)を弄って"ToolPath"が通るように試したのですが、

 

<PropertyGroup>
  <!-- ResGen.exe のあるパス(binまで。末尾に \ は不要)-->

  <ResGenToolPath>C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools</ResGenToolPath>
</PropertyGroup>

<Target Name="OverrideResGenToolPath" BeforeTargets="CoreResGen">
  <PropertyGroup>

    <ToolPath>$(ResGenToolPath)</ToolPath>
  </PropertyGroup>
</Target>

 

何ら変化はなく、同じエラーが出続けます。Chat-GPT様も、

ビルドは通ったと思ったが、実際には resgen.exe 関連のエラーがまだ出力されているという状況ですね。

これは、ToolPath の指定がうまく働いていない、または 正しいプロパティが ToolPath として使われていない 可能性が高いです。

ということで、色々とアイデアは出されますが、結局改善には至りませんでした。

 

因みにこのエラーが出た.NETFramework3.5のxamlファイルは次のようになっています。

"<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>9.0.21022</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{2E9403D0-057D-4350-861F-094BB0B338E5}</ProjectGuid>
    <OutputType>WinExe</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>contour</RootNamespace>
    <AssemblyName>contour</AssemblyName>

    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core">

      <RequiredTargetFramework>3.5</RequiredTargetFramework>
    </Reference>
    <Reference Include="System.Xml.Linq">

      <RequiredTargetFramework>3.5</RequiredTargetFramework>
    </Reference>
    <Reference Include="System.Data.DataSetExtensions">

      <RequiredTargetFramework>3.5</RequiredTargetFramework>
    </Reference>
    <Reference Include="System.Data" />
    <Reference Include="System.Deployment" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.Windows.Forms" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Form1.cs">
      <SubType>Form</SubType>
    </Compile>
    <Compile Include="Form1.Designer.cs">
      <DependentUpon>Form1.cs</DependentUpon>
    </Compile>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <EmbeddedResource Include="Form1.resx">
      <DependentUpon>Form1.cs</DependentUpon>
    </EmbeddedResource>
    <EmbeddedResource Include="Properties\Resources.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
      <SubType>Designer</SubType>
    </EmbeddedResource>
    <Compile Include="Properties\Resources.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>
    <None Include="Properties\Settings.settings">
      <Generator>SettingsSingleFileGenerator</Generator>
      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
    </None>
    <Compile Include="Properties\Settings.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Settings.settings</DependentUpon>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
    </Compile>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>
”(

:今回作成したMSBuilderが使うMSBild.exeと、それが対象とするNETFrameworkのバージョンは次の通り。

Microsoft (R) Build Engine バージョン 4.8.9032.0
[Microsoft .NET Framework、バージョン 4.0.30319.42000]
Copyright (C) Microsoft Corporation. All rights reserved.

で、ResGen.exeも"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools"にしっかりと入っています。

 

これに対して、正常にビルドできるxamlファイルは次のようになっています。

 

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="
15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{F09A8C71-6DEE-4F19-B480-885FE61BC719}</ProjectGuid>
    <OutputType>WinExe</OutputType>
    <RootNamespace>WeatherChecker</RootNamespace>
    <AssemblyName>WeatherChecker</AssemblyName>
    <TargetFrameworkVersion>
v4.7.2</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
      <HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Deployment" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Windows.Forms" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Form1.cs">
      <SubType>Form</SubType>
    </Compile>
    <Compile Include="Form1.Designer.cs">
      <DependentUpon>Form1.cs</DependentUpon>
    </Compile>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <EmbeddedResource Include="Form1.resx">
      <DependentUpon>Form1.cs</DependentUpon>
    </EmbeddedResource>
    <EmbeddedResource Include="Properties\Resources.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
      <SubType>Designer</SubType>
    </EmbeddedResource>
    <Compile Include="Properties\Resources.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>
    <None Include="packages.config" />
    <None Include="Properties\Settings.settings">
      <Generator>SettingsSingleFileGenerator</Generator>
      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
    </None>
    <Compile Include="Properties\Settings.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Settings.settings</DependentUpon>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>”

 

.NETFrameworkのバージョン差は3.5対4.7.2ですが、ToolVersionが3.5に対して15.0と大きく違っており、xamlファイル自体にも差が生じていることから、ここは

 

諦めが肝心

 

ということで、

 

旧い.NETFrameworkのプロジェクトファイルはビルドできません

 

それは

 

僕の所為じゃなく、Microsoftに言って下さい。

 

ということでこのシリーズを終了します。

 

ps. Microsoftを非難しているわけではなく、.NETFramework自体が過去の遺物になっているからです。(その後、.NET_Core~.NETに進化しています。)

.NET Framework、.NET Core、そして現在では単に .NET と呼ばれるものは、すべてマイクロソフトが開発したプラットフォームです。以前は .NET Framework が主流でしたが、その後の後継バージョンとして .NET Core が登場し、現在では両者が統合された .NET が開発の標準として使われています。」(Search Lab)

寧ろ、未だに.NETFrameworkがあり、それがビルドできることに感謝しなければならないのでしょう。

 

前々から

 

気になっていた

 

のですが、

 

.「BCCForm and BCCSkeltonサポートセンター」というタイトルは、公開しているBorland C++コンパイラー(当時-現Embarcadero C++ コンパイラー)用ライブラリーパッケージのサポートが目的だったのですが、既に公開から二十余年が経過し、あの強欲だったMicrosoftもCommunity版でロハの各種言語用IDEであるVisual Studioを提供している現在、(正直)世の中から求められていないことは身に染みています。(泣;)

 

.但し、BCCForm and BCCSkeltonを通じてC++にせよ、BCCForm and BCCSkeltonパッケージの「MSCompAss」アプリでコンパイルできるC#にせよ、プログラミングネタはそれなりに読者の関心があることは承知しています。

 

.また、話のテーマもプログラミングだけでは足らず、【無駄話】【食い物話】【Psycho】等、プログラミングとはやや離れた問題も取り上げてきていることから、

 

この際、実態に即したネーミングにしよう!

 

ということで、本ブログのタイトルを変えてみました。

 

最初は「瘋癲老人日記」にしようかな、とおもっていたのですが、これは同名の谷崎潤一郎の変態エロ爺小説があり、"afraid of possible infringement of his copyright" 観点 から、また↑の様にC言語、C++言語、C#(C++++)言語

などを扱っていることからも、

 

C調老人日記

 

で決めてみました!

 

What do you think?

 

本日【MSBuilder】ちょびっと改良...で「わたしゃ面倒なので、これで結構ですわ。」とか書きましたが、最後の注を書いたらなんだか美しくないコードを書いた罪の意識が強く...書き直しました。

 

1.ファイルを読み込み、引数を設定する共通メソッド

 

  これはMSBクラスの最後に置いています。

 

        //ファイルからビルド用ファイル名とスイッチを取得
        private void SetArg(string arg)
        {
            string ext = Path.GetExtension(arg);
            if(ext == ".MSB" || ext == ".msb")
            {
                //MSBDataFileを記録し、TargetFileとSwitchを読み込み、設定する
                MSBDataFile = arg;
                string InFile = File.ReadAllText(MSBDataFile, Encoding.GetEncoding("shift-jis"));
                string[] tokens = Regex.Split(InFile, @"\r\n|=");            //改行または'='をセパレーターとして分割する
                if(tokens[0] == "TargetFile" && tokens[2] == "MSBSwitch")    //出力形式が合う場合
                {
                    //slnまたはprojファイル名を記録
                    tssl[1].Text = TargetFile = tokens[1];
                    tssl[1].ToolTipText = TargetFile;    //ToolTip設定
                    //スイッチ文を記録
                    MSBSwitch = tokens[3];
                    //slnまたはprojファイルを表示
                    txtBox.Text = File.ReadAllText(TargetFile, Encoding.GetEncoding("shift-jis"));
                }
                else
                    MessageBox.Show("正しいmsbファイルパスではありません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else if(ext == ".CSPROJ" || ext == ".csproj" || ext == ".SLN" || ext == ".sln")
            {
                //slnまたはprojファイル名を記録
                tssl[1].Text = TargetFile = arg;
                tssl[1].ToolTipText = TargetFile;    //ToolTip設定
                //slnまたはprojファイルを表示
                txtBox.Text = File.ReadAllText(TargetFile, Encoding.GetEncoding("shift-jis"));
                MSBSwitch = "";                        //MSBSwitchを初期化する
                MSBDataFile = "";                    //MSBDataFileを初期化する
                MessageBox.Show("現在のビルド情報は「保存」しなければ失われてしまいます。\r\n必ず「保存」してください。", "注意", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
                MessageBox.Show("正しいビルド用ファイルパスではありません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
 

2.「ファイルを開く」からの呼び出し

 

  随分スッキリしました。

 

        //「ファイルを開く」処理
        private void OnOpen_Click(object sender, EventArgs e)
        {
            //ファイル選択ダイアログの設定
            OpenFileDialog ofDlg = new OpenFileDialog();
            //ファイルフィルターの指定
            ofDlg.FilterIndex = 1;            //フィルター選択番号
            ofDlg.Filter = "ビルド用ファイル(*.csproj, *.sln)|*.csproj;*.sln|msbファイル(*.msb)|*.msb";    //解説:一つに纏めました。
            ofDlg.RestoreDirectory = true;    //初期ディレクトリへ復帰
            ofDlg.CheckPathExists = true;    //ファイルパスの存在チェック
            ofDlg.InitialDirectory = ".";    // デフォルトのフォルダーの指定
            ofDlg.Title = "ファイルを開く";    //ダイアログのタイトルを指定する
            if(ofDlg.ShowDialog() == DialogResult.Cancel)    //ダイアログを表示する
            {
                MessageBox.Show("キャンセルされました。", "キャンセル", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            else
            {
                SetArg(ofDlg.FileName);    //解説:一行になりました。
            }
            // オブジェクトを破棄する
            ofDlg.Dispose();
        }

 

3.ファイルパスが引数で与えられて起動する場合

 

  ファイルパスが文字列配列で与えられるのですが、結局ループさせても最後のものしか使われないので。

 

            //2025年05月05日追加(MSB_Loadの最後に追加する)
            //起動時の引数をチェックし、引数にファイル名があればそれを読み込む

            string[] arg = System.Environment.GetCommandLineArgs();
            //ドロップされた(最後の)ファイルパスを取得
            if(arg.Length > 1)
                SetArg(arg[arg.Length - 1]);

4.ファイルパスがドラッグアンドドロップで与えられた場合

 

  これもファイルパスが文字列配列で与えられるのですが、結局ループさせても最後のものしか使われないので。

 

        //txtBoxにドロップされたとき
        private void TB_DragDrop(object sender, DragEventArgs e)
        {
            //ドロップされた(最後の)ファイルパスを取得
            string[] ddlist =  (string[])e.Data.GetData(DataFormats.FileDrop, false);
            SetArg(ddlist[ddlist.Length - 1]);
        }

 

綺麗にまとめることが出来ましたが、勿論、ちゃんと動いていますよ。(結局、僕って貧乏性?)

 

前回の「【MSBuilder】MSBuildの機能を実装する」のプログラムを使っていたら、ちょっと不満があったので、

 

ちょびっと改良

 

することにしました。その内容は、

 

(1)MSBuilder用のmsbファイルやビルド用のcsproj | slnファイルを与えて起動出来るようにする。

(2)同様にこれらのファイルをドラッグアンドドロップ出来るようにする。

 

だけです。(でも、これらをつけるとちょっと使い勝手が良くなります。)

 

変更点だけ、↓に記します。

 

            //Drag and Dropのイベントハンドラの追加(2025年05月05日追加-MSB_Loadに追加する))
            txtBox.DragEnter += new DragEventHandler(TB_DragEnter);
            txtBox.DragDrop += new DragEventHandler(TB_DragDrop);
            txtBox.AllowDrop = true;

            //2025年05月05日追加(MSB_Loadの最後に追加する)
            //起動時の引数をチェックし、引数にファイル名があればそれを読み込む

            string[] arg = System.Environment.GetCommandLineArgs();
            if(arg.Length > 1)
            {
                string ext = Path.GetExtension(arg[1]);
                if(ext == ".MSB" || ext == ".msb")
                {
                    //MSBDataFileを記録し、TargetFileとSwitchを読み込み、設定する
                    MSBDataFile = arg[1];
                    string InFile = File.ReadAllText(MSBDataFile, Encoding.GetEncoding("shift-jis"));
                    string[] tokens = Regex.Split(InFile, @"\r\n|=");            //改行または'='をセパレーターとして分割する
                    if(tokens[0] == "TargetFile" && tokens[2] == "MSBSwitch")    //出力形式が合う場合
                    {
                        //slnまたはprojファイル名を記録
                        tssl[1].Text = TargetFile = tokens[1];
                        tssl[1].ToolTipText = TargetFile;    //ToolTip設定
                        //slnまたはprojファイル名を表示
                        txtBox.Text = File.ReadAllText(TargetFile, Encoding.GetEncoding("shift-jis"));
                        MSBSwitch = tokens[3];
                    }
                }
                else if(ext == ".CSPROJ" || ext == ".csproj" || ext == ".SLN" || ext == ".sln")
                {
                    //slnまたはprojファイル名を記録
                    tssl[1].Text = TargetFile = arg[1];
                    tssl[1].ToolTipText = TargetFile;    //ToolTip設定
                    //slnまたはprojファイル名を表示
                    txtBox.Text = File.ReadAllText(TargetFile, Encoding.GetEncoding("shift-jis"));
                    MSBSwitch = "";                        //MSBSwitchを初期化する
                    MSBDataFile = "";                    //MSBDataFileを初期化する
                    MessageBox.Show("現在のビルド情報は「保存」しなければ失われてしまいます。\r\n必ず「保存」してください。", "注意", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                    MessageBox.Show("ファイルパスでない文字列です。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
 

        //2025年05月05日追加(MSBクラスの最後に追加する)
        ///////////////////////////
        //コントロール関連メソッド
        ///////////////////////////
        //txtBoxにドラッグされた時

        private void TB_DragEnter(object sender, DragEventArgs e)
        {
            if(e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }

        //txtBoxにドロップされたとき
        private void TB_DragDrop(object sender, DragEventArgs e)
        {
            //ドロップされたファイルパスを取得
            string[] ddlist =  (string[])e.Data.GetData(DataFormats.FileDrop, false);
            foreach(string dd in ddlist)
            {
                string ext = Path.GetExtension(dd);
                if(ext == ".MSB" || ext == ".msb")
                {
                    //MSBDataFileを記録し、TargetFileとSwitchを読み込み、設定する
                    MSBDataFile = dd;
                    string InFile = File.ReadAllText(MSBDataFile, Encoding.GetEncoding("shift-jis"));
                    string[] tokens = Regex.Split(InFile, @"\r\n|=");            //改行または'='をセパレーターとして分割する
                    if(tokens[0] == "TargetFile" && tokens[2] == "MSBSwitch")    //出力形式が合う場合
                    {
                        //slnまたはprojファイル名を記録
                        tssl[1].Text = TargetFile = tokens[1];
                        tssl[1].ToolTipText = TargetFile;    //ToolTip設定
                        //slnまたはprojファイル名を表示
                        txtBox.Text = File.ReadAllText(TargetFile, Encoding.GetEncoding("shift-jis"));
                        MSBSwitch = tokens[3];
                    }
                }
                else if(ext == ".CSPROJ" || ext == ".csproj" || ext == ".SLN" || ext == ".sln")
                {
                    //slnまたはprojファイル名を記録
                    tssl[1].Text = TargetFile = dd;
                    tssl[1].ToolTipText = TargetFile;    //ToolTip設定
                    //slnまたはprojファイル名を表示
                    txtBox.Text = File.ReadAllText(TargetFile, Encoding.GetEncoding("shift-jis"));
                    MSBSwitch = "";                        //MSBSwitchを初期化する
                    MSBDataFile = "";                    //MSBDataFileを初期化する
                    MessageBox.Show("現在のビルド情報は「保存」しなければ失われてしまいます。\r\n必ず「保存」してください。", "注意", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                    MessageBox.Show("ファイルパスでない文字列です。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
 

単純にコピペで追加したので「ファイルを開く」と同じ、または同様のコードが3つもできてしまいました。サイズを気にされたり、似たコードは纏めたい方はこれを一つのメソッドにして呼び出すように変更(注)してください。(わたしゃ面倒なので、これで結構ですわ。)

注:1ファイル版を用意して、起動時とドラッグアンドドロップはforeachでループさせるのが一番かと...

前回SDIエディターウィンドウの「ドンガラ」を作ったので、今度はMSBuild()を実行できるようにします。

:Visual Studioなどでは様々なバージョンのMSBuildがxamlコードで使えるのかもしれませんが、今回は話を簡単にするため、

現在使用中のC#コンパイラー(C#5のcsc.exe)と同じ場所にあるMSBuildを使うことにします。(この話は最終回にしましょう。)

 

前回のコードで、

 

MessageBox.Show("ゴメンナサイ。まだできていません。", "工事中", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);」

 

にしていた、

        //「ファイルを開く」処理
        //「保存」処理
        //「設定」処理
        //「スイッチ」処理
        //「実行」処理
        //「使い方」処理

というメニューを選択したり、ツールバーボタンを押したりという「ウィンドウズの割込み機能で」で呼び出される関数の内容、及びスイッチ文を入力するダイアログクラス(SwitchDlg)もコメント解説:で説明します。

 

先ずはメニューやツールバーボタンを押した際に呼び出される割込み処理関数の実装から。

 

        //「ファイルを開く」処理
 
       private void OnOpen_Click(object sender, EventArgs e)
        {
            //先ず*.msbファイルか、ビルド用ファイルかの確認を行う
            DialogResult dr = MessageBox.Show("MSBuilder用ファイル(*.msb)を開きますか?(「はい」)\r\nそれともビルド用ファイル(*.csproj | sln)ですか?(「いいえ」)", "ファイル種類確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            //msbファイルの場合
            if(dr == DialogResult.Yes)
            {
                OpenFileDialog ofDlg = new OpenFileDialog();
                //ファイルフィルターの指定
                ofDlg.FileName = "*.msb";        //拡張子
                ofDlg.Filter = "msbファイル(*.msb)|*.msb";    //解説:表示用のフィルターの設定です。
                ofDlg.RestoreDirectory = true;    //初期ディレクトリへ復帰
                ofDlg.CheckPathExists = true;    //ファイルパスの存在チェック
                ofDlg.InitialDirectory = ".";    // デフォルトのフォルダーの指定
                ofDlg.Title = "ファイルを開く";    //ダイアログのタイトルを指定する
                if(ofDlg.ShowDialog() == DialogResult.Cancel)    //ダイアログを表示する
                {
                    MessageBox.Show("キャンセルされました。", "キャンセル", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                {
                    //MSBDataFileを記録し、TargetFileとSwitchを読み込み、設定する
                    MSBDataFile = ofDlg.FileName;
                    string InFile = File.ReadAllText(MSBDataFile, Encoding.GetEncoding("shift-jis"));
                     //解説:Win32のGetPrivateProfileStringで扱うiniファイルの様にしてみました。

                     //解説:ファイルに次の様に書かれていることを想定しています。

                     //解説:"TargetFile=(文字列データ-ファイルパス)"

                     //解説:"MSBSwitch=(文字列データスイッチ文)"

                     //解説:同様にiniファイルの様にした「保存」も参照して下さい。

                    string[] tokens = Regex.Split(InFile, @"\r\n|=");            //改行または'='をセパレーターとして分割する
                    if(tokens[0] == "TargetFile" && tokens[2] == "MSBSwitch")    //出力形式が合う場合
                    {
                        //slnまたはprojファイル名を記録
                        tssl[1].Text = TargetFile = tokens[1];
                        tssl[1].ToolTipText = TargetFile;    //ToolTip設定
                        //slnまたはprojファイル名を表示
                        txtBox.Text = File.ReadAllText(TargetFile, Encoding.GetEncoding("shift-jis"));
                        MSBSwitch = tokens[3];
                    }
                    else
                    {
                        MessageBox.Show("msbファイル形式ではありません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                //オブジェクトを破棄する
                ofDlg.Dispose();
            }
            //ビルド用ファイルの場合
            else
            {
                //プロジェクト(*.csproj)ファイルかソリューションファイル(*.sln)か確認する
                dr = MessageBox.Show("csprojファイルを開きますか?(「はい」)\r\nそれともslnファイルですか?(「いいえ」)\r\n或いは中止しますか?(「キャンセル」)", "ファイル種類確認", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
                OpenFileDialog ofDlg = new OpenFileDialog();
                switch(dr)
                {
                case DialogResult.Yes:
                    ofDlg.FileName = "*.csproj";//拡張子
                    ofDlg.FilterIndex = 1;        //ファイルフィルターインデックス
                    break;
                case DialogResult.No:
                    ofDlg.FileName = "*.sln";    //拡張子
                    ofDlg.FilterIndex = 2;        //ファイルフィルターインデックス
                    break;
                default:
                    return;
                }
                //ファイルフィルターの指定
                ofDlg.Filter = "csprojファイル(*.csproj)|*.csproj|slnファイル(*.sln)|*.sln";
                ofDlg.RestoreDirectory = true;    //初期ディレクトリへ復帰
                ofDlg.CheckPathExists = true;    //ファイルパスの存在チェック
                ofDlg.InitialDirectory = ".";    // デフォルトのフォルダーの指定
                ofDlg.Title = "ファイルを開く";    //ダイアログのタイトルを指定する
                if(ofDlg.ShowDialog() == DialogResult.Cancel)    //ダイアログを表示する
                {
                    MessageBox.Show("キャンセルされました。", "キャンセル", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                {
                    //slnまたはprojファイル名を記録
                    tssl[1].Text = TargetFile = ofDlg.FileName;
                    tssl[1].ToolTipText = TargetFile;    //ToolTip設定
                    //slnまたはprojファイルを表示し、新しいファイルなので初期化する
                    txtBox.Text = File.ReadAllText(ofDlg.FileName, Encoding.GetEncoding("shift-jis"));
                    MSBSwitch = "";                        //MSBSwitchを初期化する
                    MSBDataFile = "";                    //MSBDataFileを初期化する
                    MessageBox.Show("現在のビルド情報は「保存」しなければ失われてしまいます。\r\n必ず「保存」してください。", "注意", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                // オブジェクトを破棄する
                ofDlg.Dispose();
            }
        }

        //「保存」処理
 
       private void OnSave_Click(object sender, EventArgs e)
        {
            //MSBDataFileにTargetFileとSwitchを保存する
            if(MSBDataFile != "")    //解説:既に*.msbファイルが設定されている場合
            {
                using(FileStream fs = new FileStream(MSBDataFile, FileMode.OpenOrCreate))
                {
                    using(StreamWriter file = new StreamWriter(fs, Encoding.GetEncoding("shift-jis")))
                    {
                        // ファイルを書き込む

                       //解説:"TargetFile=(文字列データ-ファイルパス)"

                       //解説:"MSBSwitch=(文字列データスイッチ文)"

                        file.Write("TargetFile=");
                        file.WriteLine(TargetFile);        //ビルド用ファイル
                        file.Write("MSBSwitch=");
                        file.WriteLine(MSBSwitch);        //ビルド用スイッチ
                    }
                    //ファイルクローズ
                    fs.Close();
                    fs.Dispose();
                }
            }
            //MSBDataFileが""であれば、名前を付けてTargetFileとSwitchを保存する
            else
            {
                SaveFileDialog sfDlg = new SaveFileDialog();
                //ファイルフィルターの指定
                sfDlg.AddExtension = true;        //拡張子自動付加
                sfDlg.DefaultExt = "msb";
                sfDlg.Filter = "msbファイル(*.msb)|*.msb";
                sfDlg.FilterIndex = 1;            
                sfDlg.RestoreDirectory = true;    //初期ディレクトリへ復帰
                sfDlg.CheckPathExists = true;    //ファイルパスの存在チェック
                sfDlg.InitialDirectory = ".";    // デフォルトのフォルダーの指定
                sfDlg.Title = "MSBデータファイルを保存";        //ダイアログのタイトルを指定する
                sfDlg.OverwritePrompt = true;                    //上書き確認
                if(sfDlg.ShowDialog() == DialogResult.Cancel)    //ダイアログを表示する
                {
                    MessageBox.Show("キャンセルされました。", "キャンセル", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                {
                    MSBDataFile = sfDlg.FileName;
                    using(FileStream fs = new FileStream(MSBDataFile, FileMode.OpenOrCreate))
                    {
                        using(StreamWriter file = new StreamWriter(fs, Encoding.GetEncoding("shift-jis")))
                        {
                            //ファイルを書き込む

                            //解説:"TargetFile=(文字列データ-ファイルパス)"

                            //解説:"MSBSwitch=(文字列データスイッチ文)"

                            file.Write("TargetFile=");
                            file.WriteLine(TargetFile);        //ビルド用ファイル
                            file.Write("MSBSwitch=");
                            file.WriteLine(MSBSwitch);        //ビルド用スイッチ
                        }
                        //ファイルクローズ
                        fs.Close();
                        fs.Dispose();
                    }
                }
            }
        }

        //「設定」処理
 
       private void OnSetUp_Click(object sender, EventArgs e)
        {
            
//64bit版MSBuildまたは32bit版に設定する
            string msg = "現在のMSBuildへのパスは、\r\n\"" + MSBPath +"\"\r\nとなっています。\r\n64bitにしますか?(「はい」)\r\nそれとも32bitですか?(「いいえ」))";
            DialogResult dr = MessageBox.Show(msg, "Framework種類確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if(dr == DialogResult.Yes)
                MSBPath = @"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\";
    //解説:64bit版のファイルパスです。
            else
                MSBPath = @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\";
    //解説:32bit版のファイルパスです。
        }

        //「スイッチ」処理
        private void OnSwitch_Click(object sender, EventArgs e)
        {
            SwitchDlg SwtDlg = new SwitchDlg(MSBSwitch);    
//スイッチダイアログを呼び出す
            SwtDlg.ShowDialog();
            MSBSwitch = SwtDlg.Switch;                      
 //スイッチ文を引き取る
            SwtDlg.Dispose();
        }


        //「実行」処理
        private void OnExec_Click(object sender, EventArgs e)

        {
            string msg = TargetFile + "\r\nをビルドします。\r\n", stdoutput, stderr;
            if(MSBSwitch == "")
                msg += "指定されたスイッチはありません。\r\n宜しいですか?";
            else
                msg += "指定されたスイッチは\r\n" + MSBSwitch + "\r\nです。\r\n宜しいですか?";
            DialogResult dr = MessageBox.Show(msg, "MSBuildのスイッチ確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);    //解説:ビルド用ファイルとスイッチ文を表示して実行可否を確認します。
            if(dr == DialogResult.Yes)
            {
                //コマンドライン引数を指定してMSBuildを起動する
                ProcessStartInfo startInfo = new ProcessStartInfo()
                {    FileName = MSBPath + "msbuild.exe",    //解説:あらかじめ設定したファイルパスにファイル名を付加します。
                    Arguments = "\"" + TargetFile + "\" " + MSBSwitch,    //解説:スイッチ文を引数として追加します。
                    UseShellExecute = false,    //解説:コンソールは表示しません。
                    RedirectStandardOutput = true,    //解説:MSBuildからの出力を取得します。
                    RedirectStandardError = true    //解説:MSBuildがエラーとなった時のエラー出力を取得します。
                };
                using(Process process = Process.Start(startInfo))    //解説:try~catch~finallyと同じです。
                {
                    stdoutput = process.StandardOutput.ReadToEnd();    //結果出力
                    stderr = process.StandardError.ReadToEnd();        //エラー出力(あれば)
                    process.WaitForExit();                            //終了待機
                }
                //MSBuildからの出力結果とエラーを表示
                txtBox.Text = "【出力結果】\r\n" + stdoutput + "\r\n【エラー】\r\n" + stderr;
            }
            else
                txtBox.Text = "ビルドは中止されました。";
        }

        //「使い方」処理
        private void OnHowtoUse_Click(object sender, EventArgs e)

        {
            Help.ShowHelp(txtBox, @".\MSBuilderHelp.chm");    //ヘルプ表示(*.chmファイル)-解説:Microsoft HTML ヘルプ (hh.exe) でchmファイルを表示します。
        }

そして、SwitchDlgは以下の通り。

 

    /////////////////////
    //Switch ダイアログ
    /////////////////////

    class SwitchDlg : Form
    {
        //メンバー変数
        public string Switch;        //データ受け渡し用メンバー変数(解説:なのでpublic))
        //メンバーコントロール
        Button btnOK, btnHelp, btnAdd;
        ComboBox cmbBox;
        TextBox txtBox;

        public SwitchDlg(string swt = "")
        {
            //ダイアログの属性設定(解説:サイズを変えられないダイアログとしています。)
            this.Text = "MSBuildスイッチ設定";
            this.ClientSize = new Size(320, 240);
            this.MaximizeBox = false;        // 最大化ボタン
            this.MinimizeBox = false;        // 最小化ボタン
            this.ShowInTaskbar = false;        //タスクバー上表示
            this.FormBorderStyle = FormBorderStyle.FixedDialog;        // 境界のスタイル
            this.StartPosition = FormStartPosition.CenterParent;    // 親フォームの中央に配置
            //コントロールの属性設定
            //スイッチ文選択用コンボボックス

            cmbBox = new ComboBox();
            cmbBox.DropDownStyle = ComboBoxStyle.DropDown;
            cmbBox.DropDownWidth = 176;
            cmbBox.DropDownHeight = 176;
            cmbBox.Size = new Size(180, 20);
            cmbBox.Location = new Point(10, 10);
            string[] Items = new string [] {"/consoleloggerparameters:",    //解説:ドロップダウンリストを作ります。
                                        "/distributedlogger:",
                                        "/distributedFileLogger",
                                        "/detailedsummary",
                                        "/fileLogger",
                                        "/fileloggerparameters",
                                        "/help",
                                        "/ignoreprojectextensions:",
                                        "/logger:",
                                        "/maxcpucount",
                                        "/noautoresponse",
                                        "/noconsolelogger",
                                        "/nodeReuse:",
                                        "/nologo",
                                        "/preprocess:",
                                        "/property:", 
                                        "/target:",
                                        "/toolsversion:",
                                        "/validate",
                                        "/verbosity:",
                                        "/version"};
            foreach(string item in Items)
            {
                cmbBox.Items.Add(item);
            }
            this.Controls.Add(cmbBox);
            //スイッチ文表示用テキストボックス
            txtBox = new TextBox();
            txtBox.Multiline = true;
            txtBox.WordWrap = true;
            txtBox.ScrollBars = ScrollBars.Vertical;
            txtBox.Size = new Size(this.ClientSize.Width - 20, 120);
            txtBox.Location = new Point(10, cmbBox.Height + 20);
            txtBox.Text = swt;
            this.Controls.Add(txtBox);
            //終了ボタン
            btnOK = new Button();
            btnOK.Location = new Point(ClientSize.Width - btnOK.Width - 10, ClientSize.Height - btnOK.Height - 10);
            btnOK.Text = "終了";
            btnOK.Click += new EventHandler(OnOK_Click);
            this.Controls.Add(btnOK);
            //Helpボタン
            btnHelp = new Button();
            btnHelp.Location = new Point(ClientSize.Width - btnHelp.Width - 10, ClientSize.Height - btnHelp.Height - btnOK.Height - 20);
            btnHelp.Text = "Help";
            btnHelp.Click += new EventHandler(OnHelp_Click);
            this.Controls.Add(btnHelp);
            //追加ボタン
            btnAdd = new Button();
            btnAdd.Location = new Point(ClientSize.Width - btnAdd.Width - 10, 10);
            btnAdd.Text = "追加";
            btnAdd.Click += new EventHandler(OnAdd_Click);
            this.Controls.Add(btnAdd);
        }

        private void OnOK_Click(object sender, EventArgs e)
        {
            Switch = txtBox.Text;    //データ引き渡し用メンバー変数に結果を代入
            Close();
        }

        private void OnHelp_Click(object sender, EventArgs e)
        {
            //ヘルプ表示(URLにすると既定のブラウザーで開く-解説:↑のHelp.ShowHelpとは異なる動作ですね。)
            Help.ShowHelp(btnHelp, "https://learn.microsoft.com/ja-jp/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2022#switches");
        }

        private void OnAdd_Click(object sender, EventArgs e)
        {
            txtBox.Text += cmbBox.Text + " ";    //スイッチ文を追加してゆく(削除、編集はテキストボックスで行う)
        }
    }

 

如何だったでしょうか?

 

このプログラムで注意してほしい点は、

 

(1)「実行」処理で使う(外部の実行ファイル(exeファイル等)を実行するProcessStartInfoProcess.Startメソッドの使い方

(2)ブラウザーやHTMLヘルプを使う Help.ShowHelpの使い方

(3)puyblicメンバー変数を使った自作ダイアログと呼び出しプログラムとのデータの受け渡し

でしょうか?

 

ご参考となれば幸いです。なお、次回にこのMSBuilderで遭遇したトラブルを書いて終了とさせていただきます。