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

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

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

Re[10]: PrintWindowでChromeウインドウを取得する


(過去ログ 173 を表示中)

[トピック内 23 記事 (1 - 20 表示)]  << 0 | 1 >>

■99458 / inTopicNo.1)  PrintWindowでChromeウインドウを取得する
  
□投稿者/ ぜん (1回)-(2022/04/14(Thu) 15:08:05)

分類:[.NET 全般] 

VB.NETを使っております。


PrintWindow APIを使って、Google Chromeウインドウの
スクリーンショットを取得したいと考えています。
他にもスクリーンショットをとる方法があるのは知っていますが
他のウインドウの下に隠れていても取得できるのはこれだけなので
これを使用したいと考えています。

しかし、Chrome以外のウインドウだとうまくいくのですが
Chromeだけは、画像が真っ暗になってしまいます。


https://stackoverflow.com/questions/30965343/printwindow-could-not-print-google-chrome-window-chrome-widgetwin-1

https://social.msdn.microsoft.com/Forums/windowsapps/en-US/838a0ba2-6142-4185-a2a2-0030ad02f984/printwindow-api-with-possible-solution-for-capture-screenshot-google-chrome-window?forum=winforms


同じような質問ページは見つかるのですが、
どのコードを使えば良いのか分かりません。

どなたか解決方法をご提示いただけないでしょうか?









引用返信 編集キー/
■99459 / inTopicNo.2)  Re[1]: PrintWindowでChromeウインドウを取得する
□投稿者/ くま (189回)-(2022/04/14(Thu) 16:17:34)
> Google Chromeウインドウ
画面サイズよりページが大きい場合とかどうするつもり?
(スクロールする場合)
引用返信 編集キー/
■99461 / inTopicNo.3)  Re[2]: PrintWindowでChromeウインドウを取得する
□投稿者/ ぜん (2回)-(2022/04/14(Thu) 17:05:09)
No99459 (くま さん) に返信
>>Google Chromeウインドウ
> 画面サイズよりページが大きい場合とかどうするつもり?
> (スクロールする場合)

表示している箇所だけで十分です

引用返信 編集キー/
■99462 / inTopicNo.4)  Re[3]: PrintWindowでChromeウインドウを取得する
□投稿者/ くま (190回)-(2022/04/14(Thu) 18:44:46)
chromeが黒くなるのはウインドウの描写自体が普通のウインドウと違うからなんだけど
黒くなったかな?

> 他のウインドウの下に隠れていても取得できるのはこれだけなので
> これを使用したいと考えています。

> 表示している箇所だけで十分です

それなら多分一瞬前面に持ってきてキャプチャするのが一番良いと思うよ
この場合だと色々多分試さないとうまくいかないと思うから
(最小化されている場合や画面表示外の場合、最大化の場合等条件付けが多い)

https://dobon.net/vb/dotnet/graphics/screencapture.html


引用返信 編集キー/
■99463 / inTopicNo.5)  Re[4]: PrintWindowでChromeウインドウを取得する
□投稿者/ ぜん (3回)-(2022/04/14(Thu) 19:07:32)
一瞬だけ前面に持って行く方法も知っていますが
他の作業をしながらだと
うまくいかない場合があるため、やはり背面にある状態で取得したいと思います。
何か他に方法はございませんでしょうか?
引用返信 編集キー/
■99464 / inTopicNo.6)  Re[5]: PrintWindowでChromeウインドウを取得する
□投稿者/ Hongliang (1226回)-(2022/04/14(Thu) 19:48:08)
対象がChrome限定なのであれば、Seleniumを使うのがいいかもしれません。
一応既存のChromeプロセスにアタッチすることもできます。
引用返信 編集キー/
■99466 / inTopicNo.7)  Re[6]: PrintWindowでChromeウインドウを取得する
□投稿者/ ぜん (4回)-(2022/04/14(Thu) 20:29:30)
ありがとうございます。
しかしやはりVBを使いたいと考えています。
上記のサイトによると
#if(_WIN32_WINNT >= 0x0603)
#define PW_RENDERFULLCONTENT 0x00000002
#endif /* _WIN32_WINNT >= 0x0603 */

