为什么我的C# DLL中的方法丢失了?

3

我正在尝试学习如何编写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项目):

Classes

更新

我尝试向我的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文件时,列表中没有可用的内容。

感到困惑。

更新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看到方法:

Syntax

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

更新3

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

Exception

更新4

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

::Coinitialize(true);

ExitInstance函数中:

::CoUnitialize();

然后异常消失了。


默认情况下,AssemblyInfo 有 [assembly: ComVisible(false)],要么将其更改为 true,要么标记您想要的方法为 ComVisible。请注意,我对 COM 也是相对较新的。 - prof1990
@prof1990 我已经勾选了“使程序集COM可见”,并确认在cs文件中设置为true。但我没有以任何方式标记任何方法。 - Andrew Truckle
有哪些教程可以从TLB文件中创建类呢?我很感兴趣。 - Tom Tom
@TomTom,我没有真的按照教程操作。当你将TLB导入到你的MFC或者其他项目时,Visual Studio会自动创建一个类。你有在谷歌上搜索教程吗? - Andrew Truckle
1个回答

0

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

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

编辑

请确保您的 Assembly.cs 文件中有以下这行代码:

[assembly: Guid("xxx-xxx-xxx-xxx-xxx")]


好的,我已经做了那个,并且还将我的类更改为继承自iInterface类。但是在Visual C++中创建的派生类仍然只有基本内容。 - Andrew Truckle
你是否为正确的平台编译?AnyCPU是具有欺骗性的,尝试重新编译为x86 / x64。我现在没有安装VS,但我曾经创建过用于Visual Basic 6中使用的DLL,并且我可以发誓这并不是非常困难的,可能只是缺少一些小细节。 - Fran Cerezo
你尝试过为x86编译吗?由于兼容性问题,我们没有为x64编译,客户使用32位和64位操作系统。 - Fran Cerezo
好的,如果我将DLL构建为x86,MDX EXE构建为Win32,则不会出现异常。但是hr的值为负数。 - Andrew Truckle
你的 Assembly.cs 文件中是否有像我在答案中编辑的那一行? - Fran Cerezo
显示剩余5条评论

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