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

わんくま同盟

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

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

ツリー一括表示

子ウインドウのフォームがWin7になる /ソニン (18/08/26(Sun) 19:31) #88393
Re[1]: 子ウインドウのフォームがWin7になる /とっちゃん (18/08/27(Mon) 11:04) #88396
  └ Re[2]: 子ウインドウのフォームがWin7になる /ソニン (18/08/27(Mon) 16:06) #88399
    ├ Re[3]: 子ウインドウのフォームがWin7になる /魔界の仮面弁士 (18/08/27(Mon) 16:31) #88401
    │└ Re[4]: 子ウインドウのフォームがWin7になる /魔界の仮面弁士 (18/08/27(Mon) 16:55) #88402
    └ Re[3]: 子ウインドウのフォームがWin7になる /Hongliang (18/08/27(Mon) 16:26) #88400
      └ Re[4]: 子ウインドウのフォームがWin7になる /とっちゃん (18/08/27(Mon) 17:48) #88403
        └ Re[5]: 子ウインドウのフォームがWin7になる /ソニン (18/08/29(Wed) 22:58) #88431
          └ Re[6]: 子ウインドウのフォームがWin7になる /魔界の仮面弁士 (18/08/30(Thu) 10:28) #88433
            └ Re[7]: 子ウインドウのフォームがWin7になる /とっちゃん (18/08/30(Thu) 10:51) #88434
              └ Re[8]: 子ウインドウのフォームがWin7になる /ソニン (18/09/01(Sat) 20:19) #88449
                ├ Re[9]: 子ウインドウのフォームがWin7になる /ソニン (18/09/01(Sat) 20:27) #88450
                │└ Re[10]: 子ウインドウのフォームがWin7になる /とっちゃん (18/09/03(Mon) 11:57) #88482
                │  └ Re[11]: 子ウインドウのフォームがWin7になる /ソニン (18/09/03(Mon) 22:42) #88491
                │    └ Re[12]: 子ウインドウのフォームがWin7になる /とっちゃん (18/09/04(Tue) 11:56) #88500
                │      └ Re[13]: 子ウインドウのフォームがWin7になる /ソニン (18/09/04(Tue) 12:11) #88501
                │        └ Re[14]: 子ウインドウのフォームがWin7になる /とっちゃん (18/09/04(Tue) 13:00) #88504
                │          └ Re[15]: 子ウインドウのフォームがWin7になる /ソニン (18/09/04(Tue) 14:14) #88507
                │            └ Re[16]: 子ウインドウのフォームがWin7になる /ソニン (18/09/04(Tue) 14:16) #88508
                │              └ Re[17]: 子ウインドウのフォームがWin7になる /とっちゃん (18/09/04(Tue) 15:29) #88509
                │                └ Re[18]: 子ウインドウのフォームがWin7になる /ソニン (18/09/04(Tue) 19:02) #88510
                └ Re[9]: 子ウインドウのフォームがWin7になる /魔界の仮面弁士 (18/09/05(Wed) 00:52) #88511
                  └ Re[10]: 子ウインドウのフォームがWin7になる /とっちゃん (18/09/05(Wed) 10:43) #88512
                    └ Re[11]: 子ウインドウのフォームがWin7になる /ソニン (18/09/08(Sat) 13:23) #88569 解決済み


親記事 / ▼[ 88396 ]
■88393 / 親階層)  子ウインドウのフォームがWin7になる
□投稿者/ ソニン (1回)-(2018/08/26(Sun) 19:31:09)

分類:[.NET 全般] 

Windows10、Visual Basic.NET2015の環境なのですが、
https://dobon.net/vb/dotnet/form/mdiapplication.html

このページの方法で、子フォームをもった親フォームの
プログラムを作成しました。

ところが、親フォームのスタイルはWin10のものなのですが、
子フォームのスタイルがWin7風になってしまいます。
子フォームもWin10風にしたいのですが
どのようにすれば良いでしょうか?



[ □ Tree ] 返信 編集キー/

