主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

スポンサーサイト

                
tags:
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

IronPython: アンマネージドコードを実行するために

                
当記事のスクリプトはWindows 7(64bit), .NET Framework 4.0で実行確認済み


 スクリーンショットのメソッドが、.NETのGraphicsクラスに用意されている。これを使って、スクリーンキャプチャをウィンドウに表示するアプリケーションを作ってみる。

 キャプチャしたデータはBitmapオブジェクトのGetHBitmapメソッドを呼ぶことで、WPFでも使えるBitmapオブジェクトになる……のだけど、一筋縄ではいかない。GetHBitmapのドキュメントの中段あたりに解説がある。「GDI ビットマップ オブジェクトが使用するメモリを解放するために、GDI DeleteObject メソッドを呼び出す必要があります」。このDeleteObjectメソッドを呼べるものが、.NETでは用意されていない。
 そのためC#でアンマネージドコードのラッパークラスを作成して、それをIronPythonから呼び出せるようにする必要がある。ラッパークラスのコードは下の2つめのリンクを参考にDLLを作る。
http://www.c-sharpcorner.com/uploadfile/perrylee/screencapture11142005234547pm/screencapture.aspx
http://www.voidspace.org.uk/ironpython/winforms/part10.shtml

 DLLを作成したら、あとはIronPythonからDLLを読み込んで、モジュールとして呼び出して使えばいい。スクリーンキャプチャを高速に繰り返すと、大量のビットマップが作られることになる。DeleteObjectメソッドを読びつつ、ガベージコレクションのgcモジュールからcollectionメソッドを呼ばないとメモリが解放されず、すぐにメモリリークする。アンマネージドコードの実行に際しては、CLRの外で行われるのでメモリ解放を忘れないこと。
Window1.py
import clr
import wpf
import gc

clr.AddReference("System.Drawing")
clr.AddReference("System.Windows.Forms")

import System
from System import IntPtr, TimeSpan
from System.Drawing import Bitmap, Graphics, Point, Size
from System.Windows import Window, Application, Int32Rect
from System.Windows.Input import *
from System.Windows.Threading import DispatcherTimer
from System.Windows.Media import ImageBrush
from System.Windows.Media.Imaging import BitmapImage, BitmapSizeOptions
from System.Windows.Interop import Imaging
from System.Windows.Controls import Image
from System.Windows.Forms import Screen

clr.AddReference("UnmanagedCode")
from UnmanagedCode import GDI32

WIDTH = Screen.PrimaryScreen.Bounds.Width
HEIGHT = Screen.PrimaryScreen.Bounds.Height

class Window1(Window):
def __init__(self):
wpf.LoadComponent(self, 'Window1.xaml')
self.imageBrush = self.FindName('imageBrush')
self.Show()

self.timer1 = DispatcherTimer()
self.timer1.Interval = TimeSpan(0, 0, 0.0165)
self.timer1.Tick += self.tickOn
self.timer1.Start()

def tickOn(self, target, e):
bmp = Bitmap(WIDTH, HEIGHT)
g = Graphics.FromImage(bmp)
g.CopyFromScreen(0, 0, 0, 0, Size(WIDTH, HEIGHT))
g.Dispose()
screenBmp = bmp.GetHbitmap()
source = Imaging.CreateBitmapSourceFromHBitmap(screenBmp,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions())
self.imageBrush.ImageSource = source

# to prevent memory leak
GDI32.DeleteObject(screenBmp)
gc.collect()


Window1.xaml
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Title="ScreenCapture"
Width="500"
Left="0"
Height="500"
WindowState="Normal">
<StackPanel
Name="stack00"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" >
<StackPanel.Background>
<ImageBrush x:Name="imageBrush" Stretch="Uniform" />
</StackPanel.Background>
</StackPanel>
</Window>


Application.py
import wpf

from System.Windows import Application
from Window1 import Window1

window = Window1()
app = Application()
app.Run(window)


            

コメントの投稿

非公開コメント

プロフィール

hMatoba

Author:hMatoba
Github

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。