首先,我必須說我是C#,.NET和COM Interop的新手。如何聲明一個COM接口,以便它可以被轉換?
我收到以下錯誤消息時我嘗試投了COM對象的接口類型我寫道:
錯誤消息:無法投類型的COM對象「系統.__ ComObject」的接口類型「觀察員。 IObserver」。此操作失敗,因爲IID爲「{13478219-8C3B-4849-99D9-27CEF1A49A55}」的接口的COM組件上的QueryInterface調用由於以下錯誤而失敗:沒有支持此接口(異常來自HRESULT:0x80004002(E_NOINTERFACE)) 。
我使用VS2010(.NET Framework 3.5的)在Windows 7
這裏是我的界面(觀察員類庫項目):
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 Interop註冊的類型(當然,因爲這些接口是在其他dll中實現的)。
IObserver未出現在我的註冊表中(不存在於HKEY_CLASSES_ROOT \ Interface中)。
這裏是失敗碼(合成類庫項目):
// 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(合成類庫項目),實現Observer.IObserver:
public class Etat_Technique : CODRA.SDK.DotNetUtils.COM.IObjectWithSite, Observer.IObservable, Observer.IObserver, ICalculateurEtatTechnique
我的全部組件是COM可見的。 我的觀察者項目構建選項「註冊COM Interop」被選中,我用一個強名稱密鑰文件在我的程序集上簽名。
我沒有訪問COM服務器代碼(第三方組件),但我確定這件事來自我的代碼。
有沒有人對我失蹤的線索有所瞭解?
=============================================
有關第三方軟件的更多信息:
該軟件管理對象。
數據結構似乎是一個對象樹,根節點被稱爲站點。
當一個dll類想要訪問一個對象時,它必須從該站點調用「FindObject2」方法,並將其傳遞給對象路徑。這個方法顯然返回一個COM對象,所以我們可以調用方法,獲取屬性,...
我可以開發自己的對象類型並將它們添加到軟件中,描述類(指定程序集,類,dll ,屬性...)。
在那裏,我想獲得一個我開發的對象,並將它從COM對象轉換回它實現的接口。
將對象聲明爲Object並調用它的方法工作得很好。
在那裏我需要一個Observer將它附加到Observable上,所以我必須施放。
一個解決方案肯定會使attach方法的參數成爲一個Object,但是如果我這樣做了,那麼使用接口就沒有興趣了。
=============================================
基於Michael Edenfield's answer更多信息:
[ComImport括號開]
的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圓括號關]
嚴重,FindObject2有效地返回{系統.__ ComObject},所以鑄造不工作,我堅持了一個InvalidCastException,又一次,又一次,又一次,..
好的一點是我知道它應該是什麼基礎類。
我的部分作品,即「關於第三方軟件的更多信息」中談到使得附加方法獲取對象參數,然後管理對象,而不是IObservers解決方法。 這樣做我調用IObserver的更新方法使用反射:
foreach (Object observer in m_observers)
{
Object[] args = new Object[] { this };
observer.GetType().InvokeMember("update",
BindingFlags.InvokeMethod,
null, observer, args);
}
Eeew,不是嗎?但是如果我沒有找到更清潔的東西,這種糟糕的事情會使工作完成。
它看起來像COM對象的類型根本不支持'GUID'。 –
確保你的界面有GUID。你不需要讓你的應用程序COM =可見或註冊COM互操作就可以使用第三方COM組件。 –
你的意思是已經使用了GUID?我認爲用guidgen生成它會檢查它...你稱爲COM對象是什麼? – Rifu