【问题标题】:My properties are not listed in COM DLL object from MFC我的属性未在 MFC 的 COM DLL 对象中列出
【发布时间】:2017-05-22 09:37:05
【问题描述】:

好的,这是我的 MFC 代码:

void CTestDlg::OnBnClickedButtonTest()
{
    MSAToolsLibrary::IMSAToolsLibraryInterfacePtr p;
    HRESULT hr;
    hr = p.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
    if (SUCCEEDED(hr))
    {
        __int64 i;
        p->SetPathXML(m_strPublisherDatabaseXML.AllocSysString(), &i);
        p->ReadPublisherData(&i);

        CString strName = _T("Andrew Truckle");
        CComBSTR bstrName = strName.AllocSysString();

        VARIANT_BOOL bResult;
        MSAToolsLibrary::_PublisherPtr pPublisher = NULL;
        hr = p->GetPublisher(bstrName, &pPublisher, &bResult);
        if (SUCCEEDED(hr))
        {
            if (bResult == VARIANT_TRUE)
            {
                AfxMessageBox(_T("Found"));
            }
            else
                AfxMessageBox(_T("Not found"));
        }
        else
        {
            AfxMessageBox(_T("Failed"));
        }
    }
}

这是 TLH 中定义的方法:

  virtual HRESULT __stdcall GetPublisher (
    /*[in]*/ BSTR strPublisher,
    /*[out]*/ struct _Publisher * * thePublisher,
    /*[out]*/ VARIANT_BOOL * bResult ) = 0;

对于初学者,我不确定是否必须使用 _Publisher_PublisherPtr

这是 C# DLL 中的方法:

   public void GetPublisher(string strPublisher, out Publisher thePublisher, out bool bResult)
    {
        bResult = false;
        thePublisher = null;

        if(_PublisherData.PublisherDictionary.ContainsKey(strPublisher))
        {
            bResult = true;
            thePublisher = _PublisherData.PublisherDictionary[strPublisher];
        }
    }

我不明白的是,在 MFC 中,我看不到发布者属性,例如名称等:

我可以在对象浏览器中看到它

这是Publisher 类:

using MSAToolsLibrary.PublisherEntry.AssignmentInfo;
using System.Xml.Serialization;

namespace MSAToolsLibrary.PublisherEntry
{
    public enum Appointed
    {
        NotAppointed,
        MinisterialServant,
        Elder
    }

    public enum Serving
    {
        UnbaptisedPublisher,
        Publisher,
        RegularPioneer
    }

    public enum Gender
    {
        Male,
        Female
    }


    public class Publisher
    {
        public string Name
        {
            get => _Name; set => _Name = value;
        }
        private string _Name;

        public string Notes
        {
            get => _Notes; set => _Notes = value;
        }
        private string _Notes;

        [XmlAttribute]
        public Gender Gender
        {
            get => _Gender; set => _Gender = value;
        }
        private Gender _Gender;

        [XmlAttribute("Appointed")]
        public Appointed AppointedAs
        {
            get => _AppointedAs; set => _AppointedAs = value;
        }
        private Appointed _AppointedAs;

        [XmlAttribute("Serving")]
        public Serving ServingAs
        {
            get => _ServingAs; set => _ServingAs = value;
        }
        private Serving _ServingAs;

        public Availability Availability
        {
            get => _Availability; set => _Availability = value;
        }
        private Availability _Availability = new Availability();

        public Assignments Assignments
        {
            get => _Assignments; set { _Assignments = value; }
        }
        private Assignments _Assignments = new Assignments();
   }
 }

还有图书馆的接口:

