尝试将 C# DLL 与来自非托管 C++ 的 ComVisible 属性集一起使用

Trying to use C# DLL with ComVisible attribute set from unmanaged C++

TL;DR:我正在尝试在 C++ 中使用 C# 库。为什么我在尝试使用 .tlh 文件中的标识符时会收到未声明的标识符错误?那里肯定有大量的示例,但我还没有找到任何包含 C# 和 C++ 代码的示例,并且可以正常工作。非常感谢此类示例的链接。

我在 C# 中定义了以下 classes:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using CrystalDecisions.CrystalReports.Engine;

namespace CapsCrystalReportLib
{
    [ComVisible(true)]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [Guid("B4E5F784-12E6-4311-9BB9-D5B3252F20A3")]
    public interface ICapsCrystalReport
    {
        [DispId(1)]
        void DisplayReport(string fileName);
        [DispId(2)]
        void PrintReport(string fileName);
    }

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [Guid("89402DE5-BA26-4AC0-AB40-00ADD2876FF4")]
    [ProgId("CAPSCrystalReport.Report")]
    [ComDefaultInterface(typeof(ICapsCrystalReport))]
    public class CapsCrystalReport : ICapsCrystalReport
    {

        public void DisplayReport(string fileName)
        {
            MessageBox.Show("Displaying report " + fileName);
        }

        public void PrintReport(string fileName)
        {
            MessageBox.Show("Printing report " + fileName);
        }
    }
}

我有以下 C++ 程序试图使用此 class:

#include "stdafx.h"
#import "W:\CAPS Builds\trunk\CapsCrystalReportLib\bin\Debug\CapsCrystalReportLib.tlb" no_namespace

int _tmain(int argc, _TCHAR* argv[])
{
   // Initialize COM.
   HRESULT hr = CoInitialize(NULL);

   // Create the interface pointer.
   CapsCrystalReport CRPtr(__uuidof(CapsCrystalReport));

   long lResult = 0;

   // Call the Add method.
   CRPtr->DisplayReport("SomeReport.rpt");

   // Uninitialize COM.
   CoUninitialize();

   return 0;

}

我收到未声明的标识符错误。编译器不知道 CapsCrystalReport 是什么。我做错了什么?

P.S。我又看了看我从中复制的样本。其中一条评论提出了同样的问题,但从未得到回答。

你说得非常接近,但是 CRPtr 是一个 COM 接口引用(=指针)所以它必须这样声明:

ICapsCrystalReportPtr CRPtr(__uuidof(CapsCrystalReport));

IxxxPtr class 是由 #import 在 .tlh 文件中为您生成的。当您遇到 #import 问题时,您可以做的就是打开生成的 .tlh 文件并查看它。

请注意,您不必在 C# 中声明默认接口,您可以像这样声明 class:

[ComVisible(true)]
[Guid("89402DE5-BA26-4AC0-AB40-00ADD2876FF4")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("CAPSCrystalReport.Report")]
public class CapsCrystalReport
{
    ... same ...
}

而在 C++ 中,您必须像这样调整您的导入:

#import "C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\mscorlib.tlb" auto_rename
#import "W:\CAPS Builds\trunk\CapsCrystalReportLib\bin\Debug\CapsCrystalReportLib.tlb" no_namespace

你会像那样使用它(接口由 .NET 隐式创建并由 #import 包装):

_CapsCrystalReportPtr CRPtr(__uuidof(CapsCrystalReport));

PS:我建议您保留名称空间,避免使用 no_namespace,因为它会导致冲突问题,尤其是在 C++ 中。