2008年8月13日水曜日

Zip コンポーネントの ExcludedAttributes について

IP*Works! Zip 製品の Zip コンポーネントには、Config Settings に ExcludedAttributes という項目が用意されており、ファイルの属性を指定してアーカイブ対象から「除外」する機能を提供しています。

ただしこの機能は「除外」にしか利用できません。従って、例えば「アーカイブ属性が付与されているファイルだけを Zip したい」というような用途にはご利用いただけません。

現状では、

・システムのファイルアクセス用関数を用いて必要な属性を持つファイルの一覧を取得し、Files コレクションに各ファイルを設定する。
・あるいは、対象となるフォルダを全て指定して IncludeFiles メソッドを呼び出し Files コレクションを生成する。Compress する前に Files[i].Attributes をチェックし、所定のフラグが設定されていないものを Files コレクションから削除する。その後 Compress を実行する。

のような措置が必要となります。

2008年7月24日木曜日

簡単サーバ

弊社 IP*Works! 製品には幾つかのサンプルが同梱されています。それらの大半は通常どのサイトでもほぼご利用可能なプロトコルを前提として作成されています。

しかし、中には既に古いプロトコルとなってしまい、現在ではサービスがなかなか提供されていないものもあります (Echo サーバや DateTime サーバ等)。

しかし、これらのサンプルは非常にシンプルであり、コンポーネントの動作を理解するにはお手軽で便利なものとなっています。(サーバがあれば、ですが。)

そこで、弊社の UDPPort および IPDaemonを使って非常にシンプルな UDP Echo サーバおよび DateTime サーバを C# 作成してみました。(サービス仕様の詳細に興味のある方は、RFC862 - Echo Protocol および RFC867 - Daytime Protocol をご参照ください。)

●UDPEcho サーバ

クリックすると拡大表示この UDP Echo サーバの UI は非常にシンプルです。ListView が1つと Button が1つだけです。VisualStudio でフォームを作成し、これらをドロップします。名前はそれぞれ既定値の ListView1 および button1 です。続いて UDPPort をフォームにドロップします。こちらも名前は規定値の udpport1 です。この状態で、以下のようなソースを作成します。(VS2005 の場合。) ユーザが定義するのは、ボタンクリックイベントハンドラ button1_Click と、UDPPort の DataIn イベントハンドラ udpport1_OnDataIn のみです。
namespace UDPEchoServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
if (button1.Text.Equals("&Start"))
{
udpport1.Active = false;
udpport1.InvokeThrough = this;
udpport1.LocalPort = 7; // UDP Echo
udpport1.Active = true;
udpport1.AcceptData = true;

button1.Text = "&Stop";
}
else
{
udpport1.Active = false;
button1.Text = "&Start";
}
}

private void udpport1_OnDataIn(object sender, nsoftware.IPWorks.UdpportDataInEventArgs e)
{
ListViewItem newdata = new ListViewItem(new String[] {DateTime.Now.ToString(), e.SourceAddress, e.Datagram});
listView1.Items.Add(newdata);

udpport1.RemoteHost = e.SourceAddress;
udpport1.RemotePort = e.SourcePort;
udpport1.Send(e.DatagramB);
}
}
}
非常にシンプルですね。button1_Click では、サーバ停止状態 (button1.Text が "&Start") であれば、使用するポートを設定し、udpport コンポーネントをアクティブにし、データを受け入れ可能にします。サーバ動作中であれば、サーバを非アクティブにします。動作中にデータを受信すると、udpport1_OnDataIn イベントハンドラが実行されます。ここでは受信したデータグラムの情報をリストビューに表示し、受信したデータをそのまま送信元に返送しています。

次は少し複雑な DayTime サーバを見てみましょう。

●DayTime サーバ

