<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1384551653506604356</id><updated>2012-01-15T17:00:04.293+01:00</updated><category term='wcf'/><category term='WinDbg'/><category term='virtualbox'/><category term='accessibility'/><category term='ironpython'/><category term='clrtype'/><category term='python'/><category term='links'/><category term='OpenWrt'/><category term='silverlight'/><category term='guiat'/><category term='wpf'/><title type='text'>GUI Automated Testing</title><subtitle type='html'>and other interesting topics</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>26</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-3488663419162554577</id><published>2011-11-13T20:06:00.000+01:00</published><updated>2011-11-14T00:56:58.917+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wpf'/><category scheme='http://www.blogger.com/atom/ns#' term='silverlight'/><title type='text'>Sharing .xaml in WPF and Silverlight</title><content type='html'>&lt;p&gt;Sharing code between WPF and Silverlight is not difficult. Good how-to is in the &lt;a href="http://msdn.microsoft.com/en-us/library/ff921109(v=PandP.40).aspx"&gt;Prism guide&lt;/a&gt;. However sharing more complex &lt;span class="tt"&gt;.xaml&lt;/span&gt; is not so easy. You have to handle different namespaces and properties.&lt;p&gt;&lt;b&gt;Handling different namespaces&lt;/b&gt;&lt;p&gt;Silverlight toolkit components are accessible via special namespace. So if you want to use a &lt;span class="tt"&gt;WrapPanel&lt;/span&gt; in Silverlight, you write something like this:&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;UserControl x:Class="UnifiedXaml.TestControl"&lt;br /&gt;             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;br /&gt;             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;             xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"&amp;gt;&lt;br /&gt;    &amp;lt;toolkit:WrapPanel&amp;gt;&amp;lt;/toolkit:WrapPanel&amp;gt;&lt;br /&gt;&amp;lt;/UserControl&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;WPF world is easier:&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;UserControl x:Class="UnifiedXaml.TestControl"&lt;br /&gt;             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;br /&gt;             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;&lt;br /&gt;    &amp;lt;WrapPanel&amp;gt;&amp;lt;/WrapPanel&amp;gt;&lt;br /&gt;&amp;lt;/UserControl&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;It's clear those two &lt;span class="tt"&gt;.xaml&lt;/span&gt; files are so similar that they should be just one file. Here is one tiny line that makes it possible:&lt;pre class="prettyprint"&gt;&lt;br /&gt;namespace UnifiedXaml&lt;br /&gt;{&lt;br /&gt;    public class MyWrapPanel: WrapPanel { }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;From now on, you can share the &lt;span class="tt"&gt;.xaml&lt;/span&gt; file:&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;UserControl x:Class="UnifiedXaml.TestControl"&lt;br /&gt;             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;br /&gt;             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;             xmlns:ux="clr-namespace:UnifiedXaml"&amp;gt;&lt;br /&gt;    &amp;lt;ux:MyWrapPanel&amp;gt;&amp;lt;/ux:MyWrapPanel&amp;gt;&lt;br /&gt;&amp;lt;/UserControl&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Handling different properties&lt;/b&gt;&lt;p&gt;When you follow Prism guidelines, you have separate projects for WPF and Silverlight parts. That means the WPF/SL application resources dictionaries are also separate. So the easiest way to handle different properties is to use styles. Shared &lt;span class="tt"&gt;.xaml&lt;/span&gt; file specifies just the control and its style. All necessary properties for WPF are defined in the style stored in the WPF application resources dictionary and the same is done for Silverlight.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-3488663419162554577?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/3488663419162554577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=3488663419162554577' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/3488663419162554577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/3488663419162554577'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2011/11/sharing-xaml-in-wpf-and-silverlight.html' title='Sharing .xaml in WPF and Silverlight'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-6515019268881252077</id><published>2010-09-10T20:25:00.000+02:00</published><updated>2010-09-10T20:25:52.289+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Anonymous function as default argument in methods</title><content type='html'>I was quite surprised by Python recently when I tried to use anonymous function that uses a class method (not classmethod) as a default argument for another class method and it worked. Example is worth thousands words so here it is:&lt;pre class="prettyprint"&gt;&lt;br /&gt;class ListObject(object):&lt;br /&gt;    items = ((1, 'one'), (2, 'two'), (3, 'three'))&lt;br /&gt;&lt;br /&gt;    def get_num(self, item):&lt;br /&gt;        return item[0]&lt;br /&gt;&lt;br /&gt;    def get_text(self, item):&lt;br /&gt;        return item[1]&lt;br /&gt;&lt;br /&gt;    def get_list(self, fn=lambda s, i: ListObject.get_num(s, i)):&lt;br /&gt;        return [fn(self, j) for j in self.items]&lt;br /&gt;&lt;br /&gt;lo = ListObject()&lt;br /&gt;print 'numbers:', lo.get_list()&lt;br /&gt;print 'texts:', lo.get_list(ListObject.get_text)&lt;br /&gt;print 'texts:', lo.get_list(lambda s, i: i[1])&lt;br /&gt;print 'items:', lo.get_list(lambda s, i: i)&lt;br /&gt;&lt;/pre&gt;When you run this piece of code you get what you want:&lt;pre class="prettyprint"&gt;&lt;br /&gt;numbers: [1, 2, 3]&lt;br /&gt;texts: ['one', 'two', 'three']&lt;br /&gt;texts: ['one', 'two', 'three']&lt;br /&gt;items: [(1, 'one'), (2, 'two'), (3, 'three')]&lt;br /&gt;&lt;/pre&gt;By default, &lt;span class="tt"&gt;get_list&lt;/span&gt; method uses &lt;span class="tt"&gt;get_num&lt;/span&gt; method and apply it to all items. But you can supply your own fucntion to apply it on items.&lt;p&gt;Of course, this is very stupid example but it shows the principle. And this principle is quite handy for UI automation I am currently working on :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-6515019268881252077?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/6515019268881252077/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=6515019268881252077' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/6515019268881252077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/6515019268881252077'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2010/09/anonymous-function-as-default-argument.html' title='Anonymous function as default argument in methods'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-1364485596206700157</id><published>2010-05-16T16:44:00.004+02:00</published><updated>2010-05-16T18:50:56.580+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Distributing Silverlight application written in IronPython</title><content type='html'>&lt;p&gt;When you have Silverlight application written in IronPython, it is a goodidea to split it to several files so browser can cache them separately. Later,when you change something in your application, users will download only a smallpart. During my attemts with IronPython and Silverligt, I have foundseveral catches. That's why I describe here my way how to distribute IronPythonSilverlight application.&lt;/p&gt;&lt;p&gt;I distribute my application as one &lt;span class="tt"&gt;.html&lt;/span&gt; file, one&lt;span class="tt"&gt;.xap&lt;/span&gt; file, and several &lt;span class="tt"&gt;.zip&lt;/span&gt;files. I use &lt;span class="tt"&gt;.zip&lt;/span&gt; because IIS already knows what to dowith .zip files. The files are:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="tt"&gt;index.html&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="tt"&gt;app.xap&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="tt"&gt;IronPython.zip&lt;/span&gt; - contains files from &lt;span class="tt"&gt;IronPython-2.6.1\Silverlight\bin&lt;/span&gt;:&lt;pre class="prettyprint"&gt;&lt;br /&gt;IronPython.dll&lt;br /&gt;IronPython.Modules.dll&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="tt"&gt;Microsoft.Scripting.zip&lt;/span&gt; - contains files from &lt;span class="tt"&gt;IronPython-2.6.1\Silverlight\bin&lt;/span&gt;:&lt;pre&gt;&lt;br /&gt;Microsoft.Dynamic.dll&lt;br /&gt;Microsoft.Scripting.dll&lt;br /&gt;Microsoft.Scripting.Core.dll&lt;br /&gt;Microsoft.Scripting.ExtensionAttribute.dll&lt;br /&gt;Microsoft.Scripting.Silverlight.dll&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="tt"&gt;SLToolkit.zip&lt;/span&gt; - contains files form Silverlight toolkit or SDK; in our case just&lt;/li&gt;&lt;pre&gt;&lt;br /&gt;System.Windows.Controls.dll&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Let's create a small application, that uses &lt;i&gt;ChildWindow&lt;/i&gt; control from&lt;a href="http://silverlight.codeplex.com/"&gt;Silverlight toolkit&lt;/a&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPython-2.6.1\Silverlight\script\sl.bat python childwindow&lt;br /&gt;&lt;/pre&gt;Change the &lt;span class="tt"&gt;app.py&lt;/span&gt; and &lt;spanclass="tt"&gt;app.xml&lt;/span&gt;:&lt;br /&gt;&lt;p&gt;&lt;span class="tt"&gt;app.py&lt;/span&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;from System.Windows import Application&lt;br /&gt;from System.Windows.Controls import UserControl&lt;br /&gt;&lt;br /&gt;class App:&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.root = Application.Current.LoadRootVisual(UserControl(), "app.xaml")&lt;br /&gt;&lt;br /&gt;a = App()&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;span class="tt"&gt;app.xaml&lt;/span&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;UserControl x:Class="System.Windows.Controls.UserControl"&lt;br /&gt;  xmlns="http://schemas.microsoft.com/client/2007"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;  xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"&amp;gt;&lt;br /&gt;  &amp;lt;controls:ChildWindow &amp;gt;&lt;br /&gt;    &amp;lt;StackPanel&amp;gt;&lt;br /&gt;      &amp;lt;TextBlock Text="Text in ChildWindow"/&amp;gt;&lt;br /&gt;      &amp;lt;Button x:Name="btnNewWindow" Content="New window"/&amp;gt;&lt;br /&gt;    &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;  &amp;lt;/controls:ChildWindow&amp;gt;&lt;br /&gt;&amp;lt;/UserControl&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;We don't want to Chiron automatically add necesary &lt;spanclass="tt"&gt;.dll&lt;/span&gt; files into &lt;span class="tt"&gt;.xap&lt;/span&gt; so we have toadd our own &lt;span class="tt"&gt;AppManifest.xaml&lt;/span&gt; and &lt;spanclass="tt"&gt;languages.config&lt;/span&gt; into &lt;span class="tt"&gt;childwindow\app&lt;/span&gt;folder:&lt;/p&gt;&lt;p&gt;&lt;span class="tt"&gt;AppManifest.xaml&lt;/span&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;  RuntimeVersion="2.0.31005.0"&lt;br /&gt;  EntryPointAssembly="Microsoft.Scripting.Silverlight"&lt;br /&gt;  EntryPointType="Microsoft.Scripting.Silverlight.DynamicApplication"&lt;br /&gt;  ExternalCallersFromCrossDomain="ScriptableOnly"&amp;gt;&lt;br /&gt;  &amp;lt;Deployment.Parts&amp;gt;&lt;br /&gt;  &amp;lt;/Deployment.Parts&amp;gt;&lt;br /&gt;  &amp;lt;Deployment.ExternalParts&amp;gt;&lt;br /&gt;    &amp;lt;ExtensionPart Source="Microsoft.Scripting.zip" /&amp;gt;&lt;br /&gt;    &amp;lt;ExtensionPart Source="SLToolkit.zip" /&amp;gt;&lt;br /&gt;  &amp;lt;/Deployment.ExternalParts&amp;gt;&lt;br /&gt;&amp;lt;/Deployment&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;span class="tt"&gt;languages.config&lt;/span&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;Languages&amp;gt;&lt;br /&gt;  &amp;lt;Language names="IronPython,Python,py"&lt;br /&gt;    languageContext="IronPython.Runtime.PythonContext"&lt;br /&gt;    extensions=".py"&lt;br /&gt;    assemblies="IronPython.dll;IronPython.Modules.dll"&lt;br /&gt;    external="IronPython.zip"/&amp;gt;&lt;br /&gt;&amp;lt;/Languages&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now create all three &lt;span class="tt"&gt;.zip&lt;/span&gt; files and add them into&lt;span class="tt"&gt;childwindow&lt;/span&gt; folder.&lt;/p&gt;&lt;p&gt;To test the application with Chiron, run&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPython-2.6.1\Silverlight\bin\Chiron.exe /e: /d:childwindow&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;span class="tt"&gt;/e:&lt;/span&gt;switch is important - it tells Chiron to not put any assembly into generated&lt;span class="tt"&gt;.xap&lt;/span&gt;file. Check the application on &lt;a href="http://localhost:2060/index.html"&gt;http://localhost:2060/index.html&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;To generate &lt;span class="tt"&gt;.xap&lt;/span&gt; file for distribution, run:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPython-2.6.1\Silverlight\bin\Chiron.exe /e: /d:childwindow\app /z:app.zap&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If you want to use anything from external assemblies in the code, you have toadd manually reference to those assemblies. For example, if you want to add abutton that creates a new &lt;i&gt;ChildWindow&lt;/i&gt;, you have to change you code likethis:&lt;/p&gt;&lt;p&gt;&lt;span class="tt"&gt;app.py&lt;/span&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;from System.Windows import Application&lt;br /&gt;from System.Windows.Controls import UserControl&lt;br /&gt;&lt;br /&gt;class App:&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.root = Application.Current.LoadRootVisual(UserControl(), "app.xaml")&lt;br /&gt;        self.root.btnNewWindow.Click += self.OnClick&lt;br /&gt;&lt;br /&gt;    def OnClick(self, sender, event):&lt;br /&gt;        import clr&lt;br /&gt;        clr.AddReference('System.Windows.Controls')&lt;br /&gt;        from System.Windows.Controls import ChildWindow&lt;br /&gt;        self.root.panel.Children.Add(ChildWindow(Content='new window'))&lt;br /&gt;&lt;br /&gt;a = App()&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;span class="tt"&gt;app.xaml&lt;/span&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;UserControl x:Class="System.Windows.Controls.UserControl"&lt;br /&gt;  xmlns="http://schemas.microsoft.com/client/2007"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;  xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"&amp;gt;&lt;br /&gt;  &amp;lt;controls:ChildWindow &amp;gt;&lt;br /&gt;    &amp;lt;StackPanel x:Name="panel"&amp;gt;&lt;br /&gt;      &amp;lt;TextBlock Text="Text in ChildWindow"/&amp;gt;&lt;br /&gt;      &amp;lt;Button x:Name="btnNewWindow" Content="New window"/&amp;gt;&lt;br /&gt;    &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;  &amp;lt;/controls:ChildWindow&amp;gt;&lt;br /&gt;&amp;lt;/UserControl&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If you comment out the &lt;span class="tt"&gt;clr.AddReference&lt;/span&gt; line, &lt;spanclass="tt"&gt;ImportError&lt;/span&gt; appears. See the explanation in Jimmy's &lt;ahref="http://lists.ironpython.com/pipermail/users-ironpython.com/2010-May/012804.html"&gt;email&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You can download the example &lt;ahref="http://gui-at.cendaweb.cz/2010/05/childwindow.zip"&gt;here&lt;/a&gt; but note the&lt;span class="tt"&gt;.zip&lt;/span&gt; files do not contain and &lt;spanclass="tt"&gt;.dlls&lt;/span&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-1364485596206700157?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/1364485596206700157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=1364485596206700157' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/1364485596206700157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/1364485596206700157'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2010/05/distributing-silverlight-application.html' title='Distributing Silverlight application written in IronPython'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-2319360914413472466</id><published>2010-05-12T10:53:00.006+02:00</published><updated>2010-05-16T18:55:14.045+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wpf'/><category scheme='http://www.blogger.com/atom/ns#' term='silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><category scheme='http://www.blogger.com/atom/ns#' term='clrtype'/><title type='text'>Silverlight validation with IronPython</title><content type='html'>&lt;p&gt;Validation support in Silverlight is done via &lt;ahref="http://timheuer.com/blog/archive/2008/06/04/silverlight-introduces-visual-state-manager-vsm.aspx"&gt;VisualState Manager&lt;/a&gt;. All invalid fields have red rectangle around themselves.Unfortunately, this does not work out of the box in IronPython. We have to pushit a little bit.&lt;/p&gt;&lt;p&gt;To demonstrate how, I have created a small example. Create a Silverlight apptemplate and change &lt;span class="tt"&gt;app.py&lt;/span&gt; and &lt;span class="tt"&gt;app.xaml&lt;/span&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPython-2.6.1\Silverlight\script\sl.bat python validation&lt;br /&gt;&lt;/pre&gt;&lt;span class="tt"&gt;app.py&lt;/span&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clrtype&lt;br /&gt;import pyevent&lt;br /&gt;from System.Windows import Application&lt;br /&gt;from System.Windows.Controls import UserControl&lt;br /&gt;from System.ComponentModel import INotifyPropertyChanged, PropertyChangedEventArgs&lt;br /&gt;&lt;br /&gt;class ValidationClass(INotifyPropertyChanged):&lt;br /&gt;    __metaclass__ = clrtype.ClrClass&lt;br /&gt;    PropertyChanged = None&lt;br /&gt;&lt;br /&gt;    def __init__(self, win):&lt;br /&gt;        self.win = win&lt;br /&gt;        self._text = 'text'&lt;br /&gt;        self.PropertyChanged, self._propertyChangedCaller = pyevent.make_event()&lt;br /&gt;&lt;br /&gt;    def add_PropertyChanged(self, value):&lt;br /&gt;        self.PropertyChanged += value&lt;br /&gt;&lt;br /&gt;    def remove_PropertyChanged(self, value):&lt;br /&gt;        self.PropertyChanged -= value&lt;br /&gt;&lt;br /&gt;    def OnPropertyChanged(self, propertyName):&lt;br /&gt;        if self.PropertyChanged is not None:&lt;br /&gt;            self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))&lt;br /&gt;&lt;br /&gt;    @property&lt;br /&gt;    @clrtype.accepts()&lt;br /&gt;    @clrtype.returns(str)&lt;br /&gt;    def text(self):&lt;br /&gt;        return self._text&lt;br /&gt;&lt;br /&gt;    @text.setter&lt;br /&gt;    @clrtype.accepts(str)&lt;br /&gt;    @clrtype.returns()&lt;br /&gt;    def text(self, value):&lt;br /&gt;        if not value.startswith('text'):&lt;br /&gt;            raise Exception('Value must start with text!')&lt;br /&gt;        self._text = value&lt;br /&gt;        self.OnPropertyChanged('text')&lt;br /&gt;&lt;br /&gt;class App:&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.root = Application.Current.LoadRootVisual(UserControl(), "app.xaml")&lt;br /&gt;        self.root.DataContext = ValidationClass(self.root)&lt;br /&gt;&lt;br /&gt;App()&lt;/pre&gt;&lt;span class="tt"&gt;app.xaml&lt;/span&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;UserControl x:Class="System.Windows.Controls.UserControl"&lt;br /&gt;  xmlns="http://schemas.microsoft.com/client/2007"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;&lt;br /&gt;  &amp;lt;StackPanel&amp;gt;&lt;br /&gt;    &amp;lt;TextBox x:Name="tbValidate1" Width="100" Height="25" &lt;br /&gt;      Text="{Binding text, Mode=TwoWay, ValidatesOnExceptions=True,&lt;br /&gt;      NotifyOnValidationError=True}" /&amp;gt;&lt;br /&gt;    &amp;lt;TextBox Width="100" Height="25" /&amp;gt;&lt;br /&gt;    &amp;lt;TextBlock Text="{Binding text}" HorizontalAlignment="Center" /&amp;gt;&lt;br /&gt;  &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;&amp;lt;/UserControl&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;When you run this application (&lt;spanclass="tt"&gt;C:\IronPython-2.6.1\Silverlight\script\server.bat/d:validation&lt;/span&gt;), you'll find out the validation does not work. There isno red rectangle when you enter wrong value; e.g. &lt;i&gt;wrong&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;Note the second empty TextBox is there so you can move focus out of thefirst one to update bound property.&lt;/p&gt;&lt;p&gt;For whatever reason, the invalid component is not switched into invalidstate. Could be IronPython bug, could be something else. Anyway to fix it, youhave to switch the control into invalid state manually. Add the &lt;spanclass="tt"&gt;BindingValidationError&lt;/span&gt; event:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;from System.Windows import VisualStateManager&lt;br /&gt;from System.Windows.Controls import ValidationErrorEventAction&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;class App:&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.root = Application.Current.LoadRootVisual(UserControl(), "app.xaml")&lt;br /&gt;        self.root.DataContext = ValidationClass(self.root)&lt;br /&gt;        self.root.BindingValidationError += self.OnBindingValidationError&lt;br /&gt;&lt;br /&gt;    def OnBindingValidationError(self, sender, event):&lt;br /&gt;        if event.Action == ValidationErrorEventAction.Added:&lt;br /&gt;            VisualStateManager.GoToState(event.OriginalSource, 'InvalidUnfocused', True)&lt;br /&gt;        else:&lt;br /&gt;            VisualStateManager.GoToState(event.OriginalSource, 'Valid', True&lt;/pre&gt;&lt;p&gt;Now when you enter wrong value into TextBox, you can see red rectanglearound the control. You also see, the bound variable has the old, correct value&lt;i&gt;text&lt;/i&gt;:&lt;/p&gt;&lt;img src="http://gui-at.cendaweb.cz/2010/05/SL_validation.png"/&gt;&lt;p&gt;You can download the whole source &lt;ahref="http://gui-at.cendaweb.cz/2010/05/SL_validation.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-2319360914413472466?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/2319360914413472466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=2319360914413472466' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/2319360914413472466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/2319360914413472466'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2010/05/silverlight-validation-in-ironpython.html' title='Silverlight validation with IronPython'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-5617465160135124409</id><published>2010-03-16T11:28:00.002+01:00</published><updated>2010-05-16T18:57:44.467+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wpf'/><category scheme='http://www.blogger.com/atom/ns#' term='silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Parsing XML with XDocument</title><content type='html'>&lt;p&gt;I needed to parse a XML document recently in Silverlight. Unfortunately,Silverlight does not have &lt;i&gt;System.Xml.XmlDocument&lt;/i&gt; type so you need to use&lt;i&gt;System.Xml.Linq.XDocument&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;The following example works in Silverlight and with small change also in WPF.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;# encoding: utf-8&lt;br /&gt;import clr&lt;br /&gt;clr.AddReferenceToFile('System.Xml.Linq.dll')&lt;br /&gt;from System.Xml.Linq import XDocument, XNamespace&lt;br /&gt;&lt;br /&gt;content = """&amp;lt;?xml version="1.0" encoding="utf-8" standalone="yes"?&amp;gt;&lt;br /&gt;&amp;lt;rss version="2.0" xmlns:media="http://search.yahoo.com/mrss"&lt;br /&gt;    xmlns:atom="http://www.w3.org/2005/Atom"&amp;gt;&lt;br /&gt;    &amp;lt;channel&amp;gt;&lt;br /&gt;        &amp;lt;item&amp;gt;&lt;br /&gt;            &amp;lt;title&amp;gt;This is the title&amp;lt;/title&amp;gt;&lt;br /&gt;            &amp;lt;media:description type="html"&amp;gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/media:description&amp;gt;&lt;br /&gt;            &amp;lt;link&amp;gt;html/dsc00001.html&amp;lt;/link&amp;gt;&lt;br /&gt;            &amp;lt;media:thumbnail url="preview/dsc00001.jpg"/&amp;gt;&lt;br /&gt;            &amp;lt;media:content url="web/dsc00001.jpg"/&amp;gt;&lt;br /&gt;        &amp;lt;/item&amp;gt;&lt;br /&gt;        &amp;lt;item&amp;gt;&lt;br /&gt;            &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;&lt;br /&gt;            &amp;lt;media:description type="html"&amp;gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/media:description&amp;gt;&lt;br /&gt;            &amp;lt;link&amp;gt;html/dsc00002.html&amp;lt;/link&amp;gt;&lt;br /&gt;            &amp;lt;media:thumbnail url="preview/dsc00002.jpg"/&amp;gt;&lt;br /&gt;            &amp;lt;media:content url="web/dsc00002.jpg"/&amp;gt;&lt;br /&gt;        &amp;lt;/item&amp;gt;&lt;br /&gt;    &amp;lt;/channel&amp;gt;&lt;br /&gt;&amp;lt;/rss&amp;gt;"""&lt;br /&gt;&lt;br /&gt;xDoc = XDocument().Parse(content)&lt;br /&gt;namespace = XNamespace.Get("http://search.yahoo.com/mrss")&lt;br /&gt;for item in xDoc.Element('rss').Element('channel').Elements('item'):&lt;br /&gt;    print item.Element('title').Value&lt;br /&gt;    print item.Element(namespace+'thumbnail').Attribute('url').Value&lt;br /&gt;&lt;/pre&gt;Here is the output:&lt;pre class="prettyprint"&gt;&lt;br /&gt;This is the title&lt;br /&gt;preview/dsc00001.jpg&lt;br /&gt;&lt;br /&gt;preview/dsc00002.jpg&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;You have to have &lt;span class="tt"&gt;System.Xml.Linq.dll&lt;/span&gt; fromSilverlight SDK next to your &lt;span class="tt"&gt;app.py&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;The change for WPF:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;clr.AddReference('System.Xml.Linq')&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Also make sure you don't have Silverlight's &lt;spanclass="tt"&gt;System.Xml.Linq.dll&lt;/span&gt; next to your script.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-5617465160135124409?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/5617465160135124409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=5617465160135124409' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/5617465160135124409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/5617465160135124409'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2010/03/parsing-xml-with-xdocument.html' title='Parsing XML with XDocument'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-3450623723587611353</id><published>2010-02-23T17:21:00.003+01:00</published><updated>2010-05-16T19:01:00.715+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OpenWrt'/><title type='text'>Disk Encryption in OpenWrt</title><content type='html'>&lt;p&gt;I have an external USB disk connected to my Asus WL-500gP which runsOpenWrt&amp;nbsp;KAMIKAZE (8.09.1, r16278).&lt;/p&gt;&lt;p&gt;I want to have the disk encrypted. So I installed every possible packagethat has &lt;i&gt;aes&lt;/i&gt; or &lt;i&gt;loop&lt;/i&gt; in name but I still got the following errormessage:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;root@OpenWrt:~# losetup -e aes /dev/loop/0 /dev/scsi/host0/bus0/target0/lun0/part1&lt;br /&gt;Password:&lt;br /&gt;ioctl: LOOP_SET_STATUS: Invalid argument&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The solution was easy - install &lt;i&gt;losetup&lt;/i&gt; that supports aes encryption.You can find the package on&amp;nbsp;&lt;ahref="http://www.roth.lu/download/openwrt-usb-raid1-loopaes/"&gt;http://www.roth.lu/download/openwrt-usb-raid1-loopaes/&lt;/a&gt;.Download it, install it and viola - it works :-)&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;root@OpenWrt:~# losetup -e aes /dev/loop/0 /dev/scsi/host0/bus0/target0/lun0/part1&lt;br /&gt;Password:&lt;br /&gt;root@OpenWrt:~# mkfs.ext2 -vm0 /dev/loop/0&lt;br /&gt;mkdir /mnt/disk/&lt;br /&gt;mount /dev/loop/0 /mnt/disc&lt;br /&gt;&lt;/pre&gt;To mount the disc in script use&lt;pre class="prettyprint"&gt;&lt;br /&gt;echo password | losetup -e aes /dev/loop/0 /dev/scsi/host0/bus0/target0/lun0/part1 -p0&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-3450623723587611353?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/3450623723587611353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=3450623723587611353' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/3450623723587611353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/3450623723587611353'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2010/02/disk-encryption-in-openwrt.html' title='Disk Encryption in OpenWrt'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-8141326126152157573</id><published>2010-01-21T12:15:00.089+01:00</published><updated>2010-05-16T19:06:27.146+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WinDbg'/><title type='text'>WinDbg for beginners</title><content type='html'>&lt;p&gt;A few days ago I have encountered a strange problem. When I copied &lt;spanclass="tt"&gt;IronPython.Modules.dll&lt;/span&gt; to my application's folder, itfreezed. Strange. It looked like a &lt;ahref="http://ironpython.codeplex.com/WorkItem/View.aspx?WorkItemId=25933"&gt;bug&lt;/a&gt;in IronPython for me but it wasn't. With Dino Viehland help, I have found thebug in Delphi code. Dino used &lt;b&gt;WinDbg&lt;/b&gt; to discover what is going on in thecode. I show you it is not so hard to use it.&lt;/p&gt;&lt;p&gt;WinDbg is part of &lt;ahref="http://www.microsoft.com/whdc/devtools/debugging/default.mspx"&gt;DebugingTolls for Windows&lt;/a&gt;. Download and install appropriate version for yourWindows (32 or 64 bit). And download the &lt;ahref="http://gui-at.cendaweb.cz/2010/01/WinDbgBug.zip"&gt;buggedapplication&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The &lt;span class="tt"&gt;IpyTest.exe&lt;/span&gt; is Delphi 7 application that createsthe CLR and runs function &lt;span class="tt"&gt;Add3&lt;/span&gt; from &lt;spanclass="tt"&gt;Host.dll&lt;/span&gt; inside the CLR. The &lt;span class="tt"&gt;Add3&lt;/span&gt;function creates IronPython engine and returns result of adding number 3 to theinput variabl. So when you run &lt;span class="tt"&gt;IpyTest.exe&lt;/span&gt; you shouldsee&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPythonBug\Delphi&amp;gt;IpyTest.exe&lt;br /&gt;CLRVersion = v2.0.50727&lt;br /&gt;8 + 3 = 11&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;You may actually see it because this bug does not appear on all computers.But on mine, I see just the CLRVersion. Then the program freezes.&lt;/p&gt;&lt;p&gt;Let's debug the application in WinDbg:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;"C:\Program Files\Debugging Tools for Windows (x86)\windbg.exe" C:\IronPythonBug\Delphi\IpyTest.exe&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;When WinDbg and &lt;span class="tt"&gt;IpyTest.exe&lt;/span&gt; start, you see this:&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://gui-at.cendaweb.cz/2010/01/WinDbgStart.png" imageanchor="1"style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="310"src="http://gui-at.cendaweb.cz/2010/01/WinDbgStart.png" width="400" /&gt;&lt;/a&gt;&lt;br/&gt;&lt;/div&gt;&lt;p&gt;Enter the following commands:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;0:000&gt; sxe clr&lt;br /&gt;0:000&gt; sxe av&lt;br /&gt;0:000&gt; .symfix&lt;br /&gt;0:000&gt; .reload&lt;br /&gt;Reloading current modules&lt;br /&gt;............&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If you want to know what these commands do, check the help :-) Then run thedebugger with &lt;span class="tt"&gt;g&lt;/span&gt; command. It runs for a while and thenit freezes with the following output:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;0:000&gt; g&lt;br /&gt;ModLoad: 76390000 763ad000   C:\WINDOWS\system32\IMM32.DLL&lt;br /&gt;ModLoad: 79000000 79046000   C:\WINDOWS\system32\mscoree.dll&lt;br /&gt;ModLoad: 77f60000 77fd6000   C:\WINDOWS\system32\SHLWAPI.dll&lt;br /&gt;ModLoad: 79e70000 7a400000   c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll&lt;br /&gt;ModLoad: 78130000 781cb000   C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.3053_x-ww_b80fa8ca\MSVCR80.dll&lt;br /&gt;ModLoad: 7c9c0000 7d1d7000   C:\WINDOWS\system32\shell32.dll&lt;br /&gt;ModLoad: 773d0000 774d3000   C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83\comctl32.dll&lt;br /&gt;ModLoad: 5d090000 5d12a000   C:\WINDOWS\system32\comctl32.dll&lt;br /&gt;ModLoad: 790c0000 79bb7000   C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll&lt;br /&gt;ModLoad: 79060000 790bb000   c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorjit.dll&lt;br /&gt;ModLoad: 33200000 3322c000   Microsoft.Scripting.dll&lt;br /&gt;ModLoad: 68000000 68036000   C:\WINDOWS\system32\rsaenh.dll&lt;br /&gt;ModLoad: 64020000 64033000   c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorsec.dll&lt;br /&gt;ModLoad: 76c30000 76c5e000   C:\WINDOWS\system32\WINTRUST.dll&lt;br /&gt;ModLoad: 77a80000 77b15000   C:\WINDOWS\system32\CRYPT32.dll&lt;br /&gt;ModLoad: 77b20000 77b32000   C:\WINDOWS\system32\MSASN1.dll&lt;br /&gt;ModLoad: 76c90000 76cb8000   C:\WINDOWS\system32\IMAGEHLP.dll&lt;br /&gt;ModLoad: 74e30000 74e9d000   C:\WINDOWS\system32\RichEd20.dll&lt;br /&gt;ModLoad: 04a30000 04cf5000   C:\WINDOWS\system32\xpsp2res.dll&lt;br /&gt;ModLoad: 769c0000 76a74000   C:\WINDOWS\system32\userenv.dll&lt;br /&gt;ModLoad: 5b860000 5b8b5000   C:\WINDOWS\system32\netapi32.dll&lt;br /&gt;ModLoad: 75e60000 75e73000   C:\WINDOWS\system32\cryptnet.dll&lt;br /&gt;ModLoad: 76bf0000 76bfb000   C:\WINDOWS\system32\PSAPI.DLL&lt;br /&gt;ModLoad: 722b0000 722b5000   C:\WINDOWS\system32\SensApi.dll&lt;br /&gt;ModLoad: 4d4f0000 4d549000   C:\WINDOWS\system32\WINHTTP.dll&lt;br /&gt;ModLoad: 76f60000 76f8c000   C:\WINDOWS\system32\WLDAP32.dll&lt;br /&gt;ModLoad: 33200000 3322c000   C:\IronPythonBug\Delphi\Microsoft.Scripting.dll&lt;br /&gt;ModLoad: 34700000 34860000   IronPython.dll&lt;br /&gt;ModLoad: 34700000 34860000   C:\IronPythonBug\Delphi\IronPython.dll&lt;br /&gt;ModLoad: 33000000 33064000   Microsoft.Scripting.Core.dll&lt;br /&gt;ModLoad: 33000000 33064000   C:\IronPythonBug\Delphi\Microsoft.Scripting.Core.dll&lt;br /&gt;ModLoad: 7a440000 7abc5000   C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System\80978a322d7dd39f0a71be1251ae395a\System.ni.dll&lt;br /&gt;ModLoad: 33400000 334dc000   Microsoft.Dynamic.dll&lt;br /&gt;ModLoad: 33400000 334dc000   C:\IronPythonBug\Delphi\Microsoft.Dynamic.dll&lt;br /&gt;ModLoad: 73000000 73008000   Microsoft.Scripting.ExtensionAttribute.dll&lt;br /&gt;ModLoad: 73000000 73008000   C:\IronPythonBug\Delphi\Microsoft.Scripting.ExtensionAttribute.dll&lt;br /&gt;ModLoad: 34c10000 34c80000   IronPython.Modules.dll&lt;br /&gt;ModLoad: 34c10000 34c80000   C:\IronPythonBug\Delphi\IronPython.Modules.dll&lt;br /&gt;ModLoad: 64890000 64981000   C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Configuration\b82c00e2d24305ad6cb08556e3779b75\System.Configuration.ni.dll&lt;br /&gt;ModLoad: 637a0000 63cd6000   C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Xml\773a9786013451d3baaeff003dc4230f\System.Xml.ni.dll&lt;br /&gt;(b6c.ef0): Unknown exception - code c0000091 (first chance)&lt;br /&gt;&lt;br /&gt;&gt;&gt;&gt; many lines omitted &lt;&lt;&lt;&lt;br /&gt;&lt;br /&gt;(b6c.ef0): Unknown exception - code c0000091 (first chance)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;span class="tt"&gt;IpyTest.exe&lt;/span&gt; window contains just a text:&lt;i&gt;CLRVersion = v2.0.50727&lt;/i&gt;. Break the debugger with &lt;i&gt;Ctrl-Break&lt;/i&gt;. Wesee there is an unknown exception with code &lt;i&gt;c0000091&lt;/i&gt;. Let's restart theprogram and tell WinDbg to stop on this exception with the followingcommands:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;.restart&lt;br /&gt;sxe c0000091&lt;br /&gt;.symfix&lt;br /&gt;.reload&lt;br /&gt;g&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Here is the output:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;0:003&gt; .restart&lt;br /&gt;CommandLine: C:\IronPythonBug\Delphi\IpyTest.exe&lt;br /&gt;Symbol search path is: srv*&lt;br /&gt;Executable search path is: &lt;br /&gt;ModLoad: 00400000 00455000   image00400000&lt;br /&gt;ModLoad: 7c900000 7c9af000   ntdll.dll&lt;br /&gt;ModLoad: 7c800000 7c8f6000   C:\WINDOWS\system32\kernel32.dll&lt;br /&gt;ModLoad: 7e410000 7e4a1000   C:\WINDOWS\system32\user32.dll&lt;br /&gt;ModLoad: 77f10000 77f59000   C:\WINDOWS\system32\GDI32.dll&lt;br /&gt;ModLoad: 77dd0000 77e6b000   C:\WINDOWS\system32\advapi32.dll&lt;br /&gt;ModLoad: 77e70000 77f02000   C:\WINDOWS\system32\RPCRT4.dll&lt;br /&gt;ModLoad: 77fe0000 77ff1000   C:\WINDOWS\system32\Secur32.dll&lt;br /&gt;ModLoad: 77120000 771ab000   C:\WINDOWS\system32\oleaut32.dll&lt;br /&gt;ModLoad: 77c10000 77c68000   C:\WINDOWS\system32\msvcrt.dll&lt;br /&gt;ModLoad: 774e0000 7761d000   C:\WINDOWS\system32\ole32.dll&lt;br /&gt;ModLoad: 77c00000 77c08000   C:\WINDOWS\system32\version.dll&lt;br /&gt;(ea8.a14): Break instruction exception - code 80000003 (first chance)&lt;br /&gt;eax=00351ec4 ebx=7ffd4000 ecx=00000004 edx=00000010 esi=00351f98 edi=00351ec4&lt;br /&gt;eip=7c90120e esp=0012fb20 ebp=0012fc94 iopl=0         nv up ei pl nz na po nc&lt;br /&gt;cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202&lt;br /&gt;ntdll!DbgBreakPoint:&lt;br /&gt;7c90120e cc              int     3&lt;br /&gt;0:000&gt; sxe c0000091&lt;br /&gt;0:000&gt; .symfix&lt;br /&gt;0:000&gt; .reload&lt;br /&gt;Reloading current modules&lt;br /&gt;............&lt;br /&gt;0:000&gt; g&lt;br /&gt;ModLoad: 76390000 763ad000   C:\WINDOWS\system32\IMM32.DLL&lt;br /&gt;ModLoad: 79000000 79046000   C:\WINDOWS\system32\mscoree.dll&lt;br /&gt;ModLoad: 77f60000 77fd6000   C:\WINDOWS\system32\SHLWAPI.dll&lt;br /&gt;ModLoad: 79e70000 7a400000   c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll&lt;br /&gt;ModLoad: 78130000 781cb000   C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.3053_x-ww_b80fa8ca\MSVCR80.dll&lt;br /&gt;ModLoad: 7c9c0000 7d1d7000   C:\WINDOWS\system32\shell32.dll&lt;br /&gt;ModLoad: 773d0000 774d3000   C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.5512_x-ww_35d4ce83\comctl32.dll&lt;br /&gt;ModLoad: 5d090000 5d12a000   C:\WINDOWS\system32\comctl32.dll&lt;br /&gt;ModLoad: 790c0000 79bb7000   C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll&lt;br /&gt;ModLoad: 79060000 790bb000   c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorjit.dll&lt;br /&gt;ModLoad: 33200000 3322c000   Microsoft.Scripting.dll&lt;br /&gt;ModLoad: 68000000 68036000   C:\WINDOWS\system32\rsaenh.dll&lt;br /&gt;ModLoad: 64020000 64033000   c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorsec.dll&lt;br /&gt;ModLoad: 76c30000 76c5e000   C:\WINDOWS\system32\WINTRUST.dll&lt;br /&gt;ModLoad: 77a80000 77b15000   C:\WINDOWS\system32\CRYPT32.dll&lt;br /&gt;ModLoad: 77b20000 77b32000   C:\WINDOWS\system32\MSASN1.dll&lt;br /&gt;ModLoad: 76c90000 76cb8000   C:\WINDOWS\system32\IMAGEHLP.dll&lt;br /&gt;ModLoad: 74e30000 74e9d000   C:\WINDOWS\system32\RichEd20.dll&lt;br /&gt;ModLoad: 04a30000 04cf5000   C:\WINDOWS\system32\xpsp2res.dll&lt;br /&gt;ModLoad: 769c0000 76a74000   C:\WINDOWS\system32\userenv.dll&lt;br /&gt;ModLoad: 5b860000 5b8b5000   C:\WINDOWS\system32\netapi32.dll&lt;br /&gt;ModLoad: 75e60000 75e73000   C:\WINDOWS\system32\cryptnet.dll&lt;br /&gt;ModLoad: 76bf0000 76bfb000   C:\WINDOWS\system32\PSAPI.DLL&lt;br /&gt;ModLoad: 722b0000 722b5000   C:\WINDOWS\system32\SensApi.dll&lt;br /&gt;ModLoad: 4d4f0000 4d549000   C:\WINDOWS\system32\WINHTTP.dll&lt;br /&gt;ModLoad: 76f60000 76f8c000   C:\WINDOWS\system32\WLDAP32.dll&lt;br /&gt;ModLoad: 33200000 3322c000   C:\IronPythonBug\Delphi\Microsoft.Scripting.dll&lt;br /&gt;ModLoad: 34700000 34860000   IronPython.dll&lt;br /&gt;ModLoad: 34700000 34860000   C:\IronPythonBug\Delphi\IronPython.dll&lt;br /&gt;ModLoad: 33000000 33064000   Microsoft.Scripting.Core.dll&lt;br /&gt;ModLoad: 33000000 33064000   C:\IronPythonBug\Delphi\Microsoft.Scripting.Core.dll&lt;br /&gt;ModLoad: 7a440000 7abc5000   C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System\80978a322d7dd39f0a71be1251ae395a\System.ni.dll&lt;br /&gt;ModLoad: 33400000 334dc000   Microsoft.Dynamic.dll&lt;br /&gt;ModLoad: 33400000 334dc000   C:\IronPythonBug\Delphi\Microsoft.Dynamic.dll&lt;br /&gt;ModLoad: 73000000 73008000   Microsoft.Scripting.ExtensionAttribute.dll&lt;br /&gt;ModLoad: 73000000 73008000   C:\IronPythonBug\Delphi\Microsoft.Scripting.ExtensionAttribute.dll&lt;br /&gt;ModLoad: 34c10000 34c80000   IronPython.Modules.dll&lt;br /&gt;ModLoad: 34c10000 34c80000   C:\IronPythonBug\Delphi\IronPython.Modules.dll&lt;br /&gt;ModLoad: 64890000 64981000   C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Configuration\b82c00e2d24305ad6cb08556e3779b75\System.Configuration.ni.dll&lt;br /&gt;ModLoad: 637a0000 63cd6000   C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Xml\773a9786013451d3baaeff003dc4230f\System.Xml.ni.dll&lt;br /&gt;(ea8.a14): Unknown exception - code c0000091 (first chance)&lt;br /&gt;First chance exceptions are reported before any exception handling.&lt;br /&gt;This exception may be expected and handled.&lt;br /&gt;eax=ffffff00 ebx=02643d64 ecx=02640010 edx=02648e3c esi=02643bd4 edi=02640010&lt;br /&gt;eip=79098f48 esp=0012ce30 ebp=0012ce34 iopl=0         nv up ei pl nz na po nc&lt;br /&gt;cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00010202&lt;br /&gt;mscorjit!Compiler::FlatFPIsSameAsFloat+0xa:&lt;br /&gt;79098f48 d945fc          fld     dword ptr [ebp-4]    ss:0023:0012ce30=02640010&lt;/pre&gt;&lt;p&gt;WinDbg stopped on the exception. Nice. And what now? &lt;b&gt;Analyze&lt;/b&gt; the exception!&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;0:000&gt; !analyze -v&lt;br /&gt;*******************************************************************************&lt;br /&gt;*                                                                             *&lt;br /&gt;*                        Exception Analysis                                   *&lt;br /&gt;*                                                                             *&lt;br /&gt;*******************************************************************************&lt;br /&gt;&lt;br /&gt;*** WARNING: Unable to verify checksum for C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\6d667f19d687361886990f3ca0f49816\mscorlib.ni.dll&lt;br /&gt;*** WARNING: Unable to verify checksum for image00400000&lt;br /&gt;*** ERROR: Module load completed but symbols could not be loaded for image00400000&lt;br /&gt;*** ERROR: Module load completed but symbols could not be loaded for C:\WINDOWS\system32\xpsp2res.dll&lt;br /&gt;*** ERROR: Module load completed but symbols could not be loaded for C:\IronPythonBug\Delphi\Microsoft.Scripting.Core.dll&lt;br /&gt;*** ERROR: Module load completed but symbols could not be loaded for C:\IronPythonBug\Delphi\Microsoft.Scripting.dll&lt;br /&gt;*** ERROR: Module load completed but symbols could not be loaded for C:\IronPythonBug\Delphi\Microsoft.Dynamic.dll&lt;br /&gt;*** ERROR: Module load completed but symbols could not be loaded for C:\IronPythonBug\Delphi\IronPython.dll&lt;br /&gt;*** ERROR: Module load completed but symbols could not be loaded for C:\IronPythonBug\Delphi\IronPython.Modules.dll&lt;br /&gt;*** WARNING: Unable to verify checksum for C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Xml\773a9786013451d3baaeff003dc4230f\System.Xml.ni.dll&lt;br /&gt;*** WARNING: Unable to verify checksum for C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Configuration\b82c00e2d24305ad6cb08556e3779b75\System.Configuration.ni.dll&lt;br /&gt;*** ERROR: Module load completed but symbols could not be loaded for C:\IronPythonBug\Delphi\Microsoft.Scripting.ExtensionAttribute.dll&lt;br /&gt;*** WARNING: Unable to verify checksum for C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System\80978a322d7dd39f0a71be1251ae395a\System.ni.dll&lt;br /&gt;*************************************************************************&lt;br /&gt;***                                                                   ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;***    Your debugger is not using the correct symbols                 ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;***    In order for this command to work properly, your symbol path   ***&lt;br /&gt;***    must point to .pdb files that have full type information.      ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;***    Certain .pdb files (such as the public OS symbols) do not      ***&lt;br /&gt;***    contain the required information.  Contact the group that      ***&lt;br /&gt;***    provided you with these symbols if you need this command to    ***&lt;br /&gt;***    work.                                                          ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;***    Type referenced: kernel32!pNlsUserInfo                         ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;*************************************************************************&lt;br /&gt;*************************************************************************&lt;br /&gt;***                                                                   ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;***    Your debugger is not using the correct symbols                 ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;***    In order for this command to work properly, your symbol path   ***&lt;br /&gt;***    must point to .pdb files that have full type information.      ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;***    Certain .pdb files (such as the public OS symbols) do not      ***&lt;br /&gt;***    contain the required information.  Contact the group that      ***&lt;br /&gt;***    provided you with these symbols if you need this command to    ***&lt;br /&gt;***    work.                                                          ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;***    Type referenced: kernel32!pNlsUserInfo                         ***&lt;br /&gt;***                                                                   ***&lt;br /&gt;*************************************************************************&lt;br /&gt;&lt;br /&gt;FAULTING_IP: &lt;br /&gt;mscorjit!Compiler::FlatFPIsSameAsFloat+7&lt;br /&gt;79098f45 d95dfc          fstp    dword ptr [ebp-4]&lt;br /&gt;&lt;br /&gt;EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)&lt;br /&gt;ExceptionAddress: 79098f45 (mscorjit!Compiler::FlatFPIsSameAsFloat+0x00000007)&lt;br /&gt;   ExceptionCode: c0000091&lt;br /&gt;  ExceptionFlags: 00000000&lt;br /&gt;NumberParameters: 1&lt;br /&gt;   Parameter[0]: 00000000&lt;br /&gt;&lt;br /&gt;FAULTING_THREAD:  00000a14&lt;br /&gt;&lt;br /&gt;DEFAULT_BUCKET_ID:  WRONG_SYMBOLS&lt;br /&gt;&lt;br /&gt;PROCESS_NAME:  image00400000&lt;br /&gt;&lt;br /&gt;ERROR_CODE: (NTSTATUS) 0xc0000091 - {EXCEPTION}  Floating-point overflow.&lt;br /&gt;&lt;br /&gt;EXCEPTION_CODE: (NTSTATUS) 0xc0000091 - {EXCEPTION}  Floating-point overflow.&lt;br /&gt;&lt;br /&gt;EXCEPTION_PARAMETER1:  00000000&lt;br /&gt;&lt;br /&gt;NTGLOBALFLAG:  2000000&lt;br /&gt;&lt;br /&gt;APPLICATION_VERIFIER_FLAGS:  0&lt;br /&gt;&lt;br /&gt;MANAGED_STACK: &lt;br /&gt;(TransitionMU)&lt;br /&gt;0012E0F8 02657F5C IronPython!IronPython.Runtime.PythonContext.InitializeSystemState()+0xec&lt;br /&gt;0012E108 026532E7 IronPython!IronPython.Runtime.PythonContext..ctor(Microsoft.Scripting.Runtime.ScriptDomainManager, System.Collections.Generic.IDictionary`2&lt;System.String,System.Object&gt;)+0x247&lt;br /&gt;(TransitionUM)&lt;br /&gt;(TransitionMU)&lt;br /&gt;0012E60C 792EF7C0 mscorlib_ni!System.RuntimeMethodHandle.InvokeConstructor(System.Object[], System.SignatureStruct, System.RuntimeTypeHandle)+0x10&lt;br /&gt;0012E640 792EF55A mscorlib_ni!System.Reflection.RuntimeConstructorInfo.Invoke(System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)+0xfa&lt;br /&gt;0012E6D0 79288D96 mscorlib_ni!System.RuntimeType.CreateInstanceImpl(System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])+0x3e6&lt;br /&gt;0012E730 79280E10 mscorlib_ni!System.Activator.CreateInstance(System.Type, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo, System.Object[])+0x70&lt;br /&gt;0012E754 02652BA1 Microsoft_Scripting!Microsoft.Scripting.Runtime.LanguageConfiguration.LoadLanguageContext(Microsoft.Scripting.Runtime.ScriptDomainManager, Boolean ByRef)+0x&lt;br /&gt;LAST_CONTROL_TRANSFER:  from 790a40fa to 79098f48&lt;br /&gt;&lt;br /&gt;PRIMARY_PROBLEM_CLASS:  WRONG_SYMBOLS&lt;br /&gt;&lt;br /&gt;BUGCHECK_STR:  APPLICATION_FAULT_WRONG_SYMBOLS&lt;br /&gt;&lt;br /&gt;STACK_TEXT:  &lt;br /&gt;79098f45 mscorjit!Compiler::FlatFPIsSameAsFloat+0x7&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FOLLOWUP_IP: &lt;br /&gt;mscorjit!Compiler::FlatFPIsSameAsFloat+7&lt;br /&gt;79098f45 d95dfc          fstp    dword ptr [ebp-4]&lt;br /&gt;&lt;br /&gt;SYMBOL_STACK_INDEX:  0&lt;br /&gt;&lt;br /&gt;SYMBOL_NAME:  mscorjit!Compiler::FlatFPIsSameAsFloat+7&lt;br /&gt;&lt;br /&gt;FOLLOWUP_NAME:  MachineOwner&lt;br /&gt;&lt;br /&gt;MODULE_NAME: mscorjit&lt;br /&gt;&lt;br /&gt;IMAGE_NAME:  mscorjit.dll&lt;br /&gt;&lt;br /&gt;DEBUG_FLR_IMAGE_TIMESTAMP:  492b8341&lt;br /&gt;&lt;br /&gt;STACK_COMMAND:  dds 79098f45 ; kb&lt;br /&gt;&lt;br /&gt;FAILURE_BUCKET_ID:  WRONG_SYMBOLS_c0000091_mscorjit.dll!Compiler::FlatFPIsSameAsFloat&lt;br /&gt;&lt;br /&gt;BUCKET_ID:  APPLICATION_FAULT_WRONG_SYMBOLS_mscorjit!Compiler::FlatFPIsSameAsFloat+7&lt;br /&gt;&lt;br /&gt;Followup: MachineOwner&lt;br /&gt;---------&lt;/pre&gt;&lt;p&gt;&lt;i&gt;Floating-point overflow&lt;/i&gt; in Delphi when working with foreign .dlls?Ask uncle Google about it and after a while you find something like &lt;ahref="http://digital.ni.com/public.nsf/allkb/E6A73825E57FCD9F862570DD005E594F"&gt;this&lt;/a&gt;.Or, as in my case, Dino sends you the direct link :-)&lt;/p&gt;&lt;p&gt;Another useful commands:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;.loadby sos mscorwks&lt;br /&gt;!clrstack -a&lt;br /&gt;!DumpStackObjects&lt;br /&gt;!dumpobj 07d996fc&lt;br /&gt;.load C:\Program Files (x86)\Microsoft Silverlight\3.0.40818.0\sos.dll&lt;br /&gt;.load C:\Windows\Microsoft.NET\Framework\v2.0.50727\SOS.dll&lt;br /&gt;.sympath SRV*c:\dos\DebugSymbols*http://msdl.microsoft.com/download/symbols&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To recap it:&lt;/p&gt;&lt;p&gt;&lt;b&gt;If you have a problem with your program, run it in WinDbg and &lt;spanclass="tt"&gt;!analyze -v&lt;/span&gt; it.&lt;/b&gt; WinDbg tells you a lot of usefulinformation which you can utilize and find a solution for your problem.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-8141326126152157573?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/8141326126152157573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=8141326126152157573' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/8141326126152157573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/8141326126152157573'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2010/01/windbg-for-beginners.html' title='WinDbg for beginners'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-1197273637537051751</id><published>2009-11-22T20:28:00.028+01:00</published><updated>2010-10-06T23:26:41.356+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><category scheme='http://www.blogger.com/atom/ns#' term='clrtype'/><category scheme='http://www.blogger.com/atom/ns#' term='wcf'/><title type='text'>WCF Service in pure IronPython with config file</title><content type='html'>&lt;p&gt;I was wrong when I wrote in the &lt;ahref="http://gui-at.blogspot.com/2009/11/wcf-service-in-pure-ironpython.html"&gt;lastpost&lt;/a&gt; that the IronPython service cannot be saved into an assembly. It can.Which opens a way to use &lt;i&gt;.config&lt;/i&gt; file to configure the service.&lt;/p&gt;&lt;p&gt;This is a simple config file for the service:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/11/ConfigService.exe.config"&gt;ConfigService.exe.config&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;&amp;lt;system.serviceModel&amp;gt;&lt;br /&gt;    &amp;lt;services&amp;gt;&lt;br /&gt;      &amp;lt;service name="ConfigService.myService"&amp;gt;&lt;br /&gt;        &amp;lt;host&amp;gt;&lt;br /&gt;          &amp;lt;baseAddresses&amp;gt;&lt;br /&gt;            &amp;lt;add baseAddress="http://localhost:9000/myWcfService"/&amp;gt;&lt;br /&gt;          &amp;lt;/baseAddresses&amp;gt;&lt;br /&gt;        &amp;lt;/host&amp;gt;&lt;br /&gt;        &amp;lt;endpoint address=""&lt;br /&gt;            binding="basicHttpBinding"&lt;br /&gt;            contract="TestServiceInterface.ImyService"/&amp;gt;&lt;br /&gt;      &amp;lt;/service&amp;gt;&lt;br /&gt;    &amp;lt;/services&amp;gt;&lt;br /&gt;  &amp;lt;/system.serviceModel&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;ahref="http://gui-at.cendaweb.cz/2009/11/TestServiceInterface.py"&gt;interface&lt;/a&gt;is the same as in the previous version. The only difference in the service tothe previous version is in the &lt;span class="tt"&gt; ServiceHost&lt;/span&gt;initialization - we omit the service configuration parameters because they arein the &lt;i&gt;.config&lt;/i&gt; file. I also changed the clr namespace:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/11/ConfigService.py"&gt;ConfigService.py&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clr&lt;br /&gt;import clrtype&lt;br /&gt;clr.AddReference('System.ServiceModel')&lt;br /&gt;from TestServiceInterface import ImyService&lt;br /&gt;from System import Console, Uri&lt;br /&gt;from System.ServiceModel import (ServiceHost,&lt;br /&gt;        BasicHttpBinding, ServiceBehaviorAttribute,&lt;br /&gt;        InstanceContextMode)&lt;br /&gt;&lt;br /&gt;class myService(ImyService):&lt;br /&gt;    __metaclass__ = clrtype.ClrClass&lt;br /&gt;    _clrnamespace = "ConfigService"&lt;br /&gt;    _clrclassattribs = [ServiceBehaviorAttribute]&lt;br /&gt;&lt;br /&gt;    def GetData(self, value):&lt;br /&gt;        return "IronPython config service: You entered: %s" % value&lt;br /&gt;&lt;br /&gt;sh = ServiceHost(myService)&lt;br /&gt;sh.Open()&lt;br /&gt;Console.WriteLine("Press &lt;enter&gt; to terminate\n")&lt;br /&gt;Console.ReadLine()&lt;br /&gt;sh.Close()&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;If you want to run this script, you must save the &lt;ahref="http://gui-at.cendaweb.cz/2009/11/ConfigService.exe.config"&gt;ConfigService.exe.config&lt;/a&gt;as &lt;span class="tt"&gt;ipy.exe.config&lt;/span&gt; to the folder with the IronPythoninterpreter &lt;span class="tt"&gt; ipy.exe&lt;/span&gt;.&lt;/p&gt;&lt;p&gt;To save the service as an assembly, run the following command:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPython-2.6\ipy.exe C:\IronPython-2.6\Tools\Scripts\pyc.py  /out:ConfigService /target:exe /main:ConfigService.py clrtype.py TestServiceInterface.py&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;span class="tt"&gt;ConfigService.dll&lt;/span&gt; and &lt;spanclass="tt"&gt;ConfigService.exe&lt;/span&gt; are created. Add the &lt;ahref="http://gui-at.cendaweb.cz/2009/11/ConfigService.exe.config"&gt;ConfigService.exe.config&lt;/a&gt;to the same folder and when you run &lt;span class="tt"&gt;ConfigService.exe&lt;/span&gt;,the service starts. Note you also need all IronPython .dlls in the samefolder.&lt;/p&gt;&lt;p&gt;You can adjust the .config file to expose a MEX endpoint (&lt;ahref="http://gui-at.cendaweb.cz/2009/11/ConfigService.mex.exe.config"&gt;ConfigService.mex.exe.config&lt;/a&gt;)but I don't see a big point in it because svcutil.exe generates C# or VB code.Anyway - here are the generated files: &lt;ahref="http://gui-at.cendaweb.cz/2009/11/myService.cs"&gt;myService.cs&lt;/a&gt;, &lt;ahref="http://gui-at.cendaweb.cz/2009/11/myService.config"&gt;myService.config&lt;/a&gt;&lt;/p&gt;&lt;p&gt;You can run the old &lt;span class="tt"&gt;TestClient.py&lt;/span&gt; and it willsuccessfully retrieve value from the service. But the old &lt;spanclass="tt"&gt;TestClient.py&lt;/span&gt; does not use &lt;i&gt;.config&lt;/i&gt; file. If we want touse &lt;i&gt;.config&lt;/i&gt; file for the client, we have to rewrite the WCF client.First, here is the sample client &lt;i&gt;.config&lt;/i&gt; file:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/11/ConfigClient.exe.config"&gt;ConfigClient.exe.config&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;  &amp;lt;system.serviceModel&amp;gt;&lt;br /&gt;    &amp;lt;client&amp;gt;&lt;br /&gt;        &amp;lt;endpoint address="http://localhost:9000/myWcfService"&lt;br /&gt;            binding="basicHttpBinding"&lt;br /&gt;            contract="TestServiceInterface.ImyService"/&amp;gt;&lt;br /&gt;    &amp;lt;/client&amp;gt;&lt;br /&gt;  &amp;lt;/system.serviceModel&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;You can see it is very similar to the &lt;ahref="http://gui-at.cendaweb.cz/2009/11/myService.config"&gt;generated one&lt;/a&gt;. Wedo not specify details of the binding but we specify full name of the contractinterface.&lt;/p&gt;&lt;p&gt;If you check the &lt;ahref="http://gui-at.cendaweb.cz/2009/11/myService.cs"&gt;generated client proxyclass&lt;/a&gt; by svcutil.exe, you see it is based on &lt;span class="tt"&gt;System.ServiceModel.ClientBase&lt;/span&gt; and the interface &lt;spanclass="tt"&gt;ImyService&lt;/span&gt;. There are some empty constructors and all methodsfrom &lt;span class="tt"&gt;ImyService&lt;/span&gt; interface return result of the samemethod name call on &lt;span class="tt"&gt;Channel&lt;/span&gt; property. That's why I havecreated &lt;span class="tt"&gt;WcfClient&lt;/span&gt; helper function. The client sourcethen looks like the following:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/11/ConfigService.py"&gt;ConfigService.py&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clr&lt;br /&gt;clr.AddReference('System.ServiceModel')&lt;br /&gt;import System.ServiceModel&lt;br /&gt;from TestServiceInterface import ImyService&lt;br /&gt;&lt;br /&gt;def WcfClient(interface):&lt;br /&gt;&lt;br /&gt;    class WcfClientBase(System.ServiceModel.ClientBase[interface]):&lt;br /&gt;&lt;br /&gt;        def __getattr__(self, name):&lt;br /&gt;            # if name is method from interface, return the Channel method&lt;br /&gt;            if name in (k[0] for k in interface.emitted_methods.keys()):&lt;br /&gt;                return getattr(self.Channel, name)&lt;br /&gt;&lt;br /&gt;    return WcfClientBase()&lt;br /&gt;&lt;br /&gt;wcfcli = WcfClient(ImyService)&lt;br /&gt;print "WCF config client returned:\n%s" % wcfcli.GetData(11)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;span class="tt"&gt;WcfClient&lt;/span&gt; helper function returns an instance ofclass based on &lt;span class="tt"&gt; System.ServiceModel.ClientBase&lt;/span&gt;. The&lt;span class="tt"&gt;__getattr__&lt;/span&gt; checks if the requested attribute name isinterface method and if so, it returns the Channel's method with the same name.Which is the same behavior as the generated client proxy class in couple oflines of code.&lt;/p&gt;&lt;p&gt;To save the client as an assembly, run the following command:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPython-2.6\ipy.exe C:\IronPython-2.6\Tools\Scripts\pyc.py /out:ConfigClient /target:exe /main:ConfigClient.py clrtype.py TestServiceInterface.py&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;span class="tt"&gt;ConfigClient.dll&lt;/span&gt; and &lt;spanclass="tt"&gt;ConfigClient.exe&lt;/span&gt; are created. Add the &lt;ahref="http://gui-at.cendaweb.cz/2009/11/ConfigClient.exe.config"&gt;ConfigClient.exe.config&lt;/a&gt;to the same folder and when you run &lt;span class="tt"&gt;ConfigClient.exe&lt;/span&gt;,the client calls the service.&lt;/p&gt;&lt;p&gt;Having this I think there is only a small step to use the IronPython WCFservices in IIS. Unfortunately, I do not know how to do it...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-1197273637537051751?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/1197273637537051751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=1197273637537051751' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/1197273637537051751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/1197273637537051751'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2009/11/wcf-service-in-pure-ironpython-with.html' title='WCF Service in pure IronPython with config file'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-4628222184874447225</id><published>2009-11-17T13:07:00.006+01:00</published><updated>2010-05-16T19:22:20.677+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><category scheme='http://www.blogger.com/atom/ns#' term='clrtype'/><category scheme='http://www.blogger.com/atom/ns#' term='wcf'/><title type='text'>WCF Service in pure IronPython</title><content type='html'>&lt;p&gt;I wrote about implementing WCF service in IronPython &lt;ahref="http://gui-at.blogspot.com/2009/10/wcf-service-in-ironpython.html"&gt;acouple of weeks ago&lt;/a&gt;. Meanwhile I pushed Shri a little bit with the &lt;ahref="http://gui-at.cendaweb.cz/2009/11/clrtype.py"&gt;clrtype.py&lt;/a&gt; and he hasimplemented &lt;span class="tt"&gt;ClrInterface&lt;/span&gt; metaclass there so we cancreate the whole WCF service in IronPython now.&lt;/p&gt;&lt;p&gt;The IronPython interface implementation is straightforward:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/11/TestServiceInterface.py"&gt;TestServiceInterface.py&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clr&lt;br /&gt;import clrtype&lt;br /&gt;clr.AddReference('System.ServiceModel')&lt;br /&gt;from System.ServiceModel import (&lt;br /&gt;        ServiceContractAttribute,&lt;br /&gt;        OperationContractAttribute)&lt;br /&gt;OperationContract = clrtype.attribute(&lt;br /&gt;        OperationContractAttribute)&lt;br /&gt;&lt;br /&gt;class ImyService(object):&lt;br /&gt;    __metaclass__ = clrtype.ClrInterface&lt;br /&gt;    _clrnamespace = "TestServiceInterface"&lt;br /&gt;    _clrclassattribs = [ServiceContractAttribute]&lt;br /&gt;&lt;br /&gt;    @OperationContract()&lt;br /&gt;    @clrtype.accepts(int)&lt;br /&gt;    @clrtype.returns(str)&lt;br /&gt;    def GetData(self, value):&lt;br /&gt;        raise RuntimeError("this should not get called")&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Also switching from C# interface to IronPython interface is easy:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/11/TestService.py"&gt;TestService.py&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clr&lt;br /&gt;import clrtype&lt;br /&gt;clr.AddReference('System.ServiceModel')&lt;br /&gt;from TestServiceInterface import ImyService&lt;br /&gt;from System import Console, Uri&lt;br /&gt;from System.ServiceModel import (ServiceHost,&lt;br /&gt;        BasicHttpBinding, ServiceBehaviorAttribute,&lt;br /&gt;        InstanceContextMode)&lt;br /&gt;&lt;br /&gt;class myService(ImyService):&lt;br /&gt;    __metaclass__ = clrtype.ClrClass&lt;br /&gt;    _clrnamespace = "myWcfService"&lt;br /&gt;    _clrclassattribs = [ServiceBehaviorAttribute]&lt;br /&gt;&lt;br /&gt;    def GetData(self, value):&lt;br /&gt;        return "IronPython: You entered: %s" % value&lt;br /&gt;&lt;br /&gt;sh = ServiceHost(myService, Uri(&lt;br /&gt;        "http://localhost:9000/myWcfService"))&lt;br /&gt;sh.AddServiceEndpoint(clr.GetClrType(ImyService),&lt;br /&gt;        BasicHttpBinding(), "")&lt;br /&gt;sh.Open()&lt;br /&gt;Console.WriteLine("Press &lt;enter&gt; to terminate\n")&lt;br /&gt;Console.ReadLine()&lt;br /&gt;sh.Close()&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Notice that we call &lt;span class="tt"&gt;ServiceHost&lt;/span&gt; with &lt;spanclass="tt"&gt;myService&lt;/span&gt; which is the type and not the instance of ourservice. Because of this, the &lt;span class="tt"&gt;ServiceBehavior&lt;/span&gt; attributedoes not need to have &lt;i&gt;InstanceContextMode.Single&lt;/i&gt; parameter.&lt;/p&gt;&lt;p&gt;Finally, here is the test client:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/11/TestClient.py"&gt;TestClient.py&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clr&lt;br /&gt;clr.AddReference('System.ServiceModel')&lt;br /&gt;import System.ServiceModel&lt;br /&gt;from TestServiceInterface import ImyService&lt;br /&gt;&lt;br /&gt;mycf = System.ServiceModel.ChannelFactory[ImyService](&lt;br /&gt;        System.ServiceModel.BasicHttpBinding(),&lt;br /&gt;        System.ServiceModel.EndpointAddress(&lt;br /&gt;            "http://localhost:9000/myWcfService"))&lt;br /&gt;wcfcli = mycf.CreateChannel()&lt;br /&gt;print "WCF service returned:\n%s" % wcfcli.GetData(11)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The disadvantage of having just a single service instance is gone,&lt;strike&gt;the harder configuration remains&lt;/strike&gt;. One new disadvantage can be&lt;strike&gt;it is not possible (yet) to compile the interface and save it todisk&lt;/strike&gt; nor use it from other .NET languages.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Edit 22. 11. 2009:&lt;/b&gt; See &lt;ahref="http://gui-at.blogspot.com/2009/11/wcf-service-in-pure-ironpython-with.html"&gt;WCFService in pure IronPython with config file&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-4628222184874447225?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/4628222184874447225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=4628222184874447225' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/4628222184874447225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/4628222184874447225'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2009/11/wcf-service-in-pure-ironpython.html' title='WCF Service in pure IronPython'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-8502552386187992808</id><published>2009-11-16T11:14:00.008+01:00</published><updated>2010-05-16T19:31:34.210+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><category scheme='http://www.blogger.com/atom/ns#' term='clrtype'/><title type='text'>INotifyPropertyChanged and databinding in Silverlight</title><content type='html'>&lt;p&gt;In the &lt;ahref="http://gui-at.blogspot.com/2009/11/inotifypropertychanged-in-ironpython.html"&gt;previousarticle&lt;/a&gt;, I wrote about IronPython and databinding in WPF applications. Thelast note was it does not work in Silverlight. Thanks to Shri Borde(IronPython/IronRuby dev lead) who updated &lt;ahref="http://gui-at.cendaweb.cz/2009/11/clrtype.py"&gt;clrtype&lt;/a&gt; module, thenote is not true any more.&lt;/p&gt;&lt;p&gt;Let's create a small Silverlight app in IronPython from scratch. I useIronPython 2.6 RC2. Follow &lt;ahref="http://lists.ironpython.com/pipermail/users-ironpython.com/2009-October/011543.html"&gt;http://lists.ironpython.com/pipermail/users-ironpython.com/2009-October/011543.html&lt;/a&gt;to avoid bugs in IronPython 2.6 RC2.&lt;/p&gt;&lt;p&gt;Create a new project:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPython-2.6\Silverlight\script\sl.bat python BindTest&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Change the &lt;span class="tt"&gt;app.xaml&lt;/span&gt; to&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;&amp;lt;usercontrol x:Class="System.Windows.Controls.UserControl"&lt;br /&gt;    xmlns="http://schemas.microsoft.com/client/2007"&lt;br /&gt;    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;&lt;br /&gt;    &amp;lt;stackpanel x:Name="DataPanel"&lt;br /&gt;        Orientation="Horizontal"&amp;gt;&lt;br /&gt;        &amp;lt;textblock Text="Size"/&amp;gt;&lt;br /&gt;        &amp;lt;textblock Text="{Binding size}"/&amp;gt;&lt;br /&gt;        &amp;lt;textbox x:Name="tbSize"&lt;br /&gt;            Text="{Binding size, Mode=TwoWay}" /&amp;gt;&lt;br /&gt;        &amp;lt;button x:Name="Button"&lt;br /&gt;            Content="Set Initial Value"&amp;gt;&amp;lt;/Button&amp;gt;&lt;br /&gt;    &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;&amp;lt;/UserControl&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The difference comparing to &lt;ahref="http://gui-at.blogspot.com/2009/11/inotifypropertychanged-in-ironpython.html"&gt;WPFversion&lt;/a&gt; is we have to specify binding mode because the default mode forTextBox in Silverlight is &lt;i&gt;OneWay&lt;/i&gt;. And we cannot use &lt;span class="tt"&gt;UpdateSourceTrigger=PropertyChanged&lt;/span&gt; because Silverlight does not havesuch &lt;i&gt;UpdateSourceTrigger&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;Silverlight binding is limited comparing to WPF. That's why we have tocreate &lt;i&gt;CLR properties&lt;/i&gt; to Silverlight be able to see them. DevHawk has anice serie about clr types on his &lt;ahref="http://devhawk.net/CategoryView,category,__clrtype__.aspx"&gt;blog&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Creating CLR property with &lt;ahref="http://gui-at.cendaweb.cz/2009/11/clrtype.py"&gt;clrtype.py&lt;/a&gt; is easy.Shri described it on IronPython &lt;ahref="http://lists.ironpython.com/pipermail/users-ironpython.com/2009-November/011659.html"&gt;mailinglist&lt;/a&gt;. Because I use my enhanced &lt;span class="tt"&gt;@notify_property&lt;/span&gt;decorator, I can write:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;class ViewModel(NotifyPropertyChangedBase):&lt;br /&gt;    __metaclass__ = clrtype.ClrClass&lt;br /&gt;    _clrnamespace = "BindTest"&lt;br /&gt;    &lt;br /&gt;    def __init__(self):&lt;br /&gt;        super(ViewModel, self).__init__()&lt;br /&gt;        # must be string to two-way binding work&lt;br /&gt;        # correctly&lt;br /&gt;        self.size = '10'&lt;br /&gt;&lt;br /&gt;    @notify_property&lt;br /&gt;    @clrtype.returns(str)&lt;br /&gt;    def size(self):&lt;br /&gt;        return self._size&lt;br /&gt;&lt;br /&gt;    @size.setter&lt;br /&gt;    @clrtype.accepts(str)&lt;br /&gt;    def size(self, value):&lt;br /&gt;        self._size = value&lt;br /&gt;        print 'Size changed to %r' % self.size&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;span class="tt"&gt;NotifyPropertyChangedBase&lt;/span&gt; class is the same asfor &lt;ahref="http://gui-at.blogspot.com/2009/11/inotifypropertychanged-in-ironpython.html"&gt;WPFversion&lt;/a&gt;. The enhanced &lt;span class="tt"&gt;@notify_property&lt;/span&gt; decoratorcalls automatically &lt;span class="tt"&gt;clrtype.accepts()&lt;/span&gt; for getter and&lt;span class="tt"&gt;clrtype.returns()&lt;/span&gt; for setter so we do not need to callthem manually for every property:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;class notify_property(property):&lt;br /&gt;&lt;br /&gt;    def __init__(self, getter):&lt;br /&gt;        def newgetter(slf):&lt;br /&gt;            #return None when the property does not&lt;br /&gt;            # exist yet&lt;br /&gt;            try:&lt;br /&gt;                return getter(slf)&lt;br /&gt;            except AttributeError:&lt;br /&gt;                return None&lt;br /&gt;        getter = clrtype.accepts()(getter)&lt;br /&gt;        clrtype.propagate_attributes(getter, newgetter)&lt;br /&gt;        super(notify_property, self).__init__(newgetter)&lt;br /&gt;&lt;br /&gt;    def setter(self, setter):&lt;br /&gt;        def newsetter(slf, newvalue):&lt;br /&gt;            # do not change value if the new value is&lt;br /&gt;            # the same, trigger PropertyChanged event&lt;br /&gt;            # when value changes&lt;br /&gt;            oldvalue = self.fget(slf)&lt;br /&gt;            if oldvalue != newvalue:&lt;br /&gt;                setter(slf, newvalue)&lt;br /&gt;                slf.OnPropertyChanged(setter.__name__)&lt;br /&gt;        setter = clrtype.returns()(setter)&lt;br /&gt;        clrtype.propagate_attributes(setter, newsetter)&lt;br /&gt;        return property(&lt;br /&gt;            fget=self.fget,&lt;br /&gt;            fset=newsetter,&lt;br /&gt;            fdel=self.fdel,&lt;br /&gt;            doc=self.__doc__)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Then &lt;span class="tt"&gt;App&lt;/span&gt; looks similarly to the &lt;ahref="http://gui-at.blogspot.com/2009/11/inotifypropertychanged-in-ironpython.html"&gt;WPFcounterpart&lt;/a&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;class App:&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self._vm = ViewModel()&lt;br /&gt;        self.root = Application.Current.LoadRootVisual(&lt;br /&gt;                UserControl(), "app.xaml")&lt;br /&gt;        self.DataPanel.DataContext = self._vm&lt;br /&gt;        self.Button.Click += self.OnClick&lt;br /&gt;&lt;br /&gt;    def OnClick(self, sender, event):&lt;br /&gt;        # must be string to two-way binding work&lt;br /&gt;        # correctly&lt;br /&gt;        self._vm.size = '10'&lt;br /&gt;&lt;br /&gt;    def __getattr__(self, name):&lt;br /&gt;        # provides easy access to XAML elements&lt;br /&gt;        # (e.g. self.Button)&lt;br /&gt;        return self.root.FindName(name)&lt;br /&gt;&lt;br /&gt;a = App()&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Run Chiron with the &lt;i&gt;BindTest&lt;/i&gt; app&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;C:\IronPython-2.6\Silverlight\script\sl.bat python BindTest&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;and check the application in the browser on &lt;ahref="http://localhost:2060/index.html"&gt;http://localhost:2060/index.html&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Whatever you write into the text box appears in the label in front of thetext box when the text box loses the focus. When you click the button, thevalue is reseted. You can also change the value from the console:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;a._vm.size= '3'&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Download &lt;a href="http://gui-at.cendaweb.cz/2009/11/app.xaml"&gt;app.xaml&lt;/a&gt;and &lt;a href="http://gui-at.cendaweb.cz/2009/11/app.py"&gt;app.py&lt;/a&gt;. You alsoneed &lt;a href="http://gui-at.cendaweb.cz/2009/11/clrtype.py"&gt;clrtype.py&lt;/a&gt; andpyevent.py (from C:\IronPython-2.6\Tutorial\pyevent.py) in the &lt;i&gt;BindTest&lt;/i&gt;folder.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-8502552386187992808?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/8502552386187992808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=8502552386187992808' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/8502552386187992808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/8502552386187992808'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2009/11/inotifypropertychanged-and-databinding.html' title='INotifyPropertyChanged and databinding in Silverlight'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-26309250501982853</id><published>2009-11-11T12:22:00.029+01:00</published><updated>2010-05-16T19:40:27.758+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wpf'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><category scheme='http://www.blogger.com/atom/ns#' term='clrtype'/><title type='text'>INotifyPropertyChanged and databinding in IronPython WPF</title><content type='html'>&lt;p&gt;&lt;ahref="http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx"&gt;INotifyPropertyChanged&lt;/a&gt;is important interface for building WPF or Silverlight applications using &lt;ahref="http://en.wikipedia.org/wiki/Model_View_ViewModel"&gt;M-V-VM concept&lt;/a&gt; (&lt;ahref="http://msdn.microsoft.com/en-us/magazine/dd419663.aspx"&gt;MSDNarticle&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;In simple language, you have a &lt;b&gt;Model&lt;/b&gt; which provides access to yourdata (e.g in database, files, web, etc.). Then you have a &lt;b&gt;ViewModel&lt;/b&gt; thataccess data in the Model via Model's interface and provides data to a&lt;b&gt;View&lt;/b&gt; which is XAML file with UI layout. Linkage between ViewModel andView is done by binding that utilizes &lt;i&gt;PropertyChanged&lt;/i&gt; event to properlyupdate all UI elements.&lt;/p&gt;&lt;p&gt;I have found two examples how to implement &lt;i&gt;INotifyPropertyChanged&lt;/i&gt;interface in IronPython. &lt;ahref="http://lists.ironpython.com/pipermail/users-ironpython.com/2009-August/010938.html"&gt;Thefirst one&lt;/a&gt; uses __setattr__ hook. Personally, I don't like it - it is notclear and easily readable code. &lt;ahref="http://palepoli.skr.jp/wp/2009/06/28/wpf-listview-databinding-for-ironpython/"&gt;Thesecond one&lt;/a&gt; is better because it uses properties. But you have to write&lt;span class="tt"&gt;self.OnPropertyChanged("my_property_name")&lt;/span&gt; for everyproperty. Not ideal.&lt;/p&gt;&lt;p&gt;That's why I sit down and write a &lt;b&gt;notify_property&lt;/b&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;class notify_property(property):&lt;br /&gt;&lt;br /&gt;    def __init__(self, getter):&lt;br /&gt;        def newgetter(slf):&lt;br /&gt;            try:&lt;br /&gt;                return getter(slf)&lt;br /&gt;            except AttributeError:&lt;br /&gt;                return None&lt;br /&gt;        super(notify_property, self).__init__(newgetter)&lt;br /&gt;&lt;br /&gt;    def setter(self, setter):&lt;br /&gt;        def newsetter(slf, newvalue):&lt;br /&gt;            oldvalue = self.fget(slf)&lt;br /&gt;            if oldvalue != newvalue:&lt;br /&gt;                setter(slf, newvalue)&lt;br /&gt;                slf.OnPropertyChanged(setter.__name__)&lt;br /&gt;        return property(&lt;br /&gt;            fget=self.fget,&lt;br /&gt;            fset=newsetter,&lt;br /&gt;            fdel=self.fdel,&lt;br /&gt;            doc=self.__doc__)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;With this subclass I aimed several goals:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;usage simple as &lt;span class="tt"&gt;@property&lt;/span&gt; decorator (actualy no other usage is possible as I implemented &lt;span class="tt"&gt;__init__&lt;/span&gt; with just one parameter that must be the getter)&lt;/li&gt;&lt;li&gt;when property is on yet defined, it should return &lt;span class="tt"&gt;None&lt;/span&gt;&lt;/li&gt;&lt;li&gt;automaticaly handle &lt;i&gt;PropertyChanged&lt;/i&gt; event when and only when property has changed&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We also need to implement &lt;i&gt;INotifyPropertyChanged&lt;/i&gt; interface inIronPython so we can call &lt;i&gt;OnPropertyChanged&lt;/i&gt; method. See &lt;i&gt;Overidingevents&lt;/i&gt; in &lt;span class="tt"&gt;IronPython\Doc\dotnet-integration.rst&lt;/span&gt; tounderstand what means &lt;i&gt;add_&lt;/i&gt; and &lt;i&gt;remove_&lt;/i&gt; methods.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;class NotifyPropertyChangedBase(INotifyPropertyChanged):&lt;br /&gt;    PropertyChanged = None&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.PropertyChanged, self._propertyChangedCaller = pyevent.make_event()&lt;br /&gt;&lt;br /&gt;    def add_PropertyChanged(self, value):&lt;br /&gt;        self.PropertyChanged += value&lt;br /&gt;&lt;br /&gt;    def remove_PropertyChanged(self, value):&lt;br /&gt;        self.PropertyChanged -= value&lt;br /&gt;&lt;br /&gt;    def OnPropertyChanged(self, propertyName):&lt;br /&gt;        if self.PropertyChanged is not None:&lt;br /&gt;            self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Now we can implement a simple class with properties with changenotification:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;class DataObject(NotifyPropertyChangedBase):&lt;br /&gt;    &lt;br /&gt;    def __init__(self, size):&lt;br /&gt;        super(DataObject, self).__init__()&lt;br /&gt;        self.size = size&lt;br /&gt;&lt;br /&gt;    @notify_property&lt;br /&gt;    def size(self):&lt;br /&gt;        return self._size&lt;br /&gt;&lt;br /&gt;    @size.setter&lt;br /&gt;    def size(self, value):&lt;br /&gt;        self._size = value&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;You can see it is very easy - just like any other property in Python.&lt;/p&gt;&lt;p&gt;Finaly, let's put all together. When you run the code below, it shows awindow with label, textbox and button. The label is updated as you type intothe textbox and a message is written into the console as well. By default, thetextbox is updated when it looses focus, so I have to change &lt;spanclass="tt"&gt;UpdateSourceTrigger&lt;/span&gt; to &lt;i&gt;PropertyChanged&lt;/i&gt;. When you clickthe button, the value is reset. Note if you use type &lt;spanclass="tt"&gt;int&lt;/span&gt; instead of &lt;span class="tt"&gt;string&lt;/span&gt; the two-waybindign would not work.&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/11/notpropwpf.py"&gt;notpropwpf.py&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint lang-py"&gt;&lt;br /&gt;import clr&lt;br /&gt;import System&lt;br /&gt;clr.AddReference('PresentationFramework')&lt;br /&gt;clr.AddReference('PresentationCore')&lt;br /&gt;&lt;br /&gt;from System.Windows.Markup import XamlReader&lt;br /&gt;from System.Windows import Application, Window&lt;br /&gt;from System.ComponentModel import INotifyPropertyChanged, PropertyChangedEventArgs&lt;br /&gt;import pyevent&lt;br /&gt;&lt;br /&gt;XAML_str = """&amp;lt;window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;br /&gt;    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="250" Height="62"&amp;gt;&lt;br /&gt;    &amp;lt;stackpanel x:Name="DataPanel" Orientation="Horizontal"&amp;gt;&lt;br /&gt;        &amp;lt;label Content="Size"/&amp;gt;&lt;br /&gt;        &amp;lt;label Content="{Binding size}"/&amp;gt;&lt;br /&gt;        &amp;lt;textbox x:Name="tbSize" Text="{Binding size, UpdateSourceTrigger=PropertyChanged}" /&amp;gt;&lt;br /&gt;        &amp;lt;button x:Name="Button" Content="Set Initial Value"&amp;gt;&amp;lt;/Button&amp;gt;&lt;br /&gt;    &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;&amp;lt;/Window&amp;gt;"""&lt;br /&gt;&lt;br /&gt;class notify_property(property):&lt;br /&gt;&lt;br /&gt;    def __init__(self, getter):&lt;br /&gt;        def newgetter(slf):&lt;br /&gt;            #return None when the property does not exist yet&lt;br /&gt;            try:&lt;br /&gt;                return getter(slf)&lt;br /&gt;            except AttributeError:&lt;br /&gt;                return None&lt;br /&gt;        super(notify_property, self).__init__(newgetter)&lt;br /&gt;&lt;br /&gt;    def setter(self, setter):&lt;br /&gt;        def newsetter(slf, newvalue):&lt;br /&gt;            # do not change value if the new value is the same&lt;br /&gt;            # trigger PropertyChanged event when value changes&lt;br /&gt;            oldvalue = self.fget(slf)&lt;br /&gt;            if oldvalue != newvalue:&lt;br /&gt;                setter(slf, newvalue)&lt;br /&gt;                slf.OnPropertyChanged(setter.__name__)&lt;br /&gt;        return property(&lt;br /&gt;            fget=self.fget,&lt;br /&gt;            fset=newsetter,&lt;br /&gt;            fdel=self.fdel,&lt;br /&gt;            doc=self.__doc__)&lt;br /&gt;&lt;br /&gt;class NotifyPropertyChangedBase(INotifyPropertyChanged):&lt;br /&gt;    PropertyChanged = None&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self.PropertyChanged, self._propertyChangedCaller = pyevent.make_event()&lt;br /&gt;&lt;br /&gt;    def add_PropertyChanged(self, value):&lt;br /&gt;        self.PropertyChanged += value&lt;br /&gt;&lt;br /&gt;    def remove_PropertyChanged(self, value):&lt;br /&gt;        self.PropertyChanged -= value&lt;br /&gt;&lt;br /&gt;    def OnPropertyChanged(self, propertyName):&lt;br /&gt;        if self.PropertyChanged is not None:&lt;br /&gt;            self._propertyChangedCaller(self, PropertyChangedEventArgs(propertyName))&lt;br /&gt;&lt;br /&gt;class ViewModel(NotifyPropertyChangedBase):&lt;br /&gt;    &lt;br /&gt;    def __init__(self):&lt;br /&gt;        super(ViewModel, self).__init__()&lt;br /&gt;        # must be string to two-way binding work correctly&lt;br /&gt;        self.size = '10'&lt;br /&gt;&lt;br /&gt;    @notify_property&lt;br /&gt;    def size(self):&lt;br /&gt;        return self._size&lt;br /&gt;&lt;br /&gt;    @size.setter&lt;br /&gt;    def size(self, value):&lt;br /&gt;        self._size = value&lt;br /&gt;        print 'Size changed to %r' % self.size&lt;br /&gt;&lt;br /&gt;class TestWPF(object):&lt;br /&gt;&lt;br /&gt;    def __init__(self):&lt;br /&gt;        self._vm = ViewModel()&lt;br /&gt;        self.root = XamlReader.Parse(XAML_str)&lt;br /&gt;        self.DataPanel.DataContext = self._vm&lt;br /&gt;        self.Button.Click += self.OnClick&lt;br /&gt;        &lt;br /&gt;    def OnClick(self, sender, event):&lt;br /&gt;        # must be string to two-way binding work correctly&lt;br /&gt;        self._vm.size = '10'&lt;br /&gt;&lt;br /&gt;    def __getattr__(self, name):&lt;br /&gt;        # provides easy access to XAML elements (e.g. self.Button)&lt;br /&gt;        return self.root.FindName(name)&lt;br /&gt;&lt;br /&gt;tw = TestWPF()&lt;br /&gt;app = Application()&lt;br /&gt;app.Run(tw.root)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;You need pyevent.py from IronPython\Tutorial\ folder to run to example.&lt;/p&gt;&lt;p&gt;&lt;strike&gt;Unfortunately, this does not work in Silverlight, probably becausethe property is not .NET field&lt;/strike&gt;. See &lt;ahref="http://gui-at.blogspot.com/2009/11/inotifypropertychanged-and-databinding.html"&gt;nextatricle&lt;/a&gt; for Silverlight version.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-26309250501982853?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/26309250501982853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=26309250501982853' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/26309250501982853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/26309250501982853'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2009/11/inotifypropertychanged-in-ironpython.html' title='INotifyPropertyChanged and databinding in IronPython WPF'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-3556934013257617305</id><published>2009-10-30T18:08:00.015+01:00</published><updated>2010-05-16T19:47:13.244+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><category scheme='http://www.blogger.com/atom/ns#' term='clrtype'/><category scheme='http://www.blogger.com/atom/ns#' term='wcf'/><title type='text'>WCF Service in IronPython</title><content type='html'>&lt;p&gt;&lt;b&gt;Edit 17. 11. 2009:&lt;/b&gt; See the article about &lt;ahref="http://gui-at.blogspot.com/2009/11/wcf-service-in-pure-ironpython.html"&gt;WCFservice in pure IronPython&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Until IronPython 2.6, it was not possible to create WCF service host in pureIronPython. The closest way was to create stub in C# and &lt;ahref="http://www.voidspace.org.uk/ironpython/dynamically_compiling.shtml#subclassing-in-ironpython"&gt;subclassit in IronPython&lt;/a&gt; or create the whole service in C# and &lt;ahref="http://www.darrellhawley.com/2009/03/writing-ironpython-wcf-host.html"&gt;runit from IronPython&lt;/a&gt;. It is now much simpler with IronPython 2.6 although youstill have to write a little C# code.&lt;/p&gt;&lt;p&gt;Simple WCF service implemented in C# looks like this:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/10/TestServiceInterface.cs"&gt;TestServiceInterface.cs&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.ServiceModel;&lt;br /&gt;&lt;br /&gt;namespace TestServiceInterface&lt;br /&gt;{&lt;br /&gt;    [ServiceContract]&lt;br /&gt;    public interface ImyService&lt;br /&gt;    {&lt;br /&gt;        [OperationContract]&lt;br /&gt;        string GetData(int value);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/10/TestService.cs"&gt;TestService.cs&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.ServiceModel;&lt;br /&gt;using TestServiceInterface;&lt;br /&gt;&lt;br /&gt;namespace myWcfService&lt;br /&gt;{&lt;br /&gt;    public class myService : ImyService&lt;br /&gt;    {&lt;br /&gt;        public string GetData(int value)&lt;br /&gt;        {&lt;br /&gt;            return string.Format("You entered: {0}", value);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public class mySvc&lt;br /&gt;    {&lt;br /&gt;        public static void Main()&lt;br /&gt;        {&lt;br /&gt;            ServiceHost sh = new ServiceHost(&lt;br /&gt;                typeof(myService),&lt;br /&gt;                new Uri("http://localhost:9000/myWcfService"));&lt;br /&gt;            sh.AddServiceEndpoint(&lt;br /&gt;                typeof(ImyService),&lt;br /&gt;                new BasicHttpBinding(),&lt;br /&gt;                "");&lt;br /&gt;            sh.Open();&lt;br /&gt;            Console.WriteLine("Press &lt;enter&gt; to terminate\n");&lt;br /&gt;            Console.ReadLine();&lt;br /&gt;            sh.Close();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;You build it:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;csc /target:library TestServiceInterface.cs&lt;br /&gt;csc /r:TestServiceInterface.dll TestService.cs&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The reason I put &lt;i&gt;TestServiceInterface&lt;/i&gt; into separate file is that youcannot create interfaces in IronPython. So this is the only part written in C#when implementig WCF service in IronPython.&lt;/p&gt;&lt;p&gt;The implementation then looks like this:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/10/TestService.py"&gt;TestService.py&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clr&lt;br /&gt;import clrtype&lt;br /&gt;clr.AddReference('System.ServiceModel')&lt;br /&gt;clr.AddReference('TestServiceInterface')&lt;br /&gt;from TestServiceInterface import ImyService&lt;br /&gt;from System import Console, Uri&lt;br /&gt;from System.ServiceModel import (ServiceHost, BasicHttpBinding,&lt;br /&gt;        ServiceBehaviorAttribute, InstanceContextMode)&lt;br /&gt;ServiceBehavior = clrtype.attribute(ServiceBehaviorAttribute)&lt;br /&gt;&lt;br /&gt;class myService(ImyService):&lt;br /&gt;    __metaclass__ = clrtype.ClrMetaclass&lt;br /&gt;    _clrnamespace = "myWcfService"&lt;br /&gt;    _clrclassattribs = [&lt;br /&gt;            ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]&lt;br /&gt;&lt;br /&gt;    def GetData(self, value):&lt;br /&gt;        return "IronPython: You entered: %s" % value&lt;br /&gt;&lt;br /&gt;sh = ServiceHost(&lt;br /&gt;        myService(),&lt;br /&gt;        Uri("http://localhost:9000/myWcfService")&lt;br /&gt;    )&lt;br /&gt;sh.AddServiceEndpoint(&lt;br /&gt;        clr.GetClrType(ImyService),&lt;br /&gt;        BasicHttpBinding(),&lt;br /&gt;        "")&lt;br /&gt;sh.Open()&lt;br /&gt;Console.WriteLine("Press &lt;enter&gt; to terminate\n")&lt;br /&gt;Console.ReadLine()&lt;br /&gt;sh.Close()&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The &lt;span class="tt"&gt;myService&lt;/span&gt; class must have&lt;i&gt;InstanceContextMode.Single&lt;/i&gt; ServiceBehavior attribute because we arepassing service i&lt;i&gt;nstance&lt;/i&gt; to the &lt;span class="tt"&gt;ServiceHost&lt;/span&gt;constructor. This is done via new &lt;ahref="http://devhawk.net/CategoryView,category,__clrtype__.aspx"&gt;__clrtype__metaclass&lt;/a&gt;. See the &lt;ahref="http://lists.ironpython.com/pipermail/users-ironpython.com/2009-February/009718.html"&gt;error&lt;/a&gt;if we don't use the attribute. I was not able to pass &lt;i&gt;type&lt;/i&gt; into the&lt;span class="tt"&gt;ServiceHost&lt;/span&gt; constructor.&lt;/p&gt;&lt;p&gt;To test the service, you can use C# or IronPython client implementation:&lt;/p&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/10/TestClient.cs"&gt;TestClient.cs&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.ServiceModel;&lt;br /&gt;using TestServiceInterface;&lt;br /&gt;&lt;br /&gt;namespace myWcfClient&lt;br /&gt;{&lt;br /&gt;    public class cli&lt;br /&gt;    {&lt;br /&gt;        public static void Main()&lt;br /&gt;        {&lt;br /&gt;   ChannelFactory&lt;imyservice&gt; mycf = new ChannelFactory&lt;imyservice&gt;(&lt;br /&gt;     new BasicHttpBinding(),&lt;br /&gt;        new EndpointAddress("http://localhost:9000/myWcfService"));&lt;br /&gt;   ImyService wcfcli = mycf.CreateChannel();&lt;br /&gt;   Console.WriteLine("Calling GetData(33) returns:\n{0}", wcfcli.GetData(33));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href="http://gui-at.cendaweb.cz/2009/10/TestClient.py"&gt;TestClient.py&lt;/a&gt;&lt;/p&gt;&lt;pre class="prettyprinter"&gt;&lt;br /&gt;import clr&lt;br /&gt;clr.AddReference('System.ServiceModel')&lt;br /&gt;import System.ServiceModel&lt;br /&gt;clr.AddReference('TestServiceInterface')&lt;br /&gt;from TestServiceInterface import ImyService&lt;br /&gt;&lt;br /&gt;mycf = System.ServiceModel.ChannelFactory[ImyService](&lt;br /&gt;        System.ServiceModel.BasicHttpBinding(),&lt;br /&gt;        System.ServiceModel.EndpointAddress("http://localhost:9000/myWcfService"))&lt;br /&gt;wcfcli = mycf.CreateChannel()&lt;br /&gt;print "WCF service returned:\n%s" % wcfcli.GetData(11)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Disadvantages:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;You can have only single instance of the service because you are passing the service &lt;i&gt;instance&lt;/i&gt; instead of service &lt;i&gt;type&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;You cannot easily use &lt;i&gt;.config&lt;/i&gt; file to configure your service.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-3556934013257617305?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/3556934013257617305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=3556934013257617305' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/3556934013257617305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/3556934013257617305'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2009/10/wcf-service-in-ironpython.html' title='WCF Service in IronPython'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-8991241609083242488</id><published>2009-09-24T23:53:00.015+02:00</published><updated>2010-05-16T20:42:55.428+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='virtualbox'/><title type='text'>How to clone VirtualBox virtual machine</title><content type='html'>&lt;p&gt;&lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt; is great piece ofsoftware for virtualization. I like it more than &lt;ahref="http://www.vmware.com/"&gt;VMWare&lt;/a&gt; or &lt;ahref="http://www.microsoft.com/windows/virtual-pc/"&gt;VirtualPC&lt;/a&gt;. The downsideof it is its lack of easy&amp;nbsp;cloning&amp;nbsp;or copying capabilities. There arenone. And because everything in VirtualBox has UUID (guid), pure file copy doesnot work well.&lt;/p&gt;&lt;p&gt;All advices I have seen were about: create the new virtual machinemanually,&amp;nbsp;clone HDD .vdi file with &amp;nbsp;&lt;span class="tt"&gt;&lt;ahref="http://srackham.wordpress.com/cloning-and-copying-virtualbox-virtual-machines/"&gt;VBoxManageclonevdi&lt;/a&gt;&lt;/span&gt;&amp;nbsp;command and attach it to the newly created virtualmachine. &lt;i&gt;Manually!?&lt;/i&gt;&lt;/p&gt;&lt;p&gt;That's why I've created a simple Python script that cares about exportingand importing virtual machines (Thanks for the VirtualBox 3 SDK!). Whenexporting, &lt;b&gt;you can select the virtual machine and &lt;/b&gt;&lt;b&gt;snapshot you wantto export&lt;/b&gt;:&lt;/p&gt;&lt;p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;ahref="http://3.bp.blogspot.com/_S0yH53CI4fI/SrvmorRrk5I/AAAAAAAAACI/3Xk5d1x0EIA/s1600-h/VBoxUtil.png"imageanchor="1"&gt;&lt;img border="0"src="http://3.bp.blogspot.com/_S0yH53CI4fI/SrvmorRrk5I/AAAAAAAAACI/3Xk5d1x0EIA/s400/VBoxUtil.png"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;p&gt;The exported machines are stored in &lt;span class="tt"&gt;exp&lt;/span&gt; folder atthe script file. The&amp;nbsp;time stamp&amp;nbsp;is added to the machine name forunique identification.&amp;nbsp;When importing, you are offered with the savedvirtual machines and you simply choose one. Of course you can copy the exportedmachine to different computer (having the same VirtualBox versions isrecommended).&lt;/p&gt;&lt;p&gt;The script is very simple and targeted to my needs. That means it exportsonly primary HDD and network adapter 0. It does not export CD/DVD-ROM, Floppynor Serial ports.&lt;/p&gt;&lt;p&gt;Try it and let me know whether it's helpful:&amp;nbsp;&lt;ahref="http://gui-at.cendaweb.cz/2009/09/VBoxUtil.py"&gt;downloadscript&lt;/a&gt;&amp;nbsp;(it requires&amp;nbsp;&lt;ahref="http://www.voidspace.org.uk/python/configobj.html"&gt;ConfigObj 4&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;&lt;b&gt;Update 1. 10. 2009:&lt;/b&gt;&amp;nbsp;I struggled running the script on my new Win7 64-bit system. It complained class is not registered for VirtualBox.Session.The reason was mixing 32-bit and 64-bit programs - see the &lt;ahref="http://vbox.innotek.de/pipermail/vbox-users/2008-May/003308.html"&gt;explanation&lt;/a&gt;.&lt;b&gt;If you use 64-bit OS, you have to have installed 64-bit version of Pythonand pywin32&lt;/b&gt;!&lt;/p&gt;&lt;p&gt;&lt;b&gt;Update 11. 11. 2009:&lt;/b&gt; I have updated the script to better serve myneeds. For example, when restoring virtual machine, you can enter a new namefor it. Be carefull when restoring one saved machine to two new ones as youhave to chagne MAC address manually.&lt;/p&gt;&lt;p&gt;Unfortunately, the old config file is not compactible with the new version.But I think you can guess from the Python exception what is wrong with theconfig file and fix it. The old version is still &lt;ahref="http://gui-at.cendaweb.cz/2009/09/VBoxUtil.old.py"&gt;available&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Update 29. 12. 2009:&lt;/b&gt;&amp;nbsp;When I upgraded to VirtualBox 3.1, Ireceived &lt;i&gt;KeyError&lt;/i&gt; when I run my script({2158464A-F706-414B-A8C4-FB589DFC6B62}). To get rid of it, delete all fromfrom &lt;span style="font-family: 'Courier New', Courier,monospace;"&gt;\Python26\Lib\site-packages\win32com\gen_py\&lt;/span&gt; except &lt;spanstyle="font-family: 'Courier New', Courier, monospace;"&gt;__init__.py&lt;/span&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-8991241609083242488?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/8991241609083242488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=8991241609083242488' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/8991241609083242488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/8991241609083242488'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2009/09/how-to-clone-virtualbox-virtual-machine.html' title='How to clone VirtualBox virtual machine'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_S0yH53CI4fI/SrvmorRrk5I/AAAAAAAAACI/3Xk5d1x0EIA/s72-c/VBoxUtil.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-4297872760962914668</id><published>2009-05-16T18:26:00.003+02:00</published><updated>2009-05-16T18:32:29.288+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='links'/><title type='text'>Pycon 2009: Functional Testing of Desktop Applications</title><content type='html'>Here is a link to &lt;span class="fn"&gt;Michael Foord&lt;/span&gt; talk at Pycon 2009 in Chicago about functional testing of desktop applications:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://pycon.blip.tv/file/1957454/"&gt;Functional Testing of Desktop Applications&lt;/a&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Many advocates of unit testing believe that testing desktop (GUI) applications is so difficult as to not be worth it. Not only is it possible, but 'functional testing' (testing an application from the point of view of the user) is an important part of an agile development process.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I watched it yesterday and it is very good!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-4297872760962914668?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/4297872760962914668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=4297872760962914668' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/4297872760962914668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/4297872760962914668'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2009/05/pycon-2009-functional-testing-of.html' title='Pycon 2009: Functional Testing of Desktop Applications'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-4609531643659187214</id><published>2009-05-15T17:25:00.004+02:00</published><updated>2010-05-16T20:48:11.980+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='accessibility'/><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Testing an unknown application</title><content type='html'>&lt;p&gt;From time to time you may need to test an unknown application. I haveencounter it when I needed to test our installation program. The task wassimple - install the application for automated smoke tests. In such cases Igladly return to &lt;ahref="http://gui-at.blogspot.com/2008/06/exploring-test-application.html"&gt;Accessibility&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Let's pretend our testing application is not written in .NET and the onlyway how to explore it is through the accessibility (AccExplorer):&lt;/p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"href="http://bp1.blogger.com/_S0yH53CI4fI/SEXErJpCENI/AAAAAAAAAA0/dZNbgnkTLzc/s1600-h/AccExplorer.PNG"&gt;&lt;imgstyle="margin: 0px auto 10px; display: block; text-align: center; cursor:pointer;"src="http://bp1.blogger.com/_S0yH53CI4fI/SEXErJpCENI/AAAAAAAAAA0/dZNbgnkTLzc/s320/AccExplorer.PNG"alt="" id="BLOGGER_PHOTO_ID_5207784789725286610" border="0" /&gt;&lt;/a&gt;&lt;p&gt;All we need to do is to access Accessibility objects from IronPython. Thereis a project called &lt;a href="http://mwinapi.sourceforge.net/"&gt;Managed WindowsAPI&lt;/a&gt; that nicely wraps accessibility for .NET. It also wraps other Win32 APIcalls (mouse clicks etc.) but I stay with &lt;ahref="http://gui-at.blogspot.com/2008/07/simulate-users-input.html"&gt;Win32API.dll&lt;/a&gt;because of my laziness :-).&lt;/p&gt;&lt;p&gt;Utilizing the &lt;span style="font-style: italic;"&gt;Managed Windows API&lt;/span&gt;you can control the accessibility objects. Here is the snippet:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clr&lt;br /&gt;# Win32API provide access to Win32 API functions&lt;br /&gt;clr.AddReference('Win32API')&lt;br /&gt;from Win32API import Win32API&lt;br /&gt;# ManagedWinapi provide access to Accessibility objects&lt;br /&gt;clr.AddReference('ManagedWinapi')&lt;br /&gt;import ManagedWinapi.Accessibility as ma&lt;br /&gt;import ManagedWinapi.Windows as mw&lt;br /&gt;&lt;br /&gt;def GetGUIATWindow():&lt;br /&gt;   """ Return GUIAT_PoC window accessibility object. """&lt;br /&gt;   def callback(aWindow):&lt;br /&gt;       return aWindow.Title == 'GUIAT - Proof of Concept'&lt;br /&gt;   guiat_window = mw.SystemWindow.FilterToplevelWindows(callback)&lt;br /&gt;   # assume guiat_window is list with just one object&lt;br /&gt;   return ma.SystemAccessibleObject.FromWindow(guiat_window[0],&lt;br /&gt;       ma.AccessibleObjectID.OBJID_WINDOW)&lt;br /&gt;&lt;br /&gt;guiat_acc = GetGUIATWindow()&lt;br /&gt;# position of the 'New listbox item' text box&lt;br /&gt;pos = guiat_acc.Children[3].Children[1].Location&lt;br /&gt;# focus the text box&lt;br /&gt;Win32API.MouseClick(pos.X + pos.Width/2, pos.Y + pos.Height/2)&lt;br /&gt;Win32API.SendString('Accessibility test')&lt;br /&gt;# position of the 'Add Item' button&lt;br /&gt;pos = guiat_acc.Children[3].Children[2].Location&lt;br /&gt;# click the button&lt;br /&gt;Win32API.MouseClick(pos.X + pos.Width/2, pos.Y + pos.Height/2)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;To run it, download &lt;ahref="http://prdownloads.sourceforge.net/mwinapi/managedwinapi-0.3.zip?download"&gt;managedwinapi-0.3.zip&lt;/a&gt;and extract the &lt;i&gt;ManagedWinapi.dll&lt;/i&gt; to the same folder as the &lt;ahref="http://gui-at.cendaweb.cz/GUIAT_Acc.zip"&gt;source code&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;When you run the code, it enters &lt;i&gt;Accessibility test&lt;/i&gt; text into &lt;i&gt;Newlistbox item&lt;/i&gt; text box and clicks &lt;i&gt;Add Item&lt;/i&gt; button. The controls arealways on the same position within the Children enumeration so we can usedirect referencing: e.g. &lt;spanclass="tt"&gt;guiat_acc.Children[3].Children[2]&lt;/span&gt; is the button accessibilityobject.&lt;/p&gt;&lt;p&gt;Enhancing this example is up to you - I have created several functions thattake care about entering the text into text boxes, selecting buttons or achecking check boxes. That's all I need to create a script that installs ourapplication.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-4609531643659187214?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/4609531643659187214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=4609531643659187214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/4609531643659187214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/4609531643659187214'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/10/testing-unknown-application.html' title='Testing an unknown application'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_S0yH53CI4fI/SEXErJpCENI/AAAAAAAAAA0/dZNbgnkTLzc/s72-c/AccExplorer.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-288007437954784993</id><published>2008-10-30T08:50:00.004+01:00</published><updated>2010-05-16T21:38:25.248+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Building the framework (3)</title><content type='html'>&lt;p&gt;After a while, it's time to continue building the GUI Automated Testingframework. Today, I focus on a list box. You can download the &lt;ahref="http://gui-at.cendaweb.cz/v3/v3.zip"&gt;source&lt;/a&gt; as usual.&lt;/p&gt;&lt;p&gt;I assume standard windows list box component where only unique items arestored and only one item can be selected. These two conditions are set onlybecause of simplicity of the example. If you don't like them, enhance theexample by yourself as your homework :-)&lt;/p&gt;&lt;p&gt;The &lt;a href="http://gui-at.cendaweb.cz/v3/ListBox.py"&gt;list box&lt;/a&gt; componentis again a subclass of &lt;ahref="http://gui-at.cendaweb.cz/v3/BaseComponent.py"&gt;BaseComponent&lt;/a&gt;. It isquite simple - it has one method and two properties:&lt;/p&gt;&lt;p&gt;&lt;span class="tt" style="font-size: 16px; font-weight: bold;"&gt;Select(self, aItem)&lt;/span&gt;&lt;/p&gt;The method selects &lt;span style="font-style: italic;"&gt;aItem&lt;/span&gt; in the list box.&lt;pre class="prettyprint"&gt;&lt;br /&gt;def Select(self, aItem):&lt;br /&gt;  """ select an item from list box&lt;br /&gt;  @aItem - string with item to select&lt;br /&gt;  """&lt;br /&gt;  if aItem not in self.items:&lt;br /&gt;    raise Exception("Item '%s' not in list box" % aItem)&lt;br /&gt;  self.guiat.Activate()&lt;br /&gt;  self._CheckVisibility()&lt;br /&gt;  pos = self.location&lt;br /&gt;  # click on the first item to focus the list box&lt;br /&gt;  Win32API.MouseClick(pos[0] + (pos[2]/2), pos[1] + 3)&lt;br /&gt;  # send Home to be sure we are on the first item&lt;br /&gt;  # (we could be scrolled down a little)&lt;br /&gt;  Win32API.SendKey(Win32API.VK_HOME)&lt;br /&gt;  # simulate pressing down arrow until we find the item&lt;br /&gt;  # we should find it because it is among self.items&lt;br /&gt;  while self.value != aItem:&lt;br /&gt;    Win32API.SendKey(Win32API.VK_DOWN)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;First, it checks whether &lt;i&gt;aItem&lt;/i&gt; is in the list box and raises anexception if not. Then it clicks onto the first visible list box item,simulates pressing &lt;i&gt;Home&lt;/i&gt; key to focus the first item and repeatedly press&lt;i&gt;Down&lt;/i&gt; key until the &lt;i&gt;value&lt;/i&gt; equals &lt;i&gt;aItem&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;This approach has the advantage we don't need to care about scroll box. Thebasic windows list box does not provide nice properties or methods to returnits state. We would have to dive into Win32 API to find it. For example, theDevExpress &lt;ahref="http://www.devexpress.com/Help/Content.aspx?help=XtraEditors&amp;amp;document=clsDevExpressXtraEditorsListBoxControltopic.htm"&gt;ListBoxControl&lt;/a&gt;has method &lt;ahref="http://www.devexpress.com/Help/Content.aspx?help=XtraEditors&amp;amp;document=DevExpressXtraEditorsBaseControl_GetViewInfotopic.htm"&gt;GetViewInfo&lt;/a&gt;that returns information about internal list box state.&lt;/p&gt;&lt;p&gt;This brings us to the important note:&lt;/p&gt;&lt;p&gt;&lt;span style="font-weight: bold;"&gt;We do not test the list box component. Wetest the application.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;One way of selecting item in a list box is enough. Of course, we must beaware of its limitations and side effects. Selecting an item with our GUIATcomponent fires one OnClick and several OnChange events.&lt;/p&gt;&lt;p&gt;&lt;span class="tt" style="font-size: 16px; font-weight: bold;"&gt;items&lt;/span&gt;&lt;/p&gt;The property contains read only list of all items in the list box.&lt;p&gt;&lt;span class="tt" style="font-size: 16px; font-weight: bold;"&gt;value&lt;/span&gt;&lt;/p&gt;The property contains the selected item in the list box. User can assign astring to it to select the string in the list box.&lt;p&gt;Incorporating the new GUIAT &lt;ahref="http://gui-at.cendaweb.cz/v3/ListBox.py"&gt;ListBox&lt;/a&gt; class into theframework is easy - just add it into the &lt;spanclass="tt"&gt;RecognizableComponents&lt;/span&gt; dictionary of the &lt;ahref="http://gui-at.cendaweb.cz/v3/Form.py"&gt;Form&lt;/a&gt; class.&lt;/p&gt;&lt;p&gt;This is the last post about controlling components. You know the idea sodeveloping a new GUIAT class controlling your component should be easy.&lt;/p&gt;&lt;p&gt;Next time, I show how to control application that is already started.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-288007437954784993?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/288007437954784993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=288007437954784993' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/288007437954784993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/288007437954784993'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/10/building-framework-3.html' title='Building the framework (3)'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-2844435405499264296</id><published>2008-09-26T00:55:00.010+02:00</published><updated>2009-08-26T22:46:49.214+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='links'/><title type='text'>GUI Testing at Resolver Systems</title><content type='html'>I'm currently quite busy at work and with my other activities (like &lt;a href="http://iceland.cendaweb.cz/"&gt;photos&lt;/a&gt;). That's why instead of writing another chapter of the GUI Automated Testing framework, I point you to the great article of &lt;a href="http://www.voidspace.org.uk/python/weblog/index.shtml"&gt;Michael &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Foord&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.voidspace.org.uk/python/articles/testing/index.shtml"&gt;Functional Testing of GUI Applications&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Michael describes his experiences with GUI automated testing in &lt;a href="http://www.resolversystems.com/"&gt;Resolver Systems&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;They use quite similar approach to run the tested application. It is run in another thread but the thread invoking is different. I am not a specialist in threading but I will try to find out more about which way is better or whether there are any catches[1].&lt;br /&gt;&lt;br /&gt;They also do not use &lt;a href="http://gui-at.blogspot.com/2008/07/simulate-users-input.html"&gt;win32&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;api&lt;/span&gt;&lt;/span&gt;&lt;/a&gt; for simulating user's input. They usually call directly the .NET method responsible for generating the requested event (e.g. &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.button.performclick.aspx"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;PerformClick&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;). That can be dangerous because your test can pass even when user is unable to click the button - the button  could be hidden behind another component.&lt;br /&gt;&lt;br /&gt;[1] My current problem can be caused &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;by&lt;/span&gt; threading. When I run our application from automated testing tool, two buttons overlap. When I run it normally, it is OK. To be it stranger, it occurs only on my PC. I have no idea why...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update 10/30/2008:&lt;/span&gt; I have not found any problem with my way of starting the tested application. I asked my co-&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;workers&lt;/span&gt;, searched for articles about threading and found both ways should be similar. [1] is still mystery to me, though.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update 8/20/2009:&lt;/span&gt; Mystery [1] solved - it was bug in our application :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-2844435405499264296?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/2844435405499264296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=2844435405499264296' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/2844435405499264296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/2844435405499264296'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/09/gui-testing-at-resolver-systems.html' title='GUI Testing at Resolver Systems'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-4191029127098879692</id><published>2008-08-18T00:30:00.012+02:00</published><updated>2009-05-16T18:13:20.831+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Building the framework (2)</title><content type='html'>&lt;a href="http://gui-at.blogspot.com/2008/07/building-framework-1.html"&gt;Last time&lt;/a&gt; we have started building the GUI Automated Testing framework. Today we are going to enhance it. Download the &lt;a href="http://gui-at.cendaweb.cz/v2/v2.zip"&gt;source&lt;/a&gt; to be able to follow the text.&lt;br /&gt;&lt;br /&gt;The first version implemented the &lt;a href="http://gui-at.cendaweb.cz/v2/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; class to represent windows components. We could not do anything but find out location of the component. It would be nice to be able write text into a text box or click a button by simple method, wouldn't it?&lt;br /&gt;&lt;br /&gt;To do that, we need to know the type of each component. The type name of .NET components is stored in &lt;span style="font-family:courier new;"&gt;component.GetType().Name&lt;/span&gt;. Knowing the type, we create subclass of &lt;a href="http://gui-at.cendaweb.cz/v2/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; for each type. In the subclass, we provide nice methods and properties.&lt;br /&gt;&lt;br /&gt;First, we enhance &lt;a href="http://gui-at.cendaweb.cz/v2/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; class. We add &lt;span style="font-weight: bold;font-family:courier new;" &gt;_CheckVisibility(self)&lt;/span&gt; method that checks whether the component is visible. If not, it raises an exception. We need it for checking if button is visible so we can click it or text box is visible to write it. And we add &lt;span style="font-weight: bold;font-family:courier new;" &gt;guiat&lt;/span&gt; property to be able to activate the tested application from a component by calling &lt;span style="font-family:courier new;"&gt;self.guiat.Activate()&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Let's look on a button. The &lt;a href="http://gui-at.cendaweb.cz/v2/Button.py"&gt;Button&lt;/a&gt; class is very simple:&lt;br /&gt;&lt;pre name="code" class="python"&gt;from time import sleep&lt;br /&gt;from Win32API import Win32API&lt;br /&gt;from BaseComponent import BaseComponent&lt;br /&gt;&lt;br /&gt;class Button(BaseComponent):&lt;br /&gt;   """interface to the Button component"""&lt;br /&gt;&lt;br /&gt;   def Click(self):&lt;br /&gt;       """ perform left mouse click on the center of the button, no parameters"""&lt;br /&gt;       self.guiat.Activate()&lt;br /&gt;       self._CheckVisibility()&lt;br /&gt;       pos = self.location&lt;br /&gt;       Win32API.MouseClick(pos[0] + (pos[2]/2), pos[1] + (pos[3]/2))&lt;br /&gt;       sleep(0.1)&lt;/pre&gt;The &lt;span style="font-weight: bold;font-family:courier new;" &gt;Click(self)&lt;/span&gt; method activates the tested application, checks whether the component is visible, finds out the position of the button, clicks into the middle of the button position, and finally waits a little bit. I do not like the waiting but it is here for safety. Windows may repainting some areas or do some other cool thinks, so it is better to give them some time for it.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://gui-at.cendaweb.cz/v2/TextBox.py"&gt;TextBox&lt;/a&gt; class provides three methods and one property:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;FocusEditor(self)&lt;/span&gt;&lt;br /&gt;The method essentially does the same as Button's &lt;span style="font-family:courier new;"&gt;Click&lt;/span&gt; method. It activates the tested application, checks whether the component is visible, and clicks into the middle of the &lt;a href="http://gui-at.cendaweb.cz/v2/TextBox.py"&gt;TextBox&lt;/a&gt; position to focus the editor.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;Clear(self)&lt;/span&gt;&lt;br /&gt;The method focuses the text box, moves cursor to the start position simulating pressing &lt;span style="font-style: italic;"&gt;Home&lt;/span&gt; key, and simulates pressing &lt;span style="font-style: italic;"&gt;Delete&lt;/span&gt; key until the text in text box is empty. If the text is not empty then, it raises exception.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;Write(self, aString)&lt;/span&gt;&lt;br /&gt;The method clears the text box and uses &lt;a href="http://gui-at.blogspot.com/2008/07/simulate-users-input.html"&gt;Win32API&lt;/a&gt; method &lt;span style="font-family:courier new;"&gt;SendString&lt;/span&gt; to simulate typing &lt;span style="font-style: italic;"&gt;aString&lt;/span&gt;. Then checks whether the text box contains the &lt;span style="font-style: italic;"&gt;aString&lt;/span&gt; value and raises exception if not.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;value&lt;/span&gt;&lt;br /&gt;The property contains the actual value of the text box. When user assigns a string to it, the string is written to the text box.&lt;/li&gt;&lt;/ul&gt;Now look on the creating instances of GUIAT components in the &lt;a href="http://gui-at.cendaweb.cz/v2/Form.py"&gt;Form&lt;/a&gt; class. We have simply added dictionary with known component types (&lt;span style="font-weight: bold;font-family:courier new;" &gt;RecognizableComponents&lt;/span&gt;). When we go through all components on the form in the &lt;span style="font-family:courier new;"&gt;_AnalyzeStructure&lt;/span&gt; method, we first check whether we know the component type or not. If so, we create instance of the appropriate component type class (e.g. &lt;a href="http://gui-at.cendaweb.cz/v2/Button.py"&gt;Button&lt;/a&gt; or &lt;a href="http://gui-at.cendaweb.cz/v2/TextBox.py"&gt;TextBox&lt;/a&gt;). If not, we create instance of the &lt;a href="http://gui-at.cendaweb.cz/v2/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; class.&lt;br /&gt;&lt;br /&gt;Let's try a small example:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&amp;gt;&amp;gt;&amp;gt; import GUIAT&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; g = GUIAT.GUIAT()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; g.Run()&lt;br /&gt;Starting GUIAT...&lt;br /&gt;"frmGUIAT" (frmGUIAT)&lt;br /&gt;  "btnAddItem" (Button)&lt;br /&gt;  "lblNewItem" (Label)&lt;br /&gt;  "txtNewItem" (TextBox)&lt;br /&gt;  "lbxItems" (ListBox) - UNKNOWN&lt;br /&gt;  "btnQuit" (Button)&lt;br /&gt;Starting GUIAT done.&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; txt = g.mainForm._GetComponentByName('txtNewItem')&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; btn = g.mainForm._GetComponentByName('btnAddItem')&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; txt.value = 'Hello world!'&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; btn.Click()&lt;/pre&gt;The result of the above small script is a new line in the list box. You see that the button, label, and text box are know component types. The label is treated as &lt;a href="http://gui-at.cendaweb.cz/v2/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; (see &lt;span style="font-family:courier new;"&gt;RecognizableComponents&lt;/span&gt; in &lt;a href="http://gui-at.cendaweb.cz/v2/Form.py"&gt;Form.py&lt;/a&gt;). The list box is unknown component.&lt;br /&gt;&lt;br /&gt;Today, we have shown how to create button and text box GUIAT classes that control respective .NET components. &lt;span style="font-weight: bold;"&gt;We can already script our small tested application!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Next time, we add list box class and logging.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-4191029127098879692?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/4191029127098879692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=4191029127098879692' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/4191029127098879692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/4191029127098879692'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/08/building-framework-2.html' title='Building the framework (2)'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-3097055103774776536</id><published>2008-07-29T23:28:00.004+02:00</published><updated>2009-05-16T18:12:16.715+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Building the framework (1)</title><content type='html'>Today we start building the automated test framework. We have prepared tools in previous parts. See them to learn how to &lt;a href="http://gui-at.blogspot.com/2008/06/exploring-test-application-ironpython-1.html"&gt;run tested application&lt;/a&gt; in &lt;a href="http://gui-at.blogspot.com/2008/06/exploring-test-application-ironpython-2.html"&gt;a separate thread&lt;/a&gt; or how to &lt;a href="http://gui-at.blogspot.com/2008/07/simulate-users-input.html"&gt;simulate user's input&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The foundation of our test framework are IronPython classes that control Windows components. Simply said, everything in Windows is a component. So we create IronPython layer that allows controlling each Windows component easily. Then we create classes that will control forms with many components. And finally, we build test scripts and test suites for the whole application.&lt;br /&gt;&lt;br /&gt;We start with just three simple classes. The first class, &lt;a href="http://gui-at.cendaweb.cz/v1/GUIAT.py"&gt;GUIAT&lt;/a&gt;, is the core class taking care of running, activating (focusing), and inspecting the tested application. The second class, &lt;a href="http://gui-at.cendaweb.cz/v1/BaseComponent.py"&gt;BaseComponent&lt;/a&gt;, is ancestor of all component classes. The last one, &lt;a href="http://gui-at.cendaweb.cz/v1/Form.py"&gt;Form&lt;/a&gt;, descendant of BaseComponent, is ancestor of all forms.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://gui-at.cendaweb.cz/v1/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; class provides access to common properties of all components. There is just one in the first version:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;location&lt;/span&gt; - size and position of the component on the screen (not within the parent form)&lt;/li&gt;&lt;/ul&gt;The &lt;a href="http://gui-at.cendaweb.cz/v1/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; class has also several private variables and methods:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;_name&lt;/span&gt; - name of the component, not all components have this field filled&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;_control&lt;/span&gt; - reference to the .NET component instance&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;_guiat&lt;/span&gt; - reference to the main GUIAT object (see below)&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;_guiatComponents&lt;/span&gt; - dictionary with all child GUIAT components&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;_GetComponentByName&lt;/span&gt; - method that searches for component with given name&lt;/li&gt;&lt;/ul&gt;Note: The &lt;span style="font-style: italic;"&gt;.NET component&lt;/span&gt; means instance of the Windows component in the tested application. The &lt;span style="font-style: italic;"&gt;GUIAT component&lt;/span&gt; means instance of the IronPython class that controls the .NET component.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://gui-at.cendaweb.cz/v1/Form.py"&gt;Form&lt;/a&gt; class extends the &lt;a href="http://gui-at.cendaweb.cz/v1/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; class. Its purpose is to find and store all components on itself. It has one private method that does it:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;_AnalyzeStructure&lt;/span&gt; - method that searches and stores components on a form. It is recursively called for each member of the Controls collection. It prints out the name, type, and depth level of the found components. Then it creates &lt;a href="http://gui-at.cendaweb.cz/v1/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; instance and stores it into the &lt;span style="font-style: italic;"&gt;_guiatComponents&lt;/span&gt; dictionary of the parent component.&lt;/li&gt;&lt;/ul&gt;The &lt;a href="http://gui-at.cendaweb.cz/v1/GUIAT.py"&gt;GUIAT&lt;/a&gt; class as the core class of the framework contains in the first version only one property and two methods:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;mainForm&lt;/span&gt; - GUIAT representation of the main form of the tested application (&lt;a href="http://gui-at.cendaweb.cz/v1/Form.py"&gt;Form&lt;/a&gt; instance)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Run&lt;/span&gt; - method that runs the tested application in separate thread and creates the &lt;a href="http://gui-at.cendaweb.cz/v1/Form.py"&gt;Form&lt;/a&gt; instance of the main form&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Activate&lt;/span&gt; - method that activates (focuses) the tested application&lt;/li&gt;&lt;/ul&gt;Let's try a small example:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&amp;gt;&amp;gt;&amp;gt; import GUIAT&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; g = GUIAT.GUIAT()&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; g.Run()&lt;br /&gt;Starting GUIAT...&lt;br /&gt;"frmGUIAT" (frmGUIAT)&lt;br /&gt;  "btnAddItem" (Button)&lt;br /&gt;  "lblNewItem" (Label)&lt;br /&gt;  "txtNewItem" (TextBox)&lt;br /&gt;  "lbxItems" (ListBox)&lt;br /&gt;  "btnQuit" (Button)&lt;br /&gt;Starting GUIAT done.&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; print g.mainForm._GetComponentByName('txtNewItem').location&lt;br /&gt;(212, 177, 96, 16)&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; g.Activate()&lt;br /&gt;True&lt;/pre&gt;The above code runs the tested application, lists name and type of all components, then prints location of the text box, and finally activates the tested application.&lt;br /&gt;&lt;br /&gt;To sum up the process again:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Create instance of the GUIAT class - let's call it &lt;span style="font-family:courier new;"&gt;g&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:courier new;"&gt;g.Run()&lt;/span&gt; runs the tested application&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:courier new;"&gt;g.Run()&lt;/span&gt; creates instance of IronPython &lt;a href="http://gui-at.cendaweb.cz/v1/Form.py"&gt;Form&lt;/a&gt; class for the main form of the tested application&lt;/li&gt;&lt;li&gt;The &lt;a href="http://gui-at.cendaweb.cz/v1/Form.py"&gt;Form&lt;/a&gt; instance searches during its initialization all components on the main form, prints information about them, and creates &lt;a href="http://gui-at.cendaweb.cz/v1/BaseComponent.py"&gt;BaseComponent&lt;/a&gt; instance for each of them&lt;/li&gt;&lt;li&gt;To find location of "txtNewItem" component, execute:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;g.mainForm._GetComponentByName("txtNewItem").location&lt;/span&gt;&lt;/li&gt;&lt;li&gt;To activate tested application, execute:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;g.Activate()&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;Today I presented the core of my GUI automated testing framework (&lt;a href="http://gui-at.cendaweb.cz/v1/v1.zip"&gt;source&lt;/a&gt;). I'm going to extend it and make it more user friendly in next parts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-3097055103774776536?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/3097055103774776536/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=3097055103774776536' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/3097055103774776536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/3097055103774776536'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/07/building-framework-1.html' title='Building the framework (1)'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-7327428004134885612</id><published>2008-07-08T21:12:00.011+02:00</published><updated>2010-05-16T21:46:09.268+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Simulate user's input</title><content type='html'>&lt;p&gt;We have learned in the &lt;ahref="http://gui-at.blogspot.com/2008/06/exploring-test-application-ironpython-2.html"&gt;previouspart&lt;/a&gt; how to explore the tested application and read its values. To test it,we also need set values to its fields.&lt;/p&gt;&lt;p&gt;The first idea may be to utilize the .NET objects. When we can read valuesfrom the tested application fields, we can also set them. Use the code snippetfrom the &lt;ahref="http://gui-at.blogspot.com/2008/06/exploring-test-application-ironpython-2.html"&gt;previouspart&lt;/a&gt; to run the tested application and follow it by command&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;App.Controls[2].Text = 'GUIATtext'&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The tested application is started and &lt;i&gt;GUIATtext&lt;/i&gt; appears in the &lt;i&gt;Newlistbox item&lt;/i&gt; text box.&lt;/p&gt;&lt;p&gt;Well, it does not appear as a proper testing to me. I'd rather simulateuser's interaction with mouse and keyboard. Unfortunately, sending key strokesand mouse events is not job for .NET framework. We have to dive deep intoWindows and use &lt;i&gt;Win32 API&lt;/i&gt; to perform these tasks.&lt;/p&gt;&lt;p&gt;I have created a simple DLL to make Win32 API functions available forIronPython [1]. Moreover, I have added functions to simulate user's input. Hereis the list of functions in the Win32API namespace with a shortdescription:&lt;/p&gt;&lt;pre class="prettyprint"&gt;GetForegroundWindow()&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return handle of the active window&lt;pre class="prettyprint"&gt;SetForegroundWindow(handle)&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set the active window to the window with &lt;i&gt;handle&lt;/i&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return boolean&lt;pre class="prettyprint"&gt;ShowWindow(handle, state)&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;set window with &lt;i&gt;handle&lt;/i&gt; to &lt;i&gt;state&lt;/i&gt; (minimalized, maximalized, ...)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return boolean&lt;pre class="prettyprint"&gt;GetWindowText(handle, title, capacity)&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return &lt;i&gt;title&lt;/i&gt; of window with &lt;i&gt;handle&lt;/i&gt;, &lt;i&gt;title&lt;/i&gt; variable type is &lt;i&gt;String&lt;/i&gt; of &lt;i&gt;capacity&lt;/i&gt; size&lt;pre class="prettyprint"&gt;MouseClick(X, Y)&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;simulate click with left mouse button on position &lt;i&gt;X, Y&lt;/i&gt;&lt;pre class="prettyprint"&gt;SendKey(virtual_key)&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;simulate pressing &lt;i&gt;virtual_key&lt;/i&gt;&lt;pre class="prettyprint"&gt;SendString(string)&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;simulate typing a &lt;i&gt;string&lt;/i&gt;&lt;p&gt;I will not go into details here. Anyone interested can explore the &lt;ahref="http://gui-at.cendaweb.cz/Win32API.zip"&gt;sources&lt;/a&gt; of the &lt;ahref="http://gui-at.cendaweb.cz/Win32API.dll"&gt;Win32API.dll&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Using these functions is straightforward in IronPython. Just download the &lt;ahref="http://gui-at.cendaweb.cz/Win32API.dll"&gt;Win32API.dll&lt;/a&gt; and look at theexample below how to perform a mouse click on the specific position:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;import clr&lt;br /&gt;clr.AddReference('Win32API')&lt;br /&gt;from Win32API import Win32API&lt;br /&gt;Win32API.MouseClick(10, 10)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The code snippet moves mouse to the coordinates 10, 10 (that is to thetop-left corner of the screen) and perform a click with the left mouse button.More useful examples will follow in next parts.&lt;/p&gt;&lt;p&gt;Finally, couple of warnings. The simulated mouse click is caught by the topmost window on the position. And the simulated key strokes are sent to theactive window. &lt;span style="font-weight: bold;"&gt;That means we have to payattention to position and active state of the tested application.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;In the next part, we start building the GUIAT testing framework.&lt;/p&gt;&lt;p&gt;[1] I do not know how to access Win32 API directly from IronPython.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-7327428004134885612?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/7327428004134885612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=7327428004134885612' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/7327428004134885612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/7327428004134885612'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/07/simulate-users-input.html' title='Simulate user&apos;s input'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-515908161107747009</id><published>2008-06-24T21:12:00.018+02:00</published><updated>2009-05-16T18:06:57.601+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Exploring test application: IronPython (2)</title><content type='html'>We demonstrated how to run a .NET application from IronPython in the &lt;a href="http://gui-at.blogspot.com/2008/06/exploring-test-application-ironpython-1.html"&gt;previous part&lt;/a&gt;. However, we couldn't control it while it was running. The solution for this problem is to run the tested application in a separate thread. Thus we will be able to enter commands in IronPython console while the tested application is running.  Here is a snippet from the source:&lt;br /&gt;&lt;pre name="code" class="python"&gt;import clr&lt;br /&gt;clr.AddReference('System')&lt;br /&gt;clr.AddReference("System.Windows.Forms")&lt;br /&gt;from System import *&lt;br /&gt;from System.Reflection import *&lt;br /&gt;from System.Threading import *&lt;br /&gt;from System.Windows.Forms import Application&lt;br /&gt;from time import sleep&lt;br /&gt;&lt;br /&gt;def RunMeCallBack(var):&lt;br /&gt;    global App&lt;br /&gt;    asm = Assembly.LoadFrom('GUIAT_PoC.exe')&lt;br /&gt;    asm_type = asm.GetType('GUIAT_PoC.frmGUIAT')&lt;br /&gt;    App = Activator.CreateInstance(asm_type)&lt;br /&gt;    Application.Run(App)&lt;br /&gt;&lt;br /&gt;App = None&lt;br /&gt;ThreadPool.QueueUserWorkItem(WaitCallback(RunMeCallBack))&lt;br /&gt;while not App:&lt;br /&gt;    sleep(0.2)&lt;br /&gt;&lt;/pre&gt;The &lt;span style="font-style: italic;"&gt;RunMeCallBack&lt;/span&gt; function starts the tested application the same way as we showed in the previous part. We create an independent thread and run this function in it so it does not block the console. The thread finishes its work when the tested application terminates (the main form of the application is closed) or when the console is closed.&lt;br /&gt;&lt;br /&gt;The important part is line&lt;br /&gt;&lt;pre name="code" class="python"&gt;App = Activator.CreateInstance(asm_type)&lt;/pre&gt;Here we remember the instance of the main form in the variable &lt;span style="font-style: italic;"&gt;App&lt;/span&gt;. &lt;span style="font-weight: bold;"&gt;We have access to the whole application thanks to the &lt;/span&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;App&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; variable!&lt;/span&gt; The while cycle at the end ensures waiting until the &lt;span style="font-style: italic;"&gt;App&lt;/span&gt; variable is not None. Which only happens when our tested application is up and running.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;App&lt;/span&gt; variable is our Holy Grail. Let's explore what is inside:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&amp;gt;&amp;gt;&amp;gt; App&lt;br /&gt;&amp;lt;GUIAT_PoC.frmGUIAT object at 0x000000000000002B&lt;br /&gt;[GUIAT_PoC.frmGUIAT, Text: GUIAT - Proof of Concept]&amp;gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; App.Text&lt;br /&gt;'GUIAT - Proof of Concept'&lt;br /&gt;&lt;/pre&gt;Basically, we have access to all public properties and methods. Try &lt;span style="font-family:courier new;"&gt;dir(App)&lt;/span&gt; and you'll see. With a trick, we can even access private properties and methods (using the power of reflection).&lt;br /&gt;&lt;br /&gt;To find what components are on the main form, iterate through the &lt;span style="font-style: italic;"&gt;Controls&lt;/span&gt; collection:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&amp;gt;&amp;gt;&amp;gt; for c in App.Controls:&lt;br /&gt;...   print c.Name, c.GetType()&lt;br /&gt;...&lt;br /&gt;btnAddItem System.Windows.Forms.Button&lt;br /&gt;lblNewItem System.Windows.Forms.Label&lt;br /&gt;txtNewItem System.Windows.Forms.TextBox&lt;br /&gt;lbxItems System.Windows.Forms.ListBox&lt;br /&gt;btnQuit System.Windows.Forms.Button&lt;br /&gt;&lt;/pre&gt;To find out what text is in the text box, try the following:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&amp;gt;&amp;gt;&amp;gt; App.Controls[2].Text&lt;br /&gt;''&lt;br /&gt;&lt;/pre&gt;Now, write something directly into the text box in the tested application and call the statement again:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&amp;gt;&amp;gt;&amp;gt; App.Controls[2].Text&lt;br /&gt;'something'&lt;br /&gt;&lt;/pre&gt;Cool, isn't it? ;-)&lt;br /&gt;&lt;br /&gt;Next time, I show you how to simulate user interaction programatically - how to send a text or click to the tested application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-515908161107747009?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/515908161107747009/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=515908161107747009' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/515908161107747009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/515908161107747009'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/06/exploring-test-application-ironpython-2.html' title='Exploring test application: IronPython (2)'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-1313246025409031626</id><published>2008-06-22T13:33:00.015+02:00</published><updated>2009-05-16T18:02:39.753+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><category scheme='http://www.blogger.com/atom/ns#' term='ironpython'/><title type='text'>Exploring test application: IronPython (1)</title><content type='html'>How can IronPython help with exploring the test application? The answer is &lt;span style="font-style: italic;"&gt;.NET Reflection&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Reflection&lt;/span&gt; is the mechanism of discovering information solely at run time.&lt;br /&gt;&lt;br /&gt;We can discover both class and instance information. That's important. Knowing class information, we know what the object is capable of. We know whether it is a button having &lt;span style="font-style: italic;"&gt;click&lt;/span&gt; method or a text edit having &lt;span style="font-style: italic;"&gt;value&lt;/span&gt; property. And knowing instance information, we can find out what text the text edit displays.&lt;br /&gt;&lt;br /&gt;That's nice but to be able to utilize the reflection, we need access to the tested application's objects from our testing framework.  That's easy. The tested application is a .NET application so we can run it directly from IronPython.&lt;br /&gt;&lt;br /&gt;When you look to &lt;span style="font-family:courier new;"&gt;Program.cs&lt;/span&gt; (&lt;a href="http://gui-at.cendaweb.cz/GUIAT_PoC.zip"&gt;source&lt;/a&gt;), you see how the tested application is started. If you don't have the sources of tested application available, you can use &lt;a href="http://www.aisto.com/roeder/dotnet/"&gt;Lutz Roeder's .NET Reflector&lt;/a&gt; to find the information.&lt;br /&gt;&lt;pre name="code" class="c#"&gt;static void Main()&lt;br /&gt;{&lt;br /&gt;   Application.EnableVisualStyles();&lt;br /&gt;   Application.SetCompatibleTextRenderingDefault(false);&lt;br /&gt;   Application.Run(new frmGUIAT());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Let's mimic the start in IronPython. We are not interested in the first two rows. The third row is the core. The &lt;span style="font-weight: bold;"&gt;Application&lt;/span&gt; class is part of &lt;span style="font-style: italic;"&gt;System.Windows.Forms&lt;/span&gt; namespace. So we just need to create an instance of &lt;span style="font-weight: bold;"&gt;frmGUIAT&lt;/span&gt; class. To create it, we use method &lt;span style="font-weight: bold;"&gt;CreateInstance&lt;/span&gt; of &lt;span style="font-weight: bold;"&gt;Activator&lt;/span&gt; class from &lt;span style="font-style: italic;"&gt;System&lt;/span&gt; namespace. The &lt;span style="font-weight: bold;"&gt;CreateInstance&lt;/span&gt; method needs to know the type of the future instance. We find the type utilizing the reflection.&lt;br /&gt;&lt;br /&gt;The whole code looks like this:&lt;br /&gt;&lt;pre name="code" class="python"&gt;import clr&lt;br /&gt;clr.AddReference('System')&lt;br /&gt;clr.AddReference("System.Windows.Forms")&lt;br /&gt;from System import *&lt;br /&gt;from System.Reflection import *&lt;br /&gt;from System.Windows.Forms import Application&lt;br /&gt;&lt;br /&gt;asm = Assembly.LoadFrom('GUIAT_PoC.exe')&lt;br /&gt;asm_type = asm.GetType('GUIAT_PoC.frmGUIAT')&lt;br /&gt;App = Activator.CreateInstance(asm_type)&lt;br /&gt;Application.Run(App)&lt;br /&gt;&lt;/pre&gt;When you run the above code from IronPython console, the tested application is displayed. Note the IronPython must be started form the directiory where GUIAT_PoC.exe is located. The disadvantage is we cannot do anything in IronPython console while the tested application is running. The solution is to run it in separate thread. I will show it in the next article.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-1313246025409031626?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/1313246025409031626/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=1313246025409031626' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/1313246025409031626'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/1313246025409031626'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/06/exploring-test-application-ironpython-1.html' title='Exploring test application: IronPython (1)'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-1957681261587382931</id><published>2008-06-12T23:50:00.002+02:00</published><updated>2009-05-16T17:47:01.260+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='accessibility'/><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><title type='text'>Exploring test application: Accessibility</title><content type='html'>&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Accessibility&lt;/span&gt; looks more promising:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Active Accessibility (AA) is technology developed by Microsoft to make the Windows platform more accessible to people with disabilities. It consists of a set of COM interfaces and methods which allow an application to expose information to third parties, making it easier to implement tools such as magnifiers and screen readers. It proves very useful also for testing utilities. Microsoft has implemented the accessibility interfaces for the standard Windows controls.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;AccExplorer (&lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=3755582A-A707-460A-BF21-1373316E13F0&amp;amp;displaylang=en"&gt;download&lt;/a&gt;) shows you the test application structure:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_S0yH53CI4fI/SEXErJpCENI/AAAAAAAAAA0/dZNbgnkTLzc/s1600-h/AccExplorer.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_S0yH53CI4fI/SEXErJpCENI/AAAAAAAAAA0/dZNbgnkTLzc/s320/AccExplorer.PNG" alt="" id="BLOGGER_PHOTO_ID_5207784789725286610" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You see nice hierarchical window structure. Every object has several properties:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Name&lt;/span&gt; - e.g. caption of button&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Value&lt;/span&gt; - e.g. value of list box&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Role Text&lt;/span&gt; - type of the component&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Location&lt;/span&gt; - position on the screen&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;State&lt;/span&gt; - e.g. disabled, normal, etc.&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;Def Action&lt;/span&gt; - default action for the component&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The properties provides more information than Win32 API. But when you look closer, you see it is not enough:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;We still cannot distinguish the similar controls. Both buttons have role &lt;span style="font-style: italic;"&gt;push buttons&lt;/span&gt; and can be distinguished only by displayed name. Which is problematic when names change or you need to test localized applications.&lt;/li&gt;&lt;li&gt;Some components do not have name at all. In our example it is the text box - its name in AccExplorer is &lt;span style="font-style: italic;"&gt;NAMELESS&lt;/span&gt;.&lt;/li&gt;&lt;li&gt;The third party components usually lack support for the accessibility in the same quality as Microsoft. For example, DevExpress grid only tells you "I am a grid". It does not tell you how many rows it contains, what cells are there, etc...&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The good news is developers can change this behavior. They can define AccessibleName property for a component so we can later easily find exactly what we need. If I have set AccessibleName for the text box to &lt;span style="font-style: italic;"&gt;myTextBox&lt;/span&gt;, we would have seen &lt;span style="font-style: italic;"&gt;myTextBox&lt;/span&gt; instead of &lt;span style="font-style: italic;"&gt;NAMELESS&lt;/span&gt; in AccExplorer now. For grid, they can define the whole structure of accessible objects to represent the grid (see &lt;a href="http://msdn.microsoft.com/en-us/library/ms971325.aspx"&gt;Exposing Data Tables through Microsoft Active Accessibility&lt;/a&gt;). Unfortunately, when your application does not have sufficient support for accessibility, it is quite lot of work...&lt;br /&gt;&lt;br /&gt;Microsoft tries to address testing issues with his new framework in .NET 3.5: &lt;a href="http://msdn.microsoft.com/en-us/library/ms753388.aspx"&gt;Microsoft UI Automation&lt;/a&gt;. I have not tried it as our applications do not run on .NET 3.5.&lt;br /&gt;&lt;br /&gt;Also DevExpress promised to enhance their components with better support for UI testing tools - see the &lt;a href="http://www.devexpress.com/Home/Announces/Roadmap2008.xml"&gt;2008 roadmap&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;But we don't want to wait, right? We want to test our .NET application right now! I will show how in the next article.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-1957681261587382931?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/1957681261587382931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=1957681261587382931' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/1957681261587382931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/1957681261587382931'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/06/exploring-test-application.html' title='Exploring test application: Accessibility'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_S0yH53CI4fI/SEXErJpCENI/AAAAAAAAAA0/dZNbgnkTLzc/s72-c/AccExplorer.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-451926307527729582</id><published>2008-06-04T00:30:00.005+02:00</published><updated>2009-05-16T17:45:20.866+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><title type='text'>Exploring test application: Win32 API</title><content type='html'>Let's look on what we can discover about our simple test application when it is running. Before IronPython, we had two options:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Win32 API&lt;/li&gt;&lt;li&gt;Accessibility&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Win32 API&lt;/span&gt; provides several functions that return information about an application. First, we have to find the appliction handle. We utilize functions &lt;span style="font-style: italic;"&gt;EnumWindows&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;GetWindowText&lt;/span&gt;&lt;span&gt; from &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=78018"&gt;Python for Windows extensions&lt;/a&gt; project&lt;/span&gt;:&lt;span style="font-size:100%;"&gt;&lt;pre name="code" class="python"&gt;def enum(hwnd, extra):&lt;br /&gt;   global app_handle&lt;br /&gt;   if winxpgui.GetWindowText(hwnd).find('GUIAT - Proof') &gt;= 0:&lt;br /&gt;       app_handle = hwnd&lt;br /&gt;&lt;br /&gt;app_handle = None&lt;br /&gt;winxpgui.EnumWindows(enum, '')&lt;br /&gt;print 'Test application handle:', app_handle&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;When we know the application handle, we can enumerate its children:&lt;span style="font-size:100%;"&gt;&lt;pre name="code" class="python"&gt;def enum_child(hwnd, extra):&lt;br /&gt;   print '%s %s:    %s' % (hwnd, winxpgui.GetClassName(hwnd),&lt;br /&gt;           winxpgui.GetWindowText(hwnd))&lt;br /&gt;&lt;br /&gt;winxpgui.EnumChildWindows(app_handle, enum_child, '')&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;When you run the whole script (&lt;a href="http://gui-at.cendaweb.cz/Win32API_Enum.py"&gt;source&lt;/a&gt;), you get:&lt;span style="font-size:100%;"&gt;&lt;pre name="code" class="python"&gt;Test application handle: 2949744&lt;br /&gt;2621886 WindowsForms10.BUTTON.app.0.378734a:    Add Item&lt;br /&gt;7668314 WindowsForms10.STATIC.app.0.378734a:    New listbox item&lt;br /&gt;4194952 WindowsForms10.EDIT.app.0.378734a:&lt;br /&gt;2753142 WindowsForms10.LISTBOX.app.0.378734a:&lt;br /&gt;3342924 WindowsForms10.BUTTON.app.0.378734a:    Quit&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;Here is the catch. How shall we identify &lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;Add Item&lt;/span&gt;&lt;/span&gt; button from &lt;span style=";font-family:courier new;font-size:100%;"  &gt;Quit&lt;/span&gt; button? Both have the same class name &lt;span style=";font-family:courier new;font-size:100%;"  &gt;WindowsForms10.BUTTON.app.0.378734a&lt;/span&gt;.  Sure, the text differs, but this isn't always true. Imagine two text boxes - both having the same class name &lt;span style="font-size:100%;"&gt;&lt;span style="font-family:courier new;"&gt;WindowsForms10.EDIT.app.0.378734a&lt;/span&gt;&lt;/span&gt;. What then? Of course, you can check positions. But this is leads you back to record/play tools and that is exactly what I want to avoid.&lt;br /&gt;&lt;br /&gt;So this is the terminus for Win32 API. Next time - Accessibility.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-451926307527729582?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/451926307527729582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=451926307527729582' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/451926307527729582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/451926307527729582'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/06/exploring-test-application-win32-api.html' title='Exploring test application: Win32 API'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-8060659719792604491</id><published>2008-05-28T20:40:00.012+02:00</published><updated>2009-05-16T17:36:28.702+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><title type='text'>GUI Application to Test</title><content type='html'>Let's start with something easy. We have a Windows GUI application that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_S0yH53CI4fI/SD2ozdu9qnI/AAAAAAAAAAs/eXC1eed5M98/s320/TestedApplication.PNG" alt="" id="BLOGGER_PHOTO_ID_5205502346418563698" border="0" /&gt;&lt;br /&gt;The application contains a text box, two buttons, and a list box. It simply adds a text from text box as the last item to the list box (&lt;a href="http://gui-at.cendaweb.cz/GUIAT_PoC.exe"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;exe&lt;/span&gt;&lt;/a&gt;, &lt;a href="http://gui-at.cendaweb.cz/GUIAT_PoC.zip"&gt;source&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;The testing steps might be as follows:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Run the application.&lt;/li&gt;&lt;li&gt;Check the 'New &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;listbox&lt;/span&gt; item' fields is empty.&lt;/li&gt;&lt;li&gt;Check the list box contains three rows with texts: 'This is', '&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;GUIAT&lt;/span&gt;', 'demo.'.&lt;/li&gt;&lt;li&gt;Enter a text (e.g. 'new line') into text box, press 'Add Item' button. Verify your text ('new line') appears as the fourth line/item in the list box.&lt;/li&gt;&lt;li&gt;Press 'Quit' button. Verify the application terminates.&lt;/li&gt;&lt;/ol&gt;Any record/play testing tool can do the test up to point 4. There it cannot verify whether the text was added to the correct place in the list box. These tools also cannot handle moving 'Add Item' button closer to the text box. They would then click to empty place. Sure there are more sophisticated tools that can handle the above problems. But I do not know about any for free.&lt;br /&gt;&lt;br /&gt;Next time we try some dead ends from my  beginnings :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-8060659719792604491?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/8060659719792604491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=8060659719792604491' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/8060659719792604491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/8060659719792604491'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/05/gui-application-to-test.html' title='GUI Application to Test'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_S0yH53CI4fI/SD2ozdu9qnI/AAAAAAAAAAs/eXC1eed5M98/s72-c/TestedApplication.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1384551653506604356.post-495552271729175244</id><published>2008-05-22T17:33:00.008+02:00</published><updated>2009-05-16T17:35:01.937+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='guiat'/><title type='text'>The beginning</title><content type='html'>Testing GUI application can be tedious work. Usually, you have to manually click through the interfaces. The first round is fun, the second is OK, and from the third round on it is boring.&lt;br /&gt;&lt;br /&gt;When I joined  Radiant, I started to think about automation. I searched on &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;Internet&lt;/span&gt; but I did not find anything satisfying. All tools were basically record/play applications. That is not sufficient for testing. There are many concerns, for example:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;How do you verify the test result?&lt;/li&gt;&lt;li&gt;How easy can you change the script (add testing of a new field, new form, etc.)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Scalability - how easy can you join basic scripts and create bigger (regression) script?&lt;/li&gt;&lt;li&gt;How the test application works with your amended &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;components&lt;/span&gt;?&lt;/li&gt;&lt;li&gt;etc.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I know the testing tool cannot do everything. So I set up several goals I'd like to achieve:&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Allow to control GUI application.&lt;/span&gt;&lt;br /&gt;That means to start it, navigates through it, close it. To know its status. &lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Allow to read values from the screen.&lt;/span&gt;&lt;br /&gt;You have to know what is on the screen to be able to test it.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Allow to set values.&lt;/span&gt;&lt;br /&gt;Also, you have to be able to set/write values into the application to be able to test it.&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Easy to create.&lt;/span&gt;&lt;br /&gt;Testers are not experienced programmers. The tool must be easy to use. Anybody, who knows what a &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;program&lt;/span&gt; is, should be able to write a test script.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Easy to maintain.&lt;br /&gt;&lt;/span&gt;When the tested application changes, amending a test script should not be necessary or be a piece of cake.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Scalability.&lt;/span&gt;&lt;br /&gt;Joining test scripts together, creating regression scripts.&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;In next few weeks, you'll find out on this blog how I succeed in this task.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1384551653506604356-495552271729175244?l=gui-at.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gui-at.blogspot.com/feeds/495552271729175244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1384551653506604356&amp;postID=495552271729175244' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/495552271729175244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1384551653506604356/posts/default/495552271729175244'/><link rel='alternate' type='text/html' href='http://gui-at.blogspot.com/2008/05/beginning.html' title='The beginning'/><author><name>Lukáš Čenovský</name><uri>http://www.blogger.com/profile/14627955690950344876</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://bp2.blogger.com/_S0yH53CI4fI/SDWgutu9qjI/AAAAAAAAAAQ/WYpYAVP-IB8/S220/lukas.jpg'/></author><thr:total>0</thr:total></entry></feed>