でうまくいくと書かれていると思うのですが、
これってどこで使っているのでしょうか?

また、DWM Thumbnail APIでもできそうなことが書かれてあるのですが
これはどうやって使えば良いですか?
検索してもいまいち使い方が分かりませんでした。
引用返信 編集キー/
■99467 / inTopicNo.8)  Re[7]: PrintWindowでChromeウインドウを取得する
□投稿者/ Hongliang (1227回)-(2022/04/14(Thu) 20:32:04)
> しかしやはりVBを使いたいと考えています。
SeleniumはVBを含めたいろんな言語から呼び出せる、ブラウザのオートメーション用ライブラリです。
引用返信 編集キー/
■99468 / inTopicNo.9)  Re[8]: PrintWindowでChromeウインドウを取得する
□投稿者/ ぜん (5回)-(2022/04/14(Thu) 23:19:12)
できればSeleniumを使わずに実行したいと考えていますが、
上記のサイトの方法は使えないでしょうか?
引用返信 編集キー/
■99469 / inTopicNo.10)  Re[7]: PrintWindowでChromeウインドウを取得する
□投稿者/ radian (28回)-(2022/04/15(Fri) 07:22:33)
No99466 (ぜん さん) に返信
> ありがとうございます。
> しかしやはりVBを使いたいと考えています。
> 上記のサイトによると
> #if(_WIN32_WINNT >= 0x0603)
> #define PW_RENDERFULLCONTENT 0x00000002
> #endif /* _WIN32_WINNT >= 0x0603 */
>
> でうまくいくと書かれていると思うのですが、
> これってどこで使っているのでしょうか?

C++のヘッダで定義されてる内容だと思いますが。
試しにPrintWindowのnFlagsに2指定してみたらキャプチャできたんで、やってみればよいのでは?
引用返信 編集キー/
■99472 / inTopicNo.11)  Re[1]: PrintWindowでChromeウインドウを取得する
□投稿者/ 魔界の仮面弁士 (3319回)-(2022/04/15(Fri) 10:47:26)
No99458 (ぜん さん) に返信
> しかし、Chrome以外のウインドウだとうまくいくのですが
> Chromeだけは、画像が真っ暗になってしまいます。

対象のウィンドウは "Chrome_WidgetWin_1" クラスですか?


No99466 (ぜん さん) に返信
> また、DWM Thumbnail APIでもできそうなことが書かれてあるのですが
> これはどうやって使えば良いですか?
> 検索してもいまいち使い方が分かりませんでした。
そうですか? 使い方の説明なら、すぐに出てきましたよ。
使う関数もそう多くは無いですし。
https://docs.microsoft.com/ja-jp/windows/win32/dwm/thumbnail-ovw


Option Strict On
Imports System.Runtime.InteropServices

Public Class Form1
  Private ThumbnailId As IntPtr = IntPtr.Zero
  Private Function GetChromeHandle() As IntPtr
   Throw New NotImplementedException("取得対象の HWND を取得するコードをここに記述")
  End Function

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Button1.Text = "描画開始"
  End Sub
  Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
    If ThumbnailId <> IntPtr.Zero Then
      DwmUnregisterThumbnail(ThumbnailId)
      ThumbnailId = IntPtr.Zero
    End If
  End Sub

  Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    If ThumbnailId = IntPtr.Zero Then
      Dim chromeHandle As IntPtr = GetChromeHandle()
      DwmRegisterThumbnail(Me.Handle, chromeHandle, ThumbnailId)
      UpdateThumbnail()
      Button1.Text = $"描画停止:{ThumbnailId}"
    Else
      DwmUnregisterThumbnail(ThumbnailId)
      ThumbnailId = IntPtr.Zero
      Button1.Text = "描画開始"
    End If
  End Sub

  Private Sub UpdateThumbnail()
    If ThumbnailId <> IntPtr.Zero Then
      Dim rect = Me.RectangleToClient(PictureBox1.RectangleToScreen(PictureBox1.ClientRectangle))
      DwmUpdateThumbnailProperties(ThumbnailId, New DWM_THUMBNAIL_PROPERTIES(rect, False))
    End If
  End Sub


