【问题标题】:Is this .tlh file correct, and if not, then how do I generate the correct one?这个 .tlh 文件是否正确,如果不正确,那么如何生成正确的文件?
【发布时间】:2014-07-16 13:17:58
【问题描述】:

我正在尝试从非托管 C++ 代码调用 .NET 4.0 dll。

我按照this Code Project article by Atul Mani.中的说明进行操作

我构建了 .NET dll,并按照所有步骤进行操作,包括使用 regasm 注册它。

接下来,我创建了一个非托管 C++ 项目,并在 .cpp 文件的开头添加了这一行:

#import "D:\PathToMyCSharpProject\bin\Debug\com.DeviceServices.tlb" rename ("EOF","adoEOF") no_namespace named_guids raw_interfaces_only

当我构建 C++ 项目时,在 D:\MyCPlusPlusProject\Debug 中创建了一个 .tlh 文件。

接下来,我添加了 CodeProject 文章建议的代码,该代码尝试从 C# 库创建指向对象的指针。

CoInitialize(NULL);   //Initialize all COM Components

// <namespace>::<InterfaceName>
MyCSharpNamespace::IMyCSharpInterfacePtr pMyCSharpInterfacePtr;

“MyCSharpNamespace”是我在 C# 项目中使用的命名空间。

当我构建 C++ 项目时,现在出现编译错误:

错误 2 错误 C2653:“MyCSharpNamespace”:不是类或命名空间名称

还有其他错误,因为它无法识别 IMyCSharpInterfactPtr。

于是,我查看了.tlh文件,内容如下:

// Created by Microsoft (R) C/C++ Compiler Version 10.00.40219.01 (6478e0c7).
//
// MyCPlusPlusProjectPath\debug\com.deviceservices.tlh
//
// C++ source equivalent of Win32 type library MyCSharpProjectPath\bin\Debug\com.DeviceServices.tlb
// compiler-generated file created 05/27/14 at 11:52:16 - DO NOT EDIT!

#pragma once
#pragma pack(push, 8)

#include <comdef.h>

//
// Forward references and typedefs
//

struct __declspec(uuid("961b3c24-98f2-400e-8bea-ab357a18d851"))
/* LIBID */ __MyCSharpProject;

//
// Named GUID constants initializations
//

extern "C" const GUID __declspec(selectany) LIBID_MyCSharpProject =
    {0x961b3c24,0x98f2,0x400e,{0x8b,0xea,0xab,0x35,0x7a,0x18,0xd8,0x51}};

#pragma pack(pop)

我在网上搜索了一下.tlh文件应该是什么,发现the #import page at msdn.

它说 .tlh 文件的内容应该包括我的 .tlh 文件中不存在的智能指针声明(即 IMyCSharpProjectInterfacePtr)和 typeinfo 声明。

MyCSharpProject 声明了一个公共接口,包括一个生成的 GUID,构建正确,并且我在文章中遵循的所有步骤似乎都成功了。

所以,我的问题是,有人可以建议为什么我的 .tlh 文件中不存在这些定义吗?

【问题讨论】:

  • 查看您的#import 属性rename ("EOF","adoEOF") no_namespace named_guids raw_interfaces_only。它们改变了 .tlh 和其他文件的生成方式(检查文档)。您可以尝试将它们全部删除以开始。
  • @SimonMourier - 谢谢。您的评论启发我查找#import 的文档并了解它的实际工作原理msdn.microsoft.com/en-us/library/298h7faa.aspx

标签: c# c++ com unmanaged managed


【解决方案1】:

.tlh 文件不能出错,它是从您的 COM 服务器的类型库中自动生成的。一个明显的缺陷是它相当空,你根本看不到任何声明。

问题在于 Codeproject.com 的那篇文章,与此类项目的课程一样,它缺少一个基本步骤,没有解释真正发生的事情,并且经常使用非常糟糕的做法。为了使 COM 客户端可以使用 .NET 类型,您必须明确地使其对 COM 客户端可见。将此属性添加到您要导出的每种类型:

  [ComVisible(true)]

将其应用于接口和类。

像作者建议的那样使用 [Guid] 属性是非常危险的。在开发库时保留它是可以的,它有助于避免注册表污染并让您跳过 Regasm 步骤(并非总是如此),但在发布库之前再次删除它非常重要。 COM 中的一条硬性规则是,对接口的修改需要一个新的 guid,这是一个必不可少的 DLL Hell 对策。当您让 CLR 自动生成一个时,您会自动获得一个新的。

在开发过程中最好避免在 GAC 中注册程序集,因为在 GAC 中留下过时的程序集副本会导致太多意外。在 Regasm 命令中使用 /codebase 选项,因此不需要这样做。您可以忽略收到的警告。

【讨论】:

  • 谢谢!我根据您的建议重新构建了所有内容,现在我对它的理解好多了。但我仍然无法让我的 .tlh 文件显示 C# 接口的内容。我现在怀疑我的 C# 项目是错误的,因为它比我读过的简单示例更复杂。关于这个问题有很多有用的信息,我想将其标记为关闭,并打开一个关于 C# 项目的新信息。再次,非常感谢。
  • 附录:我通过从头开始重新创建 C# 和 C++ 项目使其工作。仍然不确定是什么损坏了,但 .tlh 文件现在包含正确的声明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多