Visual Studio 2005 Term Suite Beta 2 を使ってみる

SPECIAL


Visual Studio 2005 Term Suite Beta 2

Microsoft 社の MSDN Enterprise Subscription に加入していたのですけど、ある日 Visual Studio の評価版である Visual Studio 2005 Term Suite Beta 2 が届けられてきました。

それまでは Visual Studio .NET 2002 や 2003 も利用していなかった訳ではないのですけど、ちょうど意欲を失っていた時期でもあったので、主に Visual Studio 6.0 を利用していました。意欲は徐々に戻っては来ていたのですけど、Visual Studio .NET の 2002 も 2003 も、Visual Studio 6.0 とは内部的にもだいぶ様変わりしていたことと、COM コンポーネント周りで何かと挙動が怪しかったりしたため、根気が続かず結局ずいぶんと遠ざかってしまってました。

 

COM コンポーネントの挙動不審については、IDL 属性サポートでコンパイルすると optional 指定の省略可能引数を VBScript から省略することが出来ないといった程度のようでしたけど、おそらくコーディングが間違っているわけでもないのに、修正される様子もなく放置された状態でした。

IDL 属性のサポートを無くせば Visual Studio 6.0 と同じように動作するようにはなったのですけど、それでも IDL 属性の有無でインターフェイス記載部分の構成がずいぶんと変わってきてしまいます。他にも ATL COM サービスプログラミングにおいても調整しないと正常に動作しないなどの不具合があって、これも .NET 2002 から .NET 2003 まで修正される気配さえない状態だったので、Visual Studio .NET に拭えない不信感を感じていたりしてました。

そのあたりのお話しについては、ATL でサービスプログラムを作ってみる 【失敗版】ATL でサービスプログラムを作ってみる (成功版) 、そして optional 属性がうまく動かない あたりで触れてあります。

ともあれ、Visual Studio 6.0 と Visual Studio .NET との間には、特に ATL 周りの仕様変更があってコードの調整が余儀なくされることと、バイナリレベルでの互換性がなくなって静的ライブラリをコンパイルしなおさなくてはならないなど、不具合が見つかるたびに行ったり来たりという訳にも行かなくて、その状態で試行錯誤をするにはちょっと元気が足りませんでした。

 

そこへ Visual Studio 2005 の Beta 版が送られてきて、そろそろ出るのかな…くらいにしかそのときは捉えてなくて、しばらく放置していたのですけど、でも先日に Visual Studio 2005 の発売日が気になって調べてみたついでに、ふと、Beta 版で作成したソフトウェアはどうなるのだろうかと調べてみると、追加の仕様許諾契約に同意するという条件付で Beta 2 で作成したソフトウェアは配布しても問題ないとの記載を見つけたのでした。

放置していた理由のひとつに、Beta 2 で試してみてもまたやり直しになるんだろうな…っていう感があったのですけど、配布しても良いというくらいなら、少なくともほぼ完成に近いということですよね。そう考えると .NET 2002 が .NET 2003 になったのと同じ感覚で、少なくとも同じ気分で、試すことが出来ます。しかも開発したソフトウェアを一般公開しても良いということは、もし問題なく動いたとしたら、発売を待たずとも Visual Studio 2005 を使って行けるというもの。

これはなかなか、試してみる価値はあるかもしれないです。

 

Go-Live ライセンス許諾契約に承諾する

Microsoft Visual Studio 2005 Beta 2 で開発したアプリケーションを一般に提供するには Microsoft の Go-Live ライセンス登録を行う必要があるとのことです。

この追加ライセンス登録を行うことで、基本的には "プレリリース版を利用しているために正常動作しない場合があることを示す明確な警告" を添えることで、稼働環境への配布を行うことが可能になるようです。ただし .NET Framework 2.0 Beta 2 に関してはアプリケーションとともに配布することは出来ないとのことでした。.NET Framework 2.0 Beta 2 が必要なソフトウェアを配布する場合は、その利用者も Go-Live ライセンスに同意し、.NET Framework 2.0 Beta 2 を自身で導入する必要があるそうです。

詳細については Microsoft 社の Visual Studio 2005 ホームページ のサイトにあるメニューから Go-Live を参照してください。

 

 

Visual Studio 2005 Beta 2 日本語版をインストールしてみる

続いて Visual Studio 2005 Beta 2 のインストールを行ってみます。