▲[ 88393 ] / ▼[ 88399 ]
■88396 / 1階層)  Re[1]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (511回)-(2018/08/27(Mon) 11:04:34)
No88393 (ソニン さん) に返信
> Windows10、Visual Basic.NET2015の環境なのですが、
> https://dobon.net/vb/dotnet/form/mdiapplication.html
>
> このページの方法で、子フォームをもった親フォームの
> プログラムを作成しました。
>
> ところが、親フォームのスタイルはWin10のものなのですが、
> 子フォームのスタイルがWin7風になってしまいます。
> 子フォームもWin10風にしたいのですが
> どのようにすれば良いでしょうか?
>
MDIの子ウィンドウがWin7チックに表示されるのは、それはOSの制限(仕様)です。

キャプションなどの非クライアント領域の描画方法がWindows8から変わり
その関係で、MDI子フォームなどの内側のウィンドウの描画方法も変わりました。

そのため、表示が古いままになっています。

また、アプリケーションの推奨スタイルとしてもMDI形式はずいぶんと前(Vistaあたりから)から推奨されていません。

実際、WPFではMDIはサポートしていません。

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88396 ] / ▼[ 88401 ] ▼[ 88400 ]
■88399 / 2階層)  Re[2]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (3回)-(2018/08/27(Mon) 16:06:04)
そうでしたか・・・

MDIが推奨されていないのはなぜなのでしょうか?
複数ウインドウを使いたい場合で、
ウインドウを選択しようとして
バックグランドのウインドウやデスクトップをクリックしてしまうことがあり
非常に使いづらいので、親ウインドウが使いたいのですが
どういった理由で推奨されないのですか?

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88399 ] / ▼[ 88402 ]
■88401 / 3階層)  Re[3]: 子ウインドウのフォームがWin7になる
□投稿者/ 魔界の仮面弁士 (1797回)-(2018/08/27(Mon) 16:31:35)
No88399 (ソニン さん) に返信
> MDIが推奨されていないのはなぜなのでしょうか?

理由のひとつとして、マルチモニタ環境と相性が悪いという点があります。
タスクバーからのアクセス製が問題視されることもありますね。

Excel なども、現在は MDI 方式を廃止していますし、
Visual Studio もタブ方式に切り替わっています。


> どういった理由で推奨されないのですか?

2001年時点の資料において、既に非推奨とされていますね。

【Microsoft Windows ユーザー エクスペリエンス FAQ】
 -「アプリケーションには SDI と MDI のどちらを使用するべきですか?」
https://msdn.microsoft.com/ja-jp/library/ms997581.aspx#winuifaq_topic3
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88401 ] / 返信無し
■88402 / 4階層)  Re[4]: 子ウインドウのフォームがWin7になる
□投稿者/ 魔界の仮面弁士 (1798回)-(2018/08/27(Mon) 16:55:04)
No88401 (魔界の仮面弁士) に追記
> 2001年時点の資料において、既に非推奨とされていますね。

Hongliang さんと被った。(^^;


> Excel なども、現在は MDI 方式を廃止していますし、

Excel 2013 あたりから、完全に SDI になっていますね。
https://blogs.msdn.microsoft.com/office_client_development_support_blog/2016/12/19/excel2013-changes-to-sdi/

Excel 2000〜2010 では、オプション ダイアログの[詳細設定]-[表示]あたりに
「(すべての)ウィンドウをタスクバーに表示(する)」という
オプションがありましたが、SDI 化に伴い、2013 から廃止されています。
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88399 ] / ▼[ 88403 ]
■88400 / 3階層)  Re[3]: 子ウインドウのフォームがWin7になる
□投稿者/ Hongliang (678回)-(2018/08/27(Mon) 16:26:52)
https://msdn.microsoft.com/ja-jp/library/ms997581.aspx#winuifaq_topic3
とりあえず、2001年の時点でこういう記事が発表されてますね。
もちろん特定のアプリ、特定のユーザという話ならMDIの方がって意見もあるでしょうが。