[Guid("xxx")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
public interface IMSAToolsLibraryInterface
{
    void SetPathXML(String strPathXML, out Int64 iResult);
    void ReadPublisherData(out Int64 iResult);
    void GetPublisher(string strPublisher, out Publisher thePublisher, out bool bResult);
}

我需要做什么?

更新

我仍然缺少一些东西。我已经关闭了Make assembly COM visible。我在需要它再次编译的地方添加了 GUID。

然后我像这样更改了我的 Publisher 类:

using MSAToolsLibrary.PublisherEntry.AssignmentInfo;
using System.Runtime.InteropServices;
using System.Xml.Serialization;

namespace MSAToolsLibrary.PublisherEntry
{
    [Guid("xxx")]
    [ComVisible(true)]
    public enum Appointed
    {
        NotAppointed,
        MinisterialServant,
        Elder
    }

    [Guid("xxx")]
    [ComVisible(true)]
    public enum Serving
    {
        UnbaptisedPublisher,
        Publisher,
        RegularPioneer
    }

    [Guid("xxx")]
    [ComVisible(true)]
    public enum Gender
    {
        Male,
        Female
    }

    [Guid("xxx")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IPublisher
    {

    }


    [Guid("xxx")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]
    public class Publisher : IPublisher
    {
        public string Name
        {
            get => _Name; set => _Name = value;
        }
        private string _Name;

        public string Notes
        {
            get => _Notes; set => _Notes = value;
        }
        private string _Notes;

        [XmlAttribute]
        public Gender Gender
        {
            get => _Gender; set => _Gender = value;
        }
        private Gender _Gender;

        [XmlAttribute("Appointed")]
        public Appointed AppointedAs
        {
            get => _AppointedAs; set => _AppointedAs = value;
        }
        private Appointed _AppointedAs;

        [XmlAttribute("Serving")]
        public Serving ServingAs
        {
            get => _ServingAs; set => _ServingAs = value;
        }
        private Serving _ServingAs;

        public Availability Availability
        {
            get => _Availability; set => _Availability = value;
        }
        private Availability _Availability = new Availability();

        public Assignments Assignments
        {
            get => _Assignments; set { _Assignments = value; }
        }
        private Assignments _Assignments = new Assignments();
   }
 }

它编译。然后在 MFC 中我改变了它:

void CTestDlg::OnBnClickedButtonTest()
{
    MSAToolsLibrary::IMSAToolsLibraryInterfacePtr p;
    HRESULT hr;
    hr = p.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
    if (SUCCEEDED(hr))
    {
        __int64 i;
        p->SetPathXML(m_strPublisherDatabaseXML.AllocSysString(), &i);
        p->ReadPublisherData(&i);

        CString strName = _T("Andrew Truckle");
        CComBSTR bstrName = strName.AllocSysString();

        VARIANT_BOOL bResult;
        MSAToolsLibrary::IPublisherPtr pPublisher;
        // So I don't need to use pPublisher.CreateInstance
        hr = p->GetPublisher(bstrName, &pPublisher, &bResult);
        if (SUCCEEDED(hr))
        {
            if (bResult == VARIANT_TRUE)
            {
                AfxMessageBox(_T("Found"));
            }
            else
                AfxMessageBox(_T("Not found"));
        }
        else
        {
            AfxMessageBox(_T("Failed"));
        }
    }
}

但我仍然在 Intelisense 中看不到任何成员。我错过了什么?

更新 2

好的,interface 似乎不能包含这些字段?所以我尝试为 Name 类添加一个公共方法(例如):

[Guid("xxx")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
public interface IPublisher
{
    string GetName();
}


[Guid("xxx")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class Publisher : IPublisher
{
    public string GetName()
    {
        return Name;
    }

    public string Name
    {
        get => _Name; set => _Name = value;
    }
    private string _Name;

}

那行得通。我可以从MFC 拨打GetName

【问题讨论】:

    标签: c# mfc com


    【解决方案1】:
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IMSAToolsLibraryInterface
    

    您知道如何正确执行此操作。但是您没有为您的 Publisher 类正确执行此操作。您可能发现了这一点并使用另一个锤子解决了这个问题,您使用了 Project > Properties > Application > Assembly Information > "Make assembly COM-Visible"。

    这是一种使所有公共类型可见的大锤解决方案。现在 [ClassInterface] 属性开始变得重要,它决定了如何将类自动转换为接口。必需,因为 COM 只使用接口。但是 Publisher 类没有明确地具有该属性。所以你发现你不喜欢默认的 ClassInterfaceType.AutoDispatch。这使得自动生成的界面看起来像这样:

    interface _Publisher : IDispatch {
    };
    

    只有 IDispatch 接口成员被“继承”,没有任何类成员。正是您在 IntelliSense 框中看到的,Invoke 等是 IDispatch 接口成员。对脚本语言有用,如果您喜欢 IntelliSense,则无用。

    因此,请以正确的方式执行此操作。考虑关闭复选框,它对您没有帮助。您可以使用快捷方式并将 [ClassInterface(ClassInterfaceType.AutoDual)] 应用于 Publisher 类。不太干净,因为它还公开了从 System.Object 继承的成员,并且类型库将依赖于 mscorlib.tlb。或者最正确的方式,你知道的,声明一个 IPublisher 接口。 ClassInterface.None 现在是您的 Publisher 类的正确选择。

    顺便说一句,请考虑在您的接口上使用 ComInterfaceType.InterfaceIsDual,这样您的 COM 服务器也可以通过脚本语言使用。

    【讨论】:

    • 一个空界面??请考虑一下这样做的后果。
    • 当然,问题是,它不允许我将我的field 对象添加到界面中。但我认为我应该这样做。请参阅更新的问题。认为我现在明白了吗?似乎如此。但是,返回 _Name 而不是 Name 对象更好吗?还是没那么重要?
    • 不仅仅是 C# 不允许在接口中使用字段,COM 也不允许。您改为使用属性。好吧,你知道它们是如何工作的。
    • 好的,但我不明白。 public string Name 是公共财产。但是,我无法弄清楚如何将其添加到界面中。我用 C++ 术语创建了我认为的公共method 来访问公共property。但是您的评论暗示能够使用公共财产。我想我对私有变量是一个字段这一事实感到困惑。属性是对私有字段的公共访问。但是你能澄清一下我的公共属性应该如何在接口中实现吗?我的方式,还是其他方式?谢谢。
    • 不,这是一个字段。在它后面加上{ get; set; } 和 presto-chango,它现在是一个属性。您知道这一点,您的 C# 代码已经是属性。奇怪的挂断。
    猜你喜欢
    • 1970-01-01
    • 2017-02-15
    • 2011-02-12
    • 2013-09-08
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多