2009年12月28日月曜日

Hyper-V with PowerShell

Hyper-V Serverを導入しました。これは機能制限されたWindows Server 2008 Server Coreみたいなものです。Server Coreと同じくローカルではコマンドプロンプトでの管理しかありません。 基本的にはfirewallを必要な分解放して、リモートから管理するわけですが、ここはあえてひねくれて、Hyper-V Server単独でどこまでできるかを試してみました。 デフォルトでは有効になっていませんが、

dism /online /enable-feature /featurename:NetFx2-ServerCore /featurename:MicrosoftWindowsPowerShell
とすることでPowerShellが有効になります。 さてこのPowerShell + WMIを使ってHyper-Vは管理できます。 気合いで書いてみました。
# Switch作成 $vsm = gwmi -namespace root\virtualization Msvm_VirtualSwitchManagementService $vs = [wmi]$vsm.CreateSwitch("ExternalNetwork", "ExternalNetwork", 4096).CreatedVirtualSwitch $esp = [wmi]$vsm.CreateSwitchPort($vs, "ExternalNetwork_ExternalPort", "ExternalNetwork_ExternalPort").CreatedSwitchPort $isp = [wmi]$vsm.CreateSwitchPort($vs, "ExternalNetwork_InternalPort", "ExternalNetwork_InternalPort").CreatedSwitchPort $eep = gwmi -namespace root\virtualization Msvm_ExternalEthernetPort #NICが複数ある場合は注意 $vsm.SetupSwitch($esp, $isp, $eep, "ExternalNetwork", "ExternalNetwork") # VM作成、CPU、Memoryまで  $vsm = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $gsd = (([wmiclass]"root\virtualization:Msvm_CirtualSystemGlobalSettingData").CreateInstance() $gsd .ElementName = "web" $vm = $vsm.DefineVirtualSystem($gsd.GetText([Management.TextFormat]::WmiDtd20)).DefinedSystem $sd = $vm.getRelated("Msvm_VirtualSystemSettingData") | select -first 1 $psd = $sd.getRelated("Msvm_ProcessorSettingData") $psd.VirtualQuantity = 2 $msd = $sd.getRelated("Msvm_MemorySettingData") $msd.Limit = $msd.Reservation = $msd.VirtualQuantity = 1024 $vsm.ModifyVirtualSystemResources($vm, (@($psd, $msd) |% {$_.GetText([Management.TextFormat]::WmiDtd20)})) # NIC追加 $vsm = gwmi -namespace root\virtualization Msvm_VirtualSwitchManagementService $guid = [Guid]::NewGuid().ToString() $sp = $vsm.CreateSwitchPort($vs, $guid, $guid).CreatedSwitchPort $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=10 and ResourceSubType='Microsoft Synthetic Ethernet Port'").__Path.Replace('\', '\\') # 10=EthernetAdapter $esd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $esd.Connection = $sp.__Path $esd.ElementName = "Synthetic Ethernet Port" $esd.VirtualSystemIdentifiers = [Guid]::NewGuid().ToString("B") $vsm = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $vsm.AddVirtualSystemResources($vm, $esd.GetText([Management.TextFormat]::WmiDtd20)) # Disk追加 $im = gwmi -namespace root\virtualization Msvm_ImageManagementService $dir = (gwmi -namespace root\virtualization Msvm_VirtualSystemManagementServiceSettingData).DefaultVirtualHardDiskPath $im.CreateDynamicVirtualHardDisk( (Join-Path $dir "test.vhd"), 127GB ) $ide = ($sd.getRelated("MSVM_ResourceAllocationSettingData")| where {$_.ResourceSubType -eq "Microsoft Emulated IDE Controller" -and $_.Address -eq 0}) $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=22 and ResourceSubType='Microsoft Synthetic Disk Drive'").__Path.Replace('\', '\\') # 22=Disk $dsd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $dsd.Parent = $ide.__Path $dsd.Address = 0 $vsm = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService $drive = [wmi]($vsm.AddVirtualSystemResources($vm, $dsd.GetText([Management.TextFormat]::WmiDtd20)).NewResources | select -first 1) $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=21 and ResourceSubType='Microsoft Virtual Hard Disk'").__Path.Replace('\', '\\') # 21=StorageExtent $dsd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $dsd.Connection = Join-Path $dir "test.vhd" $dsd.Parent = $drive.__Path $vsm.AddVirtualSystemResources($vm, $dsd.GetText([Management.TextFormat]::WmiDtd20)) # DVD追加 $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=16 and ResourceSubType='Microsoft Synthetic DVD Drive'").__Path.Replace('\', '\\') # 16=DVDDrive $dsd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $dsd.Parent = $ide.__Path $dsd.Address = 1 $drive = [wmi]($vsm.AddVirtualSystemResources($vm, $dsd.GetText([Management.TextFormat]::WmiDtd20)).NewResources | select -first 1) $ac = (gwmi -namespace root\virtualization Msvm_AllocationCapabilities -filter "ResourceType=21 and ResourceSubType='Microsoft Virtual CD/DVD Disk'").__Path.Replace('\', '\\') # 21=StorageExtent $dsd = [wmi](gwmi -namespace root\virtualization Msvm_SettingsDefineCapabilities -filter "GroupComponent='$ac' and ValueRange=0").PartComponent $dsd.Connection = (gwmi Win32_CdromDrive -filter "Drive='D:'").DeviceID # D:ドライブ $dsd.Parent = $drive.__Path $vsm.AddVirtualSystemResources($vm, $dsd.GetText([Management.TextFormat]::WmiDtd20))
これぐらいでVMが作成できるはず。 ここまで書いてようやく気付きました。VMの画面が見れません。VMにOSがインストールできないわけです…。もちろんP2Vとかすればできますが…。 結局、長いものに巻かれろということで、私もリモート管理することにしました。 というわけで本当に動作確認できていません。

