8

私は VBIDE API を使用していますが、ホスト アプリケーションが Excel である、または Office アプリであるとは想定できません。

だから私が知っているのは、私が を見ていることVBComponent、そしてそれが であることだけTypeですvbext_ct_document

VBE の即時ペインで、次の出力を取得できます。

?TypeName(Application.VBE.ActiveVBProject.VBComponents("Sheet1"))
VBComponent
?TypeName(Sheet1)
Worksheet

But the Sheet1 object only exists in the runtime environment, so if I'm a C# add-in I don't even see it.

The only thing that gets anywhere close to what I need, is via the Parent and Next properties of the component:

?TypeName(Application.VBE.ActiveVBProject.VBComponents("Sheet1").Properties("Parent").Object)
Workbook
?TypeName(Application.VBE.ActiveVBProject.VBComponents("Sheet1").Properties("Next").Object)
Worksheet

This gets me the type names I'm after... but on the wrong component! And for ThisWorkbook, which is the top-level document object, I get the Application object as the Parent:

?TypeName(Application.VBE.ActiveVBProject.VBComponents("ThisWorkbook").Properties("Parent").Object)
Application

このアプローチは潜在的に有用ですが、ホスト アプリケーションが Excel の場合、「アプリケーション」タイプの「親」プロパティを持つコンポーネントがインスタンスであることを認識しているホスト固有のロジックをハードコードする場合に限りWorkbookます。他のホストの他のドキュメント モジュールもその「親」プロパティを持っているので、私はほとんど困惑しています。

p/invoke 呼び出しや低レベルの COM "リフレクション" マジック (魔法のようなもの) から ... から ... わからない -コメント必要なファンキーなポインターを含むコード-実用的なソリューションになる可能性のあるリードは大歓迎です。ITypeInfounsafe// here be dragons


私の知る限り、VBEアドインはホストと同じプロセスに存在するため、VBAプロジェクトのどこかにポインタがThisWorkbookありSheet1、その他のドキュメントタイプがあります。VBComponent

?ObjPtr(ThisWorkbook)
 161150920

どうにかしてそのポインターをつかむ必要があり、必要な場所にいると思います。

4

1 に答える 1

7

残念ながら、vbComponent Properties コレクションの値/オブジェクトは、CoClass のインスタンス値を反映したものにすぎないため、すべての VBA ホストで信頼できるわけではありません。たとえば、プロパティが Properties コレクションに存在することを知ることはできません。Parent

ホストが document-type-components をサポートしている場合、ドキュメントがサポートしているインターフェイスの GUID を定義するのはホスト次第です。通常、ホストは実際のドキュメントの作成/削除も担当します。これは、Excel オブジェクト モデルだけがワークブックにシートを追加でき、VBIDE ではできないのと同じです。

ワークブックとワークシートについて話したので、両方を含めます....

残念ながら、VBIDE はドキュメント タイプ コンポーネントに関する詳細の一部を隠しており、モジュールをエクスポートするときに意図的にこれらの詳細を省略し、エクスポートされたドキュメント タイプ モジュールをクラス モジュール テキストに変換することWorksheetさえSheet1あります。文書型モジュールとして再インポート:

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "Sheet1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Sub Foo()

End Sub

上記を、モジュール内に実際に (圧縮形式で) 格納されている document-module テキストと比較しSheet1ます。

Attribute VB_Name = "Sheet1"
Attribute VB_Base = "0{00020820-0000-0000-C000-000000000046}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = True
Sub Foo()

End Sub

実際のモジュール テキストに存在する 3 つの追加属性に注意してください。

Attribute VB_Base = "0{00020820-0000-0000-C000-000000000046}"
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = True

OleViewer によると、GUID 0{00020820-0000-0000-C000-000000000046} は と完全に一致しCoClass Worksheetます。

[
  uuid(00020820-0000-0000-C000-000000000046),
  helpcontext(0x0002a410)
]
coclass Worksheet {
    [default] interface _Worksheet;
    [default, source] dispinterface DocEvents;
};

Workbook モジュールでも同じ現象が発生します。VBIDE でエクスポートされたテキストは次のとおりです。

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "ThisWorkbook"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True

そして、VBA バイナリの ISt​​ream からの未加工のテキスト:

Attribute VB_Name = "ThisWorkbook"
Attribute VB_Base = "0{00020819-0000-0000-C000-000000000046}"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
Attribute VB_TemplateDerived = False
Attribute VB_Customizable = True

今回は、予想どおり、GUID0{00020819-0000-0000-C000-000000000046}は Workbook CoClass です。

[
  uuid(00020819-0000-0000-C000-000000000046),
  helpcontext(0x000305b8)
]
coclass Workbook {
    [default] interface _Workbook;
    [default, source] dispinterface WorkbookEvents;
};

上記はすべて知っておくとよいことですが、コンポーネントのメモリ内 IStreams へのハンドルを取得できない限り、問題は解決しません。ホストドキュメントの最後に保存されたバージョンから詳細をロードすることで間に合わせることができる場合は、基になるドキュメントから詳細をロードできますが、それは望ましくないと思います.ホスト固有のものになる可能性があります( Access が VBA をテーブルに格納する方法を検討してください)。

ただし、VBIDECoClass についての手がかりを提供します。vbComponent のプロパティ コレクションは、CoClass に存在する正確な数のプロパティを返します。これらのプロパティの名前、パラメーター、および型を調べると、対応する CoClass のメンバーと正確に一致することがわかります。CoClass 定義で発生する順序。

たとえば、Worksheet vbComponent の最初の 10 個のプロパティは次のとおりです。

Application
Creator
Parent
CodeName
_CodeName
Index
Name
Next
OnDoubleClick
OnSheetActivate

CoClass Worksheet 内の dispinterface _Worksheet からの対応するpropget(および) エントリ (メソッドは削除されています):propput

    [id(0x00000094), propget, helpcontext(0x0002a411)]
    Application* Application();
    [id(0x00000095), propget, helpcontext(0x0002a412)]
    XlCreator Creator();
    [id(0x00000096), propget, helpcontext(0x0002a413)]
    IDispatch* Parent();
    [id(0x0000055d), propget, helpcontext(0x0002a7fc)]
    BSTR CodeName();
    [id(0x80010000), propget, helpcontext(0x0002a7fd)]
    BSTR _CodeName();
    [id(0x80010000), propput, helpcontext(0x0002a7fd)]
    void _CodeName([in] BSTR rhs);
    [id(0x000001e6), propget, helpcontext(0x0002a7fe)]
    long Index();
    [id(0x0000006e), propget, helpcontext(0x0002a800)]
    BSTR Name();
    [id(0x0000006e), propput, helpcontext(0x0002a800)]
    void Name([in] BSTR rhs);
    [id(0x000001f6), propget, helpcontext(0x0002a801)]
    IDispatch* Next();
    [id(0x00000274), propget, hidden, helpcontext(0x0002a802)]
    BSTR OnDoubleClick();
    [id(0x00000274), propput, hidden, helpcontext(0x0002a802)]
    void OnDoubleClick([in] BSTR rhs);
    [id(0x00000407), propget, hidden, helpcontext(0x0002a803)]
    BSTR OnSheetActivate();

ホスト タイプ ライブラリの CoClasses を反映してプロパティをハッシュできる場合(おそらく propget 名を使用するだけ)、そのハッシュを VBIDE の component.Properties コレクション内の名前のハッシュと比較できます。

これは型を取得するための回り道ですが、IStream にアクセスしないと、それが唯一の方法になると思います。

于 2016-05-07T06:27:47.097 に答える