COM互操作:索引属性签名问题

7
我正在开发一个项目,它是一个.NET扩展,用于相当大的经典ASP项目,使用了许多C++ COM对象,这些对象一直存在于我们的代码库中。不幸的是,在C++方面有很多hack-ish代码,我担心自己没有足够的经验来解决我遇到的问题。
简而言之,我可以实例化所需的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);
};

最后,这是 coclass 的定义:
[
    uuid(BF748C0A-450D-4EAF-8C39-A36F6B455587),
    helpstring("ComUser Class")
]
coclass ComUser
{
    [default] interface IComUser;
};

我该怎么做?

编辑:我应该提到我最初没有使用命名参数;我只是尝试这样做以消除错误。

1个回答

16

嗯,你的代码表明你实际上使用的是C# 4.0,因为你正在使用命名参数。该版本确实支持在COM互操作方案中使用索引属性。然而,索引器语法需要使用[方括号]。我不知道它是否仍然可以处理多个参数,示例中只有一个参数。首先尝试这个:

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

或者用以下方式解决问题:

 var result = userObject.get_LoginUser("foo", "bar");
请告诉我们你发现了什么,我很想知道是否支持带有多个参数的索引属性。

2
老兄,你一次就搞定了。我把括号换成方括号,错误立刻消失了。 - Isochronous
是啊,我完全会给你点赞的,但我还没有声望。 - Isochronous
@HansPassant,老兄,再次帮了我一个大忙(虽然你可能并不知道)。+1 表示真的是个非常有用的帖子。这里提供我修复问题时相关调用的语法在这里,仅作为另一个例子:reader.vConfig[READCOLib.ConfigItemEnum.ConfigItem_CaptureMode, 0, 0] = 113; - DanM7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接