2009年11月27日金曜日

CSS Animations Module Level 3 と CSS Sprite

CSS3のAnimation Moduleに失望しました。

GIF Animationは広く使われているものの、色数がおおよそ256色、半透明の未サポート、ファイルサイズが大きくなりやすい、などなど、欠点があるので、他の方法を模索していました。

今のところ、JavaScriptを使ってちまちまと書き換えする方法を採っています。

そこでCSS SpriteとCSS3のAnimationを組み合わせることで、GIF Animationの代わりにならないかという案を思いつきました。
CSS Animationはkeyframeでstyleを指定するとタイムラインに従ってstyleが変化するというもの。つまり、background-positionを指定すればアニメーションする! と思ったわけです。

1つ目の問題点はbackground-positionはxとyを同時に指定してしまう点。片方だけを指定してもう片方をinheritすることはできません。これは案外痛いです。
もう1つが致命的。background-positionがlinear変化する点。linearでなくてもベジエ曲線で定義することはできるものの、CSS Spriteで求められているのはstepというか、keyframeで指定した値に直接変化すること。おかげで、にょろにょろにょろとCSS Sprite画像がスムーズにスクロールしてしまいます。

まさにどうしてこうなった状態。

2009年10月17日土曜日

dojo.Deferred

JavaScriptにはスレッドがありません。時間のかかる処理をするにはsetTimeoutを使った疑似スレッドを使うことになります。
すると今度は完了待ちのための手段が大変です。いくつかの処理が終わったら最後にこれをする、とかあるわけです。
そんなときのための対策にこんな関数を用意して使っていました。

// ちょー適当な関数名…
function doat(count, func) {
return function() {
if( --count == 0 )
func();
};
}
この関数は関数を返します。返ってきた関数はcount回呼び出すとfuncを呼びます。
これで、各疑似スレッドに返ってきた関数を呼び出させれば、最後に終わったスレッドがfuncを実行してくれるわけです。

でもdojoにdojo.Deferredクラスを見つけました。dojo的にはこっちを使うみたいです。
まだ使い慣れていませんが、そのうちこっちに乗り換えよう…。

2009年9月19日土曜日

ImageLockMode.UserInputBuffer | ImageLockMode.WriteOnly

データからBitmapの生成をよくするんですが、だいたいこんなコードを書きます。

byte[] pixels;

var bitmap = new Bitmap( width, height, PixelFormat.Format32bppArgb );
var data = bitmap.LockBits( new Rectangle( 0, 0, width, height ), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb );
Marshal.Copy( pixels, 0, data.Scan0, pixels.Length );
bitmap.UnlockBits( data );
Marshal.Copy()が無駄に思えたのでImageLockMode.UserInputBufferを使ってみました。するとこんな風に書き換わります。
byte[] pixels;

var bitmap = new Bitmap( width, height, PixelFormat.Format32bppArgb );
bar handle = GCHandle.Alloc( pixcels, GCHandleType.Pinned );
try{
var data = new BitmapData{
PixelFormat = PixelFormat.Format32bppArgb,
Width = width,
Height = height,
Stride = stride,
Scan0 = Marshal.UnsafeAddrOfPinnedArrayElement( pixels, 0 ),
};
bitmap.LockBits( new Rectangle( 0, 0, width, height ), ImageLockMode.UserInputBuffer|ImageLockMode.WriteOnly,
PixelFormat.Format32bppArgb, data );
bitmap.UnlockBits( data );
}
finally{
handle.Free();
}
無駄なコピーが排除できた! と喜んだものの、処理がかなり遅くなりました…。GCHandle.Alloc()のせいではなく、ImageLockMode.UserInputBufferが原因のようです。

2009年9月7日月曜日

IE6 CSSのclass selectorの酷さ

IE6の酷いところはいろいろ言われていますが、今更ながらこんなことではまるとは。と言うことで書き留めておきます。

<style type="text/css">
.a.c {
color: red;
}
.b.c {
color: blue;
}
</style>
何の変哲もないスタイルです。classにa cが同時に含まれていれば赤く、b cが同時に含まれていれば青くなります。
そうこんな感じ
<div class="a c">
color: red;
</div>
…ところが、IE6はclassにbが含まれていないのに青くなります。いやマジで。