// 私はAlt+Tabで選択することがほとんどなので、MDIは使いづらいですね〜。
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88400 ] / ▼[ 88431 ]
■88403 / 4階層)  Re[4]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (512回)-(2018/08/27(Mon) 17:48:34)
No88399 (ソニン さん) に返信
> MDIが推奨されていないのはなぜなのでしょうか?
> 複数ウインドウを使いたい場合で、
> ウインドウを選択しようとして
> バックグランドのウインドウやデスクトップをクリックしてしまうことがあり
> 非常に使いづらいので、親ウインドウが使いたいのですが
> どういった理由で推奨されないのですか?
>
推奨の話のリンクはすでに出てるので割愛。



MDIは推奨しないというだけで、今後使えなくなるではありません。
確かにWPFやUWPアプリなど、最近のプラットフォームでは使えませんが(同じようなことをしたい場合は、自前実装)
限定的な範囲(デスクトップの WindowsForms and Win32のみ)であれば今後も利用は可能です。

あとは、見た目の問題(質問当初のもの)だけだと思って割り切って使うのか、
あれはだめだ。。。となってMDIをあきらめるのか?の2択になると思います。

結局のところUXを今まで通りとするか新しいものを取り入れるか?なので
開発コストと併せて考えればいいと思います。
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88403 ] / ▼[ 88433 ]
■88431 / 5階層)  Re[5]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (4回)-(2018/08/29(Wed) 22:58:05)
ありがとうございます。

納得しました。

ところで、親ウインドウから子ウインドウがはみ出した場合に、
親ウインドウにスクロールバーが表れるのですが、
これを非表示するにはどうしたら良いでしょうか?

他のMDIプログラムをいくつか使っているのですが
これらではスクロールバーは表示されないので
これらと同じようにしたいのですが。

よろしくお願いいたします。

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88431 ] / ▼[ 88434 ]
■88433 / 6階層)  Re[6]: 子ウインドウのフォームがWin7になる
□投稿者/ 魔界の仮面弁士 (1803回)-(2018/08/30(Thu) 10:28:47)
No88431 (ソニン さん) に返信
> ところで、親ウインドウから子ウインドウがはみ出した場合に、
> 親ウインドウにスクロールバーが表れるのですが、
> これを非表示するにはどうしたら良いでしょうか?

通常の SDI における「子.Show(親)」で表示させる方法ではなく、
あくまでも親のクライアント領域内に子を表示させる画面構成でしょうか。


だとしたら、System.Windows.Forms.Form において、子フォームを
TopLevel = False かつ MdiParent = Nothing の状態にしておいてから
 親.Controls.Add(子)
 子.Show()
 子.BringToFront()
などとすれば、親フォームのスクロールバーの影響を受けることなく配置できます。
これで要件を満たせるでしょうか?

この場合、子.Parent が指す内容が MdiClient コントロールではなく、
親 Form そのものになります。最後に BringToFront することで、
親の MDIClient 内 よりも手前に子フォームが配置されるというわけです。


ただこれだと、そもそも親を IsMdiContainer = True にする意味が無いですし、
通常の MDI 子フォームと併用すると、聊か使い難くなるので、個人的にはお奨めしません。

そもそもスクロールバーが無いと、子フォームの右下座標が XY 共にマイナスになった場合や
子フォームの左X座標が親フォームの幅を超えていた場合に、ユーザーが子フォームへ
アクセスすることが難しくなってしまいます。
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88433 ] / ▼[ 88449 ]
■88434 / 7階層)  Re[7]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (514回)-(2018/08/30(Thu) 10:51:02)
No88431 (ソニン さん) に返信
> ありがとうございます。
>
> 納得しました。
>
> ところで、親ウインドウから子ウインドウがはみ出した場合に、
> 親ウインドウにスクロールバーが表れるのですが、
> これを非表示するにはどうしたら良いでしょうか?
>
> 他のMDIプログラムをいくつか使っているのですが
> これらではスクロールバーは表示されないので
> これらと同じようにしたいのですが。
>
MDICLIENT ウィンドウの作成時に、スクロールバースタイルをつける・つけないのいずれかを選択することで
スクロールバーの有無を決めるのが本来の在り方です。

