ここでは、ActiveX DLL について、思った事を記しています。
(コンポーネント作成側)
| CLSID と IID | 自動生成 (ただし生成タイミングが [バージョン間の互換性] により違う) |
| ProgID | プロジェクト名 + ピリオド + クラス名 |
| CoClass名 | クラス名 (レジストリの説明は ProgID と同じ) |
| タイプライブラリ名 | プロジェクト名 (レジストリの説明は [プロジェクトの説明]) |
| インターフェイス名 | クラス名の先頭にアンダーバーを付けたもの |
ActiveX DLL のスレッドモデルは2つ選択出来きます。
(ActiveX EXE は別です)
| VB での呼び方 | COM での呼び方 |
|---|---|
| アパートメント スレッド | STA |
| シングル スレッド | プライマリSTA / 第1STA |
どちらも、シングルスレッドです。
通常は、アパートメントスレッド の方を使います。
(STA は Windows95 から、プライマリSTA は、それ以前、つまりスレッドが無かった OLE 時代のもの)
標準モジュールのグローバル変数は、スレッド(アパートメント)ごとに独立しています。
同スレッドの異なるインスタンス間では共有されます。
プロセス間での共有ではありません。
(クライアントが MTA の場合、ちと厄介)
プロセス間にすると、同期処理が必要になり、VB の範疇では無いとの判断でしょう。
アパートメント間なら、スレッド間マーシャリングで同期がとれるし。
このグローバル変数の初期化が必要な時は、Sub Main で行います。Sub Main は、1つのアパートメントで、
最初のインスタンスが作成された時に、1度だけ呼ばれます。
マルチスレッドのテストクライアントとして、IE/HTA を使うのが手軽です。
以下のように、試験的にエラーを発生させて見ます。
Err.Raise &H8007000E
クライアントが VB の場合の結果は、
実行時エラー '7':
メモリが不足しています。
になりました。 (&H8007000E → 7)
ただし VB 以外のクライアントが受け取る生のエラーコードは &H800A0007 です。
このことは、VB で作成したコンポーネントでは、
COMの標準的なエラーの発行が出来ない事を意味します。(一部のみ)
Err.Raise 1
のクライアント(VB以外)が受け取るエラーコードは &H800A0001 でした。
未定義のエラーは &H800A0000 が付加されるようです。
ただ、これは試験的に行ったのものですので、
実際には未定義エラーは使用せず、カスタムエラーを使います。
カスタムエラーの番号は
(512〜65535) + vbObjectError(&H80040000)
の範囲です。
(&H80040200〜&H8004FFFF)
エラーについては資料ページをどうぞ。
(資料ページ) HRESULT
VB がどのようなタイプライブラリを生成するのか調べてみました。
(資料ページ) テータ型
VBScript, JScript のスクリプト環境では、参照渡し ByRef の変数を引数として使えません。
Public Sub SubMethod(ByRef arg As Integer)
↓ ↓
HRESULT SubMethod([in, out] short* arg);
Public Function FunctionMethod(ByVal arg As Byte) As Single
↓ ↓
HRESULT FunctionMethod(
[in] unsigned char arg,
[out, retval] single* );
あれ、Single って float にならないのか...
(後述: OLE/COM Viewer の誤りだと思われます)
Public Sub DefOption(
Optional ByVal bOption As Boolean = True)
↓ ↓
HRESULT DefOption(
[in, optional, defaultvalue(-1)] VARIANT_BOOL bOption);
Public Property Let LetProperty(ByVal vData As Variant)
↓ ↓
[propget] HRESULT LetProperty([in] VARIANT vData );
Public Property Set SetProperty(ByVal vData As Variant)
↓ ↓
[propputref] HRESULT SetProperty([in] VARIANT vDAta );
Set は参照だから、ref 。ふむふむ。
Public Property Get typeArray() As type()
↓ ↓
[propget] HRESULT typeArray([out, retval] SAFEARRAY(type)* );
Public Property Let typeArray(ByRef ary() As type)
↓ ↓
[propput] HRESULT typeArray([in, out] SAFEARRAY(type)* );
Public Enum typeEnum
Large = &H7FFFFFFF
Minus = &H80000000
End Enum
↓ ↓
typedef [
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
version(1.0)
]
enum
{
Large = 2147483647,
Minus = -2147483648
} typeEnum;
あれ、v1_enum 付いてない...