インストールする環境は、Visual Studio 6.0 Enterprise Edition および Visual Studio .NET 2003 Enterprise Developer がインストールされている PC です。これは Microsoft Virtual PC 2004 上で動作している Windows XP Professional にインストールされています。

 

CD-ROM ドライブへ "Visual Studio 2005 Term Suite Beta 2 日本語版" の DVD を挿入します。

そして、表示された "Visual Studio 2005 Beta 2 セットアップ" ウィンドウから "Visual Studio 2005 Beta 2 のインストール" をクリックすることで、インストール手続きが始まります。

 

Microsoft Visual Studio 2005 Beta 2 インストールウィザードが起動して、しばらくしたら 「次へ」 ボタンが押せるようになるので次へと手順を進めます。そして使用許諾契約書に同意して、さらに次へと進みます。そして、インストールしたい機能とインストールするフォルダを指定して、あとはインストール作業の完了を待ちます。

なお、今回は個人的な都合で "Visual SourceSafe 2005" と "Microsoft SQL Server 2005 Express Edition" はインストールしないでおきました。

 

インストールが完了すると、"Office 依存関係の警告" なるメッセージが表示されました。

これは Visual Studio 2005 Term Suite Beta 2 に付属している Microsoft Visual Studio Tools for Microsoft Office System の一環として用意されている Microsoft Office 2003 プロジェクトを作成したい場合には、Microsoft Office 2003 SP1 またはそれに相当するコンポーネントが必要だということを示すメッセージでした。

それともうひとつ、Windows Update を実行してシステムを最新の状態にすることをお勧めするとのことでしたので、さっそく Windows Update を行って、最新の更新プログラムがないかどうか確認してみることにします。

そのまえに、セットアッププログラムを終了したときに再起動を求められたので、まずは PC の再起動を行いました。

 

再起動を終えてみると、再び "Visual Studio 2005 Beta 2 セットアップ" ダイアログが起動したので、まずはそこから製品ドキュメントのインストールを行っておくことにしました。そしてこれは特に難しいことはなく、手順通りに進めることで "MSDN Library for Visual Studio 2005 Beta 2" のインストールは完了しました。

そして "Service Release の有無を調べる" をクリックしてみると、Microsoft Update のサイトへと接続されました。

「カスタム」 ボタンを押して最新の更新プログラムをチェックしてみましたけど、更新プログラムは特にない様子だったので、これで Visual Studio 2005 Beta 2 のインストール作業は完了です。

 

optional 属性を持った COM を作成してみる

インストールしたばかりの Visual Studio 2005 Beta 2 を使って、さっそく COM コンポーネントを作成してみようと思います。

インストールウィザードで Visual C++ の説明を見たときに IDL 属性のサポートをうたった紹介文が表示されていたので、きっと問題なく動作してくれることでしょう。というか、Visual Studio .NET 2003 までで動作しなかったのがようやく改善されて、それが前面に押し出されたような気がしてならないのですけど…。

ともあれ、IDL 属性を有効にして、optional 属性を使用した COM コンポーネントの作成を行ってみます。

 

TestCom コンポーネントの作成

Microsoft Visual Studio 2005 Beta 2 を起動して、TestCom という名前の "ATL プロジェクト" を作成します。

すると "ATL プロジェクトウィザード" が起動するのですけど、まず始めに、現在のプロジェクト設定が "非属性" に設定されているのが気になりました。Visual Studio .NET 2003 では "属性" が標準であったにも関わらず正常に動かなかったのが、今回はディフォルトで "非属性" でした。なんだかどちらがお勧めなのか良く判らないですね。まだ試験段階なのでしょうか…、なんだか不安なところです。

ともあれ "アプリケーションの設定" をクリックして 「属性」 チェックボックスを ON にして、属性を有効にしてみます。

 

ITestInterface インターフェイスの作成

そして、まずは ITestInterface インターフェイスを作成します。

プロジェクト名 "TestCom" 上で右クリックして、【追加】 から 【クラス】 を選択します。そして "ATL" から "ATL シンプル オブジェクト" を選択します。そして "短い名前" のところへ "TestInterface" と入力すれば、その他の必要事項が自動的に埋め合わされます。"オプション" については今回はディフォルトの設定で作成してみることにします。

 

 

投げ出した当時は Visual Studio .NET (2002) だったのですけど、今はいつのまにか MSDN で手に入れた Visual Studio .NET 2003 です。

もし仮にバグだったとしたならば、こっそり修正が入って、普通に使えるようになっているはず…。そんな淡い期待とともに、次のような TestCom という COM コンポーネントを Visual C++ で作成してみます。

