今や、Windowsを使う上でもっとも重要な知識は、OLEの活用方法だろう。ActiveXコントロールやDCOMを使った分散オブジェクト環境の構築などは、すべてOLEをベースにしている。Visual Basic 5.0でも、ActiveXコントロールやActiveX Documentsの作成ができるようになっている。これにともなってOLE関連は大幅な強化がなされている。それらのトピックについて紹介しよう。
酒井 法雄
一言でOLEと言っても、実にたくさんのものがある。以前であれば、OLE Serverとコンテナというシンプルなものであった。Visual BasicはOLEコンテナとしてサーバーを呼び出すためだけに存在していた。Visual Basic 3.0でOLE Automationをサポートしても、これは変わらなかった。
しかし、Visual Basic 4.0と共に、OLEベースのカスタムコントロールとしてOCXが登場し、Visual BasicでもOLE Serverが作れるようになった。これにともない、OLE Serverを作るためのClassモジュールが登場し、オブジェクト指向的な考え方が必要になってきた。また、OLEの基礎的な知識として、インスタンシングの方法やインプロセス、アウトオブプロセスといった概念が入ってきた。
もちろん、OLE ServerをコントロールするVBAや、オブジェクトの階層構造などについても考えなくてはならなくなってきた。さらには、Remote Automaitonを使ったネットワーク対応のn階層システムの構築といった具合に、次第にOLEをベースにしてトピックは増えてきた。これらの詳細については、本誌先月号の特集の中で解説しているので、参考にしてほしい。
そして、Visual Basic 5.0ではOLEをベースにして、次のような新しい機能が追加されている。
従来はOCXと呼ばれていたOLEベースのカスタムコントロールが、インターネット対応になり、ActiveXと呼ばれるようになった。Visual Basic 5.0ではActiveXコントロールを開発可能である。Professional Edition以上では、ネイティブコードコンパイルも可能である。ActiveXコントロールの開発については、すでに本誌でも紹介しているが、次号以降にまとめ直す予定だ。
Active Documentsとも言われる。これは、Webブラウザ(IE3.x以降)上で動作するアプリケーションである。ActiveXコントロールは部品であるが、ActiveX Documentsはアプリケーションそのものであるところが大きな違いだ。これについても、来月以降に詳細に述べることにしたい。
Visual Basic 5.0からは、ActiveX EXEとActiveX DLLを作成できるようになっている。これは何かと言えば、OLE Serverのことである。Microsoftは名前遊びが好きなのだろうか。アウトオブプロセスのOLE ServerをActiveX EXE、インプロセスOLE ServerをActiveX DLLと呼ぶことになったのだ。
しかし、今までとは大幅に仕様が変わっている。作り方や用途も、大幅に広がっていると言ってよいだろう。
ActiveXコントロールやActiveX Documentsは、イントラネットに活用するためにDCOMを使った別セッションでのn階層システムへの発展という要素もある。このあたりの話まで次号以降していきたい。
というわけで、今回はこのActiveX EXE、ActiveX DLLについての新機能を紹介しよう。
まずは、OLEに関する言語仕様、とりわけOLE Serverを作るに当たってのClassを扱う仕様が大きく変更されている。これについて概要を述べよう。
Classにもイベントが追加された。つまり、オブジェクトを呼び出す側にイベントを起こすことができるようになった。
Instancingプロパティに、Globlというキーワードが増えた。これは、 参照設定さえしておけば、インスタンシングしなくても、実行時にメンバーにアクセスできるようなオブジェクトだ。
Class以外のスタートアップモジュールが必要なくなった。
PublicとPrivateの間にあたる。同じプロジェクト内でのみ参照可能なメンバーを決められる。
新しいデータ型名を決め、それに属する定数を列挙する。ActiveXコントロールでリストされるプロパティや、一般的なオブジェクトの外部に公開したい定数とすることができる。
クラスを元に新しいクラスのインターフェイスを作れる。あまりスマートではないが、オーバーライドや継承も可能である。
項目としては5つだが、それぞれに重要な意味を持った改良である。現実的には、OLEオブジェクトを柔軟に設計し、使い勝手もよくすることができる。OLEをベースにしてコードを再利用するための仕組みが充実したと考えるべきだろう。
次に、それぞれの項目について、詳細を述べることにしよう。
Classモジュールは、Visual Basic 4.0からサポートされたものである。Classというと、どうもオブジェクト指向のための道具というニュアンスなのだが、これはOLE Serverを作るための仕組みである。
Visual Basic 5.0からは、こうしたOLE Serverの特殊な形としてOLEベースのカスタムコントロールであるActiveXコントロールを作ることができるようになった。よく聞かれることだが、ふつうのOLE ServerとActiveXコントロールはどこが違うのだろうか。
機能的な面からカンタンに言えば、インプロセスOLE Serverで、イベントがついているものがActiveXコントロールである。
Visual Basic 5.0からは、ActiveXコントロールが作れるようになったので、イベントを作るための仕組みも用意されることになった。だからというわけでもないのだろうが、何とClassモジュールでもイベントを呼び出すことができるようになった。
そんなことをして何が嬉しいかといえば、コンテナ側にサーバーから通知を出すことができるということに尽きる。OLE Serverは基本的にはコンテナからOLE Automationで呼び出されたメソッドがなんらかの処理をして、場合によってはその結果を返すというものだが、OLEは同期して実行される。このため、時間のかかる処理の終了通知や、なんらかの監視をして通知をするというようなことはできなかった。これが可能になったのである。
具体的には、次の手順でコーディングする。
例
Public Event MaxReached(ByVal LoopCount As Integer)
例
RaiseEvent MaxReached(LCount)
例
Private WithEvents oc As Counter
Private Sub Form_Load()
Set oc = New Counter
End Sub
例
Private Sub oc_MaxReached(ByVal LoopCount As Integer)
MsgBox CStr(LoopCount) & "回目です。", vbInformation, "Loop"
End Sub

