2010-09-29 47 views
4

我正在處理一個項目,這是一個.NET擴展到一個相當大的傳統ASP項目,它使用了很多C++ COM對象,這些對象一直存在於我們的代碼庫中。不幸的是,C++端有很多黑客代碼,我擔心我沒有足夠的經驗來解決我遇到的問題。COM Interop:索引屬性簽名問題

簡而言之,我可以實例化有問題的COM對象,並且Visual Studio告訴我應該能夠調用其「方法」(在引號中,因爲它們實際上是作爲參數化屬性公開的)。但是,我嘗試調用的任何方法都會給我提供錯誤「索引屬性'CoreAspLib.IComUser.LoginUser'具有必須提供的非可選參數。」問題是,我使用的是與經典ASP世界中使用的參數完全相同的參數,即使是針對屬性的IntelliSense幫助也告訴我,我正在使用正確的參數集。例如,「LoginUser」屬性的簽名是「dynamic IComUser.get_LoginUser(string username,string password)」,我用兩個字符串調用它,但我仍然得到「非可選參數」錯誤。

下面是一些相關的代碼 - 首先,我正在嘗試進行方法調用的類。 CComUtils是一個幫助程序類,它只接受COM的GUID和對目標對象的引用,創建所需COM對象的實例,並將目標引用分配給新對象。

public static class CurrentUser 
{ 
    public static void Authenticate(string userName, string password) 
    { 
     CoreAspLib.ComUser userObject = Cache.Request<CoreAspLib.ComUser>("UserComObject"); 

     if (userObject == null) { 
      Guid userGuid = new Guid("BF748C0A-450D-4EAF-8C39-A36F6B455587"); 
      CComUtils.CreateCOMInstance(userGuid, ref userObject); 
      Cache.Request("UserComObject", userObject); 
     } 

     var result = userObject.LoginUser(sUserName:"foo", sPassword:"bar"); 

     if (result.Failed) { 
      throw (new System.Security.Authentication.InvalidCredentialException("Bad username or password".tr())); 
     } else { 
      FormsAuthentication.SetAuthCookie(userName, false); 
     } 
    } 
} 

下面是來自COM對象的源的實際方法簽名:

STDMETHODIMP CComUser::get_LoginUser(BSTR bsUserName, BSTR bsPassword, IDispatch ** pResult) 

下面是來自IDL接口定義:

[ 
    object, 
    uuid(1F4D8A57-BDE1-4D47-A9BC-5F541A0ED184), 
    dual, 
    nonextensible, 
    helpstring("IComUser Interface"), 
    pointer_default(unique) 
] 
interface IComUser : IDispatch{ 
    [propget, id(1), helpstring("property LoginUser")] HRESULT LoginUser([in] BSTR sUserName, [in] BSTR sPassword, [out, retval] IDispatch ** pResult); 
    [propget, id(2), helpstring("property m_nUserID")] HRESULT m_nUserID([out, retval] ULONG* pVal); 
    [propget, id(3), helpstring("property m_nUserRightsMask")] HRESULT m_nUserRightsMask([out, retval] ULONG* pVal); 
    [propget, id(4), helpstring("property SetPassword")] HRESULT SetPassword([in] BSTR sPassword, [in,optional] VARIANT nUserID, [out, retval] IDispatch ** pResult); 
    [propget, id(6), helpstring("property VerifyLdapCredentials")] HRESULT VerifyLdapCredentials([in]BSTR sUserName, [in]BSTR sPassword, [in]BSTR sLdapServer,[in]ULONG nLdapPort,[in]BSTR sAuthorizeDn,[in]VARIANT_BOOL bSecure, [out, retval] IDispatch ** pResult); 
    [propget, id(7), helpstring("property CreateUser")] HRESULT CreateUser([in] BSTR sUserName, [in] BSTR sPassword, [in]ULONG nUserRightsMask, [in] ULONG nAuthenticationType, [in] ULONG nHomeGroupID, [in] ULONG nLanguageID, [out, retval] IDispatch** pVal); 
    [propget, id(8), helpstring("property m_nLanguageID")] HRESULT m_nLanguageID([out, retval] ULONG* pVal); 
}; 

最後,這裏的共類定義:

[ 
    uuid(BF748C0A-450D-4EAF-8C39-A36F6B455587), 
    helpstring("ComUser Class") 
] 
coclass ComUser 
{ 
    [default] interface IComUser; 
}; 

我該怎麼辦?

編輯:我應該提到,我最初並沒有使用命名參數;我試圖讓錯誤消失。

回答

11

嗯,你的代碼建議你事實上使用C#4.0,因爲你使用的是命名參數。該版本確實支持COM互操作場景中的索引屬性。然而,索引器語法需要[方括號]。不知道它是否仍然適用於多個參數,這些例子都只有一個。首先試試這個:

var result = userObject.LoginUser["foo", "bar"]; 

或用撐船的問題:

var result = userObject.get_LoginUser("foo", "bar"); 

請讓我們知道你發現了什麼,我有興趣學習,如果有多個參數索引屬性的支持。

+2

男人,你釘了它第一次嘗試。我將括號切換到方括號,並立即錯誤消失。 – Isochronous 2010-09-29 21:28:14

+0

是的,我完全投你一票,但我還沒有聲望。 – Isochronous 2010-09-29 21:52:52

+0

@HansPassant我的男人,再次爲我而來(不是你會知道的)。 +1爲一個嚴重有用的職位。以下是我修復的與我的問題相關的調用的語法[這裏](http://stackoverflow.com/questions/13130365/convert-a-clarion-procedure-declaration-to-c-sharp-dllimport),就像另一個例如:'reader.vConfig [READCOLib.ConfigItemEnum.ConfigItem_CaptureMode,0,0] = 113;' – DanM7 2012-11-05 20:15:02