// ITestInterface

[

object,

uuid("AD708034-3127-4A3E-A863-BAC0BE45A3FC"),

dual, helpstring("ITestInterface インターフェイス"),

pointer_default(unique)

]

__interface ITestInterface : IDispatch

{

};

 

// CTestInterface

[

coclass,

default(ITestInterface),

threading(apartment),

vi_progid("TestCom.TestInterface"),

progid("TestCom.TestInterface.1"),

version(1.0),

uuid("6C760E85-674F-4223-965A-30A5F8407FCD"),

helpstring("TestInterface Class")

]

class ATL_NO_VTABLE CTestInterface :

public ITestInterface

{

public:

CTestInterface()

{

}

 

DECLARE_PROTECT_FINAL_CONSTRUCT()

 

HRESULT FinalConstruct()

{

return S_OK;

}

 

void FinalRelease()

{

}

 

public:

 

};

すると、上記の様なコードを持ったソースファイルが出来上がりました。

今までと違う点と言うと、"default(ITestInterface)" という指定がなされているというところと、"threading(apartment)" の apartment の部分が引用符でくくられなくなったという感じでしょうか。とりあえず、属性まわりに調整は加えられているようです。

 

では "TestInterface" に、"ReturnString(BSTR)" と "ReturnStringOptional(VARIANT)" の二つのメソッドを実装してみます。

"ITestInterface" 上で右クリックして 【追加】 から 【メソッド】 を選択します。そして名前とともに、どちらとも [in] 属性を指定した引数 message と、[out, retval] 属性を指定した引数 pResult を登録します。

引数の型は、ReturnString メソッドの方は BSTR 型で、ReturnStringOptional メソッドの方は VARIANT 型とします。これは [optional] 指定を行うためには、その型が VARIANT 型でないといけないはずな為です。また、戻り値の型は "*" をつけてポインタ指定とします。

 

すると "TestCom.TestInterface.1" のヘッダー部分に、次のようなコードが追加されました。

// ITestInterface

[

object,

uuid("AD708034-3127-4A3E-A863-BAC0BE45A3FC"),

dual, helpstring("ITestInterface インターフェイス"),

pointer_default(unique)

]

__interface ITestInterface : IDispatch

{

[id(1), helpstring("メソッド ReturnString")] HRESULT ReturnString([in] BSTR message, [out,retval] BSTR* pResult);

[id(2), helpstring("メソッド ReturnStringOptional")] HRESULT ReturnStringOptional([in] VARIANT message, [out,retval] VARIANT* pResult);

};

 

// CTestInterface

[

coclass,

default(ITestInterface),

threading(apartment),

vi_progid("TestCom.TestInterface"),

progid("TestCom.TestInterface.1"),

version(1.0),

uuid("6C760E85-674F-4223-965A-30A5F8407FCD"),

helpstring("TestInterface Class")

]

class ATL_NO_VTABLE CTestInterface :

public ITestInterface

{

public:

CTestInterface()

{

}

 

DECLARE_PROTECT_FINAL_CONSTRUCT()

 

HRESULT FinalConstruct()

{

return S_OK;

}

 

void FinalRelease()

{

}

 

public:

STDMETHOD(ReturnString)(BSTR message, BSTR* pResult);

STDMETHOD(ReturnStringOptional)(VARIANT message, VARIANT* pResult);

};

"ReturnStringOptional" メソッドの方には [optional] 属性も付けたいので、ITestInterface 内の記述を次のように、[in] から [in,optional] に修正します。ついでなので "ReturnString" メソッドの方には、[defaultvalue] 属性を指定して引数を省略できるようにしてみます。

// ITestInterface

[

object,

uuid("AD708034-3127-4A3E-A863-BAC0BE45A3FC"),

dual, helpstring("ITestInterface インターフェイス"),

pointer_default(unique)

]

__interface ITestInterface : IDispatch

{

[id(1), helpstring("メソッド ReturnString")] HRESULT ReturnString([in,defaultvalue("--- default ---")] BSTR message, [out,retval] BSTR* pResult);

[id(2), helpstring("メソッド ReturnStringOptional")] HRESULT ReturnStringOptional([in,optional] VARIANT message, [out,retval] VARIANT* pResult);

};

 

そして、メソッド部分の実装です。

コードを記載しようと思って "CTestInterface" の [+] をクリックしても、追加したはずのメソッドが表示されなくて少し困ったのですけど、良くみたら "クラスビュー" が 2 分割されていて、下のほうにメソッド一覧が表示されていました。