コードを見れば一目瞭然だろう。いちいち細かい説明はしないが、プログラムの内容としては、メソッドを呼び出してチェックさせているわけで、実はイベントにする必然性はない。
基本的にはこれだけの話である。後は実際にどう使っていくかということになるのだが、これは結構深い問題が関わってくる。つまり、非同期通知処理をするために、サーバー側で標準モジュール中にアイドルループを作り、監視しなくてはならない。イベントを起こしたいときには、ClassモジュールからRaiseEvent文を使わなくてはならないので、一度ローカルオブジェクトの参照をするなどして対処しなくてはならない。これについては、稿を改めたいと思う。
Visual BasicでOLE Serverを作るときに使われるのがClassであるが、これには従来は二つの重要なプロパティがあった。InstancingとPublicである。 Visual Basic 5.0はこれらのプロパティがひとつにまとめられてInstancingプロパティひとつになっている。
Instancingプロパティは、次のようになっている。
まさに今まで分かれていた二つのプロパティがまとめられたわけだが、実はこれによる変更も二つある。
ひとつは、従来は自由に組み合わせられたPublicとInstancingは、プロジェクトの種類によって、選べないものが出てきた。具体的なプロジェクトの種類と指定できるInstancingプロパティは次の通りである。
| プロジェクト | instancing |
| 標準EXE | なし |
| ActiveX EXE | 1〜6 |
| ActiveX DLL | 1,2,5,6 |
| ActiveX Control | 1,2 |
| ActiveX Documents | EXE 1〜6 |
| ActiveX Documents DLL | 1,2,5,6 |
DLLでSingleUseがあり得ないのは当然なので、ここでの変更は標準EXEでの設定と考えられる。標準EXEで使うClassは、まさにローカルに使うだけのものになってしまった。つまり外部に公開できなくなったのだ。
従来、非同期通知処理のためにローカルオブジェクトをサーバーに渡すことがあったが、これすらできない。Visual Basic4.0で書かれたコードをVisual Basic 5.0で読み込ませたとき、Publicにでもなっていようものなら、
「(クラス)は、この種類のオブジェクトでは、Publicに設定できません。このアイテムはPrivateに変更されます。」
というメッセージボックスがでてきてしまう。
さらに、実行すると、
「実行時エラー’98’: プロパティまたはメソッド呼び出しの場合には、引数または戻り値としてプライベートオブジェクトへの参照を含めることはできません」
というメッセージボックスが出てくる。
したがって、
「Visual Basic 4.0で使われていた非同期通知処理のためのコールバック手法は、もう使えなくなり、今後はEventを使えということだろう」
と思われた。そのため、WithEventを使ったコードをさんざんためしてみたが、なかなかうまくいかなかった。
うまく行かない原因のひとつには、Windows NTのSP2(サービスパック2)を入れていないことにあった。SP2をインストールした瞬間に大幅に動きが変わった。SP2ではOLEまわりに大きな変更がされているので、Visual Basic 5.0を使う方は、アップデートが必須である。
実際にいろいろいじっていくと、いまくいかないことはないのだが、どうにも効率が悪い処理になりがちである。かえってWithEventsという便利な文に躍らされて、かえって複雑になってしまうのだ。たとえば、こんな感じで悩むことになる。
.... イベントを起こすのは、クラスモジュール内のメソッドでなければならない。 (Sub Mainからクラスモジュールの別インスタンスのメソッドを呼び出すことは できない。) したがって、イベント起こすための監視ループは、クラスモジュールでなければ ならない。 Initializeイベントで無限ループを使うと、他のメソッドは動かない。 ループを起動するメソッドが必要 ループを起動するメソッドを呼び出すところは、どうしても同期で実行されるの で、Form_Loadなどに記述することはできない。 監視の開始はユーザー操作による必要がある ダメだ すると Sub Mainからクラスモジュールの別インスタンスのメソッドを呼び出す方法を考 えるべきか そんなのできるのか ....
ところが、よくよくサンプルプログラムを見ていったところ、従来と同じ方法でコールバックが実現されている。いったいどうしたらそんなことができるのだろうか???
カラクリはカンタンだった。クライアントもActiveX EXEにすればよいのである。これならば、Instancingプロパティの種類はすべて選ぶことができる。ただし、このとき、次の2点が変更点となる。
Sub Main()
frmClient.Show
End Sub
Visual Basic 5.0ではActiveXコントロールのデバッグをひとつのVB.EXE内で行える。これは、複数プロジェクトをひとつの環境でデバッグできるようになっており、複数プロジェクトはひとつのグループとしてグループファイルに保存することもできるようになっている。
OLE Serverでのデバッグにも、この手法は使える。このとき、プロジェクトエクスプローラーで、複数プロジェクトを管理することができる。