ですが、.NET にはそういう選択肢そのものがないので(問答無用でスクロールバースタイルをつける)
作成後に、あとからスタイルを外す(多分それでできると思います)かたちで対応するしかないのでは?という気がします。

このあたりが推奨されないものの操作の限界といえます。

段取りとしては、IsMdiContaioner = True を行った直後に
Controls から、MdiClient を探し、APIを使ってスタイルを外す形になります。

MdiClientの検索方法も、スタイルを設定する方法も
「MDICLIENT」
を検索キーにして検索すれば出てきます。

APIを使ってスタイルを外すコードは、C#でしたが。
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88434 ] / ▼[ 88450 ] ▼[ 88511 ]
■88449 / 8階層)  Re[8]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (5回)-(2018/09/01(Sat) 20:19:56)
>魔界の仮面弁士 さん


> 通常の SDI における「子.Show(親)」で表示させる方法ではなく、
> あくまでも親のクライアント領域内に子を表示させる画面構成でしょうか。

これはどういう画面構成のことをさしていますか?
自分としては、
通常の MDI における「子.Show(親)」で表示させる方法を使うつもりですので
異なる方法でしょうか?



>とっちゃん さん

検索して調べたところ、恐らくこの方法を使えばいけると思います。

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1475227379

翻訳サイトを使ってVBに変換したのですが

            InitializeComponent()
            Dim hwnd As IntPtr = Form1.GetWindow(Me.Handle, GW_CHILD)
                    Me.wpd = New WndProcDelegate(NewWndProc)


の三カ所でエラーが出てしまいます。


一体どのように修正すればよろしいでしょうか?


        Private Declare Function GetWindow Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal uCmd As Integer) As IntPtr

        Private Declare Function GetClassName Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Integer) As Integer

        Private Declare Function SetWindowLong Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal NewWndProc As WndProcDelegate) As IntPtr

        Private Declare Function SetWindowLongPtr Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal NewWndProc As WndProcDelegate) As IntPtr

        Private Declare Function CallWindowProc Lib "user32.dll" (ByVal lpPrevWndFunc As IntPtr, ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

        Private Const GW_HWNDNEXT As Integer = 2

        Private Const GW_CHILD As Integer = 5

        Private Const WM_NCCALCSIZE As Integer = 131

        Private Const GWL_WNDPROC As Integer = -4

        Private PrevWndProc As IntPtr

        Public Delegate Function WndProcDelegate(ByVal hWnd As IntPtr, ByVal uMsg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

        Private wpd As WndProcDelegate

        Public Sub New()
            MyBase.New
            InitializeComponent()
        End Sub

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
            Dim sb As StringBuilder = New StringBuilder(100)
            Dim hwnd As IntPtr = Form1.GetWindow(Me.Handle, GW_CHILD)

            While (hwnd <> IntPtr.Zero)
                Form1.GetClassName(hwnd, sb, sb.Capacity)
                If (sb.ToString.IndexOf("MDICLIENT") <> -1) Then
                    Me.wpd = New WndProcDelegate(NewWndProc)
                    If (IntPtr.Size = 4) Then
                        Me.PrevWndProc = Form1.SetWindowLong(hwnd, GWL_WNDPROC, Me.wpd)
                    Else
                        Me.PrevWndProc = Form1.SetWindowLongPtr(hwnd, GWL_WNDPROC, Me.wpd)
                    End If

                    Return
                End If

                hwnd = Form1.GetWindow(hwnd, GW_HWNDNEXT)

            End While

        End Sub

        Private Function NewWndProc(ByVal hWnd As IntPtr, ByVal uMsg As UInteger, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
            If (uMsg = WM_NCCALCSIZE) Then
                Return 0
            End If

            Return Form1.CallWindowProc(Me.PrevWndProc, hWnd, uMsg, wParam, lParam)
        End Function
    End Class



[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88449 ] / ▼[ 88482 ]
■88450 / 9階層)  Re[9]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (6回)-(2018/09/01(Sat) 20:27:24)

Me.wpd = New WndProcDelegate(AddressOf NewWndProc)

でデバッグはできるようになりました。

しかし、

Form0.GetClassName(hwnd, sb, sb.Capacity)

のところで

追加情報:DLL 'user32.dll' の 'GetClassName' というエントリ ポイントが見つかりません。

というエラーが出て、実行することができません。

どうすれば良いですか?

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88450 ] / ▼[ 88491 ]
■88482 / 10階層)  Re[10]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (515回)-(2018/09/03(Mon) 11:57:40)
No88450 (ソニン さん) に返信
> Form0.GetClassName(hwnd, sb, sb.Capacity)
>
を行っているところは、MDICLIENT のウィンドウハンドルを特定しているところですよね?