#Region "DWM サムネイル API"
  Private Declare Auto Function DwmRegisterThumbnail Lib "dwmapi" (hwndDestination As IntPtr, hwndSource As IntPtr, <Out> ByRef phThumbnailId As IntPtr) As Integer
  Private Declare Auto Function DwmUpdateThumbnailProperties Lib "dwmapi" (hThumbnailId As IntPtr, <[In]> ptnProperties As DWM_THUMBNAIL_PROPERTIES) As Integer
  Private Declare Auto Function DwmUnregisterThumbnail Lib "dwmapi" (hThumbnailId As IntPtr) As Integer
  <StructLayout(LayoutKind.Sequential)>
  Public Structure RECT
    Public left As Integer, top As Integer, right As Integer, bottom As Integer
    Public Shared Widening Operator CType(r As RECT) As Rectangle
      Return Rectangle.FromLTRB(r.left, r.top, r.right, r.bottom)
    End Operator
    Public Shared Widening Operator CType(r As Rectangle) As RECT
      Return New RECT With {.left = r.Left, .top = r.Top, .right = r.Right, .bottom = r.Bottom}
    End Operator
  End Structure
  <Flags>
  Private Enum DWM_TNP As UInteger
    None = 0
    RectDestination = &H1UI
    RectSource = &H2UI
    Opacity = &H4UI
    Visible = &H8UI
    SourceClientAreaOnly = &H10UI
  End Enum
  <StructLayout(LayoutKind.Sequential)>
  Private Class DWM_THUMBNAIL_PROPERTIES
    Public dwFlags As DWM_TNP = DWM_TNP.None
    Public rcDestination As RECT
    Public rcSource As RECT
    Public opacity As Byte = 255
    <MarshalAs(UnmanagedType.Bool)> Public fVisible As Boolean = False
    <MarshalAs(UnmanagedType.Bool)> Public fSourceClientAreaOnly As Boolean = False
    Public Sub New()
    End Sub
    Public Sub New(destination As Rectangle, clientOnly As Boolean)
      dwFlags = DWM_TNP.RectDestination Or DWM_TNP.SourceClientAreaOnly
      rcDestination = destination
      fSourceClientAreaOnly = clientOnly
    End Sub
  End Class
#End Region
End Class
引用返信 編集キー/
■99474 / inTopicNo.12)  Re[2]: PrintWindowでChromeウインドウを取得する
□投稿者/ 魔界の仮面弁士 (3320回)-(2022/04/15(Fri) 13:40:07)
2022/04/15(Fri) 13:53:51 編集(投稿者)

No99472 (魔界の仮面弁士) に追記
> ■No99466 (ぜん さん) に返信
>>また、DWM Thumbnail APIでもできそうなことが書かれてあるのですが
>>これはどうやって使えば良いですか?
>>検索してもいまいち使い方が分かりませんでした。
> そうですか? 使い方の説明なら、すぐに出てきましたよ。
> 使う関数もそう多くは無いですし。

すみません。質問の意図を勘違いしていました。


サムネイルを取得したいわけではなく、あくまでも「スクリーンショット」が目的なので、
恐らくはそれを画像として保存する必要があるのですよね。
(クリップボードに送るのか、ファイルとして保持するのかはさておき)


DWM でサムネイルを得る方法の場合、撮影対象のアプリは背面表示でも構いませんが、
撮影結果は HDC でなく、トップレベルウィンドウの HWND を指定する方法であるため、
そのサムネイルを、画像として直接保存する手段が無さそうですね…。

二次転写でも構わないのであれば、Graphics.CopyFromScreen あるいは BitBlt で、
サムネイルを再撮影するという手が一応あります。
(二次転写ゆえ、サムネイルを表示中のウィンドウを可視状態にしておく必要あり)
https://dobon.net/vb/dotnet/graphics/screencapture.html