図3:プロジェクトエクスプローラー
ひとつのVB.EXEでプロジェクトグループとしてデバッグするときには、先にクライアント側のプロジェクトが存在している必要がある。これは、プロジェクトエクスプローラーのプロジェクトを右クリックしてメニューを出し、スタートアッププロジェクトを変更することができる。

図4:スタートアッププロジェクトの変更
この設定が正しくないときには、クライアントのフォームが起動しないでOLE Serverだけ起動する。
また、ActiveX EXEをひとつのVB.EXEでマルチプロジェクトデバッグをすることはできない。これは、クライアント側プロジェクトで参照設定できないからである。ActiveX DLLのみ参照設定可能なので、このプログラムでも、サーバーをActiveX DLLにしてデバッグしている。
もちろん、2つのVB.EXEでデバッグすることもできる。このときは、サーバーをActiveX EXEにしてもデバッグできる。ユーザーインターフェイスが必要ないサーバーであれば、ActiveX DLLにして、ひとつのVB.EXEでデバッグした方が効率よいだろう。
ClassモジュールのInstancingプロパティのもう一つの変更点は、GlobalSingleUse(4), GlobalMultiUse(6)でという新しい設定が増えていることである。
これは、クライアント側で参照設定してあれば、EXEまたはDLL(MultiUseのみ)は、CreateObjectやNewキーワードを使わなくても、起動時に自動的にインスタンシングされるというものだ。
このとき、プロパティやメソッドは、オブジェクト名をつけないで、通常の変数や関数のように使うことができる。つまり、Visual BasicやVBAの言語仕様のように使うことができるわけである。
つまり、自分で作った関数を、ActiveX DLL、すなわちインプロセスOLE Serverとしておけば、参照設定さえしてあれば自由に呼び出すことができるようになる。よく使うようなサブルーチンやAPIを隠蔽して使いやすくするなど、アイデア次第で多くの可能性が出てきたと言えるだろう。
しかし、手放しでは喜べない。制限もあるからである。
まず悲しいのは、Globalのときにはイベントは使えないということだ。すでに述べたように、イベントを使うにはコンテナ側にWithEvents文を使ってオブジェクトの宣言しておかなくてはならない。ところが、そもそもオブジェクトの宣言も必要ないのだから、Eventも使えないのである。これは、コードウィンドウの左上にあるオブジェクトのリストにオブジェクトが出てこなくなることからも分かる。
参照設定でGlobalなEvent付きオブジェクトを指定してあったとき、クライアント側でもWithEventでオブジェクトを作ってあると、もちろん、作ったオブジェクトのメソッドを呼び出したときのイベントは発生する。しかし、Globalとしてのメソッドを呼び出してもイベントは発生しない。GlobalではWithEventでないのだから当然である。
このようなときには、元々あるオブジェクトとコードで作ったオブジェクトは別(MultiUse)である。
なお、WithEventsを使うOLE Serverは、CreateObjectでもNewでも、参照設定さえローカルにできていれば、DCOMを使ってもイベントを使える。
もう一つの問題は、せっかくメソッドを参照設定だけで呼び出せるようになったのに、Publicな定数はコンテナ側では知ることができないということだ。これは、オブジェクトブラウザを動かしてみればわかる。定数などもセットになって、初めて使いやすいオブジェクトになるはずである。
実は、これを解決するのがEnumキーワードである。これについては、後ほどGlobalの実例と合わせて説明しよう。
従来のOLE Serverには、Sub Mainあるいはフォームなどがスタートアップモジュールとして必要であった。しかし、Visual Basic 5.0からは、次のように変更されている。
Friendは、PublicとPrivateの間にあたるスコープを持つものだ。
従来は、ClassをPublicにすると、Publicなメンバーは外部のアプリケーションに公開された。しかし外部に公開しないで内部的に使いたいメソッドやプロパティもある。このようなものは、Privateにしてしまうと他のクラスから見えなくなるし、Publicにすれば外部のアプリケーションにも見えてしまう。
そこで、Friendの登場となったわけだ。Friendは、同じプロジェクト内でのみ参照可能なメンバーを指定するときに使われる。
Enumは、新しいデータ型名を決め、それに属する定数を列挙して宣言するときに使われる。目的としては、ActiveXコントロールでリストされるプロパティや、一般的なオブジェクトの外部に公開したい定数を作ることにある。
サンプルプログラムEnumAPIObjは、前述したGlobalタイプのクラスの中に、Windows API関数をカプセル化したものである。いや、カプセル化というと語弊があるかもしれない。Windows APIのDeclare宣言をしなくても、API関数を呼び出せるようにしたと言った方が正しいだろう。
ここでは、以前に本誌で紹介したマウス関係のWindows APIをActiveXコントロール化したものから、一部の機能を抜き出してみた。これは、Windows API mouse_eventというマウスの操作をシミュレートするものだ。マウスの移動、ボタンのDownとUpについて制御することができるが、その違いは引数で渡される数値による。もちろん、プログラムでは意味のない数値を書いても分かりにくくなるばかりだから、定数にすべきである。
そこで、Enumの出番である。Enumは一般的に次のように記述する。
[Public|Private] Enum <データ型名>
<メンバー名> [= 定数値]
<メンバー名> [= 定数値]
....
End Enum
ここでは、MouseEventConstans型データとして、各定数を次のように定義した。
Public Enum MouseEventConstants
MOUSE_MOVED = &H1
MOUSEEVENTF_ABSOLUTE = &H8000
MOUSEEVENTF_LEFTDOWN = &H2
MOUSEEVENTF_LEFTUP = &H4
MOUSEEVENTF_MIDDLEDOWN = &H20
MOUSEEVENTF_MIDDLEUP = &H40
MOUSEEVENTF_MOVE = &H1
MOUSEEVENTF_RIGHTDOWN = &H8
MOUSEEVENTF_RIGHTUP = &H10
End Enum
さらに、実際にこの定数を使ったメソッドを定義する。このとき、引数のデータ型として、Enumで定義しておいた定数のデータ型名にしておく。
Public Sub mouse_event(ByVal dwFlags As MouseEventConstants, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)
Xmouse_event dwFlags, dx, dy, cButtons, dwExtraInfo
End Sub
すると、コンテナ側では図のようにクイックヒントとして定数の一覧を出すことができるようになる。
もう一つサンプルプログラムを紹介しておこう。EnumCtlはActiveXコントロールとしてみた。ここでは非常に単純なプログラムで、Numberというプロパティを作り、そこでプロパティのリストが使えるようにしてみよう。
まずは、Enumの定義であるが、NumList型として1から5までの数値を、次のようにUserControlモジュールに定義した。
Public Enum NumList
One = 1
Two = 2
Three = 3
Four = 4
five = 5
End Enum
次に、このNumList型のプロパティを作る。Wizardでは、Enumの宣言を見て新しいデータ型として見てくれなかったので、次のように空のプロパティプロシージャを作っておこう。
Public Property Get Number() As NumList End Property
ここさえ作っておけば、あとはWizardがやってくれるので、通常の手順でコントロールを作ればよい。次のように、自動的にLetのプロパティプロシージャも作ってくれるハズだ。
Public Property Get Number() As NumList
Attribute Number.VB_Description = "番号を選んでください。"
Number = m_Number
End Property
Public Property Let Number(ByVal New_Number As NumList)
m_Number = New_Number
PropertyChanged "Number"
lblNumber.Caption = New_Number
End Property
ここでは、単純にラベルlblNumberにこの数値を表示するだけにしておく。
こうして作ったコントロールをフォームに貼り付ける。このコントロールのプロパティをプロパティウィンドウから変えてみよう。図のように、Numberはドロップダウンされてリストの中から選べるようになる。
図9: IblNumberに表示
もちろん、コードを書いていっても、適切な場面で図のようにクイックヒントがドロップダウンされて選べるようになる。
このように、Enumを使えば、単純にOLEサーバーができるとか、ActiveXコントロールができるということだけでなく、必要な定数までもカプセル化して使いやすくすることができる。まさに、コードの再利用のための仕組みである。
Visual BasicのClassは、名前からオブジェクト指向的なものと考えられがちだが、実際にはOLE Serverを作るための仕組みであり、真のオブジェクト指向の言語仕様とは言えない。というのも、継承やpolymorphism(多態性あるいは多様性と訳されることが多い)をサポートしていなかったからである。たしかにコンポーネント化はできたが、それはオブジェクト指向のメリットのひとつでしかない。
Visual Basic 5.0で新しく追加されたImplementsステートメントは、このような問題をある程度は解決してくれるものだ。ただし、Visual Basic自体の言語仕様が継承やpolymorphismを完全にサポートしたということではないので、誤解がないようにしてほしい。
Implementsステートメントでできることは、元のクラスと同じインターフェイスを持つクラスのテンプレートを作ることだ。Implementステートメントを使って同じインターフェイスを持つクラスを作れば、元となるクラスを継承したり、デレゲート、つまりオーバーライドしたインターフェイスを作ることができる。ただし、C++などのようなスマートな方法ではない。
サンプルプログラムImplementはVisual Basicのオンラインヘルプのサンプルを改良したものだ。ここでは、3つのクラスを定義している。
PersonalDataは、NameとAddressというPublicな変数、すなわちプロパティと、SubProcというプロシージャ、すなわちメソッドを持っている。ClassのInitializeで、それぞれのプロパティに文字列を代入している。これは、個人情報を入れる汎用のクラスである。
※PersonalData.Cls
Public Name As String
Public Address As String
Public Sub SubProc()
MsgBox "This is Original."\"
End Sub
Private Sub Class_Initialize()
Name = "Original Name"
Address = "Original Address"
End Sub
このクラスは、個人情報を入れるPersonalDataと同じプロパティやメソッドなどのインターフェイスを持つものだが、サプライヤー向けのものであり、内容は異なるものにしたい。これを実現するために、Implementsキーワードを使う。
Implements PersonalData
と記述すれば、PersonalDataと同じインターフェイスを実装することができる。書いた直後にコードウィンドウのオブジェクトやメソッドのドロップダウンリストボックスを開いてみると、すでにメソッドやプロパティプロシージャが用意されていることが分かる。

