C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ツリー一括表示

.NET8でフォーム表示前に実行 /tako (25/03/03(Mon) 11:35) #103571
Re[1]: .NET8でフォーム表示前に実行 /魔界の仮面弁士 (25/03/03(Mon) 12:36) #103572
  └ Re[2]: .NET8でフォーム表示前に実行 /tako (25/03/03(Mon) 15:26) #103573
    └ Re[3]: .NET8でフォーム表示前に実行 /魔界の仮面弁士 (25/03/03(Mon) 20:07) #103574
      └ Re[4]: .NET8でフォーム表示前に実行 /tako (25/03/03(Mon) 21:22) #103575 解決済み


親記事 / ▼[ 103572 ]
■103571 / 親階層)  .NET8でフォーム表示前に実行
□投稿者/ tako (1回)-(2025/03/03(Mon) 11:35:52)

分類:[.NET 全般] 

VS2022を使って、VB.NETでプログラムを開発しているのですが、
プログラム起動時にフォーム表示前にコードを実行したいと考えています。

.Net frameworkを使った場合には、
このページにある通り、
https://dobon.net/vb/dotnet/programing/makeentrypoint.html

Module Program
    <STAThread()> _
    Sub Main()
        Application.Run(New Form1())
    End Sub
End Module

を設定し、スタートアップオブジェクトでこのSubを設定すればできました。

しかし、.NET8に移行すると、
上記のSubを追加しても、
スタートアップオブジェクトのドロップダウンリストに
上記のSubが表れないため、
設定することができません。


どのようにすれば、.NET8でエントリポイントを設定することができますか?





[ □ Tree ] 返信 編集キー/

▲[ 103571 ] / ▼[ 103573 ]
■103572 / 1階層)  Re[1]: .NET8でフォーム表示前に実行
□投稿者/ 魔界の仮面弁士 (3830回)-(2025/03/03(Mon) 12:36:29)
2025/03/03(Mon) 13:34:12 編集(投稿者)

No103571 (tako さん) に返信
> VS2022を使って、VB.NETでプログラムを開発しているのですが、
> プログラム起動時にフォーム表示前にコードを実行したいと考えています。

フォーム起動前の処理を書きたい場合は、ApplicationEvents.vb にて、
MyApplication の Startup イベントを仕込めば、事前処理を記述できます。
このとき、e.Cancel プロパティに True を仕込めむことで、
フォームの起動を中止してアプリケーションを終了させることもできます。

また、プロジェクトのプロパティで「単一インスタンス アプリケーション」を有効にしていた場合は、
StartupNextInstance イベントも利用できます。

ちなみに .NET Framework の場合は、プロジェクトのプロパティの
[アプリケーション]タブの[アプリケーション イベントの表示]に、上記と同じものがあります。


この MyApplication クラスを使うには、プロジェクトのプロパティで
[アプリケーション フレームワーク]を有効にしておく必要があります。


一方、Sub Main から起動させたい場合はその逆で、[アプリケーション フレームワーク]を無効化せねばなりません。
先述の MyApplication (≠My.Application)のイベント定義があれば削除してから、
[アプリケーション フレームワーク]を無効化させたのち、ソリューション エクスプローラーで
プロジェクトファイルをダブルクリックして、*.vbproj を XML モードで開いて、
/Project/PropertyGroup/MyType を WindowsForms ではなく WindowsFormsWithCustomSubMain であることを確認した後、
/Project/PropertyGroup/StartupObject を削除します。

念のため保存してプロジェクトを閉じ、プロジェクトフォルダーに bin および obj フォルダーがあれば、
それらをいったん削除してからプロジェクトを開きなおします。

これで、Sub Main から始めることができますが、VB の WinForms の場合は
Main を自作するのではなく、Startup イベントを使った方が安全かと思います。


> <STAThread()> _
VB の場合、この属性を明示的に付与せずとも、自動的に
System.Threading.Thread.CurrentThread.ApartmentState は STA になります。

> Sub Main()
> Application.Run(New Form1())
> End Sub
EnableVisualStyles / SetCompatibleTextRenderingDefault を使わないのは意図的なものですか?
[ 親 103571 / □ Tree ] 返信 編集キー/

▲[ 103572 ] / ▼[ 103574 ]
■103573 / 2階層)  Re[2]: .NET8でフォーム表示前に実行
□投稿者/ tako (2回)-(2025/03/03(Mon) 15:26:31)
ありがとうございます。

うまくいきました。
検索しても見つからなかったので、驚きです。
ありがとうございます。

ちなみに、
System.Threading.Thread.CurrentThread.ApartmentState は STA になります。
というのはどういう意味でしょうか?

System.Threading.Thread.CurrentThread.ApartmentState
というものはどこにも設定していないと思いますが
<STAThread()> _を付けなくても良いという意味なのでしょうか?
[ 親 103571 / □ Tree ] 返信 編集キー/

