広告

検索

RSS RSSフィード

カレンダー

2018年12月
« 4月    
 12
3456789
10111213141516
17181920212223
24252627282930
31  

カテゴリー

最新のコメント

リンク

ASP.NETの例外処理を考える

投稿者:yasu 更新日時:2011年11月16日 0時55分28秒
カテゴリプログラム
タグ

最近ASP.NETで入力フォームを作る仕事がありまして、1からプログラムをしこしこと書いている訳ですが、例外制御をどうしようかずっと悩んでいました。

今まではどちらかというと例外制御があまり必要でないプログラムっていうんですかね。
いわゆるパーツ類の作成が多かったのでちゃんとした例外処理はメインプログラムにまかせて、パーツ類はとにかく処理全体をtry-catchで囲ってcatchはExceptionでひとまとめに例外処理をするって方法でかなりおおざっぱにやっていたのですが、今回は入力フォームの作成なのであまりおおざっぱに作ると後で苦労すると思い、これぞ例外制御っていう手法を探していたのですが例外制御の手法として参考になりそうなブログがありました。

.NETの例外処理 Part.1 - とあるコンサルタントのつぶやき - Site Home - MSDN Blogs
.NETの例外処理 Part.2 - とあるコンサルタントのつぶやき - Site Home - MSDN Blogs
.NETの例外処理 Part. 3 - とあるコンサルタントのつぶやき - Site Home - MSDN Blogs

今まではtry-catchかtry-catch-finallyってやる事しか考えていなかったのですが、局面によってtry-catchとtry-finallyを使い分けるのがいいやり方みたいです。
try-catch ブロックは

・例外が発生しうる『1 行』のみ(囲っても2〜3行程度←こういうケースもあるだろうという想像を含む)を囲む。
・一般例外(Exception クラス)ではなく、特定の例外(SqlException など)のみを捕捉する。
・catch した後には、必ず後処理(業務エラーへの変換など)を記述する。

一方、try-finally ブロックは

・try-finally ブロックは、アプリケーション全体を囲む。
・一般例外(Exception クラス)すべてに対して有効になるように記述する。
・catch ブロックは書かない。

っていうのを気をつけて使うのがいいみたい。

あと別にwikiにも例外処理の設計ガイドなるものが。
MSDN:例外処理の設計ガイド(要約) - isla-plata.org Wiki
こっちには自前の例外クラスの設計思想が記載されていました。

クラス名は末尾にExceptionをつけること
コンストラクタを以下のように3つ作るのが望ましい

デフォルトコンストラクタ(空)
文字列1つ(メッセージ)を引数に持つコンストラクタ
文字列一つ(メッセージ)と、ラップする例外を引数に持つコンストラクタ

自分が担当しているシステムは元々大きなシステムベンダーに作って貰ったんだけど、そのベンダーも自前例外クラスを作っていてソースみたけど例外の種類によって○○ExceptionだのxxExceptionだのクラスが5つか6つくらいあって、そのどれもが「どうやって使い分けてるんだ!?」ってくらいコンストラクタが(たしか20個くらい)あって、でもこれがデファクトスタンダードなんだろうって思い込んでたんだけど、そうでもないって事がわかっただけでも収獲かな。

何はともあれ例外処理の実装をしてみる事にします。

JavaScriptで入力フォームのマウス右クリック、コピー、ペーストを制御するには

投稿者:yasu 更新日時:2010年8月4日 10時40分40秒
カテゴリプログラム
タグ

入力フォームの改修でメールアドレスの再入力項目を追加する事になりそうです。
できれば再入力項目なのでメールアドレスをコピー&ペーストできないようにしたいところ。

そこでJavaScriptで制御できないか調べてみました。

<html>
<head>
<title>キーイベント</title>
</head>
<body>
<form>
マウス右クリック禁止、コピー禁止、ペースト禁止<br>
<input type="text" oncontextmenu="return false;" oncopy="return false;" onpaste="return false;">
</form>
</body>
</html>

inputタグに記載した
oncontextmenu="terurn false;" はマウスの右クリックを禁止します。
oncopy="return false;" はコピーを禁止します。
onpaste="return false;" はペーストを禁止します。

OS/Browser IE6 IE7 IE8 Firefox3.6 Safari4 Safari5 Google
Chrome5
Opera10 Opera
Mini5
Windows XP
Windows Vista
Windows 7
Mac OS X 10.6
Ubuntu 10.04
iOS4 × ×
Android2.1(※1) × ×