追記:
間違ってました。IE6はCSS1しかサポートしておらず、CSS1ではclass selectorのネストを許していませんでした。

2009年8月13日木曜日

Windows 7 導入

Windows 7を導入しました。Hyper-Vが使いたかったのでWindows Server 2008 R2の方がよかったのですが、Hyper-Vを有効にするとスリープが使えないのは痛いです。サーバーOSだから当たり前ですね。

以降、愚痴です。
今更ながらIRQの競合が起きてる模様?
video card、onboard sound、onboard nicがIRQを共有しているらしく、Windows 7起動時にsoundやnicが認識されない現象が。必ずvide cardは認識される辺り怪しいです。
XP / Vistaでは発生しなかった現象です。またWindows Server 2008 R2でも発生します。

2009年6月7日日曜日

Visual Studio 2010 beta1 C++でのinclude

なんでもVC++が進化しているそうなので試してみたく。
プログラムを書こうとして#include <...>まで書いて気がついた。はてさて、header fileのdirectoryはどう設定するの?

Visual Studio 2008までは ツール - オプション - プロジェクトおよびソリューション - VC++ディレクトリ という設定項目があり、そこにディレクトリを入力できた。が、2010 beta1ではそこがなくなっている。
もちろんプロジェクトのプロパティに設定してもコンパイルできることにはできるが、システムにインストールしたheader fileのdirectoryをプロジェクトごとに書くのはおかしい。

プロジェクトファイルを参照したところ答えがあった。

<ImportGroup Label="PropertySheets">
<Import Project="$(LocalAppData)\Microsoft\VisualStudio\10.0\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(LocalAppData)\Microsoft\VisualStudio\10.0\Microsoft.Cpp.$(Platform).user.props')" />
</ImportGroup>
つまり$(LocalAppData)\Microsoft\VisualStudio\10.0\Microsoft.Cpp.$(Platform).user.propsに書けば取り込まれます。

2009年6月5日金曜日

C# 4.0 dynamic その2

というわけでサンプルコードを使って、C# 3.0とC# 4.0とでどのように変わってくるかを説明します。
サンプルは、Outlook 2007の受信トレイ以下のフォルダにある重複メール(Message-Idが一致するメール)をゴミ箱へ移動するコードです。Outlook 2007の新機能Tableオブジェクトを使用しているのでOutlook 2003以前では動作しません。

まずはC# 3.0でのコード

static class Program {
// Outlookを初期化し、受信トレイに対してVisit()を呼びます。
static void Main( string[] args ) {
var application = new Application();
Visit( application.Session.GetDefaultFolder( OlDefaultFolders.olFolderInbox ) );
}

// 各フォルダに対してProcess()を呼びます。また再帰的にフォルダを探索していきます。
static void Visit( MAPIFolder folder ) {
Process( folder );
foreach( MAPIFolder f in folder.Folders )
Visit( f );
}

// ちょっとだけ読みやすくなる拡張メソッドです。
static IEnumerable<Row> AsEnumerable( this Table table ) {
while( !table.EndOfTable )
yield return table.GetNextRow();
}

// 本題の処理です。Message-Id一覧を作成し、重複するものがあったらゴミ箱へ移動します。
static void Process( MAPIFolder folder ) {
var messageIds = new HashSet<string>();
var table = folder.GetTable( null, OlTableContents.olUserItems );
table.Columns.RemoveAll();
table.Columns.Add( "http://schemas.microsoft.com/mapi/proptag/0x1035001E" );
table.Columns.Add( "EntryID" );
var ns = folder.Session;
var trash = ns.GetDefaultFolder( OlDefaultFolders.olFolderDeletedItems );
foreach( var row in table.AsEnumerable() )
if( !messageIds.Add( (string)row[1] ) ) {
MailItem mailItem = (MailItem)ns.GetItemFromID( (string)row[2], null );
Console.WriteLine( "{0}", mailItem.Subject );
mailItem.Move( trash );
}
}
}

続いてC# 4.0でのコード。違いがあるのはProcess()メソッドだけです。
static void Process( MAPIFolder folder ) {
var messageIds = new HashSet<string>();
var table = folder.GetTable( TableContents: OlTableContents.olUserItems );
table.Columns.RemoveAll();
table.Columns.Add( "http://schemas.microsoft.com/mapi/proptag/0x1035001E" );
table.Columns.Add( "EntryID" );
var ns = folder.Session;
var trash = ns.GetDefaultFolder( OlDefaultFolders.olFolderDeletedItems );
foreach( var row in table.AsEnumerable() )
if( !messageIds.Add( row[1] ) ) {
MailItem mailItem = ns.GetItemFromID( row[2] );
Console.WriteLine( "{0}", mailItem.Subject );
mailItem.Move( trash );
}
}
まず、デフォルト引数に対応したため、本質的でないnull引数を記述しなくてもよくなっています。