(1) 一瞬だけ前面に持ってきてから撮影する案
(2) PrintWindow(hwnd, hdc, PW_RENDERFULLCONTENT) 案
(3) Selenium 案(WebDriver の ITakesScreenshot インターフェイス)
(4) DWM Thumbnail 後に二次転写案
引用返信 編集キー/
■99476 / inTopicNo.13)  Re[3]: PrintWindowでChromeウインドウを取得する
□投稿者/ 魔界の仮面弁士 (3321回)-(2022/04/15(Fri) 14:25:08)
No99474 (魔界の仮面弁士) に追記
> サムネイルを取得したいわけではなく、あくまでも「スクリーンショット」が目的なので、
> 恐らくはそれを画像として保存する必要があるのですよね。
> (クリップボードに送るのか、ファイルとして保持するのかはさておき)

Win10 1803 以降の場合は、Windows.Graphics.Capture で撮影する方法もあるようですね。
背面にあっても撮影できるし、HWND 単位 でも HMONITOR 単位でも取得可能とのこと。

https://docs.microsoft.com/ja-jp/windows/uwp/audio-video-camera/screen-capture
https://docs.microsoft.com/ja-jp/uwp/api/windows.graphics.capture?view=winrt-22000
https://qiita.com/eguo/items/90604787a6098af404d9
https://qiita.com/everylittle/items/c80de379e644397ceabc

WinForms (.NET Framework)で使う場合は、NuGet で「Microsoft.Windows.SDK.Contracts」を
指定すれば呼べるのかもしれません(要 PackageReference モード)。試したことは無いですが。
https://docs.microsoft.com/ja-jp/windows/apps/desktop/modernize/desktop-to-uwp-enhance
引用返信 編集キー/
■99478 / inTopicNo.14)  Re[4]: PrintWindowでChromeウインドウを取得する
□投稿者/ ぜん (6回)-(2022/04/15(Fri) 19:27:57)
ありがとうございます。

(2) PrintWindow(hwnd, hdc, PW_RENDERFULLCONTENT) 案

これでうまくいきました。
https://docs.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-printwindow

このページを見ると

nflagsにはPW_CLIENTONLYのオプションしかないように思えたのですが
他にオプションがあったのですね。
オプションを使い分ければもっと良い動作ができるのではないかと思い
nflagsのオプションを調べてみたのですが
検索しても書かれているページが見つかりませんでした。
どこかで解説されていますでしょうか??

引用返信 編集キー/
■99480 / inTopicNo.15)  Re[5]: PrintWindowでChromeウインドウを取得する
□投稿者/ ぜん (7回)-(2022/04/15(Fri) 20:36:43)
https://jpdebug.com/p/117894

これを見ると
二つしかオプションなさそうですね。

どうもありがとうございました。

解決済み
引用返信 編集キー/
■99481 / inTopicNo.16)  Re[5]: PrintWindowでChromeウインドウを取得する
□投稿者/ 魔界の仮面弁士 (3322回)-(2022/04/15(Fri) 20:48:01)
No99478 (ぜん さん) に返信
> nflagsにはPW_CLIENTONLYのオプションしかないように思えたのですが
> 他にオプションがあったのですね。

PrintWindow API は XP/2003 からの機能で、
PW_CLIENTONLY は Windows 8.1 で追加されたオプションですね。
現時点ではドキュメントに記載のない隠しフラグになります。


> オプションを使い分ければもっと良い動作ができるのではないかと思い
0 だとウィンドウ全体、
1 だとクライアント領域のみ(PW_CLIENTONLY)
2 がフルコンテキスト(PW_RENDERFULLCONTENT)のようですが、そのほかに
3 を渡すこともできるみたいですね。undocumented ゆえ詳細は不明ですが。

上記以外の値を渡した時は、当方環境では戻り値が FALSE となりました。
※エラー 87 (パラメーターが間違っています。)
引用返信 編集キー/
■99482 / inTopicNo.17)  Re[6]: PrintWindowでChromeウインドウを取得する
□投稿者/ ぜん (8回)-(2022/04/15(Fri) 20:53:50)
ありがとうございます。

気になっているのですが
オプション0と1って違うものなのでしょうか?
https://jpdebug.com/p/117894