○・・・マウス右クリック禁止、コピー禁止、ペースト禁止全て制御可能
△・・・マウス右クリック禁止、コピー禁止、ペースト禁止一部制御可能
×・・・マウス右クリック禁止、コピー禁止、ペースト禁止全て制御不可
※1・・・Android2.1に標準インストールされているブラウザはSafariと同じWebKitベースなのでSafariの欄に制御状況を記載

PCのIE、Firefox、Safari、Google Chromeは制御可能でOperaはマウス右クリックだけ制御可能でした。
またiOSやAndroidのSafari、Opera Miniはコピー・ペーストとも制御不可でした(タッチパネルの為、右クリックはイベント制御不可)。

DOSのバッチファイルでカレントディレクトリを取得するには

投稿者:yasu 更新日時:2010年2月6日 0時44分18秒
カテゴリプログラム
タグ

DOSのバッチファイルでカレントディレクトリを取得するには

%CD%

で取れます。

JSONPを試してみる

投稿者:yasu 更新日時:2009年10月17日 22時39分41秒
カテゴリプログラム
タグ

JSONPを試してみました。
JSONPとは - はてなキーワード

まずサーバー側の実装をPHPで作ります。
QueryStringのp1とp2を足し算して答えを返すプログラムです。
jsonp.php

<?php
	$param1 = $_GET["p1"];
	$param2 = $_GET["p2"];

	$ret = $param1 + $param2;

	echo "callback($ret);";
?>

ポイントは最後の「echo "callback($ret);";」です。
クライアントのJavaScriptからjsonp.phpを呼び出すので返り値「"callback($ret);";」をJavaScriptで解釈できるようにしてあげます。

次にクライアント側の実装をHTMLとJavaScriptで実装します。
テキストボックスを2つ作って答えボタンをクリックすると答えボタンの下のspanタグに答えを返すようにします。
jsonp.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
    <title>jsonpのテスト</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="content-type" content="text/html; charset=Shift-JIS">
	<meta http-equiv="Content-Script-Type" content="text/javascript">
	<meta http-equiv="Content-Style-Type" content="text/css">
	<script type="text/javascript" src="jsonp.js"></script>
</head>
<body>
	<form action="#" method="get">
		<p><input id="p1" type="text"></p>
		<p><input id="p2" type="text"></p>
		<p><input id="retAnswer" type="button" value="答え" onclick="calljsonp()"></p>
	</form>
	<span id="answer"></span>
</body>
</html>

jsonp.js

function callback(val) {
	document.getElementById("answer").innerHTML = val;
}

function calljsonp() {
	var script = document.createElement('script');
	var p1 = document.getElementById('p1').value;
	var p2 = document.getElementById('p2').value;

	script.type = "text/javascript";
	script.charset = "UTF-8";
	script.src = 'jsonp.php?p1=' + p1 + '&amp;amp;amp;p2=' + p2;
	document.body.appendChild(script);
}

calljsonp関数でサーバー側のPHPを呼び出します。
例えば1と2を入力して答えボタンを押した場合、「"callback(3);";」という文字列がクライアントに返ってきます。
するとJavaScriptとして解釈されるのでcallback関数が動き出します。
callback関数は引数として受け取った3をspanタグにセットしています。

ということで結果はこちら。
スクリーンショット(2009-10-16 22.50.28)

theadタグ、tbodyタグ、tfootタグを調べていて

投稿者:yasu 更新日時:2009年10月15日 23時06分16秒
カテゴリプログラム
タグ

theadタグ、tbodyタグ、tfootタグの用途っていったいなんだろうって事で調べていたら、theadタグ部は固定でtbodyタグ部だけスクロールすることができるっていうのを始めて知った。

Tableのヘッダ(thead)を固定して、

内をスクロールさせる方法 » 株式会社ジラフィー(Giraffy) :: ソフトウェア開発・ウェブデザイン

Firefox3.5ではtbodyタグ部だけ綺麗にスクロールできた。
IE6〜8はスクロールした内容がtheadタグ部に突き抜けてしまうのでぎりぎりセーフみたな感じだったな。

また一つ勉強になった。

JavaScriptで数値をランダムに発番(Math.random())

投稿者:yasu 更新日時:2009年10月5日 22時42分52秒
カテゴリプログラム
タグ