次に、row[1]とrow[2]の実体はstring型ですが宣言はobject型でした。C# 4.0ではここがdynamic型になっているため、明示的なキャストなしでメソッド引数に使えます。
ns.GetItemFromID()の戻り値もobjectがdynamicに変わっています。実体はCOMオブジェクトです。dynamicのまま扱ってもSubjectプロパティやMove()メソッドは呼び出せますが、MailItem型ということがわかっていますのでキャストしています。その際にも明示的にキャスト式を書く必要はありません。

2009年6月4日木曜日

C# 4.0 dynamic

Visual Studio 2010 beta1で遊んでいます。
C# 4.0および.NET Framework 4.0で提供されるdynamicキーワードについて誤解していました。

dynamic宣言した変数はメソッド呼び出しを行っても、実行時にバインドされます。
ここまでは合ってます。

誤解していたのは、ソースコード上で明示的に宣言したもののみがdynamic変数になると考えていました。(object→dynamicにキャストするイメージでした。)しかし、Visual Studio 2010で試していてわかったのですが、PIAなどのクラスメソッドの戻り値がそもそもdynamicになっています。(C# 3.0まではobject型)
なので、今までstringなどの変数に代入するためにはobject→stringの明示的なキャストが必要でした。C# 4.0ではdynamicになっているため、stringに代入しようとするだけで自動的にキャストされます。C# 3.0のvarで受けた場合、dynamicのままでした。

文字だけなのでイメージがわきづらいですが、PIAを使った場合に思った以上にdynamicの恩恵が受けられそうです。

サンプルコードでも書けばわかりやすいかな?

2009年4月19日日曜日

mod_cacheまわり

Apache Web Serverでコンテンツのcacheをしたくなり調査しました。
まず、cache方法には3種類あって

  1. Reverse Proxy
    Web serverとWeb browserとの間に介入して、cacheする。Apacheにもその機能はあるし、別のツールでも実現できる。Web serverとは別モノを必要とするので構造がややこしくなるのでパス。
  2. mod_file_cache
    Apacheが最終的に読み込むfileそのものをcacheしてしまう。方法をfile openしっぱなしやmmap()しっぱなしなど、安直だけどうまくいけば効果的。cacheの対象がfileなので動的なコンテンツには対応できない。パス。
  3. mod_cache
    Apacheのfilterとして動作し、出力内容をcacheし、次に同じリクエストがあればcache内容を返す。動的なコンテンツにも対応する。本命。
というわけでmod_cacheの設定をします。
そもそもmod_rewriteを使った記事を参考に、コンテンツ圧縮をしていました。というのもApacheのmod_deflateはリクエストの度にコンテンツ圧縮をするので効率が悪かったのです。mod_cacheで圧縮後のコンテンツをcacheできればmod_rewriteのトリッキーな方法ともおさらばです。

さてmod_cacheにはdisk cacheを行うmod_disk_cacheとmemory cacheを行うmod_mem_cacheがあります。ディスクアクセスを減らしたいのでここはmod_mem_cacheで決まりです。
mod_mem_cacheはプロセスごとにmemory cacheを行うためマルチプロセスとなるpreforkモデルでは効果がありません。ここはマルチスレッドを併用するworkerモデルに切り替えます。(Debianなのでapache2-mpm-workerパッケージをインストールするだけ。)

次にmod_deflateによるコンテンツ圧縮の設定です。
AddOutputFilterByType DEFLATE text/plain text/xml application/javascript
text/htmlは加えません。そもそも細かい設定もしません。そこには事情があります。
text/htmlをコンテンツ圧縮したところIE6が固まりました。正確にはKeep Aliveが切断されるまで処理が固まり、他のコンテンツはタイムアウトエラーになりました。mod_setenvifを使用してIE6のみKeep Aliveを拒否してみましたがいまいち効果もなく、またConnection continueが使えないのは応答速度にも影響します。htmlコンテンツは大きくもなく、数も少ないため圧縮対象外としました。
mod_deflateに対して細かい設定をしないことにも事情があります。コンテンツ圧縮を行うことで古いブラウザでは問題を引き起こします。一般的にはそこでブラウザごとに圧縮可否を変えます。これを行ってしまうと、Varyレスポンスヘッダに影響を与えてしまいます。つまり、User-Agentリクエストヘッダに応じてコンテンツを切り替えていることになり「Vary: Accept-Encoding, User-Agent」となってしまいます。mod_cacheはこれを見てUser-Agentごとに異なるcacheを生成します。User-Agentにはブラウザバージョンなどの文字列が含まれているためほとんどcache hitが見込めなくなります。というわけであえてUser-Agentには依存しない設定にしました。

Vary: Accept-Encodingにも問題がありました。リクエストヘッダに「Accept-Encoding: gzip」とあれば圧縮する(なければ圧縮しない)わけですから、Varyに含めるのは当然なのですが、Accept-Encodingの内容がブラウザごとに異なるため、それぞれにcacheを生成してしまいます。そこで考えました。
SetEnvIf Accept-Encoding "\bgzip\b" gzip
RequestHeader set Accept-Encoding gzip env=gzip
RequestHeader unset Accept-Encoding env=!gzip
Accept-Encodingにgzipを含むか含まないかの2択でヘッダを書き換えてしまう方法です。これはどうやらダメでした。cacheのhit判定にはこの書き換えは含まれず、逆にcache保存時にはこの書き換えの影響を受けるためcache hitしなくなりました。というわけでこれに関しては目をつぶります。

他にも問題がありました。mod_deflateはコンテンツ圧縮後のETagに「-gzip」を付与します。cacheのhit判定には「-gzip」が付与されていないためこれまたcache hitしませんでした。そこで
FileETag None
でETagを消しました。元々Last-Modifiedレスポンスヘッダは付いているのでそれほど問題にはなりません。

最後にmod_cacheとmod_mem_cacheの設定です。これはパラメータを適切に設定するだけです。

2009年4月11日土曜日

ToolStripMenuItem.CheckOnClick

こんな機能が欲しかった!
ToolStripMenuItem.CheckOnClickより

ToolStripMenuItemが自動的にチェックされた状態で表示され、クリックしたときにチェック解除されるかどうかを示す値を取得または設定します。
...
クリックしたときにToolStripMenuItemが自動的にチェックされた状態で表示される場合はtrue。それ以外の場合はfalse。既定値はfalseです。
何か矛盾してる。ソースコードを追ってみたところ、前半はウソ。後半が正しい。もう一度、引用しよう。
クリックしたときにToolStripMenuItemが自動的にチェックされた状態で表示される場合はtrue。それ以外の場合はfalse。
翻訳すると、trueにした場合の振る舞いとして、このメニューをクリックするとチェックが付く…チェックを外す方法については言及していません。

大事なことなので2度言いましたよ。

2009年4月4日土曜日

C#でできることはC++/CLIでもできる

私にもそう思っていた頃がありました。
ADO.NET周りに新機能が多くて何か使ってみようと思って調べてみました。

Data Entity Framework
C#とVB.NETのみ。code generatorがC++/CLIに対応してない。ちなみにVisual Studioが生成するファイルとcode generatorが引数に要求するファイルは異なるので自分で処理するのは面倒。次バージョンに期待。
SQL Server Compact 3.5 SP1
C++/CLIからも使用可能。やったね☆
Linq to SQL
さすがにC#のような構文拡張はC++/CLIに期待しないとして…C#とVB.NETのみ。code generatorがC++/CLIに対応してない。更にSQL Server Compact 3.5 SP1はLinq to SQLに未対応。
型指定されたDataSet
C#とVB.NETのみ。code generatorがC++/CLIに対応してよくわからないエラーを吐く。そのためなのか、Visual Studioでも「新しい項目の追加」のテンプレートからも外されている。
Linq to DataSet
型指定されたDataSetが作れない時点で終わってます。
番外編…Settings.settings
動いてるような、動いてないような。型指定されたwrapperクラスを作ろうとSettings.hファイルを作成しstdafx.hに書き込むところまで自動でやってくれます。Settings.hファイルの中身? しらんがな。そのためなのか、Visual Studioでも「新しい項目の追加」のテンプレートからも外されている。

C++/CLIはnativeと.NETとの橋渡し程度に考えておくべきかもしれません…。

2009年4月2日木曜日

逆double thunking

double thunkingに逆も何もないけどなんとなく…。

状況としては次の関数をnative C++でコンパイルしa.dllに入れます。

__declspec(dllexport) LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam );

