リンクエラー

1>LINK : fatal error LNK1123: COFF への変換中に障害が発生しました: ファイルが無効であるか、または壊れています。

のメモ。
VC2012をインストールすると、VC2010で出るようになるっぽい。
リンクオプションでインクリメンタルリンクをNOにする。

premake4.lua的には

flags {
  "NoIncrementalLink"
}

premake4.4新機能

rails-3.1.0をcygwinでやるメモ

sqlite

sqlite-develをsetup.exeでいれとく

javascript engine

なんとなくspidermonkeyにする。
http://ftp.mozilla.org/pub/mozilla.org/js/
から
js-1.7.0.tar.gz
をダウンロードする。

$ cd /usr/local/src
$ wget http://ftp.mozilla.org/pub/mozilla.org/js/js-1.7.0.tar.gz
$ tar xzf js-1.7.0.tar.gz
$ cd js/src
$ make -f Makefile.ref OS_ARCH=Linux LD=gcc
$ cp cp Linux_All_DBG.OBJ/js.exe /usr/local/bin/

railsを使うシェルに環境変数をセットする

export EXECJS_RUNTIME=SpiderMonkey
Ruby version	1.9.3 (i386-cygwin)
RubyGems version	1.8.23
Rack version	1.3
Rails version	3.1.0
JavaScript Runtime	SpiderMonkey
Active Record version	3.1.0
Action Pack version	3.1.0
Active Resource version	3.1.0
Action Mailer version	3.1.0
Active Support version	3.1.0
Middleware	ActionDispatch::Static
Rack::Lock
#<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x80ef9ba8>
Rack::Runtime
Rack::MethodOverride
Rails::Rack::Logger
ActionDispatch::ShowExceptions
ActionDispatch::RemoteIp
Rack::Sendfile
ActionDispatch::Reloader
ActionDispatch::Callbacks
ActiveRecord::ConnectionAdapters::ConnectionManagement
ActiveRecord::QueryCache
ActionDispatch::Cookies
ActionDispatch::Session::CookieStore
ActionDispatch::Flash
ActionDispatch::ParamsParser
ActionDispatch::Head
Rack::ConditionalGet
Rack::ETag
ActionDispatch::BestStandardsSupport
Application root	/cygdrive/c/work/_rails/demo
Environment	development
Database adapter	sqlite3
Database schema version	0

JSONと相互変換できるXMLの記述

JsonReaderWriterFactoryはどんなJSONでもParseしてXElemnt化できるが、XmlをJSON化するには特定の構造を持っている必要がある。
objectとarrayとその他の単一項目(number, boolean, stringなど)の持ち方が決まっている。
見た目に分かるようなものをwpfで作ってみた。あとで続きを作るかもしれないが原型ができたのでメモ。

<Window x:Class="XMLExperiment.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TreeView x:Name="tree" Grid.Column="0" ItemsSource="{Binding Root.Children}">
            <!--DirectoryViewModel のデータを表示するときに使うテンプレート-->
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
        <TextBox x:Name="xml" Grid.Column="1" Text="{Binding Xml}" />
        <TextBox x:Name="json" Grid.Column="2" Text="{Binding Json}" />
    </Grid>
</Window>
namespace XMLExperiment
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var tree = new Tree();
            DataContext = tree;
        }
    }
}
namespace XMLExperiment
{
    public class Node : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        private XElement _e;
        private ObservableCollection<Node> _children;

        public Node(XElement e)
        {
            _e = e;
        }

        public String Name
        {
            get
            {
                return _e.Name.ToString();
            }
        }
        
        public ObservableCollection<Node> Children
        {
            get
            {
                if (_children == null)
                {
                    _children = new ObservableCollection<Node>(_e.Elements().Select(e => new Node(e)));
                }
                return _children;
            }
        }
    }

    public class Tree
    {
        public Tree()
        {
            Json = @"{
""hoge"":[
1
,2
,3
,{
""nazo"": true
}
]
}";
        }

        private XElement _root;
        public Node Root
        {
            get
            {
                return new Node(_root);
            }
        }

        public String Xml
        {
            set
            {
            }
            get
            {
                return _root.ToString();
            }
        }

        public String Json
        {
            set
            {
                using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.Unicode.GetBytes(value), XmlDictionaryReaderQuotas.Max))
                {
                    _root=XElement.Load(reader);
                }
            }
            get
            {
                using (var ms = new MemoryStream())
                using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.Unicode))
                {
                    _root.WriteTo(writer);
                    writer.Flush();
                    return Encoding.Unicode.GetString(ms.ToArray());
                }
            }
        }
    }
}

自分はobjectをシリアライズしたりデシリアライズしたいのではなくて動的に組み立ててそれをJSONと相互に変換したいので、
いまいち既存のライブラリとは目的が一致しないのだよな・・・。
泥臭いXElementラッパを作るのが早いかも知れぬ。