JavaScriptで数値(この例では0から9)をランダムに発番するプログラムを書いてみました。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>ランダム関数</title>
</head>
<body>
<script type="text/javascript">
<!--
	var MAXNUM = 10;
	var CurNUM;
	var t = new Array(MAXNUM - 1);
	var breakFlg;

	for (i=0; i<maxnum; i++) {
		t[i] = 0;
	}
	for (;;) {
		CurNUM = Math.floor(Math.random() * MAXNUM);
		for (;;) {
			if (t[CurNUM] == 0) {
				t[CurNUM] = 1;
				document.write(CurNUM + "<br />");
				break;
			} else {
				CurNUM += 1;
				if (CurNUM >= MAXNUM) {
					CurNUM = 0;
				}
			}
		}

		breakFlg = 1;
		for (i=0; i<maxnum; i++) {
			if (t[i] == 0) {
				breakFlg = 0;
				break;
			}
		}
		if (breakFlg == 1) break;
	}
//-->
</script>
</body>
</html>

まず18行目の「Math.random()」ですが0以上1未満のランダムな浮動小数点を返します。
これに発番したい範囲のMAXの数値を掛け合わせた数値を「Math.floor()」の引数に渡すことで小数点以下の数値を切り捨てた数値を返してくれます。

19行目〜30行目で1度発番した数値にフラグを立てて同じ数値を2度発番しないようチェックしています。また同じ数値を発番した場合は+1して同じ数値を発番していないかチェックしています。

32行目〜39行目は全部の数値を発番したかチェックしています。

こういったユニークにランダムな数値を発番するロジックってどうするのが正解なんですかね?

正しい結果は得られましたが、0
から10万とか100万になっても数秒で実行できるロジックにしたいです。
もう少し調べてみようかと思います。

Windows Script Host(WSH)からtar32.dllを実行してtarファイルを圧縮・解凍する

投稿者:yasu 更新日時:2008年12月16日 18時44分00秒
カテゴリプログラム
タグ

Windowsのコマンドラインでバッチ処理を作るときに意外と困るのがファイルの圧縮・解凍で、Windows標準機能ではcabファイルしか取扱いできません。
WindowsXPやWindowsServer2003以降だとWindowsの標準機能でzipファイルの取扱いができるようになりましたが、それもエクスプローラ上などUIが必要でコマンドラインから圧縮・解凍可能なのはcabファイルだけです。
先日もサーバからダウンロードしたtar形式のファイルを解凍するバッチを作る事になったのですがWindowsの標準機能では解凍できません。
今回作成しようとしている、tarファイル解凍バッチはバッチ処理用サーバーOS上で動かす必要があり、安易にコマンドラインに対応している外部のアーカイバもインストールできません。
そこで試行錯誤した結果、吉岡 恒夫さんの作られたtar32.dllをWindows Script Host(WSH)で実行してtarファイルを解凍する方法をご紹介します。

まず今回作業するフォルダとして C:Worktar-test を作ります。

次に上記サイトのTAR32.DLL Ver2.xx(最新版) のDLL単体からtar32.dllをダウンロードして、C:Worktar-testフォルダに保存します。

次に適当に複数のファイルを圧縮したtar形式のファイルを準備してC:Worktar-testフォルダに保存します。
※圧縮するファイルは何でもいいです。

次にtar32.dllを実行してファイルを解凍するWSHを作ります。
C:Worktar-testフォルダにtar.jsというファイル名で保存します。


// WSH版tarコマンド
//
//  第一引数 オプション
// 第二引数 ファイル名
//
//

var objWshShell;
var objExecCmd;

if (funcParamCheck()) {
 try {
  objWshShell = WScript.CreateObject(&quot;WScript.Shell&quot;);
  objExecCmd = objWshShell.Exec(&quot;rundll32.exe C:\Work\tar-test\tar32.dll, TarCommandLine &quot; + WScript.Arguments(0) + &quot; &quot; + WScript.Arguments(1));
 } catch(e) {
  WScript.ECho(&quot;tarコマンド失敗!&quot;);
 } finally {
  objWshShell = null;
  objExecCmd = null;
 }
}

function funcParamCheck() {

 if (WScript.Arguments.Unnamed.Length == 0) {
  WScript.Echo(&quot;オプションの指定がありません。&quot;);
  return false;
 }
 if (WScript.Arguments.Unnamed.Length == 1) {
  WScript.Echo(&quot;ファイルの指定がありません。&quot;);
  return false;
 }

 return true;

}

ポイントとしては[rundll32.exe]というdllを実行する実行ファイルを使ってtar32.dllを実行しtarファイルを解凍しています。
またコマンド実行時にパラメタとしてtarコマンドのオプションとファイル名を受け取りtarファイルの圧縮・解凍ができるようにしました。

ここまでの準備でC:Worktar-testフォルダにはtar.js、test.tar、tar32.dllの3つのファイルが格納されているかと思います。

