4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PowerShell でスクリーンショットを Excel シートに自動ペースト

Last updated at Posted at 2020-04-04

C♯ のたすけをかりてクリップボードのイベント駆動に成功

拙文『スクリーンショットをExcelシートに半自動でペーストする(エビデンス取得用)』 (Excel VBA) ではイベント駆動に挫折し無限ループをまわしていますが、こちらは成功いたしました。

2019/04/09 更新

  • ワークシートを追加するとアクティブ ワークシートにペーストされるようにしました。
  • ただし、このスクリプトから起動した Excel でべつのワークブックをひらいても干渉しないようにしました1

2019/04/09 再更新

  • アクティブ ワークブックのきりかえではアクティブ ワークシートが「リセット」されてしまうので修正しました。
Paste-ScreenshotToExcelSheet.ps1
Add-Type -TypeDefinition @'
    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    public class ClipboardListeningForm : Form
    {
        [DllImport("user32.dll", SetLastError = true)]
        private extern static void AddClipboardFormatListener(IntPtr hwnd);

        [DllImport("user32.dll", SetLastError = true)]
        private extern static void RemoveClipboardFormatListener(IntPtr hwnd);

        public event EventHandler ClipboardUpdate;
        public const int WM_CLIPBOARDUPDATE = 0x031D;

        protected override void OnLoad(EventArgs e)
        {
            AddClipboardFormatListener(Handle);
            base.OnLoad(e);
        }

        protected override void Dispose(bool disposing)
        {
            RemoveClipboardFormatListener(Handle);
            base.Dispose(disposing);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_CLIPBOARDUPDATE)
            {
                OnClipboardUpdate(EventArgs.Empty);
                m.Result = IntPtr.Zero;
            }
            else
                base.WndProc(ref m);
        }

        protected virtual void OnClipboardUpdate(EventArgs e)
        {
            EventHandler handler = ClipboardUpdate;
            if (handler != null)
            {
                handler(this, e);
            }
        }            
    }
'@ -ReferencedAssemblies System.Windows.Forms

Add-Type -AssemblyName Microsoft.Office.Interop.Excel

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$excel.DisplayAlerts = $true
$xlWorkbook = $excel.Workbooks.Add([Microsoft.Office.Interop.Excel.xlWBATemplate]::xlWBATWorksheet)
$excel.ActiveWindow.Caption = 'Screenshots'
$xlWorksheet = $xlWorkbook.Worksheets(1)
$xlActiveSheet = $xlWorksheet

$form = New-Object -TypeName ClipboardListeningForm
$form.Text = 'Start Capturing'

$toggleButton = New-Object -TypeName System.Windows.Forms.CheckBox
$toggleButton.Appearance = [System.Windows.Forms.Appearance]::Button
$toggleButton.Left = ($form.ClientRectangle.Width - $toggleButton.Width) / 2
$toggleButton.Top = ($form.ClientRectangle.Height - $toggleButton.Height) / 2
$toggleButton.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
$toggleButton.Text = 'Start'
$toggleButton.add_CheckedChanged({
    if ($toggleButton.Checked) {
        $toggleButton.Text = 'Stop'
        $form.Text = 'Capturing'
    } else {
        $toggleButton.Text = 'Start'
        $form.Text = 'Stopped'
    }
})
$form.Controls.Add($toggleButton)

$form.add_ClipboardUpdate({
    $xlActiveSheet = $excel.ActiveWorkbook.ActiveSheet
    $xlWorksheet = $xlWorkbook.ActiveSheet
    $targetColumn, $targetRow = 2, 2
    if ($toggleButton.Checked -and [System.Windows.Forms.Clipboard]::ContainsImage()) {
        $shapesCount = $xlWorksheet.Shapes.Count
        if ($shapesCount -gt 0) {
            $targetRow = $xlWorksheet.Shapes($shapesCount).BottomRightCell.Offset(1).Row
        }
        $xlWorksheet.Activate()
        $xlWorksheet.Cells($targetRow, $targetColumn).Select()
        $xlWorksheet.Paste()
        $xlActiveSheet.Activate()
    }
})

$form.ShowDialog()

$excel.Quit()
[void] [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlWorksheet)
[void] [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlActiveSheet)
[void] [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlWorkbook)
[void] [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)

参考文献

  1. アクティブ ワークシートおよびアクティブ ワークブックのきりかえで対処してるのでちらつきます。また、フォームをとじるとこのプロセスの Excel からひらいたワークブックはすべてとじます。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?