COM Interop:索引属性签名问题

问题描述:

我正在处理一个项目,这是一个.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; 
}; 

我该怎么办?

编辑:我应该提到,我最初并没有使用命名参数;我试图让错误消失。

嗯,你的代码建议你事实上使用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://*.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