さてtarファイルの解凍ですが、コマンドプロンプトから以下のように入力します。

 cd worktar-test
 cscript tar.js xzvf test.tar

これでtest.tarファイルが解凍されたはずです。

またこの解凍したxmlファイルを別のtarファイルで再圧縮する場合は

 cd worktar-test
 cscript tar.js cvf "xml.tar *.xml"

これでxml.tarファイルができあがりました。

この後tar.jsの第一パラメタに「tvf」を渡してファイルの一覧を表示しようと思ったのですが、一覧は返ってきませんでした。

原因はわからなかったのですが、恐らくrundll32.exe経由でtar32.dllを実行している為だと思われます。
正しく圧縮できたか任意のアーカイバでtarファイルの中を参照して確認してみてください。

今度はWindowsXPやWindowsServer2003以降のWindowsOSで標準搭載されているzipファイルの圧縮・解凍をWSHで実装してみたいと思います。
恐らく今回同様rundll32.exeを使ってできるのではないかと思いますが、それは次回のお楽しみということで。

でわ!

サイボウズのスケジュールをWindows Mobile(Advanced/W-ZERO3 [es])に自動同期した時の削除済みアイテムに残った予定を自動削除する

投稿者:yasu 更新日時:2008年12月8日 19時06分00秒
カテゴリプログラム
タグ

前回サイボウズのスケジュールをOutlook2003を経由してWindows Mobile(Advanced/W-ZERO3[es])に自動同期する方法をご紹介しましたが、手順6でご紹介したWSHだとOutlookの削除済みアイテムに削除した予定が残ってしまっておりました。
OutlookはあくまでサイボウズとWindows Mobile(Advanced/W-ZERO3[es])のスケジュール橋渡し的な用途としているので、この際WSHで削除済みアイテムも全削除したいと思います。
※Outlookをメインのメーラーとして使われている方は削除済みアイテムが空になってしまいますので、導入しない方がいいかもしれません。

// 定数宣言
var olSave = 0;
var olAppointmentItem = 1;
var olFolderDeletedItems = 3;
var olFolderCalendar = 9;

var adTypeText = 2;
var adCRLF = -1;
var adReadLine = -2;

var strFileName = "C:\cybozu2ical-0.32\Cybozu.ics";

var strBuf;
var intReadFlg;
var strStartDate;
var strStartTime;
var strEndDate;
var strEndTime;
var strTitle;
var strBody;
var strBreakStartDate = "0";
var strBreakStartTime = "0";
var strBreakEndDate = "0";
var strBreakEndTime = "0";
var strBreakTitle = "0";
var strBreakBody = "0";

// Outlook用オブジェクト
var objOl = new ActiveXObject("Outlook.Application");
var objNs = objOl.GetNamespace("MAPI");
var objFd = objNs.GetDefaultFolder(olFolderCalendar);
var objDust = objNs.GetDefaultFolder(olFolderDeletedItems);
var objItems = objFd.Items;
var objDItems = objDust.Items;
var objAppo;

