VB.NETユーザー定義型でLong型を用いたい場合のマーシャリング

解決


yy  2012-10-26 15:30:23  No: 147926  IP: 192.*.*.*

先日、ご質問しました
「引数が構造体のVBのDLLの関数をVBAから呼び出すには?」
<http://madia.world.coocan.jp/cgi-bin/vbnet/wwwlng.cgi?print+201210/12100006.txt>
で、ユーザー定義型でString 型を用いた場合には、String 型をBSTR 型にマーシャリングするということを教えていただきましたが、Long型を用いた場合には何にマーシャリングすればよいのでしょうか。マーシャリングしないとエラーになりますし、I4型やU4型やSysInt型にしてもエラーになってしまいます。

Public Structure T1
  <MarshalAs(UnmanagedType.BStr)> Dim x As String
  <MarshalAs(UnmanagedType.????)> Dim y As Long
End Structure

もし、この対応の調べ方や、対応表などがどこかに記載されていましたら教えてください。よろしくお願いします。

編集 削除
shu  2012-10-26 15:41:45  No: 147927  IP: 192.*.*.*

Longは32bitではなく64bitです。

編集 削除
魔界の仮面弁士  2012-10-26 19:35:15  No: 147928  IP: 192.*.*.*

プリミティブの Long 型は、.NET の Int64 型にマッピングされています。
強いてマーシャリング指定するなら、MarshalAs(UnmanagedType.I8) であり、
COM のバリアント型として扱う場合は、VT_I8 相当の型となります。


Int64 型をもつ COM 構造体を、64bit 版の VBA で参照設定した場合、
VBA の オブジェクトブラウザ上からは
  y As LongLong
のように見えます。一方、32bit 版の VBA や VB6 等で参照設定した場合は、
  y As <サポートされていないバリアント型>
のように表示されます。


VBA 側で「Dim xy As T1」のように宣言した場合、VBA32 では
上記の理由から、コンパイルエラーになりますのでご注意ください。


64bit版の VBA で使う場合は構いませんが、VBA32 でも使いたいなら、
Long(Int64)型の利用は避けた方が無難です。代わりに、Integer(Int32)型の
メンバーを2つ用意したり、String や Decimal 等で代用できないか検討してみてください。


COM 連携などの都合上、どうしても Int64 のメンバーが必要な場合には、
代用として「内部処理形式 LongLong の Variant 型」を使う事で、
VBA32 でも限定的に利用可能でとなります。この場合、VB.NET 側では、
As Object にしておいて、そこに Long 値を受け渡す形にします。


VBA 側では、内部処理形式 LongLong の Variant 型で受け取った場合、
  Debug.Print VarType(v)
が、32bit/64bit共に「20」を返します。つまり、VT_I8 相当ですね。

なお VBA64 では、列挙値定数 vbLongLong (=20) が定義されています。


ちなみに上記の Variant 値を「Debug.Print TypeName(v)」した場合、
VBA64 では "LongLong" という文字列が返されますが、
VB6 や VBA32 では、TypeName 関数が以下のエラーを返します。

| 実行時エラー '458':
| Visual Basic でサポートされていないオートメーションが変数で使用されています。


ちなみに VT_I8 は、Windows 2000 以下の OS では利用できません。
しかし最近の OS であれば、その Variant 値を四則演算したり、
CStr 等で変換したりすることが、32bit/64bit 共に可能となっています。
ただ、やはり VBA32 ではサポートされない型なので、
32bit版環境で使うなら、値を受け取った後で「CDec関数」で
変換しておくと良いでしょう。(64bit版VBAでは、CLngLng関数でOK)


この他、VB2005 以降で追加されたプリミティブ型
(SByte, UShort, UInteger, ULong)も、VBA では
サポートされていませんので、取扱いにご注意ください。

編集 削除
yy  2012-10-30 08:58:58  No: 147929  IP: 192.*.*.*

魔界の仮面弁士さん
shuさん

>64bit版の VBA で使う場合は構いませんが、VBA32 でも使いたいなら、
>Long(Int64)型の利用は避けた方が無難です。
>代わりに、Integer(Int32)型のメンバーを2つ用意したり、
>String や Decimal 等で代用できないか検討してみてください。
>この他、VB2005 以降で追加されたプリミティブ型
>(SByte, UShort, UInteger, ULong)も、VBA では
>サポートされていませんので、取扱いにご注意ください。

VBA32でサポートされていないものは極力使わないようにします。

Integer(Int32)型のメンバーを2つ用意する方向で検討し始めたのですが
コードを書き換えているうちに何をしているのかよく分からなくなってきて、
元々したかったことは、VB.NETの32ビットの整数値とVBA32の32ビットの整数値
の受け渡しをしたかったのですが、shuさんからのご指摘のように、
VB.NETのLongを32ビットと勘違いしていたことと、
VB.NETのLongは同じ名称のVBA32のLongに対応させるもの
と思い込んでいたため、今回のようなご質問をしたのですが、
いろいろ確認していたら、質問の意図とは少し違ってしまったのですが
VB.NETのInteger(32bit)とVBA32のLong(32bit)とでは、
マーシャリングしなくてもそのまま受け渡しができているようなので、
この対応でなんとか解決しそうです。

ありがとうございました。

編集 削除