2

regasm.exeを使用して COM DLL を登録しましたが、DLL のクラスを使用する VBA スクリプトを作成しようとしています。DLL はExcelDataReaderLibrary.dll. C# ソースでは、クラスは次のように記述されています (このライブラリのコードが含まれています)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using Excel;

namespace ExcelDataReaderLibrary
{
    public class ExcelDataReader
    {
        public void readSheet(string filePath,string sheetName,string outPath)
        {
            // code for method here
        }
    }
}

私のassembly.csファイルには次のものが含まれています。

[assembly: ComVisible(true)]

[assembly: Guid("b1e78f8f-9ab0-46d8-beac-b843656aacdb")]

VBA エディタを開いて [参照] に移動すると、 の参照が表示されExcelDataReaderLibraryます。この参照に関連付けられているファイルはExcelDataReaderLibrary.tlbであり、 ExcelDataReaderLibrary.dllではないことに注意してください。ExcelDataReaderこのリファレンスを確認した後、次のように VBA でオブジェクトを作成して使用したいと考えています。

Sub x()    
 Dim xyz As New ExcelDataReaderLibrary.ExcelDataReader
 xyz.readSheet "c:\mypath\testfile.xlsx", "Sheet1", "c:\outputPath"
End Sub

オブジェクトは正常に作成されますが、次のreadSheetエラーが発生します。

Automation error
The system cannot find the file specified.

また、ExcelDataReaderLibrary名前空間には Intellisense がありますが、ExcelDataReaderオブジェクトには Intellisense がありません。私のクラスは登録されていますが、そのメソッドは登録されていないと思います.Guidで何か違うことをする必要がありますか? VBA コードからメソッドを呼び出すにはどうすればよいですか?

4

1 に答える 1

7

質問の最初の部分では、呼び出しプロセスの場所/コンテキストからアセンブリを見つける必要があるという問題がmscoree.dllあり、オブジェクトのアセンブリは通常、プロセス (技術的には .NET Fusion) が検索するフォルダーにありません。アセンブリの場所を .NET に伝えるには、次の 2 つのオプションがあります。

  • /codebase(Hans が述べたように) のパラメーターを使用するREGASMと、アセンブリの場所を指すレジストリにヒントが残ります。また

  • アセンブリに強力な署名を付けて、GAC に追加します。GACmscoree.dllは常に検索して見つけます。

アセンブリのすべての依存関係が等しく「検索可能」でなければならないことに注意してください。

マイクロソフトは、人々がこの手法を使用することを非常に厳しく思いとどまらせていることを警告しなければなりません/codebase。彼らは、これは開発/デバッグ手法として設計されており、運用モードでは使用すべきではないと主張しています。彼らの理論的根拠を完全に理解しているかどうかはわかりません。おそらく、MSDN のドキュメントやその他のリファレンスを調べて、REGASMこれについて自分で判断する必要があります。個人的には、自分のオブジェクトを GAC に追加するのが を使用するより面倒だとは思いません/codebase

質問の 2 番目の部分、IntelliSense を取得しないことについて: あなたの問題は、既定では、.NET によって生成された COM タイプ ライブラリが純粋なdispinterfaces を公開することです (それらは のみを実装し、タイプ ライブラリはメンバーIDispatchをリストしません)。dispinterfaceVB6 の用語では、クラスは として公開されobject、すべてのメソッド名とパラメーターは実行時に決定する必要があります。

COM クラスの生成は、クラスに適用される という属性によって制御されますClassInterfaceAttribute

オプションは次のとおりです。

  • ClassInterfaceType.AutoDispatch: これはデフォルトであるため、現在クラスに適用されます。クラスは純粋なディスパッチ インターフェイスとして公開され、レイト バインドのみ可能です。インテリセンスなし。TLB には dispinterface メンバーのリストすら含まれていないため、レイト バインドされたクライアントは、クラスが公開する内容に関する詳細をキャッシュすることはできません。

これにより、少なくともクライアントのハードクラッシュが関係していない限り、メンバーを追加、変更、および削除するための最大限の柔軟性が可能になります。私はこれを「スクリプトモード」と呼んでいます。

  • ClassInterfaceType.None: これはより厳密なモードで、IDL/C++ で行ったように、オブジェクトをより明示的に公開するよう求めます。公開するメソッドを使用して 1 つ以上のインターフェイスを宣言し、クラスがインターフェイスから明示的に継承されるようにする必要があります。複数のインターフェースから継承する場合、最初の[default]インターフェースがインターフェースとして選択されますが、ComDefaultInterfaceAttribute. インターフェイスから継承しない場合、CoClass は IDispatch から直接継承されます。(COM オブジェクトとして公開されるすべての .NET クラスは、IDispatch を介して公開されます)。

これは私の好みのモードですが、COM プログラミングに関しては、どちらかというと伝統主義者です。インターフェイスから明示的に宣言して継承する限り、IntelliSense を取得できます。明らかに、インターフェイスにリストされているメンバーのみを呼び出すことができます。私はこれを「Strict モード」または「IDL モード」と呼んでいます。

  • ClassInterfaceType.AutoDualこれにより、公開するメソッドのすべての詳細を含む COM インターフェイスが自動的に生成されます。つまり、IntelliSense を利用できるので、明示的なインターフェイスの作成について心配する必要はありません。ただし、バージョン管理は王室の苦痛です。オブジェクトを再コンパイルおよび/または再登録する前に、すべてのクライアントを停止するように細心の注意を払う必要があります。私はこれを「VB6 モード」と呼んでいます。なぜなら、VB6 があなたのために行ったことによく似ているからです (VB6 での COM のバージョン管理も王様の苦痛です)。

Microsoft はまた、ユーザーが を使用することを強く思いとどまらせていAutoDualます。これは、生成されたインターフェイスへの変更が、気付かないうちに簡単に発生する可能性があるためだと思います。まだ実際に使用する機会はありませんが、それよりもはるかに危険かどうかはわかりませんNone

要約すると、IntelliSense を取得したい場合は、クラスに適用する[ClassInterface(ClassInterfaceType.None)](そして明示的に実装するインターフェイスにメソッドを配置する) か、[ClassInterface(ClassInterfaceType.AutoDual)]. いずれにせよ、アセンブリに変更を加える前に、クライアントを停止する (そして、参照を "削除" および "再追加" することさえも) 十分に注意する必要があります。

于 2013-05-24T05:19:25.570 に答える