try {
 // 予定表を全削除
 var i = 1;
 while (objItems.Count >= i) {
  objAppointment = objItems(i);
  if (getYYYYMMDD(String(objItems(i).Start)) < getYYYYMMDD()) {
   i++;
  } else {
   objItems(i).Delete();
   objItems = objFd.Items;
   i = 1;
  }
 }

 // 削除済みアイテム全削除
 objDItems = objDust.Items;
 while (objDItems.Count >= 1) {
  objDItems(1).Delete();
  objDItems = objDust.Items;
 }

 // iCalファイルを読込み、予定表に書込み
 intReadFlg = 9;

 var objStream = OpeniCalFile(strFileName);
 do {
  strBuf = objStream.ReadText(adReadLine);

  if (strBuf == "BEGIN:VEVENT") {
   intReadFlg = 1;
  } else if (strBuf == "END:VEVENT") {
   intReadFlg = 0;
  } else if (strBuf == "BEGIN:VTIMEZONE") {
   intReadFlg = 9;
  }

  if (intReadFlg == 1) {
   // 予定開始日
   if (strBuf.indexOf('DTSTART;TZID=Asia/Tokyo', 0) >= 0) {
    strStartDate = strBuf.substring(strBuf.indexOf(":", 0) + 1, strBuf.indexOf("T", strBuf.indexOf(":", 0) + 1));
    strStartTime = strBuf.substring(strBuf.indexOf("T", strBuf.indexOf(":", 0)) + 1);
   } else if (strBuf.indexOf('DTSTART;VALUE=DATE', 0) >= 0) {
    strStartDate = strBuf.substring(strBuf.indexOf(":", 0) + 1);
   }
   // 予定終了日
   if (strBuf.indexOf('DTEND;TZID=Asia/Tokyo', 0) >= 0) {
    strEndDate = strBuf.substring(strBuf.indexOf(":", 0) + 1, strBuf.indexOf("T", strBuf.indexOf(":", 0) + 1));
    strEndTime = strBuf.substring(strBuf.indexOf("T", strBuf.indexOf(":", 0)) + 1);
   } else if (strBuf.indexOf('DTEND;VALUE=DATE', 0) >= 0) {
    strEndDate = strBuf.substring(strBuf.indexOf(":", 0) + 1);
   }
   // タイトル
   if (strBuf.indexOf("SUMMARY:", 0) >= 0) {
    strTitle = strBuf.substring(strBuf.indexOf(":", 0) + 1);
   }
   // 内容
   if (strBuf.indexOf("DESCRIPTION:", 0) >= 0) {
    strBody = strBuf.substring(strBuf.indexOf(":", 0) + 1);
   }
  } else if (intReadFlg == 0) {
   if (strStartDate >= getYYYYMMDD()) {
    if (strBreakStartDate != strStartDate || strBreakStartTime != strStartTime
    || strBreakEndDate != strEndDate || strBreakEndTime != strEndTime
    || strBreakTitle != strTitle || strBreakBody != strBody) {
     objAppo = objOl.CreateItem(olAppointmentItem);
     if (strStartTime != "") {
      objAppo.Start = getYYYYsMMsDD(strStartDate) + " " + getHHMMSS(strStartTime);
     } else {
      objAppo.Start = getYYYYsMMsDD(strStartDate);
     }
     if (strEndTime != "") {
      objAppo.End = getYYYYsMMsDD(strEndDate) + " " + getHHMMSS(strEndTime);
     } else {
      objAppo.End = getYYYYsMMsDD(strEndDate);
     }
     objAppo.Subject = strTitle;
     objAppo.Body = strBody;
     objAppo.ReminderSet = false;

     objAppo.Close(olSave);

     strBreakStartDate = strStartDate;
     strBreakStartTime = strStartTime;
     strBreakEndDate = strEndDate;
     strBreakEndTime = strEndTime;
     strBreakTitle = strTitle;
     strBreakBody = strBody;
    }

    strStartDate = "";
    strStartTime = "";
    strEndDate = "";
    strEndTime = "";
    strTitle = "";
    strBody = "";
   }
  }
 } while(strBuf != "END:VCALENDAR")
 objFile.Close();

} catch (ex) {
} finally {

 if (objStream) objStream = null;
 objDItems = null;
 objItems = null;
 objDust = null;
 objFd = null;
 objNs = null;
 objOl = null;
}

function OpeniCalFile(pFileName) {
 var objStream = new ActiveXObject("ADODB.Stream");
 objStream.Type = adTypeText;
 objStream.Charset = "UTF-8";
 objStream.LineSeparator = adCRLF;
 objStream.Open();
 objStream.LoadFromFile(pFileName);

 return(objStream);
}

function Now() {
 var today = new Date();
 return(today);
}

function getYYYYMMDD(strDate) {
 var today;

 if (strDate) {
  today = new Date(strDate);
 } else {
  today = new Date();
 }
 return(today.getFullYear().toString() + Right("0".toString() + (today.getMonth() + 1), 2).toString() + Right("0".toString() + today.getDate(), 2).toString());
}


function getYYYYsMMsDD(strDate) {
 return(strDate.substring(0, 4) + "/" + strDate.substring(4, 6) + "/" + strDate.substring(6, 8));
}

function getHHMMSS(strTime) {
 return(strTime.substring(0, 2) + ":" + strTime.substring(2, 4) + ":" + strTime.substring(4, 6));
}

function Right(str, n) {
  l = str.length;
  if (n > l) n = l;

  return(str.substring(l - n, l));
}

以前作ったc2o.jsを今回ご紹介したコードに置き換えてください。

これで削除済みアイテムに削除された予定が残らなくなりましたね。

サイボウズのスケジュールをWindows Mobile(Advanced/W-ZERO3 [es])に自動同期する

投稿者:yasu 更新日時:2008年11月21日 19時52分00秒
カテゴリプログラム
タグ