▲[ 103573 ] / ▼[ 103575 ]
■103574 / 3階層)  Re[3]: .NET8でフォーム表示前に実行
□投稿者/ 魔界の仮面弁士 (3831回)-(2025/03/03(Mon) 20:07:45)
2025/03/03(Mon) 20:22:28 編集(投稿者)

No103573 (tako さん) に返信
> System.Threading.Thread.CurrentThread.ApartmentState は STA になります。
> というのはどういう意味でしょうか?

最初にご自身が書かれた dobon! さんの URL に
『STAThreadAttribute属性の必要性については、こちらで説明しています。』
と書かれていたと思いますが、そちらは読まれましたか?
https://dobon.net/vb/dotnet/form/stathread.html


…まぁ、とりあえず「COM の世界のオヤクソク」だと思っておきましょう!


> System.Threading.Thread.CurrentThread.ApartmentState
> というものはどこにも設定していないと思いますが
それは、現在のアパートメント状態が STA か MTA か(あるいは Unknown か)を返す読み取り専用プロパティです。


> <STAThread()> _を付けなくても良いという意味なのでしょうか?

私自身、うまく説明できる自信が無いですが、ザックリ説明すると:

まずはじめに
STA「シングルスレッドアパートメント」と
MTA「マルチスレッドアパートメント」という用語があります。
※Windows の世界には、他にも ASTA とか RTA といった関連用語がありますがひとまず割愛。

それが何であるかは後述するとして、大前提として、
Windows Forms や WPF などといった「Windows Message を取り扱うもの」では、
「STA であること」が求められるのだと思ってください。
故に STA スレッドは、UI スレッドと呼ばれることもあります。
(メッセージ ループやウィンドウメッセージという用語はわかりますか?)

それがたとえワーカースレッドであっても、ウィンドウメッセージを扱うのであれば、
STA でなければならない、ということです。

エントリポイントに付与する STAThreadAttribute属性/MTAThreadAttribute属性は
アパートメントを明示指定するためのものですが、この属性を付与しなかった場合、
VB2005 以降では自動的に STAThreadAttribute 属性を付与したエントリポイントが生成される仕様です。

ゆえに「VB を利用している場合は、<STAThread> の指定は必須ではない(暗黙的に設定されるので)」というわけです。
ちなみに C# や C++ では MTAThreadAttribute 属性が既定となっているため、
C# 製の WinForms アプリのエントリポイントでは、必ず [STAThread] が明示されているはずです。


もう少し細かい話になると:

プロセス内の COM オブジェクトの各インスタンスは、それぞれが "アパートメント"
と呼ばれるグループに分けられています。それぞれの COM オブジェクトのメソッドを
直接呼び出すことができるのは、そのアパートメントに属するスレッドからだけです。

シングルスレッドアパートメント(STA)は、文字通り『1 つのスレッド』で構成されており、
マルチスレッドアパートメント(MTA)は『1 つ以上のスレッド』で構成されています。

COM スレッド モデルは、WinForms や WPF などといった
COM 相互運用機能を使用するアプリケーションにのみ適用されるものです。

シングルスレッドアパートメント内の COM オブジェクトに対するすべてのメソッド呼び出しは、
そのアパートメントに属する1つのスレッドからのメソッド呼び出ししか受け取ることができません。
シングルスレッドアパートメントのスレッドの Windows メッセージ キューと同期されるため、
各シングルスレッドアパートメントには、他のプロセスや同じプロセス内のアパートメントからの呼び出しを
処理するためのメッセージ ループが必ず必要です。

一方、マルチスレッドアパートメント内に存在している COM オブジェクトは、
そのマルチスレッドアパートメントに属する任意のスレッドから、
メソッド呼び出しを直接受け取ることができます。


まぁ、図示無しで説明しても伝わりにくいと思いますし、掲示板で説明しても
長くなるだけなので、上記の用語で検索してみてください。

公式ドキュメントだと、下記(とその周辺記事)ですが…これは流石に専門的過ぎるかな。
昔は、旧MSDN Libraryにもう少し分かりやすい資料があった気もするのだけれど。
https://learn.microsoft.com/ja-jp/windows/win32/com/processes--threads--and-apartments?WT.mc_id=DT-MVP-8907
[ 親 103571 / □ Tree ] 返信 編集キー/

▲[ 103574 ] / 返信無し
■103575 / 4階層)  Re[4]: .NET8でフォーム表示前に実行
□投稿者/ tako (4回)-(2025/03/03(Mon) 21:22:10)
No103574 (魔界の仮面弁士 さん) に返信

詳細な回答ありがとうございます。
非常に勉強になりました。
自分でも調べてみます。

解決済み
[ 親 103571 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -