Process.Start(url)で開いたブラウザそのもののプロセスを取得したい
        投稿者 とくま  (社会人)
        
        投稿日時 
            2025/3/4 17:28:16
        
    
    
        > そこで、上記で取得したProcessオブジェクトのMainWindowHandleを取得しようとすると、
基本はそれで合ってるはずです。ただ、この方法では取れない場合があるのも事実です。
https://ja.stackoverflow.com/questions/9338/c-%E5%A4%96%E9%83%A8%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%95%E3%81%9B%E3%81%9F%E9%9A%9B%E3%81%AB-%E7%89%B9%E5%AE%9A%E3%81%AE%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%88%E3%82%8A%E3%82%82%E5%89%8D%E9%9D%A2%E3%81%AB%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
とりあえず、ProcessStartInfo の方を使って、UseShellExecute = true も試してみてください。
https://qiita.com/tsukasa_labz/items/80a94d202f5e88f1ddc0
そのあと、Process.WaitForExit(10000)
を間に入れた後に、MainWindowHandle が取れるか確認してもらえますか?MainWindowHandle を取得するのが早すぎると取れなかったので。
こちらの環境では、notepad.exe と chrome.exe はハンドル取得できました。
msedge.exe がダメだったです。(x86)だからかなぁ?プロセスIDまで全く違うやつで立ち上がってくる。。。
ただ、自分で書いたオリジナルコードだと、Process.Start 直後で MainWindowHandle を取っても、
0 になるだけでエラーは出ないんですよね。。。
    
基本はそれで合ってるはずです。ただ、この方法では取れない場合があるのも事実です。
https://ja.stackoverflow.com/questions/9338/c-%E5%A4%96%E9%83%A8%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%95%E3%81%9B%E3%81%9F%E9%9A%9B%E3%81%AB-%E7%89%B9%E5%AE%9A%E3%81%AE%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%88%E3%82%8A%E3%82%82%E5%89%8D%E9%9D%A2%E3%81%AB%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
とりあえず、ProcessStartInfo の方を使って、UseShellExecute = true も試してみてください。
https://qiita.com/tsukasa_labz/items/80a94d202f5e88f1ddc0
そのあと、Process.WaitForExit(10000)
を間に入れた後に、MainWindowHandle が取れるか確認してもらえますか?MainWindowHandle を取得するのが早すぎると取れなかったので。
こちらの環境では、notepad.exe と chrome.exe はハンドル取得できました。
msedge.exe がダメだったです。(x86)だからかなぁ?プロセスIDまで全く違うやつで立ち上がってくる。。。
ただ、自分で書いたオリジナルコードだと、Process.Start 直後で MainWindowHandle を取っても、
0 になるだけでエラーは出ないんですよね。。。
Imports System.Runtime.InteropServices
Public Class Form1
    ' Windows APIの関数を定義 
    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function EnumWindows(ByVal lpEnumFunc As EnumWindowsProc, ByVal lParam As IntPtr) As Boolean
    End Function
    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, ByRef lpdwProcessId As UInteger) As UInteger
    End Function
    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer
    End Function
    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function GetWindowTextLength(ByVal hWnd As IntPtr) As Integer
    End Function
    Public Delegate Function EnumWindowsProc(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        ' 開きたいURLを指定 
        Dim url As String = "https://www.umayadia.com/"
        ' ブラウザを起動 
        'Dim browserProcess As Process = Process.Start("notepad.exe") 
        Dim browserProcess As Process = Process.Start("chrome.exe", url)
        'Dim browserProcess As Process = Process.Start("msedge.exe", url) 
        'Dim browserProcess As Process = Process.Start(url) 
        ' プロセスIDを取得 
        Dim processId As UInteger = Convert.ToUInt32(browserProcess.Id)
        Console.WriteLine("processId: " & processId.ToString())
        Try
            Console.WriteLine("MainWindowHandle: " & browserProcess.MainWindowHandle.ToString())
        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try
        browserProcess.WaitForExit(10000)
        Console.WriteLine("MainWindowHandle: " & browserProcess.MainWindowHandle.ToString())
        ' ウィンドウハンドルを列挙してプロセスIDに対応するウィンドウハンドルを検索 
        EnumWindows(AddressOf EnumWindowsCallback, IntPtr.Zero)
    End Sub
    Private Function EnumWindowsCallback(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
        Dim getProcessId As UInteger
        GetWindowThreadProcessId(hWnd, getProcessId)
        Dim length As Integer = GetWindowTextLength(hWnd)
        If length > 0 Then
            Dim windowTitle As New System.Text.StringBuilder(length + 1)
            GetWindowText(hWnd, windowTitle, windowTitle.Capacity)
            Console.WriteLine("ウィンドウハンドル: " & hWnd.ToString() & ", ウィンドウタイトル: " & windowTitle.ToString() & ", プロセスID: " & getProcessId.ToString())
        End If
        Return True ' 次のウィンドウを列挙 
    End Function
End Class
        投稿者  ポッキー  (社会人)
        
        投稿日時 
            2025/3/15 15:03:41
        
    
    
        ちょっと入院することになり、返信が遅れて申し訳ございません。
戻ってきてから試したら、Process.Start(url)で取得したオブジェクトのMainWindowHandleは0が返ってきて、
エラーにはなりませんでした。
当時何か問題があったのかも知れませんが、再現しませんでした。
とは言え、Process.Start(url)で取得したオブジェクトのMainWindowHandleが0ということは、
実際に起動したブラウザのWindowハンドルは得られていないということになるので、
この方法ではブラウザの特定ができなさそうです。
今回の問題は、必ずしも重要なポイントではないので、あきらめようと思います。
ありがとうございました。
    
戻ってきてから試したら、Process.Start(url)で取得したオブジェクトのMainWindowHandleは0が返ってきて、
エラーにはなりませんでした。
当時何か問題があったのかも知れませんが、再現しませんでした。
とは言え、Process.Start(url)で取得したオブジェクトのMainWindowHandleが0ということは、
実際に起動したブラウザのWindowハンドルは得られていないということになるので、
この方法ではブラウザの特定ができなさそうです。
今回の問題は、必ずしも重要なポイントではないので、あきらめようと思います。
ありがとうございました。
関連付けられたアプリケーションでファイルを開く
https://www.umayadia.com/vbsample/sample0000/Sample093ShellEx.htm
例えば、
Dim p As Process = Process.Start("https://www.umayadia.com/")
を実行すると、通常使用するブラウザがChromeの場合、Chromeが起動し、ここにVisual Basic 中学校のトップページが表示されます。
すでにChromeが起動している場合、起動中のChromeの新しいタブに指定ページが表示されます。
これはこれでいいのですが、その場合、そのChromeブラウザが手前に表示されないことがあります。
この場合、どのようにすればそのChromeブラウザを手前に表示できるようになりますか?
色々調べたところ、Win32 APIのSetForegroundWindowを使用すれば、そのWindowを全面表示できるようですが、
今回のケースでは対象ブラウザのWindowHandleが必要になります。
そこで、上記で取得したProcessオブジェクトのMainWindowHandleを取得しようとすると、
「System.InvalidOperationException: プロセスは終了しているため、要求された情報は利用できません。」
という例外が出ます。
おそらく、上記で取得したProcessオブジェクトは通常使用するブラウザのプロセスではなく、
ファイルの関連付けで起動したShellか何かなのだろうと思いますが、
Process.Startでページを開いたブラウザのプロセスの取得方法を知りたくて、質問しました。