APIで探してもいいと思いますが、下記のページにある
GetMdiClient というメソッドを使うほうが簡単でいいと思います。

https://dobon.net/vb/dotnet/form/mdibackgroundimage.html

親フォームの InitializeComponent() の後(具体的には、IsMdiContainer = True がセットされた後)であれば
どのタイミングで呼び出しても取得できます。


それと、プロシージャの設定変更は、32/64 のどちらの場合でも

SetWindowLongPtr( hwnd, GWLP_WNDPROC, proc );

です。

GWLP_WNDPROC は、GWL_WNDPROC と同じ値です。
IntPtrのサイズを判定した分離処理は「不要」です。
プロシージャの変更に関しては。

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88482 ] / ▼[ 88500 ]
■88491 / 11階層)  Re[11]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (8回)-(2018/09/03(Mon) 22:42:54)

ありがとうございます。

しかし、どのように修正したら良いか分かりません。

hwndはintptr、mcはSystem.Windows.Forms.MdiClientですが
どのように変換したら良いのですか?

また、sbはどのように取得すれば良いですか?

SetWindowLongPtr( hwnd, GWLP_WNDPROC, proc );


Me.wpdがprocに変わっていますが
procはどこで取得するのですが、
修正案を教えていただけないでしょうか?


[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88491 ] / ▼[ 88501 ]
■88500 / 12階層)  Re[12]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (518回)-(2018/09/04(Tue) 11:56:05)
No88491 (ソニン さん) に返信

> hwndはintptr、mcはSystem.Windows.Forms.MdiClientですが
> どのように変換したら良いのですか?
>
MdiClient の親クラスをたどっていくと、IWin32Window というインターフェースがあります。
このインターフェースに、Handle というプロパティがあるのでそれで取得できます。

変換する必要はありません。


> また、sbはどのように取得すれば良いですか?
>
sb は利用しませんよ。ウィンドウハンドルを特定するための方法そのものが全く違う手段に代わっています。

> SetWindowLongPtr( hwnd, GWLP_WNDPROC, proc );
>
> で
> Me.wpdがprocに変わっていますが
> procはどこで取得するのですが、
> 修正案を教えていただけないでしょうか?
>
proc は単に、書くのが面倒だったからそうしただけで、Me.wpd をセットすればOKです。

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88500 ] / ▼[ 88504 ]
■88501 / 13階層)  Re[13]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (9回)-(2018/09/04(Tue) 12:11:27)
もしかしてこれだけで良いのでしょうか?

Dim mc As System.Windows.Forms.MdiClient = GetMdiClient(Me)

Me.wpd = New WndProcDelegate(AddressOf NewWndProc)
Me.PrevWndProc = Form0.SetWindowLongPtr(mc.Handle, GWL_WNDPROC, Me.wpd)



しかし、
3行目で

追加情報:DLL 'user32.dll' の 'SetWindowLongPtr' というエントリ ポイントが見つかりません。

というエラーが出てしまいます。