仕事場のスケジュール管理としてサイボウズを使っているのですが、セキュリティの関係上、インターネットに公開しておらず仕事場からでないとスケジュールを確認できません。
サイボウズのスケジュールをcsv形式で出力して、outlookにcsvファイルを手動インポートして、Active Syncで同期してWindows Mobileのスケジュールと同期をとることはできるのですが、めんどくさいです。
できれば手動作業なしにサイボウズのスケジュールをWindows Mobile(Advanced/W-ZERO3 [es])に同期してみたいと思います。

サイボウズからWindows Mobileの予定表にスケジュールを同期させる為には

小川宏高さんの作られたcybozu2icalでサイボウズのスケジュールをiCalendar形式で出力する
出力したiCalendar形式の予定表ファイルをOutlookの予定表に取り込む
Active SyncでOutlookからWindows Mobileの予定に自動同期する

を実施していきます。

1.cybozu2ical動かすのに必要なPerlを導入します。
ActiveStateのサイトから執筆開始日現在(2008年11月12日)最新版のActivePerl-5.10.0.1004-MSWin32-x86-287188.msi をダウンロードします。

ダウンロードが完了したらインストールを開始します。
[Next >]ボタンをクリックします。

[I accept the terms in the License Agreement]にチェックをつけて、[Next >]ボタンをクリックします。

[Next >]ボタンをクリックします。

[Next >]ボタンをクリックします。

[Install]ボタンをクリックします。

インストールが開始されます。

インストールが完了したら、[Display the release notes]のチェックを外して[Finish]ボタンをクリックします。

2.cybozu2icalをダウンロードします。
ダウンロードしたzipファイルは任意の場所に解凍します。
(今回はCドライブ直下に解凍します。)

3.Perl Package Managerを使ってcybozu2icalを動かすのに必要な外部モジュールを導入します。
Cybozu2ICal.ja_JP - Ogawa::Codeにも記載されているのですが

Text::CSV_XS または Text::CSV
DateTime
LWP::UserAgent
Class::Accessor::Fast
Data::ICal
YAML または YAML::Tiny

の6モジュールを追加します。
[スタート]-[プログラム]-[ActivePerl 5.10.0 Build 1004]-[Perl Package Manager]をクリックします。
Perl Package Managerが起動したらメニューバーの[View]-[All Packages]を選択して[F5]キーをクリックします。
未導入のモジュールが表示されますので対象のモジュールを選択して右クリックし[Install ライブラリ名 バージョン]をクリックします。
なお

Text-CSV_XS
LWP::UserAgent
Class::Accessor::Fast

は初期導入済みなのでそれ以外を選択していきます。

このままではモジュールが導入されていませんので、メニューバーの[File]-[Run Marked Actions]を選択します。
導入前の確認ダイアログが表示されるので[OK]ボタンをクリックします。

これで必要な外部モジュール導入は完了しました。

4.cybozu2icalの設定ファイルを設定します。
C:cybozu2ical-0.32にあるconfig.yaml.sampleファイルを同じフォルダにコピーしてconfig.yamlに名前を変えます。
テキストエディタでconfig.yamlファイルを開きます。
設定は適時変更します。

cybozu_url
サイボウズオフィスのURLを指定します。
calname
カレンダー名を指定します。X-WR-CALNAMEヘッダを利用するiCalendarアプリでは、ここで指定した文字列がカレンダーの名前として利用されることが期待されます。
username, userid
サイボウズオフィスのユーザ名もしくはユーザIDを指定します。
password
サイボウズオフィスのパスワードを指定します。
time_zone
サイボウズオフィスのTimeZoneを指定します(例: Asia/Tokyo)。
tzname
サイボウズオフィスのTimeZoneを指定します(例: JST)。
input_encoding
サイボウズオフィスのcharsetを指定します。デフォルトは「shiftjis」。
output_encoding
出力するiCalendarファイルのcharsetを指定します。デフォルトは「utf8」。マルチバイト文字を数値文字参照で出力する場合には「ncr」を指定します。
calendar_driver
使用するカレンダードライバーを指定します。
デフォルトでは「ApiCalendar」が使われます。
現在のところ、カレンダードライバーとしてApiCalendarとSyncCalendarの
2つが使用できます。
サイボウズオフィス6を使用している場合には
SyncCalendarを指定することを強く勧めます。
それ以外の場合はデフォルトで問題ありません。
date_range (experimental)
カレンダーの日付レンジを指定します。
date_range にNを指定すると、今日のN日前からN日後までの
日付レンジのアイテムのみをサイボウズオフィスから取得して処理します。
デフォルトの date_rangeは「30」です。
この機能はカレンダードライバーとしてApiCalendarを指定している場合のみ有効です。