ファイラーその4

アイコンをつける。
Win32apiのSHGetFileInfoを呼べるようにする

    [StructLayout(LayoutKind.Sequential)]
    public struct SHFILEINFO
    {
        public IntPtr hIcon;
        public IntPtr iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    };

    class Win32
    {
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
        public const uint SHGFI_SMALLICON = 0x1; // 'Small icon

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(
            string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

        [DllImport("user32")]
        public static extern int DestroyIcon(IntPtr hIcon);
    }

ファイルパスからアイコン画像を得る。ObservableCollection

    class Item
    {
        public FileSystemInfo Info
        {
            set;
            get;
        }

        public String Name
        {
            get { return Info.Name; }
        }

        public String Length
        {
            get
            {
                var file = Info as FileInfo;
                if (file == null)
                {
                    return "";
                }
                else
                {
                    return file.Length.ToString();
                }
            }
        }

        public BitmapSource Bitmap
        {
            get
            {
                SHFILEINFO shinfo = new SHFILEINFO();
                var hImgLarge = Win32.SHGetFileInfo(Info.FullName, 0,
                    ref shinfo, (uint)Marshal.SizeOf(shinfo),
                    Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);
                BitmapSource source = Imaging.CreateBitmapSourceFromHIcon(shinfo.hIcon, Int32Rect.Empty, null);
                Win32.DestroyIcon(shinfo.hIcon);
                return source;
            }
        }
    };

ListViewのDataTemplateにBitmapをバインディングする

        <ListView Grid.Row="1" ItemsSource="{Binding Path=Files}" AlternationCount="2">
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="Name">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto" />
                                            <ColumnDefinition Width="*" />
                                        </Grid.ColumnDefinitions>
                                        <Image Grid.Column="0" Source="{Binding Path=Bitmap}" Margin="5,0,5,0" />
                                        <Label Grid.Column="1" Content="{Binding Path=Name}"/>
                                    </Grid>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Size">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <Label Content="{Binding Path=Length}" HorizontalAlignment="Right"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                    </GridView.Columns>
                </GridView>
            </ListView.View>
            <ListView.ItemContainerStyle>
                <Style TargetType="{x:Type ListViewItem}"  >
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                    <EventSetter Event="MouseDoubleClick" Handler="listBoxItem_DoubleClick"/>
                </Style>
            </ListView.ItemContainerStyle>
        </ListView>

アイコンが出るようになった。

別スレッドでアイコン画像の読み込みをする

        public DirectoryInfo Current
        {
            get { return current_; }
            set
            {
                current_ = value;
                NotifyPropertyChanged("Current");
                NotifyPropertyChanged("Path");
                files_.Clear();
                var workList=new List<Item>();
                try
                {
                    foreach (var e in current_.GetFileSystemInfos())
                    {
                        // FileSystemInfoだけのリストを作って、
                        // 後でアイコン画像をロードする
                        var item=new Item
                        {
                            Info = e
                        };
                        files_.Add(item);
                        workList.Add(item);
                    }

                    // 別スレッドでビットマップ更新を呼び出す
                    var task = new Task(() =>
                    {
                        foreach (var item in workList)
                        {
                            var source = LoadBitmapSource(item.Info);
                            source.Freeze(); // 重要
                            Action action = () =>
                            {
                                // UIスレッド
                                item.Bitmap = source;
                            };
                            dispatcher_.Invoke(action);
                        }
                    });
                    task.Start();
                }
                catch (UnauthorizedAccessException e)
                {
                    // do nothing
                }
                catch (DirectoryNotFoundException e)
                {
                    // do nothing
                }
            }
        }

github作った。
https://github.com/ousttrue/CSFiler

ファイラーその3

ListBoxからListViewに変えてみる。

MainWindow.xaml

<Window x:Class="filer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:IO="clr-namespace:System.IO;assembly=mscorlib"
        Title="Filer" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="ListViewItem">
            <EventSetter Event="MouseDoubleClick" Handler="listBoxItem_DoubleClick"/>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <TextBox Grid.Column="0" Name="currentFolder" Text="{Binding Path=Path}" />
            <Button Grid.Column="1" Name="goParent" Width="30" Content=".." Click="goParent_Click" Cursor="Hand"/>
        </Grid>
        <ScrollViewer Grid.Row="1" >
            <ListView ItemsSource="{Binding Path=Files}" AlternationCount="2">
                <ListView.View>
                    <GridView>
                        <GridView.Columns>
                            <GridViewColumn Header="Name">
                                <GridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <Label Content="{Binding Path=Name}"/>
                                    </DataTemplate>
                                </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                            <GridViewColumn Header="Size">
                                <GridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <Label Content="{Binding Path=Length}"/>
                                    </DataTemplate>
                                </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                        </GridView.Columns>
                    </GridView>
                </ListView.View>
            </ListView>
        </ScrollViewer>
    </Grid>
</Window>

ListBoxをListViewに変更して、中のGridViewにカラムを2つ作った。
さらにDataTemplateをWindow.ResourcesからGridViewColumn.CellTemplateに移動した。
DataTypeとColumn番号からDataTemplateを選択する方法を模索したのだが、
CellTemplateSelectorを書く方法しか見つからなかったのでなるべくxamlだけで済ます方針から見送った。

右寄せにする

Styleで伸ばしてから

        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        </Style>

DataTemplateで右に寄せる

                                    <DataTemplate>
                                        <Label Content="{Binding Path=Length}" HorizontalAlignment="Right"/>
                                    </DataTemplate>

スタイルをResourcesからListViewの下に移動する

                <ListView.ItemContainerStyle>
                    <Style TargetType="{x:Type ListViewItem}"  >
                        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                        <EventSetter Event="MouseDoubleClick" Handler="listBoxItem_DoubleClick"/>
                    </Style>
                </ListView.ItemContainerStyle>

FileSystemInfoのラッパを作ってLengthプロパティアクセス時にエラーが出ないようにする

DirectoryInfo.Lengthにアクセスしたとき、そんなプロパティは無いというエラーが出る。
ObservableCollectionからObservableCollectionに換装する。

    class Item
    {
        public bool IsDirectory
        {
            set;
            get;
        }

        public FileSystemInfo Info
        {
            set;
            get;
        }

        public String Name
        {
            get { return Info.Name; }
        }

        public String Length
        {
            get
            {
                var file = Info as FileInfo;
                if (file == null)
                {
                    return "";
                }
                else
                {
                    return file.Length.ToString();
                }
            }
        }
    };

ToDo: アイコンをつける

ファイラーその2

ListBoxItemのダブルクリックイベントを実装する。

MainWindow.xaml

            <ListBox Name="currentFolderFiles" ItemsSource="{Binding Path=Files}">
                <ListBox.ItemContainerStyle>
                    <Style TargetType="{x:Type ListBoxItem}">
                        <EventSetter Event="MouseDoubleClick" Handler="listBoxItem_DoubleClick" />
                    </Style>
                </ListBox.ItemContainerStyle>
            </ListBox>

MainWindow.xaml.cs

    public partial class MainWindow : Window
    {
        private FileView fileView_ = new FileView("C:\\");

        public MainWindow()
        {
            InitializeComponent();

            DataContext=fileView_;
        }

        private void listBoxItem_DoubleClick(object sender, MouseButtonEventArgs args)
        {
            var item = sender as ListBoxItem;
            var directory = item.Content as DirectoryInfo;
            if (directory != null)
            {
                fileView_.Current=directory;
                return;
            }
            var file = item.Content as FileInfo;
            if(file != null)
            {
                return;
            }

        }
    }

FileView.cs

        private DirectoryInfo current_;

// 追加
        public DirectoryInfo Current
        {
            get { return current_; }
            set
            {
                current_ = value;
                NotifyPropertyChanged("Current");
                NotifyPropertyChanged("Path");
                /* 入れ物が変わってしまう・・・
                files_ = new ObservableCollection<FileSystemInfo>(
                current_.GetFileSystemInfos().ToArray());
                 */
                files_.Clear();
                foreach (var e in current_.GetFileSystemInfos())
                {
                    files_.Add(e);
                }
            }
        }

        public string Path
        {
            get { return current_.FullName; }
            set
            {
                Current = new DirectoryInfo(value);
            }
        }

ディレクトリの上に来たらマウスカーソルを変える

MainWindow.xaml

        <DataTemplate DataType="{x:Type IO:DirectoryInfo}">
            <Label Content="{Binding Path=Name}"  Foreground="#FF2222" Cursor="Hand"/>
        </DataTemplate>

横いっぱいに広げる

<ListBox x:Name="currentFolderFiles" ItemsSource="{Binding Path=Files}" HorizontalContentAlignment="Stretch">

親ディレクトリに戻るボタン

MainWindow.xaml

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <TextBox Grid.Column="0" Name="currentFolder" Text="{Binding Path=Path}" />
            <Button Grid.Column="1" Name="goParent" Width="30" Content=".." Click="goParent_Click" Cursor="Hand"/>
        </Grid>

立て分割のGridに、横分割のGridを入れ子にした
MainWindow.xaml.cs

        private void goParent_Click(object sender, RoutedEventArgs e)
        {
            if (fileView_.Current.Parent != null)
            {
                fileView_.Current = fileView_.Current.Parent;
            }
        }

ToDo:アイコン表示