[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88501 ] / ▼[ 88507 ]
■88504 / 14階層)  Re[14]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (519回)-(2018/09/04(Tue) 13:00:31)
No88501 (ソニン さん) に返信
> もしかしてこれだけで良いのでしょうか?
>
> Dim mc As System.Windows.Forms.MdiClient = GetMdiClient(Me)
>
> Me.wpd = New WndProcDelegate(AddressOf NewWndProc)
> Me.PrevWndProc = Form0.SetWindowLongPtr(mc.Handle, GWL_WNDPROC, Me.wpd)
>
はい。
ですが、mc が Null になっていないことは確認したほうがいいと思います。

>
>
> しかし、
> 3行目で
>
> 追加情報:DLL 'user32.dll' の 'SetWindowLongPtr' というエントリ ポイントが見つかりません。
>
> というエラーが出てしまいます。
>
>
すっかり忘れていた。
SetWindowLongPtr は、64bit の場合だけです。

なので、IntPtr.Size = 4 で、SetWindowLong または SetWindowLongPtr を呼び出すようにしないと駄目ですね。

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88504 ] / ▼[ 88508 ]
■88507 / 15階層)  Re[15]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (10回)-(2018/09/04(Tue) 14:14:36)
ありがとうございます。
一応、動作したように思います。

mcがnullになっていないか確認する方法に関してですが、

If mc <> Null Then
だと受け付けないですが

If mc IsNot Nothing Then

で良いのでしょうか?

また、どのような場合にNullになることがあり得ますか?
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88507 ] / ▼[ 88509 ]
■88508 / 16階層)  Re[16]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (11回)-(2018/09/04(Tue) 14:16:49)
うまくいったと思いましたが勘違いでした。


Dim mc As System.Windows.Forms.MdiClient = GetMdiClient(Me)

If mc IsNot Nothing Then

Me.wpd = New WndProcDelegate(AddressOf NewWndProc)

If (IntPtr.Size = 4) Then
Me.PrevWndProc = Form0.SetWindowLong(mc.Handle, GWL_WNDPROC, Me.wpd)
Else
Me.PrevWndProc = Form0.SetWindowLongPtr(mc.Handle, GWL_WNDPROC, Me.wpd)
End If

End If

とやってみたのですが、
追加情報:DLL 'user32.dll' の 'SetWindowLongPtr' というエントリ ポイントが見つかりません。

というエラーが出てしまいます。
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88508 ] / ▼[ 88510 ]
■88509 / 17階層)  Re[17]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (520回)-(2018/09/04(Tue) 15:29:34)
No88507 (ソニン さん) に返信

> mcがnullになっていないか確認する方法に関してですが、
>
> If mc <> Null Then
> だと受け付けないですが
>
> If mc IsNot Nothing Then
>
> で良いのでしょうか?
>

「受け付けない」というのがどういう状態を指しているのかわかりませんが
うまくいくほうを採用すればいいと思います。

> また、どのような場合にNullになることがあり得ますか?

MdiClientが作られる前の状況で呼び出せばNullになります。

まぁ、めったにないですが、エラーチェックは自分のプログラムが安全に動くために
強いてはのちのユーザーサポートを軽減するためにも常に心が変えておくことをお勧めします。



No88508 (ソニン さん) に返信

> 追加情報:DLL 'user32.dll' の 'SetWindowLongPtr' というエントリ ポイントが見つかりません。
>
> というエラーが出てしまいます。

pinvoke.net という、P/Invoke(プラットフォーム呼び出し)コードが載ってるサイトを紹介しておきます。

やってることは同じに見えますが、これでどうかなどを確認してみてください。

http://www.pinvoke.net/default.aspx/user32.setwindowlong