図:11,12 メソッドやプロパティプロシージャが用意される。
ここに、独自のコードを書いていけば、PersonalDataからの派生クラスができるというわけだ。面白いのは、単純に同じ名前のプロパティやメソッドができるのではなく、
Private Sub PersonalData_SubProc()のように、元のクラス名を継承した名前になることだ。 ここでは、それぞれのプロパティとメソッドを独自に記述した。これで、インターフェイスだけ同じで、処理の違うClassを作ることができたわけだ。\<リスト>
しかし、これではすべてオーバーライドしたことになり、継承ができていない。継承をするには、元となるPersonalDataクラスをインスタンシングして、それを呼び出すという手法を取る必要がある。Customerクラスでは、これを実現している。
やり方はいたってカンタンだが、バカみたいな方法とも言える。Implementsステートメントでインターフェイスをここでは、ClassのInitializeで、PersonalData型オブジェクトを作成する。
Private Sub Class_Initialize()
Set pd1 = New PersonalData
End Sub
プロパティは、Supplierのときと同じように、独自のものを作るが、SubProcだけはオリジナルを使おう。これは、次のようにコーディングすればよい。
Private Sub PersonalData_SubProc()
pd1.SubProc
End Sub
このように、継承されるものは、インターフェイスだけであり、インプリメンテーリョンではない。では、実際にこれらのClassを使った例を示そう。
ここでは二つのFormがある。一つ目は、2つ目を呼び出すためのものである。3つのクラスを元にしてローカルにインスタンシングしたオブジェクトを、Form2のpdプロパティに代入している。
Form2には、あらかじめモジュールレベルに次のようにPersonalData型のオブジェクト変数が用意されている。
Private m_pd As PersonalData
プロパティpdには、Form1で作られたCustomer, Supplier, PersonalDataのいずれかのインスタンスが渡される。
念のために言っておくと、このような処理のとき本来ならば元となるPersonalDataは渡す意味がない。これは、テストなので元の内容も見てみようというだけだ。
ここで重要なのは、SupplierとCustomerの二つのClassは、本来ならばPersonalDataとはまったく違うクラスなのだが、PersonalData型オブジェクト変数m_pdに代入できてしまう。これは、 PersonalDataという大元の型を元にしてImplementsステートメントで派生させたClassだからである。
したがって、このプロパティプロシージャでは、m_pdに渡されたオブジェクトが格納される。
Public Property Set pd(Data As PersonalData)
Set m_pd = Data
End Property
Form1では、Form2型のインスタンスを作っているので、このあとにShow 1された段階で、Form2のLoadイベントが発生する。ここで、各プロパティの内容をテキストボックスに表示している。
Private Sub Form_Load()
With m_pd
Text1 = .Name
Text2 = .Address
End With
End Sub
また、コマンドボタンを押すと、m_pdのSubProcメソッドが呼び出されるというわけだ。
Private Sub Command1_Click()
m_pd.SubProc
End Sub
次に、PersonalData, Customer, Supplierそれぞれを呼び出したときの図を示す。
<リスト4>