そしてa.dllにリンクするb.exe内でC++/CLIを使って次の呼び出しをします。
HINSTANCE module = GetModuleHandleW( L"a.dll" );
SetWindowsHookExW( WH_CBT, CBTProc, module, 0 );
するとどうなるか。

コンパイラは単なる関数ポインタCBTProcをmanaged codeから呼べるようwrapします(1段目のthunk)。
次にwrapされたmanagedな関数ポインタをunmanaged codeから呼べるようにwrapします(2段目のthunk)。
この2重にthunkされた関数ポインタをSetWindowsHookExW()に渡します。

#pragma unmanagedとか試してみましたが変化しませんでした。結局、この部分だけソースコードを独立させ、/clrコンパイルオプションを外して強制的にnative C++としてコンパイルすることで回避できました。もっとsmartな方法がありそうですが、見つけられなかった。

2009年3月29日日曜日

/NODEFAULTLIB:msvcmrt.lib

どこかでVS2008のC++/CLIだと.NET Frameworkを使用しているのにVC++ランタイムライブラリとの依存関係が切れなくて、結局VC++ランタイムライブラリもインストール必要になってしまう&x86とx64で共存できない、というような記述を見かけた…気がしました。
後になって探したのですがどこで見かけたのやら。

で、方法 : CRT ライブラリ DLL との依存関係を削除して部分信頼アプリケーションを作成するによると/NODEFAULTLIB:msvcmrt.libを指定することにより依存関係を切れるとのこと。ただしこれでは必要な処理が足りていないのでptrustm.libかptrustmd.libのどちらかとリンクすること。