なお自分が変更したのは

cybozu_url: 職場のサイボウズのURL
calname: 何でもいいはず(Cybozu6とかにしました)
username: コメント化(#username)
userid: コメントを解除してユーザID(ユーザIDはスケジュールで自分の名前のリンクをクリックすると表示されます)
password: ログイン時のパスワード

です。
それ以外は変更していません。

5.cybozu2icalを実行する。
コマンドプロンプトから
perl cybozu2ical-0.32cybozu2ical --output cybozu2ical-0.32Cybozu.ics
と入力して実行すると、--outputに指定したファイル名でスケジュールが出力されます。
このスケジュールファイルはGoogle カレンダーやMacのiCal、mozillaのSunbirdなど多くの
スケジュール管理ソフトにインポート可能です。

6.出力したスケジュールファイルをOutlookに取り込むWSHを作成します。

// 定数宣言
var olSave = 0;
var olAppointmentItem = 1;
var olFolderCalendar = 9;

var adTypeText = 2;
var adCRLF = -1;
var adReadLine = -2;

var strFileName = 'C:\cybozu2ical-0.32\Cybozu.ics';

// 変数宣言
var strBuf;
var intReadFlg;
var strStartDate;
var strStartTime;
var strEndDate;
var strEndTime;
var strTitle;
var strBody;
var strBreakStartDate = '0';
var strBreakStartTime = '0';
var strBreakEndDate = '0';
var strBreakEndTime = '0';
var strBreakTitle = '0';
var strBreakBody = '0';

// Outlook用オブジェクト
var objOl = new ActiveXObject('Outlook.Application');
var objNs = objOl.GetNamespace('MAPI');
var objFd = objNs.GetDefaultFolder(olFolderCalendar);
var objItems = objFd.Items;
var objAppo;

// システム日付以降の予定表を削除
try {
	var i = 1;
	while (objItems.Count >= i) {
		objAppointment = objItems(i);
		if (getYYYYMMDD(String(objItems(i).Start)) < getYYYYMMDD()) {
			i++;
		} else {
			objItems(i).Delete();
			objItems = objFd.Items;
			i = 1;
		}
	}

	intReadFlg = 9;

	var objStream = OpeniCalFile(strFileName);

	do {
		strBuf = objStream.ReadText(adReadLine);

	    if (strBuf == 'BEGIN:VEVENT') {
			intReadFlg = 1;
		} else if (strBuf == 'END:VEVENT') {
			intReadFlg = 0;
		} else if (strBuf == 'BEGIN:VTIMEZONE') {
			intReadFlg = 9;
		}

		if (intReadFlg == 1) {
			// 予定開始日
			if (strBuf.indexOf('DTSTART;TZID=Asia/Tokyo', 0) >= 0) {
				strStartDate = strBuf.substring(strBuf.indexOf(':', 0) + 1, strBuf.indexOf('T', strBuf.indexOf(':', 0) + 1));
				strStartTime = strBuf.substring(strBuf.indexOf('T', strBuf.indexOf(':', 0)) + 1);
			} else if (strBuf.indexOf('DTSTART;VALUE=DATE', 0) >= 0) {
				strStartDate = strBuf.substring(strBuf.indexOf(':', 0) + 1);
			}
			// 予定終了日
			if (strBuf.indexOf('DTEND;TZID=Asia/Tokyo', 0) >= 0) {
				strEndDate = strBuf.substring(strBuf.indexOf(':', 0) + 1, strBuf.indexOf('T';, strBuf.indexOf(':', 0) + 1));
				strEndTime = strBuf.substring(strBuf.indexOf('T', strBuf.indexOf(':', 0)) + 1);
			} else if (strBuf.indexOf('DTEND;VALUE=DATE', 0) >= 0) {
				strEndDate = strBuf.substring(strBuf.indexOf(':', 0) + 1);
			}
			// タイトル
			if (strBuf.indexOf('SUMMARY:', 0) >= 0) {
				strTitle = strBuf.substring(strBuf.indexOf(':', 0) + 1);
			}
			// 内容
			if (strBuf.indexOf('DESCRIPTION:', 0) >= 0) {
				strBody = strBuf.substring(strBuf.indexOf(':', 0) + 1);
			}
		} else if (intReadFlg == 0) {
			if (strStartDate >= getYYYYMMDD()) {
				if (strBreakStartDate != strStartDate || strBreakStartTime != strStartTime || strBreakEndDate != strEndDate ||
					strBreakEndTime != strEndTime || strBreakTitle != strTitle || strBreakBody != strBody) {
					objAppo = objOl.CreateItem(olAppointmentItem);
					if (strStartTime != '') {
						objAppo.Start = getYYYYsMMsDD(strStartDate) + ' ' + getHHMMSS(strStartTime);
					} else {
						objAppo.Start = getYYYYsMMsDD(strStartDate);
					}
					if (strEndTime != '') {
						objAppo.End = getYYYYsMMsDD(strEndDate) + ' ' + getHHMMSS(strEndTime);
					} else {
						objAppo.End = getYYYYsMMsDD(strEndDate);
					}
					objAppo.Subject = strTitle;
					objAppo.Body = strBody;
					objAppo.ReminderSet = false;

					objAppo.Close(olSave);

	                strBreakStartDate = strStartDate;
					strBreakStartTime = strStartTime;
					strBreakEndDate = strEndDate;
					strBreakEndTime = strEndTime;
					strBreakTitle = strTitle;
					strBreakBody = strBody;
				}

	            strStartDate = '';
				strStartTime = '';
				strEndDate = '';
				strEndTime = '';
				strTitle = '';
				strBody = '';
			}
		}
	} while(strBuf != 'END:VCALENDAR')
	objFile.Close();

} catch (ex) {
} finally {
	if (objStream) objStream = null;
	objItems = null;
	objFd = null;
	objNs = null;
	objOl = null;
}

function OpeniCalFile(pFileName) {
	var objStream = new ActiveXObject('ADODB.Stream');
	objStream.Type = adTypeText;
	objStream.Charset = 'UTF-8';
	objStream.LineSeparator = adCRLF;
	objStream.Open();
	objStream.LoadFromFile(pFileName);

	return(objStream);
}

function Now() {
	var today = new Date();
	return(today);
}

function getYYYYMMDD(strDate) {
	var today;

	if (strDate) {
		today = new Date(strDate);
	} else {
		today = new Date();
	}

	return(today.getFullYear().toString() + Right('0'.toString() + (today.getMonth() + 1), 2).toString() + Right('0'.toString() + today.getDate(), 2).toString());
}

function getYYYYsMMsDD(strDate) {
	return(strDate.substring(0, 4) + '/' + strDate.substring(4, 6) + '/' + strDate.substring(6, 8));
}

function getHHMMSS(strTime) {
	return(strTime.substring(0, 2) + ':' + strTime.substring(2, 4) + ':' + strTime.substring(4, 6));
}

function Right(str, n) {

	l = str.length;
	if (n > l) n = l;

    return(str.substring(l - n, l));
}

仕様としましてはこのWSHを実行した日以降(実行日含む)の予定を一度削除してスケジュールファイルの予定を取り込み直します。
あとエラーハンドリングはほとんどやっていません(汗
これは今後の課題ですね。
今回はC:cybozu2ical-0.32c2o.jsに保存します。

7.サイボウズスケジュールファイル出力とスケジュールファイルをOutlookに取り込みバッチを作って実行します。

cd cybozu2ical-0.32perl cybozu2ical --output Cybozu.icscscript c2o.js

バッチファイルはWindowsのタスクで定期実行するようにしておけばバッチリです。

8.WindowsXPを使っているので、Active Syncをダウンロードしてインストールします。
ダウンロードが終了したらsetup.msiファイルをダブルクリックします。
インストーラーが起動しますので、[次へ]ボタンをクリックします。

[使用許諾契約書の内容に同意します]を選択して、[次へ]ボタンをクリックします。

[次へ]ボタンをクリックします。

[次へ]ボタンをクリックします。

[インストール]ボタンをクリックします。

インストールが開始されます。

インストールが終了したら、[終了]ボタンをクリックします。

※Windowsの再起動を求められたら再起動します。

9.パソコンとWindows Mobile機をUSBで繋ぎます。
すると同期セットアップ ウィザードが起動しますので、[次へ]ボタンをクリックします。

[次へ]ボタンをクリックします。

パソコンとWindows Mobile機で同期を取る情報を選択します。
ここでは「予定表」以外はチェックを外します。

「デバイスがコンピュータに接続されている間の無線データ接続(MMS またはインターネット電話など)を許可します」にチェックを入れて、[次へ]ボタンをクリックします。

[完了]ボタンをクリックします。

するとActiveSyncが起動し、予定表の同期が始まります。

どうでしょうか?
手順が少し長いですが、ここまでやっておけばサッとWindowsMobile機を取り出して予定が確認できますネ。