クリックすると拡大表示こちらの DayTime サーバは、UDP/IP と TCP/IP を両方サポートする関係上 UI も少し項目が増えています。情報表示用のリストビュー、プロトコル選択用チェックボックス (UDP TIME と TCP TIME)、返す日時フォーマット選択用のラジオボタン (US 形式か UK 形式か)、そして起動/停止用のボタンです。これらをフォームのドロップした後、UDPPort コンポーネントおよび IPDaemon コンポーネントをフォームにドロップします。今回もユーザが作成しなければならないのは、起動/停止ボタンのクリックイベントハンドラ、UDPPort の OnDataIn イベントハンドラ、および IPDaemon の OnDataIn イベントハンドラのみです。
namespace DayTimeServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void bStart_Click(object sender, EventArgs e)
{
Control[] controls = { chkbUDP, chkbTCP, rbUK, rbUS };

if (bStart.Text.Equals("&Start"))
{
foreach (Control c in controls)
{
c.Enabled = false;
}

if (chkbUDP.Checked)
{
udpport1.Active = false;
udpport1.InvokeThrough = this;
udpport1.LocalPort = 13; // UDP Daytime port
udpport1.Active = true;
udpport1.AcceptData = true;
}
if (chkbTCP.Checked)
{
ipdaemon1.InvokeThrough = this;
ipdaemon1.LocalPort = 13; // TCP Daytime port
ipdaemon1.Listening = true;
}
bStart.Text = "&Stop";
}
else
{
if (chkbUDP.Checked)
{
udpport1.AcceptData = false;
}
if (chkbTCP.Checked)
{
ipdaemon1.Listening = false;
}
foreach (Control c in controls)
{
c.Enabled = true;
}
bStart.Text = "&Start";
}
}

private void udpport1_OnDataIn(object sender, nsoftware.IPWorks.UdpportDataInEventArgs e)
{
DateTime now = DateTime.Now;
ListViewItem newdata = new ListViewItem(new string[] {
now.ToString(), e.SourceAddress, "UDP"
});
listView1.Items.Add(newdata);

String fmt = rbUK.Checked ? "dd MMM yy hh:mm:ss' UTC'" : "dddd', 'MMMM dd', 'yyyy hh':'mm':'ss'-UTC'";
String utcnow = now.ToUniversalTime().ToString(fmt);

udpport1.RemoteHost = e.SourceAddress;
udpport1.RemotePort = e.SourcePort;
udpport1.Send(System.Text.Encoding.UTF8.GetBytes(utcnow+"\r\n"));
}

private void ipdaemon1_OnDataIn(object sender, nsoftware.IPWorks.IpdaemonDataInEventArgs e)
{
DateTime now = DateTime.Now;
ListViewItem newdata = new ListViewItem(new string[] {
now.ToString(), ipdaemon1.Connections[e.ConnectionId].RemoteHost, "TCP"
});
listView1.Items.Add(newdata);

String fmt = rbUK.Checked ? "dd MMM yy hh:mm:ss' UTC'" : "dddd', 'MMMM dd', 'yyyy hh':'mm':'ss'-UTC'";
String utcnow = now.ToUniversalTime().ToString(fmt);

ipdaemon1.Send(e.ConnectionId, System.Text.Encoding.UTF8.GetBytes(utcnow+"\r\n"));

ipdaemon1.Connections[e.ConnectionId].AcceptData = false;
ipdaemon1.Connections[e.ConnectionId].Connected = false;
}
}
}
bStart_Click はサーバの起動と停止を制御します。起動時にはチェックボックスやラジオボタンを無効化して動作中に変更できなくし、またプロトコル選択チェックボックスの状態に応じて UDPPort コンポーネントおよび IPDaemon コンポーネントのインスタンスをアクティブ化します。停止時にはプロトコルの選択状態に応じて対応するコンポーネントを非アクティブ化し、チェックボックスおよびラジオボタンを有効にします。

udpport1_OnDataIn では UDP で受信したデータから得られた送信元に対し、現在時刻を指定されたフォーマットで UDP で返信します。同様に ipdaemon1_OnDataIn では TCP で受信したデータから得られた送信元に対し現在時刻を指定されたフォーマットで TCP で返信します。なお、この DateTime サーバでは、日時は UTC で返すようにしています。

このどちらのサーバも、弊社のデモに対するテスト用サーバとしてご利用いただけます。

2008年7月9日水曜日

IP*Works! 製品の複数バージョンの共存について

殆どの IP*Works! 製品には複数のバージョンが存在しています。
通常は最新バージョンのみをご利用になることが殆どだと思いますが、共有サーバ上に複数の開発部隊がそれぞれの所有しているバージョンを同時にインストールしなければならないようなケースがあります。

この場合、製品によっては異なるバージョンの共存インストールができないものがありますのでご注意ください。基本的には以下のようになります。
  • .NET/Java 系製品は、バージョン間の共存が可能です。プロジェクトごとに参照するバージョンを指定できます。
  • ActiveX 製品は、バージョン間の共存が可能です。
  • Delphi / C++ Builder 製品はバージョン間の共存インストール自体は可能ですが、ツールパレットには1つのバージョンのアイコンしか表示できず IDE そのものが単一のバージョンしか管理できません。利用可能なバージョンはメニューの [コンポーネント] - [インストールパッケージ] で選択します。

その他の製品に関しましては、製品名およびバージョン番号をご明記の上、弊社までお問い合わせください。

なお、バージョン間共存インストールができても、同一プロジェクト内で複数のバージョンのコンポーネントを参照すること (たとえば同一のプロジェクト内で同一製品の V6 と V8 のコンポーネントを混在参照する等) はできませんのでご注意ください。

2008年7月8日火曜日

IPDaemon/IPPort の SendFile(...) と Timeout

IPDaemon や IPPort では、V8 から SendFile(...) メソッドをサポートしています。
これを使うことで、ファイルに格納されたデータをまとめて送信することができ大変便利です。

ただし、IPDaemon や IPPort の設定を既定値のまま SendFile(...) を使用すると IPWorksException (code=702; message="This operation cannot be performed in a non-blocking manner.") が発生してしまいます。

これは、IPDaemon および IPPort では既定値では Timeout は 0 になっており、非同期動作するように構成されているためです。SendFile を使用する際には Timeout 値に適当な正の整数値を指定してからお使いください。

また、IPDaemon では Timeout 値の設定には2つの方法があります。
  • DefaultTimeout プロパティを使用して、全てのコネクションの既定値として設定する方法。こちらの場合は、コネクションの生成前に値を設定しておく必要があります。
  • コネクションごとに Timeout を設定する方法。こちらの場合は、コネクション生成後でも必要に応じて当該コネクションの Timeout フィールドの値を設定・変更することが可能です。

状況に応じてこの2つの方法を使い分けることが可能です。

2008年6月24日火曜日

トライアル版から製品版への移行

弊社製品をご検討頂いているお客様から時々頂くご質問に、

「トライアル版(評価版)で検証した後、製品版に移行するにはどうするのか」
「トライアル版に製品版キー/シリアル番号を適用して製品にしたいがどうするのか」

というものがあります。

弊社のシステムでは、評価版を製品版キー/シリアル番号で制限解除する方法は採用しておりません

製品版の setup.exe を実行し、インストール中に示される手順に従って再インストールして頂く形になります。この手順内で製品版のキーとシリアル番号を要求されますので、ここに入力することにより製品版のライセンスが登録されます。

既に評価版がインストールされている環境の場合、ライセンス情報はこの時点で製品版のものにより置換されます。

製品版 setup.exe は弊社公式サイトの http://www.nsoftware.com/download/ からダウンロードしていただけます。

2008年6月20日金曜日

IPDaemon のイベントとマルチスレッド

以前あったお問い合わせに、

「IPDaemon をメインフォームではないクラスで別スレッドで動作させているのだが、そのクラスに InvokeThrough してもイベントを受け取れない」

というものがありました。私もちょっと気になったので弊社技術者の回答をチェックしてみたところ、以下のような回答がなされていました。

「IPDaemon は非同期に動作するため、イベントは DoEventS() 呼び出しが行われるまで発生しない。これを解決するには、IPDaemon の DoEvents() をプログラムのループ内で明示的に呼び出すか、タイマーを使って (定期的に) DoEvents() を呼び出すようにすることで解決できる」

ちょっと面倒ではありますが、シングルスレッドでは動作していたプログラムをマルチスレッド化してイベントを受け取れなくなった場合はこれをお試しください。

2008年6月18日水曜日

インストール時の "key verification failed" エラー

弊社製品をインストールする際に、製品シリアル番号およびキーを入力すると

"key verification failed (xx)"

のようなエラーが表示されることがあります。これは、入力したデータが実行中のインストーラ (setup.exe) に適合しないものであった場合に発生します。(例: C++ Builder Edition のインストーラで C++ Edition のシリアル番号とキーを使用した、等。)

このエラーが発生した場合は、使用しているインストーラとシリアル番号およびキーが一致しているかどうかをご確認ください。

インストーラの情報は、インストーラ起動時に表示されるスプラッシュ画面をご参照ください。シリアル番号の種別は先頭4バイトで識別されます。

例)

IPN8 - IP*Works! V8 .NET Edition
IPJ8 - IP*Works! V8 Java Edition
ISN8 - IP*Works! SSL V8 .NET Edition
ISJ8 - IP*Works! SSL V8 Java Edition
IZN8 - IP*Works! ZIP V8 .NET Edition
IZJ8 - IP*Works! ZIP V8 Java Edition
IPA6 - IP*Works! V6 ActiveX Edition
ISC6 - IP*Works! SSL V6 C++ Edition