それらを使って該当するコード部分へ移動し、次のようなプログラムを実装します。

// TestInterface.cpp : CTestInterface の実装

#include "stdafx.h"

#include "TestInterface.h"


 

// CTestInterface

 

STDMETHODIMP CTestInterface::ReturnString(BSTR message, BSTR* pResult)

{

*pResult = ::SysAllocString(message);

return S_OK;

}

 

STDMETHODIMP CTestInterface::ReturnStringOptional(VARIANT message, VARIANT* pResult)

{

VariantInit(pResult);

 

if (message.vt == VT_ERROR)

{

pResult->vt = VT_BSTR;

pResult->bstrVal = ::SysAllocString(L"--- optional ---");

}

else

{

VariantCopy(pResult, &message);

}

 

return S_OK;

}

ReturnString メソッドは、渡された文字列をそのまま返すメソッドです。ただし [defaultvalue] 属性によって省略時には "--- default ---" という文字列が指定されたのと同じにします。

ReturnStringOptional メソッドは、渡された文字列をそのまま返しますが、文字列が省略された場合には "--- optional ---" という文字列を返します。コードが少しややこしいですけど、[optional] 指定の VARIANT 型は、その値が省略されたときに "VT_ERROR" という値を示すようなので、それを判定して的確な処理を行います。

 

WSH で実験してみる

Debug モードでコンパイルしたら、さっそく、Windows XP Professional 上の WSH で動作実験を行ってみます。実験の仕方は単純で、下記のスクリプトを保存した test.vbs ファイルを実行するだけです。

まずは、そもそも TestCom が正常に動くかどうかのテストです。

' ---- TestCom.TestInterface の作成

Set test = WScript.CreateObject("TestCom.TestInterface.1")

 

' ---- まずは引数を省略せずに呼び出します。

WScript.Echo test.ReturnString("test1")

WScript.Echo test.ReturnStringOptional("test2")

 

' ---- あとしまつ

Set test = Nothing

これを実験してみると、問題なく "test1" と "test2" という文字列が表示されました。

 

では、それぞれの引数を省略してみます。

' ---- TestCom.TestInterface の作成

Set test = WScript.CreateObject("TestCom.TestInterface.1")

 

' ---- まずは引数を省略せずに呼び出します。

WScript.Echo test.ReturnString()

WScript.Echo test.ReturnStringOptional()

 

' ---- あとしまつ

Set test = Nothing

すると…、どちらとも "引数の数が一致していません。または不正なプロパティを指定しています。" というエラーになってしまいました。Visual Studio .NET 2003 のときと同じですね…。

 

これは [optional] の指定方法が間違っているということなのでしょうか。いや、[defaultvalue] も間違っているということになりますね。IDE 属性を使用する場合は何か特別な書き方をしないといけないのか…。

MSDN の IDL 属性のページをみると [optional] も [defaultvalue] も利用可能のように書かれていますし、その用例も特に特殊な様子はみられないのですけど…。なんだか良く判らないです。

 

プロジェクト作成時に設定されているように、IDL 属性は使用しない方を選択しないといけない、と割り切った方が早そうですね。ディフォルトで IDE 属性が OFF になっていれば、なんとなく諦めはつきますし。

個人的には、C++ コード内に属性を含ませた方が、プログラムの構造的にも、そして視覚的にも、けっこう好きなので残念ですけど。

 

IDL 属性を無効にしてコンポーネントを作成する

念のため、IDL 属性を無効にしたら正常に動作するのか確かめてみます。

新しく "TestCom2" という名前で新しく ATL プロジェクトを立ち上げます。このとき IDL 属性のチェックボックスは無効のまま触らないでおきます。そして、上記の "TestCom1" と同じインターフェイスおよびメソッドを、同じ実装コードで記載します。

そして実験してみたところ、[defaultvalue] の方も [optional] の方も、問題なく引数を省略することが出来ました。

 

ATL サービスプログラムを作成してみる

Visual Studio .NET 2002 から 2003 のもうひとつの問題が、ATL によるサービスプログラムを作成しようとしたときに、自動生成されたコードを修正しないといけないというものがありました。

これはどうなっているか、ちょっと実験してみます。

 

IDL 属性を無効のまま ATL サービスを作成してみる

"TestService" という名前で ATL プロジェクトを作成して、アプリケーションの設定にて "サービス (EXE)" を指定します。