[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88509 ] / 返信無し
■88510 / 18階層)  Re[18]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (12回)-(2018/09/04(Tue) 19:02:41)
やはり
うまくいきません。
http://www.pinvoke.net/default.aspx/user32.setwindowlong
のコードで
第3引数の
ByVal dwNewLong As IntPtr
には何を指定したら良いですか?
[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88449 ] / ▼[ 88512 ]
■88511 / 9階層)  Re[9]: 子ウインドウのフォームがWin7になる
□投稿者/ 魔界の仮面弁士 (1811回)-(2018/09/05(Wed) 00:52:11)
No88449 (ソニン さん) に返信
>>通常の SDI における「子.Show(親)」で表示させる方法ではなく、
>>あくまでも親のクライアント領域内に子を表示させる画面構成でしょうか。
> これはどういう画面構成のことをさしていますか?
> 自分としては、
> 通常の MDI における「子.Show(親)」で表示させる方法を使うつもりですので
> 異なる方法でしょうか?

親フォームが「Owner プロパティ」と「MdiParent プロパティ」の
いずれで管理されているのか、ということです。

たとえば、
 MDIParentForm.Show()
 MDIChildForm.MdiParent = MDIParentForm
 MDIChildForm.Show(MDIParentForm)
のような記述はエラーになりますよね。

※ MDIParentForm.Show(他フォーム) は OK




>> 検索して調べたところ、恐らくこの方法を使えばいけると思います。
>> https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1475227379
> 翻訳サイトを使ってVBに変換したのですが

意訳してみました。
MDI 親フォームに「MdiClientScrollBars プロパティ」を実装しています。


Option Strict On
Option Explicit On
Imports System.ComponentModel
Imports System.Runtime.InteropServices

Partial Public NotInheritable Class MDIParent1
    Inherits System.Windows.Forms.Form