このページでは
"Only the client area of the window is copied to hdcBlt. By default, the entire window is copied.")]
と書かれてありますが、
デフォルトの設定だと1を選んだとしてもウインドウ全体を取得することになるが、
何か設定するとクライアント領域のみを取得できるという意味なのでしょうか??
引用返信 編集キー/
■99483 / inTopicNo.18)  Re[6]: PrintWindowでChromeウインドウを取得する
□投稿者/ 魔界の仮面弁士 (3323回)-(2022/04/15(Fri) 21:12:17)
2022/04/15(Fri) 21:13:57 編集(投稿者)

No99481 (魔界の仮面弁士) に追記
>>オプションを使い分ければもっと良い動作ができるのではないかと思い
> 0 だとウィンドウ全体、
> 1 だとクライアント領域のみ(PW_CLIENTONLY)
> 2 がフルコンテキスト(PW_RENDERFULLCONTENT)のようですが、そのほかに
> 3 を渡すこともできるみたいですね。undocumented ゆえ詳細は不明ですが。

https://docs.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-printwindow
によれば
  By default, the entire window is copied.
  既定ではウィンドウ全体がコピーされる。
とあり、PW_CLIENTONLY を指定した場合は
  Only the client area of the window is copied to hdcBlt.
  ウィンドウのクライアント領域のみがhdcBltにコピーされる。
とあることから、1 (PW_CLIENTONLY) だけでなく 0 も有効であると読み取ることができます。

2 (PW_RENDERFULLCONTENT) は、WinUser.h の記載から、
PrintWindow に渡せるのだと推察できますが、このフラグの意味は、
現時点において、明確に文書化されてはいないようです。

3 については、当方で実際に試してみたら動いた、という状況です。
メモ帳で試した場合、1 と 3 は、共に「クライアント領域」を描画しました。


Chrome の場合は、タイトルバー部にタブを重ねているので、
ウィンドウ全体の撮影なのかクライアント領域の撮影なのか区別し辛いですが
手元の環境では、2 と 3 の内容がほぼ同じになりました。
しかし、たまに違う結果になるウィンドウもありました。謎。

0 = 黒一色(0x000000)。稀に、左端と下端に、ビジュアル スタイルのウィンドウ枠が現れる事もある。
1 = 黒一色。
2 = 0 でウィンドウ枠が出ていた場合は、左端に黒い余白が入る。
3 = 2 を指定したようなズレは生じず、全体が綺麗に描画された。
引用返信 編集キー/
■99484 / inTopicNo.19)  Re[7]: PrintWindowでChromeウインドウを取得する
□投稿者/ ぜん (9回)-(2022/04/15(Fri) 21:40:22)
文書化されていないオプションが存在するのですね。
ユーザーがどうやって発見したのか気になりますね。
どうもありがとうございました。
解決済み
引用返信 編集キー/
■99485 / inTopicNo.20)  Re[7]: PrintWindowでChromeウインドウを取得する
 
□投稿者/ 魔界の仮面弁士 (3324回)-(2022/04/15(Fri) 21:51:45)
No99483 (魔界の仮面弁士) に追記
> Chrome の場合は、タイトルバー部にタブを重ねているので、
> ウィンドウ全体の撮影なのかクライアント領域の撮影なのか区別し辛いですが
> 手元の環境では、2 と 3 の内容がほぼ同じになりました。
> しかし、たまに違う結果になるウィンドウもありました。謎。
>
> 0 = 黒一色(0x000000)。稀に、左端と下端に、ビジュアル スタイルのウィンドウ枠が現れる事もある。
> 1 = 黒一色。
> 2 = 0 でウィンドウ枠が出ていた場合は、左端に黒い余白が入る。
> 3 = 2 を指定したようなズレは生じず、全体が綺麗に描画された。


参考までに、フラグ 0〜4 に変化させて Chrome を撮影した結果を載せておきます。
前半は通常サイズのウィンドウで、後半は最小化されている状態で PrintWindow したものです。

https://www.vb-user.net/junk/replySamples/2022.04.15.21.45/PrintWindow.apng

※PNG アニメで保存しているので、IE 以外のブラウザで見てください。
解決済み
引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -