我的属性未在 MFC 的 COM DLL 对象中列出
My properties are not listed in COM DLL object from MFC
好的,这是我的 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
class:
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。
然后我像这样更改了我的发布者 class:
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
不能包含字段?所以我尝试将 public 方法添加到 class 的名称(例如):
[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
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
public interface IMSAToolsLibraryInterface
你知道如何正确地做到这一点。但是您没有为您的发布者正确执行此操作 class。您可能发现了这一点并使用了另一个锤子来解决该问题,您使用了 Project > Properties > Application > Assembly Information > "Make assembly COM-Visible".
这是使所有 public 类型可见的大锤解决方案。现在 [ClassInterface] 属性开始变得重要,它决定了 class 如何自动转换为接口。必需的,因为 COM 只使用接口。但是 Publisher class 没有明确的属性。所以您发现您不喜欢默认值 ClassInterfaceType.AutoDispatch。这使得自动生成的界面看起来像这样:
interface _Publisher : IDispatch {
};
只是 IDispatch 接口成员是 class 成员中的 "inherited"、none。正如您在 IntelliSense 框中看到的那样,Invoke 等是 IDispatch 接口成员。对脚本语言有用,如果你喜欢 IntelliSense 就没用了。
所以要以正确的方式进行。考虑关闭复选框,它对你没有帮助。您可以使用快捷方式并将 [ClassInterface(ClassInterfaceType.AutoDual)] 应用到 Publisher class。不太干净,因为它还暴露了从 System.Object 继承的成员,并且类型库将依赖于 mscorlib.tlb。或者最正经的方法,你知道的,声明一个 IPublisher 接口。 ClassInterface.None 现在是您的 Publisher class.
的正确选择
顺便说一句,请考虑在您的界面上支持 ComInterfaceType.InterfaceIsDual,这样您的 COM 服务器也可以通过脚本语言使用。
好的,这是我的 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
class:
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。
然后我像这样更改了我的发布者 class:
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
不能包含字段?所以我尝试将 public 方法添加到 class 的名称(例如):
[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
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComVisible(true)]
public interface IMSAToolsLibraryInterface
你知道如何正确地做到这一点。但是您没有为您的发布者正确执行此操作 class。您可能发现了这一点并使用了另一个锤子来解决该问题,您使用了 Project > Properties > Application > Assembly Information > "Make assembly COM-Visible".
这是使所有 public 类型可见的大锤解决方案。现在 [ClassInterface] 属性开始变得重要,它决定了 class 如何自动转换为接口。必需的,因为 COM 只使用接口。但是 Publisher class 没有明确的属性。所以您发现您不喜欢默认值 ClassInterfaceType.AutoDispatch。这使得自动生成的界面看起来像这样:
interface _Publisher : IDispatch {
};
只是 IDispatch 接口成员是 class 成员中的 "inherited"、none。正如您在 IntelliSense 框中看到的那样,Invoke 等是 IDispatch 接口成员。对脚本语言有用,如果你喜欢 IntelliSense 就没用了。
所以要以正确的方式进行。考虑关闭复选框,它对你没有帮助。您可以使用快捷方式并将 [ClassInterface(ClassInterfaceType.AutoDual)] 应用到 Publisher class。不太干净,因为它还暴露了从 System.Object 继承的成员,并且类型库将依赖于 mscorlib.tlb。或者最正经的方法,你知道的,声明一个 IPublisher 接口。 ClassInterface.None 现在是您的 Publisher class.
的正确选择顺便说一句,请考虑在您的界面上支持 ComInterfaceType.InterfaceIsDual,这样您的 COM 服务器也可以通过脚本语言使用。