図13.14:Personal Data


図15.16:Customer


図17.18:Supplier
このように、Implementsキーワードは継承というよりは、元となるClassをベースにして別のクラスを派生させ、用途によって使い分けるという目的に良さそうだ。継承はオーバーヘッドが大きすぎるし、コード量が多くなるので、現実的ではない。
OLE Serverを作るための新しい言語仕様について述べてきたが、もちろんOLEコンテナとしてもVisual Basic 5.0は大きな進歩を遂げている。
たとえば、従来はダミーのメニューを作ってMDIにしないと、OLEでのIn-Place Activation時にメニューやツールバーなどが表示されなかった。Visual Basic 5.0では、メニューを作らずSDIのままでもメニューは表示されるようになっている。しかし、MDIにしないとツールバーなどは表示できない。
しかし、もっと大きな変更がある。それは、OLEでのDrag&Dropへ本格的に対応したことだ。フォームやコントロールの多くには、OLEDragModeとOLEDropModeという二つのプロパティが追加されている。
これらは、OLEベースでのDrag&Dropをサポートし、その動作をVisual Basicから制御することができるようにしたものだ。
| コントロール | OLEDragMode | OLEDropMode |
|---|---|---|
| Form | × | 手動のみ |
| TextBox | ○ | ○ |
| PictureBox | ○ | ○ |
| Image | ○ | ○ |
| Label | ○ | 手動のみ |
| Frame | × | 手動のみ |
| CommandButton | × | 手動のみ |
| CheckBox | × | 手動のみ |
| OptionButton | × | 手動のみ |
| ComboBox | ○ | 手動のみ |
| ListBox | ○ | 手動のみ |
| DriveListBox | × | 手動のみ |
| DirListBox | ○ | 手動のみ |
| FileListBox | ○ | 手動のみ |
| Data | × | 手動のみ |
OLEDragModeは、コントロール内のオブジェクトをドラッグ開始するときに、自動的にするためのものだ。値には手動、自動がある。これはヘタに自動にしておくと、リストボックス中のアイテムをドラッグできたりして、かえってパニックになる可能性もあるので注意していただきたい。
OLEDropModeは、オブジェクトがドロップされたときの処理を自動で行うかどうかを設定するもので、値には、なし、手動、自動がある。自動にできるコントロールは限られており、テキストボックス、ピクチャーボックス、イメージなどである。自動にしておけば、テキストやピクチャーをコントロール間でドラッグ&ドロップできるようになる。たとえば、Internet ExplorerからGIFファイルをドラッグして、Visual Basicのピクチャーボックスに貼り付けるということもできる。
ここで、ひとつ面白い機能を発見したので紹介しておこう。それは、Explorerからのファイルのドラッグ&ドロップである。従来はこれを知るイベントがなかったため、実現するためにはWindows APIのPeekMessageを使ったり、SpyWorks/OCXを使ったりしていた。前の項で紹介したAddressOfとSetWindowLongでも、もちろん可能になったわけだが、Visual Basicだけでもできるようになっている。
OLEDropMode = 1 手動 にすれば、ExplorerからのファイルのDrag&Drop時に、 OLEDragDropイベントが発生する。ここで引数を調べてファイル名を取得することができるのである。
厳密には、引数Effectのビットを調べて、コピーなのか移動なのかといったことを知り、それに応じた処理をするのが正しい方法だ。ここでは、単純にドロップされたファイルをDebug.Printしてみよう。なお、図のリストボックスでは、リストボックスに追加されるようにコーディングしてみた。
やりかたはカンタンで、ドロップされたDataObject型引数DataのFilesコレクションのCountプロパティで、ドロップされたファイルの数を知ることができる。実際のファイル名はDataのFilesコレクションにあるItemプロパティから知ることができる。
実際のコーディングは次のようになる。
Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim i As Integer
For i = 1 To Data.Files.Count
Debug.Print Data.Files.Item(i)
Next i
End Sub
実行画面とイミディエイトウィンドウにリストされたドロップされたファイルの一覧を、それぞれ図19、図20に示す。
Visual Basic 5.0のOLE Serverまわりを中心に新機能を紹介してきたが、意外にも多くのトピックがあった。単純に「OLE Serverも作れるようになりました」というレベルではなく、かなりのことができそうだ。言語仕様としてはまだまだ中途半端なところが見受けられるが、これらの機能を使いこなしていければ、Visual BasicでもOLEをうまく使ってコードの再利用がしやすくなるハズだ。このような進歩には好感が持てる。
非同期通知処理やDCOMとの絡みなど、まだまだ調査しないといけないことは多いが、いざ調査しはじめると、なかなか分からないことや難しいことが多かった。
今後、Visual BasicからOLE Serverを作って効率よく開発をしていくには、OLEについても、もう一歩深いレベルの理解が必要になりそうだ。