まず、私は C#、.NET、および COM 相互運用性については初めてだと言わざるを得ません。
COM オブジェクトを自分が作成したインターフェイス型にキャストしようとすると、次のエラー メッセージが表示されます。
エラー メッセージ: タイプ 'System.__ComObject' の COM オブジェクトをインターフェイス タイプ 'Observer.IObserver' にキャストできません。IID '{13478219-8C3B-4849-99D9-27CEF1A49A55}' を持つインターフェイスの COM コンポーネントでの QueryInterface 呼び出しが次のエラーのために失敗したため、この操作は失敗しました: No such interface supported (HRESULT からの例外: 0x80004002 (E_NOINTERFACE)) .
Windows 7 で VS2010 (.NET Framework 3.5) を使用しています。
これが私のインターフェースです(オブザーバークラスライブラリプロジェクト):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Observer
{
[ComImport]
[Guid("2B2D0BC7-A7C6-4924-A3DE-42F7075E5947")]
public interface IObservable
{
void attach(IObserver observer);
void detach(IObserver observer);
void notify();
}
[ComImport]
[Guid("13478219-8C3B-4849-99D9-27CEF1A49A55")]
public interface IObserver
{
void update(IObservable observable);
}
}
この dll をビルドするときに、次の警告が表示
されます。Observer.dll には、COM 相互運用に登録できる型が含まれていません (インターフェイスが他の dll に実装されているため)。
IObserver がレジストリに表示されません (HKEY_CLASSES_ROOT\Interface にありません)。
失敗したコードは次のとおりです (Syntheses クラス ライブラリ プロジェクト):
// Arguments de la méthode permettant de récupérer un objet selon son chemin
Object[] args;
// Objet représentant l'état technique de la synthèse
Observer.IObserver pEtatTechniqueSynthese;
args = new Object[] { m_sFullName + "/Etat_Technique" };
pEtatTechniqueSynthese = m_typeSite.InvokeMember("FindObject2",
BindingFlags.InvokeMethod,
null, m_pSite, args) as Observer.IObserver;
//Here pEtatTechniqueSynthese is null
//This call works fine without casting when pEtatTechniqueSynthese's type is Object
//but I need to cast it because my Observer.IObservable's attach method waits for an Observer.IObserver
//If I don't cast I get a "Exception has been thrown by the target of an invocation"
//=> InnerException : "La valeur n'est pas comprise dans la plage attendue"
//I don't know the exact translation, but it sort of means "Value not in expected range"
pEtatTechniqueSynthese = (Observer.IObserver)m_typeSite.InvokeMember("FindObject2",
BindingFlags.InvokeMethod,
null, m_pSite, args);
//Exception raised
pEtatTechniqueSynthese の実数型 Etat_Technique (Syntheses クラス ライブラリ プロジェクト) は、 Observer.IObserver を実装します。
public class Etat_Technique : CODRA.SDK.DotNetUtils.COM.IObjectWithSite, Observer.IObservable, Observer.IObserver, ICalculateurEtatTechnique
私のアセンブリはすべて COM 可視です。Observer プロジェクトのビルド オプション [COM 相互運用に登録] がオンになっていて、厳密な名前のキー ファイルでアセンブリに署名しました。
COM サーバー コード (サード パーティ コンポーネント) にはアクセスできませんが、問題は私のコードにあると確信しています。
誰かが私が行方不明になっていることについての手がかりを持っていますか?
=============================================
サードパーティ ソフトウェアの詳細:
このソフトウェアは、オブジェクトを管理します。
データ構造はオブジェクト ツリーのようで、ルート ノードはサイトと呼ばれます。
dll クラスがオブジェクトにアクセスする場合、サイトから "FindObject2" メソッドを呼び出して、オブジェクト パスを渡す必要があります。このメソッドは明らかに COM オブジェクトを返すので、メソッドを呼び出したり、プロパティを取得したりできます...
独自のオブジェクト タイプを開発し、それらをソフトウェアに追加して、クラスを記述できます (アセンブリ、クラス、dll、プロパティなどを指定します)。
そこで、私が開発したオブジェクトを取得し、それを COM オブジェクトからそれが実装するインターフェイスにキャストし直します。
オブジェクトを Object として宣言し、そのメソッドを呼び出すと、問題なく機能します。
Observable にアタッチするには Observer が必要なので、キャストする必要があります。
attach メソッドの引数を Object にすれば解決するのですが、そうするとインターフェースを使う意味がありません。
=============================================
Michael Edenfield の回答に基づく詳細情報:
[ComImport括弧ON]
ComImport 属性は推測でした。サードパーティのコードとやり取りするために指定された utils ファイルにアクセスできるため、これを使用しました。
このファイルで定義されているインターフェイスを次に示します。サード パーティ ソフトウェアのドキュメントに記載されている方法で実装すると、サイト ルート オブジェクトにアクセスできます。
彼らがそれを使うなら、私も使わなければならないと思いました。
[ComVisible(true)]
[ComImport]
[Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352") ]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectWithSite
{
void SetSite([MarshalAs(UnmanagedType.IUnknown)]
[In] object pSite);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")]
void GetSite([In] ref Guid riid, [Out] out IntPtr pvSite);
}
私はこの属性を削除します。あなたは私よりも根本にあるものをよく理解しています。さらに、問題は同じなので、この属性は役に立たなかった。
[ComImport 括弧 OFF]
悪いことに、FindObject2 は効果的に {System.__ComObject} を返すため、キャストが機能せず、InvalidCastException に何度も何度も何度も悩まされます...
良い点は、それが必要な基本クラスを知っていることです。なれ。
「サード パーティ製ソフトウェアに関する詳細情報」の部分で説明した回避策は機能します。つまり、attach メソッドで Object パラメータを取得し、IObserver の代わりに Object を管理します。これを行うには、Reflection を使用して IObserver の update メソッドを呼び出します。
foreach (Object observer in m_observers)
{
Object[] args = new Object[] { this };
observer.GetType().InvokeMember("update",
BindingFlags.InvokeMethod,
null, observer, args);
}
ええええええええええええええええええええええええええええええええええええええええええええええええええええええええ しかし、私がよりきれいなものを見つけなければ、このくだらないことで仕事は終わります。