#Region "MdiClientScrollBars プロパティ / IsMdiContainer が True の時に、MdiClient にスクロールバーが表示されるかどうかを示す値を取得または設定します"
    ''' <summary>
    ''' <see cref="IsMdiContainer"/>が<code>True</code>の時に、<see cref="MdiClient"/>にスクロールバーが表示されるかどうかを示す値を取得または設定します
    ''' </summary>
    <DefaultValue(False)>
    Public Property MdiClientScrollBars As Boolean
        Get
            Return IsMdiContainer AndAlso _MdiClientScrollBars
        End Get
        Set(value As Boolean)
            _MdiClientScrollBars = MdiClientProcWithoutScrollbars(value)
        End Set
    End Property
    Private _MdiClientScrollBars As Boolean = False
#End Region


#Region "API 宣言"
    Private Const GWL_WNDPROC As Integer = -4
    Private Delegate Function WndProcDelegate(hWnd As IntPtr, ByVal uMsg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    Private Declare Auto Function SetWindowLongPtr32 Lib "user32" Alias "SetWindowLong" (hWnd As HandleRef, nIndex As Integer, dwNewLong As IntPtr) As IntPtr
    Private Declare Auto Function SetWindowLongPtr64 Lib "user32" Alias "SetWindowLongPtr" (hWnd As HandleRef, nIndex As Integer, dwNewLong As IntPtr) As IntPtr
    Private Declare Auto Function CallWindowProc Lib "user32" (lpPrevWndFunc As IntPtr, hWnd As IntPtr, Msg As UInteger, wParam As IntPtr, lParam As IntPtr) As IntPtr
    Private Shared ReadOnly SetWindowLongPtr As Func(Of HandleRef, Integer, IntPtr, IntPtr)
    Shared Sub New()
        If IntPtr.Size = 8 Then
            SetWindowLongPtr = AddressOf SetWindowLongPtr64
        Else
            SetWindowLongPtr = AddressOf SetWindowLongPtr32
        End If
    End Sub
#End Region

#Region "MdiClient の取得処理"
    'MdiClient を保持する変数。OnControlAdded / OnControlRemoved で更新される。
    Private MdiClientHandle As HandleRef = New HandleRef(Nothing, IntPtr.Zero)

    '本来のプロシージャ
    Private MdiClientOriginalProc As IntPtr = IntPtr.Zero

    'CallbackOnCollectedDelegate 対策のため、GC されないよう保持しておく
    Private MdiClientProc As WndProcDelegate = Nothing

    Protected Overrides Sub OnControlAdded(e As ControlEventArgs)
        MyBase.OnControlAdded(e)
        If TypeOf e.Control Is MdiClient Then
            MdiClientHandle = New HandleRef(e.Control, e.Control.Handle)
        End If
    End Sub
    Protected Overrides Sub OnControlRemoved(e As ControlEventArgs)
        If TypeOf e.Control Is MdiClient Then
            If MdiClientOriginalProc <> IntPtr.Zero Then
                'MdiClient が削除される前にサブクラス化を解除しておく
                SetWindowLongPtr(MdiClientHandle, GWL_WNDPROC, MdiClientOriginalProc)
                MdiClientOriginalProc = IntPtr.Zero
            End If
            MdiClientHandle = New HandleRef(Nothing, IntPtr.Zero)
        End If
        MyBase.OnControlRemoved(e)
    End Sub
#End Region

#Region "MDI のスクロールバー制御"
    Private Function MdiClientProcWithoutScrollbars(visible As Boolean) As Boolean
        If Not IsMdiContainer OrElse MdiClientHandle.Handle = IntPtr.Zero Then
            Return False
        End If
        Dim mc = TryCast(MdiClientHandle.Wrapper, MdiClient)
        If mc Is Nothing Then
            Return False
        End If
        If visible Then
            If MdiClientOriginalProc <> IntPtr.Zero Then
                'サブクラス化解除
                SetWindowLongPtr(MdiClientHandle, GWL_WNDPROC, MdiClientOriginalProc)
                MdiClientOriginalProc = IntPtr.Zero
            End If
        Else
            If MdiClientOriginalProc = IntPtr.Zero Then
                'サブクラス化
                MdiClientProc = New WndProcDelegate(AddressOf MdiClientProcWithoutScorollbars)
                MdiClientOriginalProc = SetWindowLongPtr(MdiClientHandle, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(MdiClientProc))
            End If
        End If
        'リサイズすることで、スクロールバーを強制再描画させる
        '(ただし mc.Dock は Fill なので、実際にはリサイズされない)
        mc.Width -= 1
        Return visible
    End Function

    Private Function MdiClientProcWithoutScorollbars(hWnd As IntPtr, uMsg As UInteger, wParam As IntPtr, lParam As IntPtr) As IntPtr
        'サブクラス化して WM_NCCALCSIZE を無視する
        Const WM_NCCALCSIZE As UInteger = 131UI
        Return If(uMsg = WM_NCCALCSIZE, IntPtr.Zero, CallWindowProc(MdiClientOriginalProc, hWnd, uMsg, wParam, lParam))
    End Function

    Protected Overrides Sub OnLoad(e As EventArgs)
        MyBase.OnLoad(e)
        'MdiClient のスクロールバーの状態を更新する
        _MdiClientScrollBars = MdiClientProcWithoutScrollbars(IsMdiContainer AndAlso _MdiClientScrollBars)
    End Sub
#End Region

End Class

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88511 ] / ▼[ 88569 ]
■88512 / 10階層)  Re[10]: 子ウインドウのフォームがWin7になる
□投稿者/ とっちゃん (521回)-(2018/09/05(Wed) 10:43:12)
No88510 (ソニン さん) に返信
> やはり
> うまくいきません。

うまくいかないとはどういうことでしょうか?
何がうまくいかないのかをできるだけ具体的に書くとより適切な回答が得られると思います。



とはいえ、今回に関しては、■No88511 で、魔界の仮面弁士 さんがコード例として綺麗にまとめてくれているので
それを参考にすればいいと思います。

> 第3引数の
> ByVal dwNewLong As IntPtr
> には何を指定したら良いですか?

これについても回答例となるものがコードに含まれています。

[ 親 88393 / □ Tree ] 返信 編集キー/

▲[ 88512 ] / 返信無し
■88569 / 11階層)  Re[11]: 子ウインドウのフォームがWin7になる
□投稿者/ ソニン (14回)-(2018/09/08(Sat) 13:23:07)
ありがとうございます。

うまくいきました。

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


管理者用

- Child Tree -