尝试将 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++ 中。
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++ 中。