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

わんくま同盟

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

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

ツリー一括表示

別のアプリに対してモーダルとなるウィンドウの作成 /HiHi (19/10/10(Thu) 12:47) #92606
Re[1]: 別のアプリに対してモーダルとなるウィンドウの作成 /とっちゃん (19/10/10(Thu) 13:55) #92608
│└ Re[2]: 別のアプリに対してモーダルとなるウィンドウの作成 /HiHi (19/10/10(Thu) 15:21) #92609
│  ├ Re[3]: 別のアプリに対してモーダルとなるウィンドウの作成 /とっちゃん (19/10/10(Thu) 17:03) #92611
│  │└ Re: 別のアプリに対してモーダルとなるウィンドウの作成 /HiHi (19/10/11(Fri) 11:35) #92621
│  │  ├ Re[5]: Re: 別のアプリに対してモーダルとなるウィンドウの作成 /魔界の仮面弁士 (19/10/11(Fri) 18:50) #92630
│  │  └ Re[5]: Re: 別のアプリに対してモーダルとなるウィンドウの作成 /PANG2 (19/10/11(Fri) 12:57) #92622
│  └ Re[3]: 別のアプリに対してモーダルとなるウィンドウの作成 /PANG2 (19/10/10(Thu) 18:24) #92615
│    └ Re[4]: 別のアプリに対してモーダルとなるウィンドウの作成 /とっちゃん (19/10/11(Fri) 10:05) #92617
Re[1]: 別のアプリに対してモーダルとなるウィンドウの作成 /Azulean (19/10/11(Fri) 06:27) #92616


親記事 / ▼[ 92608 ] ▼[ 92616 ]
■92606 / 親階層)  別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ HiHi (1回)-(2019/10/10(Thu) 12:47:54)

分類:[VB.NET/VB2005 以降] 

使用言語:VB2013(WindowsFormアプリ)
OS:Windows10(64bit)

こんにちは。
今、別のアプリに対してモーダルとなるウィンドウを作成できるか試しています。
例えば、以下のように、IWin32Windowインタフェースを実装したクラスを用意し、
これに別アプリのウィンドウハンドルを適用したものをFormのShowDialogの引数に渡すことにより、
別アプリに対してモーダルとなるウィンドウになることを確認しましたが、
このやり方は(別アプリが操作できないことは別として)問題はないでしょうか?

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim hWnd As IntPtr = (別アプリのウィンドウハンドル)
        Using f As New Form2
            f.ShowDialog(New OwnerWindow(hWnd))
        End Using
    End Sub

    Private Class OwnerWindow
        Implements IWin32Window

        Private m_hWnd As IntPtr

        Public Sub New(ByVal hWnd As IntPtr)
            m_hWnd = hWnd
        End Sub
        Public ReadOnly Property Handle() As System.IntPtr Implements System.Windows.Forms.IWin32Window.Handle
            Get
                Return m_hWnd
            End Get
        End Property
    End Class
End Class

また、自身のアプリはx86ビルドの場合で、別アプリがx64で実行されている場合でも
この方法は使えますか?問題がありますか?
よろしくお願いいたします。

[ □ Tree ] 返信 編集キー/

▲[ 92606 ] / ▼[ 92609 ]
■92608 / 1階層)  Re[1]: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ とっちゃん (637回)-(2019/10/10(Thu) 13:55:38)
No92606 (HiHi さん) に返信
> 今、別のアプリに対してモーダルとなるウィンドウを作成できるか試しています。
> 例えば、以下のように、IWin32Windowインタフェースを実装したクラスを用意し、
> これに別アプリのウィンドウハンドルを適用したものをFormのShowDialogの引数に渡すことにより、
> 別アプリに対してモーダルとなるウィンドウになることを確認しましたが、
> このやり方は(別アプリが操作できないことは別として)問題はないでしょうか?
>
ウィンドウハンドルは、そのマシン内で一意な値として存在しているので、問題になることはありません。

> また、自身のアプリはx86ビルドの場合で、別アプリがx64で実行されている場合でも
> この方法は使えますか?問題がありますか?

試してみてはいかがでしょう?64bitOS 環境はあるので簡単に試せますよね?

一応。。。逆のパターンもあります。もし試すのなら、両方試してみることをお勧めします。

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

▲[ 92608 ] / ▼[ 92611 ] ▼[ 92615 ]
■92609 / 2階層)  Re[2]: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ HiHi (2回)-(2019/10/10(Thu) 15:21:10)
No92608 (とっちゃん さん) に返信
>
> 試してみてはいかがでしょう?64bitOS 環境はあるので簡単に試せますよね?
>

ありがとうございます。
こちらのアプリはx86ビルドなので、とりあえずx64ビルドのテストアプリ(フォーム表示のみ)を作成し、
上記投稿の方法でフォームを開いたら、テストアプリのフォームに対してモーダル表示ができました。
(とりあえず表示ができただけなので、潜在的な問題があるかどうかは判りませんが)

ちなみに、今回、x86ビルドのテストアプリをx64ビルドのテストアプリに対してモーダル表示した方法は
以下の通りです。

1.x64ビルドのテストアプリのフォームで、自身のウィンドウハンドルを取得する。
  上記ウィンドウハンドル.ToStringをコマンドライン引数としてx86ビルドのアプリをProcess.Startで起動する。
2.x86ビルドのアプリ起動時にコマンドライン引数の内容をIntPtrにキャストする。
  (StringからIntPtrにダイレクトにキャストできるのかどうか分からなかったので、
   とりあえずString→Integer→IntPtrの順で変換)
3.x86ビルドのアプリのForm1が開いた後、Form1上のButton1クリックにより、
  上記投稿の方法でForm2を開く→x64アプリに対してモーダル表示

「うまくいった」と言ってもよろしいでしょうか?

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

▲[ 92609 ] / ▼[ 92621 ]
■92611 / 3階層)  Re[3]: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ とっちゃん (638回)-(2019/10/10(Thu) 17:03:34)
No92609 (HiHi さん) に返信

> 「うまくいった」と言ってもよろしいでしょうか?
>

IntPtr->Stringあるいは、String->IntPtr の変換工程にバグがなければ、うまくいってると言って、差し支えないと思います。


なぜそうなのか、技術的な裏付けを書いておきますね(説明としてはかなり端折っています)。

HWND型(ウィンドウハンドルなどと呼ばれるOS定義に型の名称)は、マシン全体で一意になるように管理されています。
32bitアプリが 64bitアプリのHWNDの値を見た場合でも、64bitアプリが32bitアプリのHWNDの値を見た場合でも
同じウィンドウを指している値であれば同じ数値になるように作られています。

そのため、数値として正しく値を渡すことができれば(その手段は問わない)、相互に連携させることができるようになっています。

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

▲[ 92611 ] / ▼[ 92630 ] ▼[ 92622 ]
■92621 / 4階層)  Re: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ HiHi (3回)-(2019/10/11(Fri) 11:35:24)
2019/10/11(Fri) 11:39:46 編集(投稿者)

皆さん、ありがとうございます。
非常に勉強になります。

以下のとっちゃん様の書き込みの内容、

> HWND型(ウィンドウハンドルなどと呼ばれるOS定義に型の名称)は、マシン全体で一意になるように管理されています。
> 32bitアプリが 64bitアプリのHWNDの値を見た場合でも、64bitアプリが32bitアプリのHWNDの値を見た場合でも
> 同じウィンドウを指している値であれば同じ数値になるように作られています。

を見る限り、任意のアプリのHWNDは、32bitアプリから見ても64bitアプリから見ても同じ値であると理解しました。
この通りであれば、32bitアプリのIntPtrは32bit(4バイト)で、64bitアプリのIntPtrは64bit(8バイト)ではあるけれど、
32bit・64bitのアプリで同じ数値になる(ただし型サイズは無視)、ということは、
少なくともInt32の範囲には収まると考えてよろしいでしょうか?
それであれば、モーダルで表示したいウィンドウのアプリは32bitなので、受け取った数値文字列を
String→Integer(Int32)→IntPtrの順で変換でよいと考えています。
(具体的には、StringをInteger.TryParseでIntegerにして、それをNew IntPtr(左記のInteger値)として変換しています。)
いかがでしょうか?
[ 親 92606 / □ Tree ] 返信 編集キー/

▲[ 92621 ] / 返信無し
■92630 / 5階層)  Re[5]: Re: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ 魔界の仮面弁士 (2424回)-(2019/10/11(Fri) 18:50:03)
No92621 (HiHi さん) に返信
> を見る限り、任意のアプリのHWNDは、32bitアプリから見ても64bitアプリから見ても同じ値であると理解しました。

正の 32bit 値の範囲、
&H0I〜&H7FFFFFFFI および
&H0L〜&H7FFFFFFFL の範囲は気にしなくて良さそう。


HWND 自体は、互換性の理由から利用可能なハンドル数が
今でも 16bit 分(数万個)しかないようです。
https://www.wdic.org/w/TECH/HWND
https://cpplover.blogspot.com/2007/07/blog-post_19.html

肝心な値の範囲については、負数もありえますが、実際のところ、
Win32/Win64 とも、下位 32bit 分までが有効値のようです。
https://docs.microsoft.com/ja-jp/windows/win32/winprog64/interprocess-communication