えっとこの.libによってx86かx64のどちらかに固定されてしまうのか。でも.NET Frameworkだけで動作できるようになる、VC++ランタイムライブラリのインストール不要となるならそれはそれで大きいかな。

あ、ちなみに結果がどうなるか試してません。

2009年3月28日土曜日

zh-Hansとzh-CHS

カルチャには特定カルチャとニュートラルカルチャとインバリアントカルチャがある。
特定カルチャはja-JPとかen-USとか、言語+地域情報を持つもの。
ニュートラルカルチャはjaとかenとか、言語だけで地域情報を持たないもの。特定カルチャで完全一致できなかった場合にニュートラルカルチャにフォールバックします。
インバリアントカルチャは言語も地域も表さないもの。「要するに、体系を体系たらしめるために要請される意味の不在を否定する記号なんだよ。そのアナログなのが神で、デジタルなのがゼロ。どうかな?」

で、ニュートラルカルチャには唯一の例外としてzh-CHSとzh-CHTがある。中国語には簡体字と繁体字があるから。そしてこのカルチャ名はWindows Vistaからzh-Hansとzh-Hantに変更されてたりする。

  • Windows XP上の.NET Framework 2.0 SPなしだとzh-Hansを認識しない
  • Windows XP上の.NET Framework 2.0 SP1以降だとzh-Hansを認識し、zh-CHS→zh-Hansの順でフォールバックする
  • Windows Vista上の.NET Framework 2.0 SPなし(SP1以降も)zh-CHSを認識し、zh-CHS→zh-Hansの順でフォールバックする
結局の所、Windows XPを意識するならzh-CHSを使うことになるが、例えば.NET Framework 3.5 SP1 Client Profileだと.NET Framework 2.0 SP2を含むのでzh-Hansでもいいかもしれない。

2009年3月22日日曜日

自作ツールのWindows 7対応

対応に向けて調査を始めました。途中で飽きたらそのまま放置になりますが…。
まず今のツールはUIを設計する気がないため設定項目は全てiniを使い、タスクトレイに置いたアイコンのメニューから最低限の操作ができるようになっています。
Windows 7ではタスクトレイはデフォルトで非表示なので困ってしまうため抜本的な見直しを行うことにしました。

Windows Live Messengerがtaskbarを使いこなしているためこれを参考に調査を進めます。まずWindows 7環境ではこんな感じ。

タスクトレイにはアイコンが出なくなります。メインウィンドウの他にもう一つウィンドウが存在するような。そしてタスクバーを右クリックするとこんな感じ。
プログラムから好きなメニューを登録できます。ちなみにこのメニューはスタートメニューにも表示されてこんな感じ。

さてメインウィンドウを閉じるとこんな感じ。

やはり何かいるようです。spyで見ると


とんでもない座標に隠しWindowがいました。これを参考にしてみようと思います。

2009年3月19日木曜日

二項係数

どこかの影響を受けて書いてみました。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>二項係数</title>
<base href="http://ajax.googleapis.com/ajax/libs/dojo/1.2.3/" />
<link rel="stylesheet" type="text/css" href="dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css" href="dijit/themes/soria/soria.css" />
<script type="text/javascript" src="dojo/dojo.xd.js" djconfig="parseOnLoad: true"></script>
<script type="text/javascript">
// <![CDATA[
dojo.require("dijit.form.NumberTextBox");
var MAX = 10000000;
function onChange() {
var n = N.attr('value');
var k = K.attr('value');
if (isNaN(n) || isNaN(k) || k > n)
return;
k = Math.min(k, n - k);
if(k == 0)
k = 1;
else {
var numerator = [];
for(var i = 0; i < k; i++)
numerator.push(n - i);

for(var i = 2; i <= k; i++) {
var j = i;
for(var p = 2; j > 1; p++) {
while(j % p == 0) {
j /= p;
for(var l = 0; l < numerator.length; l++) {
if(numerator[l] % p == 0) {
numerator[l] /= p;
break;
}
}
}
}
}
var result = [1];
dojo.forEach(numerator, function(i) {
var rest = 0;
for(var j = 0; j < result.length; j++) {
var k = result[j] * i + rest;
result[j] = k % MAX;
rest = (k - result[j]) / MAX;
}
if(rest > 0)
result.push(rest);
});
k = result.pop().toFixed();
dojo.forEach(result.reverse(), function(i) {
k += (i + MAX).toFixed().substr(1);
});
}
dojo.byId('result').innerHTML = k;
}
// ]]>
</script>
</head>
<body class="soria">
<h1><sub>n</sub>C<sub>k</sub></h1>
n = <input type="text" dojotype="dijit.form.NumberTextBox" jsid="N" value="0"
required="true" constraints="{fractional: false, min: 0}" intermediatechanges="true" onchange="onChange" /><br />
k = <input type="text" dojotype="dijit.form.NumberTextBox" jsid="K" value="0"
required="true" constraints="{fractional: false, min: 0}" intermediatechanges="true" onchange="onChange" /><br />
<span id="result"></span>
</body>
</html>