そして、そのままプロジェクトをビルドしてみます。ビルドしたサービスは自動的には登録されないようなので、次のようにしてコンピュータへサービスを登録します。

TestService.exe /Service

すると、何も通知はありませんでしたけど、サービスのところに "TestService" が登録されました。そして 「開始」 ボタンを押してみると、次のようなエラーとなりました。

ローカル コンピュータ 上の Test Service サービスは起動して停止しました。パフォーマンス ログ、警告サービスなど、一部のサービスは作業がない場合に自動停止します。

症状だけを見ると、Visual Studio .NET 2003 のときと同じ感じですね…。

 

いったん、次のようにしてサービスを停止しします。

TestService.exe /UnregServer

このときも何も通知はありませんでしたけど、サービスから "TestService" は削除されたようです。

それにしても、オプションのつづりが違っても何も通知がないのでちょっと判りにくいです。以前はたしかダイアログが表示された気がするのですけど…、個人的には標準出力に通知が欲しなとか思ってみたり…。

 

とりあえず .NET 2003 の頃にやってみた解消方法を試してみます。

"CTestServiceModule" クラスに次のようなコードの "PreMessageLoop" 関数と "PostMessageLoop" 関数を実装します。

 

HRESULT CTestService4Module::PreMessageLoop(int nShowCmd)

Run ループの最初で呼び出されるメソッドをオーバーライドします。

HRESULT PreMessageLoop(int nShowCmd)

{

HRESULT hr = __super::PreMessageLoop(nShowCmd);

 

// _ATL_VER の判定は、Visual Studio 2005 の場合は 0x800 を .NET 2003 (VC7.1) の場合は 0x710 を .NET 2002 (VC7.0) の場合は 0x700 を指定します。

#if _ATL_VER == 0x0800

if (SUCCEEDED(hr) && !m_bDelayShutdown) hr = CoResumeClassObjects();

#endif

 

if (SUCCEEDED(hr))

{

// ここにサービスの初期化に必要な処理を書きます

 

}

 

return hr;

}

HRESULT CTestService4Module::PostMessageLoop()

このメソッドは実装上の不足等はないようですけど、重要なのでオーバーライドしておきましょう。この関数は Handler がサービスの停止 (SERVICE_CONTROL_STOP) を受け取った際に OnStop から呼び出されます。

HRESULT PostMessageLoop()

{

// ここにサービス終了時に必要な後処理を書きます。

 

return __super::PostMessageLoop();

}

そうしてみたところ、今度は正常にサービスを起動することが出来るようになりました。

IDL 属性を有効にしてみる

ATL プロジェクトでサービスを作るときにも IDL 属性の有効化を指定できるようになっていました。

ディフォルトでは "無効" に設定されていましたので、ためしに有効にして作成してみましたけど、やはりそのままの状態だと、同じエラーでサービスは起動し続けることが出来ないようでした。

 

Visual Studio 2005 Beta 2 を使ってみた感想

今までも ATL 周りくらいしか見て来なかったので他はどうなっているか判りませんけど、少なくとも ATL 周りに関して言えば、Visual Studio .NET 2002 の頃から上手く行かなかった 2 つのことが、そのまま放置されている感じですね…。ATL 周りも改善されないということは、もうそういうものだと思って使わなくてはいけないのでしょう。

そもそも今回から IDL 属性の使用はディフォルトで無効になったところをみると、そのままで使ってくれと言っているような気がします。

他の点はと言うと、使い勝手が若干変わってそれに戸惑うくらいを除けば、クラスビューはきっと以前よりも使いやすい気がしますし、見た目もなんとなく落ち着くので、Visual Studio .NET 2002 の代わりと見れば良い感じですので、これからは素直に Visual Studio 2005 を使って行こうと思います。

 

ちなみに Visual C++ のプロジェクトで気になった "CLR" という名称は "Common Language Runtime" の略で、.NET Framework 対応ソフトウェアが動作する実行環境のことなのだそうです。つまり Visual Studio .NET 2003 までは ".NET" と言っていたものみたいです。

それで Visual Studio から .NET の文字が消えたのでしょうか。別に .NET のままで良いと思うんですけどね。

バージョン番号も、各社の製品で言えることですけど、6.0 みたいな数字だったと思ったら、年を表す 2002 とかに変わったり、かと思えば XP とか文字だったり。それでいて内部ではバージョン 8.0 だったりで、バージョンを調べたり比較するだけでも大変だったりして、ころころと変えない方が良いような気がする自分でした。