Win32/Win64 間で、コマンドラインで受け渡す際には、手順によっては、
上位ビットの部分を切り捨て(64→32)たり、符号拡張(32→64)する必要があるかも知れません。

まぁ、INVALID_HANDLE_VALUE などであれば、New IntPtr(-1) で済ませられますし、
さほど問題無いとは思いますが、IntPtr 自体はどういう動作を取るのか、一応実験。


《x64 の場合》
Dim P1 As New IntPtr(&H80000000L) '0x0000000080000000 扱い。ToInt64() 可能。ToInt32() は OverflowException。
Dim P2 As New IntPtr(&H80000000I) '0xFFFFFFFF80000000 扱い。ToInt32() と ToInt64() の両方が使用可能。
Dim P3 As New IntPtr(2147483648L) '0x0000000080000000 扱い。ToInt64() 可能。ToInt32() は OverflowException。
Dim P4 As New IntPtr(-2147483648) '0xFFFFFFFF80000000 扱い。ToInt32() と ToInt64() の両方が使用可能。

《x86 の場合》
Dim P1 As New IntPtr(&H80000000L) 'OverflowException で生成できない。
Dim P2 As New IntPtr(&H80000000I) '0x80000000 扱い。ToInt32() と ToInt64() の両方が使用可能。
Dim P3 As New IntPtr(2147483648L) 'OverflowException で生成できない。
Dim P4 As New IntPtr(-2147483648) '0x80000000 扱い。ToInt32() と ToInt64() の両方が使用可能。
[ 親 92606 / □ Tree ] 返信 編集キー/

▲[ 92621 ] / 返信無し
■92622 / 5階層)  Re[5]: Re: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ PANG2 (322回)-(2019/10/11(Fri) 12:57:43)
No92621 (HiHi さん) に返信
> 少なくともInt32の範囲には収まると考えてよろしいでしょうか?

根拠となる資料を探して確信は出来ていないです。

https://msdn.microsoft.com/ja-jp/windows/aa384203(v=vs.80)

プロセス間通信
32 ビット アプリケーションと 64 ビット アプリケーションの間で使用できる通信手段には以下のようなものがあります。
ウィンドウのハンドル (HWND) が共有されます。

英語読めないんで解説お願いします。
https://docs.microsoft.com/ja-jp/windows/win32/winprog64/interprocess-communication?redirectedfrom=MSDN
[ 親 92606 / □ Tree ] 返信 編集キー/

▲[ 92609 ] / ▼[ 92617 ]
■92615 / 3階層)  Re[3]: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ PANG2 (321回)-(2019/10/10(Thu) 18:24:44)
No92609 (HiHi さん) に返信
> 「うまくいった」と言ってもよろしいでしょうか?

IntPtrのコマンドライン渡しは、8byte整数を4byte整数に渡すことになりますので破綻する可能性はあります。

IntPtr.Size
https://docs.microsoft.com/ja-jp/dotnet/api/system.intptr.size



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

▲[ 92615 ] / 返信無し
■92617 / 4階層)  Re[4]: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ とっちゃん (639回)-(2019/10/11(Fri) 10:05:45)
No92615 (PANG2 さん) に返信
> ■No92609 (HiHi さん) に返信
>>「うまくいった」と言ってもよろしいでしょうか?
>
> IntPtrのコマンドライン渡しは、8byte整数を4byte整数に渡すことになりますので破綻する可能性はあります。
>
> IntPtr.Size
> https://docs.microsoft.com/ja-jp/dotnet/api/system.intptr.size
>
>
>
コマンドライン私は文字列で処理してるそうなので、渡す部分だけは問題ないようです。
(そのあと受け取ってどうしてるかはソースコードがないのでわからない)

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

▲[ 92606 ] / 返信無し
■92616 / 1階層)  Re[1]: 別のアプリに対してモーダルとなるウィンドウの作成
□投稿者/ Azulean (1088回)-(2019/10/11(Fri) 06:27:57)
No92606 (HiHi さん) に返信
> これに別アプリのウィンドウハンドルを適用したものをFormのShowDialogの引数に渡すことにより、
> 別アプリに対してモーダルとなるウィンドウになることを確認しましたが、
> このやり方は(別アプリが操作できないことは別として)問題はないでしょうか?

経験的・感覚的にはある程度動くと思います。
ただ、ごく一部でトラブルが出たという話も聞きますし、そのときに Microsoft のサポートからはつれない答えが返ってきたとも聞いていますので、自己責任の範疇という印象です。
(サポート云々は「聞いた話」レベルなので、ソースは出せませんが…)
[ 親 92606 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -