【问题标题】:Why are the methods from my C# DLL missing?为什么我的 C# DLL 中的方法丢失了?
【发布时间】:2017-05-17 09:10:12
【问题描述】:

我正在尝试学习如何编写 C# DLL 并从 MFC 应用程序中调用它。

这里是一些 DLL 代码:

using System;
using System.IO;
using System.Xml.Serialization;

namespace MSATools
{
    public class MSAToolsLibrary
    {
        public MSAToolsLibrary()
        {
            _PublisherData = new PublisherData();
        }

        [XmlIgnore]
        private string _strPathXML;

        public void SetPathXML(String strPathXML)
        {
            _strPathXML = strPathXML;
        }

        [XmlIgnore]
        private PublisherData _PublisherData;

        public void SavePublisherData()
        {
            XmlSerializer x = new XmlSerializer(_PublisherData.GetType());
            using (StreamWriter writer = new StreamWriter(_strPathXML))
            {
                x.Serialize(writer, _PublisherData);
            }
        }

        public void ReadPublisherData()
        {
            _PublisherData.Publishers.Clear(); // Reset

            XmlSerializer x = new XmlSerializer(_PublisherData.GetType());
            using (StreamReader reader = new StreamReader(_strPathXML))
            {
                _PublisherData = (PublisherData)x.Deserialize(reader);
            }
        }

        public void AddPublisherData()
        {
            _PublisherData.AddStudent("Andrew", "Andrew notes");
            _PublisherData.AddStudent("Rachel", "Rachel notes");
            _PublisherData.AddStudent("Joshua", "Joshua notes");
            _PublisherData.AddStudent("Finlay", "Finlay notes");
        }
    }
}

我勾选了将其注册为互操作的选项,并且我有一个 TLB 文件。

然后我进入一个新的 MFC 项目并按照教程从 TLB 文件创建一个类。但它创造的只是:

// Machine generated IDispatch wrapper class(es) created with Add Class from Typelib Wizard

#import "D:\\My Programs\\2017\\MSATools\\MSATools\\bin\\Release\\MSATools.tlb" no_namespace
// CMSAToolsLibrary wrapper class

