Curl Global Community
スクリーンショットを取得したい - Printable Version

+- Curl Global Community (https://communities.curl.com)
+-- Forum: Discussions (https://communities.curl.com/forumdisplay.php?fid=1)
+--- Forum: General Curl questions (https://communities.curl.com/forumdisplay.php?fid=2)
+--- Thread: スクリーンショットを取得したい (/showthread.php?tid=906)



スクリーンショットを取得したい - Kaneko - 05-29-2013

Curlのアプリで、エラーが発生した際にスクリーンショットを送ってもらうことが、時々あるんですが、
これをCurlのアプリ側でハンドリングすることはできないでしょうか?

①スクリーンショットを取得する(クリップボードでも、メモリ上でも、ファイルでも)
②特定のフォルダに吐き出す

の処理ができれば嬉しいんですが、
ActiveXで出来るのか?とも思ったんですが、ActiveXの情報の集め方がよくわからず、
苦戦しています。

よろしくお願いします。



RE: スクリーンショットを取得したい - dyoshida - 05-31-2013

Curlアプリのエラー状況のスクリーンショットに使えるか怪しい感もありますが
試しにCurlで保存するコードを書いてみました。

Code:
|| CurlのグラフィックをPNG形式のファイルに保存するプロシージャ
{define-proc {save-root-graphic g:Graphic}:void
    || GraphicからPixmapを生成
    def pm = {Graphic-to-Pixmap g}

    || ImageDataを生成してPixmapを格納
    let img:ImageData = {ImageData}
    {img.pixmaps.append pm}

    || ファイル保存先のダイアログを表示
    {let file-url:#Url =
        {choose-file
            style = FileDialogStyle.save-as,
            title="Save screen shot",
            filters={{Array-of FileDialogFilter}
                        {FileDialogFilter
                            "PNG",
                            {new
                                {Array-of FileDialogTypeFilter},
                                {FileDialogTypeFilter "png"}
                            }
                        }
                    }
        }
    }

    || ImageDataをPNG形式で指定ファイルパスへ保存  
    {if-non-null file-url then
        {img.save-to-url file-url, "image/png"}
        {popup-message "保存しました"}
    }
}

|| スクリーンショットを取る領域の名前定義
{def main-box-name = "main-box"}

|| 保存ボタン押下イベント
{def on-save-button-event:EventHandler =
    {on Action at b:CommandButton do
        || ボタンから親をたどってスクリーンショットを取る領域のグラフィックを取得
        let grp:Graphic = b
        {while grp.parent != null do
            set grp = grp.parent
            {if grp.name == main-box-name then
                {break}
            }
        }
        || グラフィックを保存
        {save-root-graphic grp}
    }
}

|| 画面表示
{value
    {VBox name = main-box-name,
        halign="center",
        margin=2mm,
        {bold このアプリのスクリーンショットを保存},
        {Fill height = 2mm},
        {CommandButton
            label="スクリーンショット保存",
            on-save-button-event
        }
    }
}

画面がリフレッシュされると直ってしまうエラーの場合は上記の方法だと駄目かもしれないので、
その場合はスクリーンショットを取るActiveXコンポーネントを使った方がよいかもしれないですね。

Windwos標準でもっているActiveX だと、WScript.Shell が使えそうなのですが、これで
OSにALT + PrintScreenキーイベントを送ればクリップボードにスクリーンショットをとれるかとも
思ったのですが、情報抜き取りの悪用を避けるためかPrintScreenキー送信は不可でした・・・

他の方法も探してみます


RE: スクリーンショットを取得したい - Kaneko - 05-31-2013

試してみました。
かなりいい!ですが、POPUPだったり、Viewだったりで複数のオブジェクトが表示されている場合があるので、
あと一歩!(勝手に、評価してすいません)という印象でした。

たしかにPrintScreenは渡せないみたいですね。
ちょっと調べた範囲では、Excelを使った方法があるみたいですが
http://d.hatena.ne.jp/language_and_engineering/20081121/1227203100

これと同等のことをCurlからやる方法がイマイチわからず。。。

CurlとActiveXを駆使すればなんでもできてしまいそうな反面、
ActiveXとかWindowsの知識がシッカリしていないので、実装が難しいです。。。

上のコードをCurlに変換して頂けませんか!
期待してます。。。



RE: スクリーンショットを取得したい - dyoshida - 05-31-2013

ご指摘の通り、エラーが発生したときの状況把握という目的だとイマイチなのですよね・・・
Curlだけで書いているのでプラットフォーム依存がないというメリットはあるのですが

>ちょっと調べた範囲では、Excelを使った方法があるみたいですが

Excelマクロの機能をつかってWin32APIのkeybd_event()でキーイベントを送信・・・
なにかいろいろとレガシーな機能やAPIを使った方法のようなので、OSやExcelの
バージョンによっては動かなくなりそうな裏技っぽい気もしますが、書いてみました。

とりあえず、Windows7 pro(32bit) +Excel2007の環境ではこれで動作しました。
Code:
{import * from CURL.GRAPHICS.ACTIVEX}
{import * from CURL.DESKTOP.CLIPBOARD}


|| WindowsへALT+PrintScreenキー押下イベントを送るプロシージャ
{define-proc {send-alt-print-screen-key}:void
    def obj-excel =
        {ActiveXObject
            ProgId = "Excel.Application"
        }
    {obj-excel.ExecuteExcel4Macro( "CALL(\"user32\",\"keybd_event\",\"JJJJJ\",18, 0, 1,0)" )} || ALT press
    {obj-excel.ExecuteExcel4Macro( "CALL(\"user32\",\"keybd_event\",\"JJJJJ\",44, 0, 1,0)" )} || PrintScreen press
    {obj-excel.ExecuteExcel4Macro( "CALL(\"user32\",\"keybd_event\",\"JJJJJ\",44, 0, 3,0)" )} || PrintScreen release
    {obj-excel.ExecuteExcel4Macro( "CALL(\"user32\",\"keybd_event\",\"JJJJJ\",18, 0, 3,0)" )} || ALT release
}

|| クリップボードの画像をPNG形式のファイルに保存するプロシージャ
{define-proc {save-clip-board}:void
    || クリップボードを取得
    let cb:Clipboard = {Clipboard.get-system-clipboard}
    def cb-obj = {cb.get-object}

    || クリップボードから取得したPixmapをImageDataへ格納
    || Todo クリップボードから取得したオブジェクトがpixmapかチェックが必要
    let img:ImageData = {ImageData}
    {img.pixmaps.append (cb-obj asa Pixmap)}

    || ファイル保存先のダイアログを表示
    {let file-url:#Url =
        {choose-file
            style = FileDialogStyle.save-as,
            title="Save screen shot",
            filters={{Array-of FileDialogFilter}
                        {FileDialogFilter
                            "PNG",
                            {new
                                {Array-of FileDialogTypeFilter},
                                {FileDialogTypeFilter "png"}
                            }
                        }
                    }
        }
    }
    
    || ImageDataをPNG形式で指定ファイルパスへ保存  
    {if-non-null file-url then
        {img.save-to-url file-url, "image/png"}
        {popup-message "保存しました"}
    }
}

|| 保存ボタン押下イベント
{def on-save-button-event:EventHandler =
    {on Action at b:CommandButton do
        || WindowsへALT+PrintScreenキー押下イベントを送る
        {send-alt-print-screen-key}
        || クリップボードに貼られたスクリーンショットを保存する処理をイベントキューへ積む
        || Todo
        ||  PrintScreenキーによるスクリーンショットのクリップボードへの貼り付けの完了待ちが
        ||  イベントキューへ積むだけで取れるのか不明なので念のため1s待って処理
        {after 1s do
            {save-clip-board}
        }
    }
}

|| 画面表示
{value
    {View
        visibility = "normal",
        {VBox
            halign="center",
            margin=2mm,
            {bold このアプリのスクリーンショットを保存},
            {Fill height = 2mm},
            {CommandButton
                label="スクリーンショット保存",
                on-save-button-event
            }
        },
        {on WindowClose do
            {exit}
        }
    }
}

アクティブウィンドウをキャプチャするために、ALTキーのon/offを追加していますが、
ディスクトップ全体をキャプチャしたい場合は"ALT press"/ ”ALT release”の
コメントが付いている行を削ってください。

とりあえず動きますという程度のコードですが、Curlでもこの技つかえましたね、
ということでご参考まで。