2009年3月13日金曜日

Windows Server 2008 R2 build 7048

そろそろ2008 R2に環境を移そうとしています。ベータテストと、自作アプリのWindows 7対応のために。
Windows 7ではタスクバーが新しくなり、右下の通知領域がデフォルトで非表示になってしまうので、
アプリケーションの設計を見直す必要が。
で、どうせならHyper-Vとか使いたいので2008 R2です。

build 7048ですがところどころ不安定でした。まだ翻訳がおかしいですし、機能の追加の後の再起動に
失敗したりVirtual Clone Driveのインストールの直後はシャットダウンできなかったり。
ただ、RadeonのバグいドライバでWindows Vistaだとblue screenなのが、2008 R2だとドライバの
再起動を繰り返しつつも耐えてました。(耐えてる間に正常に再起動がかけれた。)
まぁRadeonがわるいんですが。

2009年2月22日日曜日

PNGの再圧縮

GDI+で作成したPNGファイルをGIMPで開いて保存し直したところ結構ファイルサイズが大きくなってびっくり。そういえば色形式も色々ありましたっけ。
調べたところ、OptiPNGとか他にもいろいろ再圧縮ツールがあるそうで。
手元のWebページの画像7,433ファイルをこのツールにかけたところ82MB→65MBと削減できました。

2009年2月21日土曜日

Debian 5.0 lenny

Debian 5.0 (lenny)がリリースされたのでアップグレードしました。
思兼 GNU/Linuxからアップグレードを繰り返してそろそろ10年でしょうか。

find /etc/ -type f | xargs ls -ltdr | head
で/etc内にある一番古いファイルが2000/01/29でした。

アップグレードの中でproftpdがはまることがわかっています。FTPにはそもそもファイル名に関する規定がありません。今までproftpdは8bit cleanでしたが、Debian 5.0にパッケージされているproftpd 1.3.1は8bit cleanではなくなり、日本語ファイル名を通すことが困難になりました。
こんなときでもDebianは古いパッケージをholdしておけば共存できます。つまりproftpdとそれに依存するパッケージはDebian 4.0のままで、それ以外はDebian 5.0に移行しました。

それでもまだはまることがあるんですね。
iptablesがバージョンアップして以前のiptables.confが使えませんでした。おかげでfirewall設定が消えて外部から攻撃を受ける羽目に…。
udev絡みでしょうか、mdのデバイスファイル名が/dev/md/1から/dev/md1に変わってしまいました。おかげでmount失敗に泣きました。
dhcpサーバが設定に厳しくなりました。ノートパソコンに対して無線LAN経由でも有線LANでも同じIPアドレスを割り当てていましたが、まとめて1つの設定にできなくなり、2つに分ける必要がありました。
rexecプロトコルが勝手にtcpd経由にされ、接続できなくなりました。tcpd嫌いっ

Apache、samba辺りは設定もややこしく毎回見直すべきなのは、それなりに。

まぁそれでもいい感じにアップグレードできたと思います。
ちなみにGCC周りが4.1から4.3にアップグレードされていますが、なぜか4.1のパッケージも残ったままなので手動で消す必要があります。

2009年2月6日金曜日

ADODB.SreamのSaveToFile()メソッド

ADODB.SreamオブジェクトにSaveToFile()メソッドがあります。書き込みのオプションとしてSaveOptionsEnumを設定します。これによると…

adSaveCreateNotExist1既定値です。FileNameパラメータで指定したファイルがない場合は新しいファイルが作成されます。
adSaveCreateOverWrite2FileNameパラメータで指定したファイルがある場合は、現在開かれているStreamオブジェクトのデータでファイルが上書きされます。
一見普通のEnumです。
でもよく読むと…
これらの値はAND演算子で結合することができます。
ちょっと待て。新規作成もしくは上書きをするにはAND結合? 1と2をAND結合すると0ですよね? ね?
こういうとき普通はOR結合して3になりませんか? いえ、値が重複していない以上、識別は可能ですが。
で、試してみる……0→引数エラー、1→OK、2→OK、3→引数エラー。
あれっ? ANDもORも受け付けないんですが。

仕方がないのでSRきりました。最終回答は出ていないもののドキュメントミスで次のようになるらしいとのこと。
adSaveCreateNotExist1既定値です。新規作成します。ただし上書きはしません。
adSaveCreateOverWrite2新規作成もしくは上書きします。

2009年1月28日水曜日

Windows 7 RRP

世の中、Windows 7βで賑わってますが、RRPというのを試してみました。何の略語かわかりません。
ともかくβのビルド番号が7000でRRPは7022となってました。
よく言われているようにセットアップ直後の感想として早い気がします。Vistaよりスムーズ、動きがなめらかな印象です。
今後、時間を見つけてアプリを入れてソフトの動作確認などもしていこうかと。

ちなみにβを試している友人と表示を比較させてもらいましたが、文字化けが酷い…悪化してます。

2009年1月15日木曜日

RAIDの拡張

Linuxのsoftware RAID(md)の場合、disk controllerをまたがって好きなようにRAIDを構成できるため重宝します。云々はに書きました。

今回ハードディスクを更新したので、RAIDの拡張をしてみました。

md2 : active raid5 sdf[0] sdg[3] sde[2] sdh[1]
という4玉構成のRAID5に対してsda4とsdc4を追加して6玉構成にしようと思います。

# mdadm /dev/md2 -a /dev/sda4
# mdadm /dev/md2 -a /dev/sdc4
# mdadm /dev/md2 -G -n 6
最初にSpare Devicesとして2玉追加し、次にgrowコマンドでActive Devicesを6玉に変更します。えー、7800min後に完了とか言い出しました。

よく見ると
md: reshape of RAID array md2
md: minimum _guaranteed_ speed: 1000 KB/sec/disk.
md: using maximum available idle IO bandwidth (but not more than 200000 KB/sec) for reshape.
md: using 128k window, over a total of 488386496 blocks.
とか言って本気を出していません。
こんなときLinux Kernelはオープンソースなので出しているメッセージや理由、どうすればいいかなどをソースコードから調べることができます。

# cat /proc/sys/dev/raid/speed_limit_min
1000
# echo 6000 > /proc/sys/dev/raid/speed_limit_min
他のプロセスの邪魔にならないようにこうやって速度が抑えられていたようです。その上で、早く完了させたいためスピードアップしてみました。これで残り1300minに…それでも丸一日かかるのね。

2009年1月11日日曜日

S.M.A.R.T on Linux

久々にハードディスクの健康状態が知りたくなり、smartmontoolsで情報を見てみました。
まずはありきたりなところからHDDの温度

# for d in a b c d e f g h; do echo -n "sd$d "; smartctl -a -d ata /dev/sd$d|grep Temperature_Celsius; done
sda 194 Temperature_Celsius 0x0022 035 055 000 Old_age Always - 35 (Lifetime Min/Max 0/17)
sdb 194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 28 (Lifetime Min/Max 16/55)
sdc 194 Temperature_Celsius 0x0002 196 196 000 Old_age Always - 28 (Lifetime Min/Max 16/58)
sdd 194 Temperature_Celsius 0x0022 034 047 000 Old_age Always - 34 (Lifetime Min/Max 0/16)
sde 194 Temperature_Celsius 0x0002 214 214 000 Old_age Always - 28 (Lifetime Min/Max 14/50)
sdf 194 Temperature_Celsius 0x0022 120 099 000 Old_age Always - 30
sdg 194 Temperature_Celsius 0x0002 230 230 000 Old_age Always - 26 (Lifetime Min/Max 14/38)
sdh 194 Temperature_Celsius 0x0022 120 097 000 Old_age Always - 30
あからさまな温度差はなさそうです。
次にread error
# for d in a b c d e f g h; do echo -n "sd$d "; smartctl -a -d ata /dev/sd$d|grep Raw_Read_Error_Rate; done
sda 1 Raw_Read_Error_Rate 0x000f 109 099 006 Pre-fail Always - 0
sdb 1 Raw_Read_Error_Rate 0x000b 094 094 016 Pre-fail Always - 851977
sdc 1 Raw_Read_Error_Rate 0x000b 085 085 016 Pre-fail Always - 6029424
sdd 1 Raw_Read_Error_Rate 0x000f 119 091 006 Pre-fail Always - 0
sde 1 Raw_Read_Error_Rate 0x000b 100 100 016 Pre-fail Always - 0
sdf 1 Raw_Read_Error_Rate 0x000f 200 200 051 Pre-fail Always - 0
sdg 1 Raw_Read_Error_Rate 0x000b 100 100 016 Pre-fail Always - 0
sdh 1 Raw_Read_Error_Rate 0x000f 200 200 051 Pre-fail Always - 0
sdbとsdcでエラーが出てる…そろそろやばいかも。

そして「for d in a b c d e f g h; do echo sd$d; smartctl -A -d ata /dev/sd$d; done」を眺めて気になる表示をピックアップ。
sda 190 Unknown_Attribute 0x0022 064 045 045 Old_age Always In_the_past 756809764
sda 195 Hardware_ECC_Recovered 0x001a 061 058 000 Old_age Always - 6361756
sdd 190 Unknown_Attribute 0x0022 064 053 045 Old_age Always - 740032548
sdd 195 Hardware_ECC_Recovered 0x001a 067 064 000 Old_age Always - 42581156


そこでテストを実行し、エラーの確認
# for d in a b c d e f g h; do smartctl -t short -d ata /dev/sd$d; done
# for d in a b c d e f g h; do echo "sd$d "; smartctl -l error -d ata /dev/sd$d; done
(特にエラーなし)
# for d in a b c d; do smartctl -t long -d ata /dev/sd$d; done
# for d in a b c d e f g h; do echo sd$d; smartctl -l selftest -d ata /dev/sd$d; done
sbc
Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error
# 1 Extended offline Completed: read failure 30% 22500 387518271
うわーsbcダメかも。