class CMSAToolsLibrary : public COleDispatchDriver
{
public:
    CMSAToolsLibrary() {} // Calls COleDispatchDriver default constructor
    CMSAToolsLibrary(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
    CMSAToolsLibrary(const CMSAToolsLibrary& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

    // Attributes
public:

    // Operations
public:


    // _MSAToolsLibrary methods
public:

    // _MSAToolsLibrary properties
public:

};

我显然在这里遗漏了一些东西。我期待看到我的公共方法:

SetPathXML
ReadPublisherData
SavePublisherData
AddPublisherData

我错过了什么?

这是类在 IDE(MSATools DLL 项目)中的外观:

更新

我试图向我的 C# 库添加一个接口,但我一定做错了什么:

using System;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.InteropServices;

namespace MSATools
{
    [Guid("xxxxxx")]
    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface iInterface
    {
        void SetPathXML(String strPathXML);
        void SavePublisherData();
        void ReadPublisherData();
        void AddPublisherData();
    }

    [Guid("xxxx")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]
    public class MSAToolsLibrary
    {
#region iInterface Members
        public MSAToolsLibrary()
        {
            _PublisherData = new PublisherData();
        }

        [XmlIgnore]
        private string _strPathXML;

        public void SetPathXML(String strPathXML)
        {
            _strPathXML = strPathXML;
        }

        [XmlIgnore]
        private PublisherData _PublisherData;

        public void SavePublisherData()
        {
            XmlSerializer x = new XmlSerializer(_PublisherData.GetType());
            using (StreamWriter writer = new StreamWriter(_strPathXML))
            {
                x.Serialize(writer, _PublisherData);
            }
        }

        public void ReadPublisherData()
        {
            _PublisherData.Publishers.Clear(); // Reset

            XmlSerializer x = new XmlSerializer(_PublisherData.GetType());
            using (StreamReader reader = new StreamReader(_strPathXML))
            {
                _PublisherData = (PublisherData)x.Deserialize(reader);
            }
        }

        public void AddPublisherData()
        {
            _PublisherData.AddStudent("Andrew", "Andrew notes");
            _PublisherData.AddStudent("Rachel", "Rachel notes");
            _PublisherData.AddStudent("Joshua", "Joshua notes");
            _PublisherData.AddStudent("Finlay", "Finlay notes");
        }
#endregion
    }
}

编译正常。但是当我转到 Visual C++ MFC 并从 TypeLib 添加一个类并选择此 TLB 文件 nothing 在列表中显示为可用时。

困惑。

更新 2

我决定尝试创建自己的类作为包装器:

#pragma once

#import "D:\\My Programs\\2017\\MSATools\\MSATools\\bin\\Release\\MSATools.tlb" raw_interfaces_only named_guids

class CMSATools
{
public:
    CMSATools();
    ~CMSATools();
    void SetPathXML(CString strPath);
    void Test();
};

还有:

#include "stdafx.h"
#include "MSATools.h"


CMSATools::CMSATools()
{
}


CMSATools::~CMSATools()
{
}


void CMSATools::SetPathXML(CString strPath)
{
    MSATools::iInterfacePtr     pInterface = NULL;

    HRESULT         hr;
    hr = pInterface.CreateInstance(__uuidof(MSATools::MSAToolsLibrary));

    if (SUCCEEDED(hr))
    {
        CComBSTR    bstrText = strPath.AllocSysString();
        pInterface->SetPathXML(bstrText);
    }
}


void CMSATools::Test()
{
    MSATools::iInterfacePtr     pInterface = NULL;

    HRESULT         hr;
    hr = pInterface.CreateInstance(__uuidof(MSATools::MSAToolsLibrary));

    if (SUCCEEDED(hr))
    {
        CComBSTR    bstrText(_T("d:\\TestStudents.XML"));

        pInterface->SetPathXML(bstrText);
        pInterface->AddPublisherData();
        pInterface->SavePublisherData();
    }
}

它可以编译,我可以使用 VisualAssist 查看方法:

但由于某种原因,hr 没有通过 SUCCEEDED 调用。

更新 3

如果我将 DLL 重新构建为 x64 并将 MFC EXE 重新构建为 x64,则会出现异常:

更新 4

我必须在我的 MFC 应用程序中添加 InitInstance

::Coinitialize(true);

ExitInstance:

::CoUnitialize();

然后异常消失了。

【问题讨论】:

  • 默认情况下,AssemblyInfo 有 [assembly: ComVisible(false)],要么将其更改为 true,要么将您想要的方法标记为可共享。请注意,我对 COM 也比较陌生
  • @prof1990 我已经勾选了“使程序集 COM-Visible”,并确认它在 cs 文件中设置为 true。但是我没有以任何方式标记任何方法。
  • 您关注哪个从 TLB 文件创建类的教程?我很感兴趣。
  • @TomTom 我还没有真正遵循教程。当您将其导入 MFC 或其他项目时,Visual Studio 会从 TLB 中创建一个类。你用谷歌搜索过教程吗?

标签: c# mfc tlb


【解决方案1】:

试试这个修改,用VS生成一个新的guid,因为我不记得它是否自动写入另一个文件。

using System.Runtime.InteropServices;
...
[ComVisibleAttribute(true)]
[Guid("xxx-xxx-xxx-xxx-xxx")]
[ProgId("MSAToolsLibraryClass")]    
public class MSAToolsLibrary
{
...

编辑

确保您的 Assembly.cs 有这样一行:

[程序集:Guid("xxx-xxx-xxx-xxx-xxx")]

【讨论】:

  • 好的,我做到了,并且还将我的类更改为从 iInterface 类继承。但是用Visual C++创建的派生类仍然只有基本的内容。
  • 您是否在为正确的平台进行编译? AnyCPU 是欺骗性的,请再次尝试为 x86 / x64 编译。我现在还没有安装 VS,但是我创建了用于 Visual Basic 6 的 DLL,我可以向你发誓这不是很困难,缺少一些小细节。
  • 你试过为 x86 编译吗?由于我们没有针对 x64 编译的兼容性问题,客户同时使用了 32 和 64 SO。
  • 好的,如果我将 DLL 构建为 x86 并将 MDX EXE 构建为 Win32,则不会出现异常。但是 hr 是负值。
  • 您的 Assembly.cs 是否有像我在答案中编辑的行?
猜你喜欢
  • 2021-01-02
  • 1970-01-01
  • 1970-01-01
  • 2014-08-23
  • 2017-04-27
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
相关资源
最近更新 更多