【问题标题】:How can I use a User Defined Type (UDT) in a COM server?如何在 COM 服务器中使用用户定义类型 (UDT)?
【发布时间】:2010-10-21 11:03:54
【问题描述】:

我有一个 COM 服务器,其方法当前返回一个整数:

[
    object,
    uuid("..."),
    dual,
    helpstring("IMyCOMServer Interface"),
    pointer_default(unique)
]
__interface IMyCOMServer : IDispatch
{
    [id(1), helpstring("method MyQuery")]
    HRESULT MyQuery([in] BSTR instr, [out,retval] int* outint);
};

这编译得很好,但我宁愿返回一个枚举:(这段代码实际上在接口定义之上)

typedef
[
    uuid("..."),
    v1_enum,
    helpstring("Enum")
]
enum {
    value_a,
    value_b,
    value_c
} MyEnum;

这再次编译它自己的权利,但只要我在接口和实现中将int* 更改为MyEnum*,我就会收到链接器错误:

[id(1), helpstring("method MyQuery")]
HRESULT MyQuery([in] BSTR instr, [out,retval] MyEnum* outint);

error MIDL2025 : syntax error : expecting a type specification near "MyEnum"

无论我怎么做,我都无法编译。


感谢Euro Micelli 事实证明,真正的问题是我的用户定义类型(枚举)没有进入生成的 .IDL 文件。从网上的论坛查询来看,这似乎是一个普遍的问题。

一篇博客文章Star Tech: UDT (User Defined Types) and COM 引导我走上了正确的道路。使用属性化 ATL 时似乎需要一种解决方法。

总的来说,我做了以下更改:

创建udt.idl:

import "oaidl.idl";
import "ocidl.idl";

[
    uuid("..."),
    v1_enum,
    helpstring("Enum")
]
typedef enum MyEnum {
    value_a,
    value_b,
    value_c
} MyEnum_t;

[
    version(1.0),
    uuid(...),
    helpstring(...)
]
library MyLibrary
{
    enum MyEnum;
}

.cpp 主文件中的模块属性之前添加了以下行,以便将上述 IDL 导入到生成的文件中:

[importidl("udt.idl")];

【问题讨论】:

  • 你能试试enum AA {}; HRESULT MyQuery([out,retval] enum AA*) 我记得midl 有一个非常C 的行为(没有自动类型定义)。
  • 你使用的是哪个编译器?
  • @John Dibling:Visual Studio 2005(出于某种原因,我还没有升级到 2008)。
  • @Ismael:好吧,我得到了一个不同的错误:错误 1 ​​错误 MIDL2011:未解析的类型声明:[过程'MyQuery'的参数'AA'(接口'IMyCOMServer')]与nichow的相同建议如下。

标签: c++ com enums


【解决方案1】:

(这是根据实际的 IDL 改编的,所以我知道它有效)

[uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX), v1_enum, helpstring("Enum")]
enum MyEnum {
    value_a,
    value_b,
    value_c
} ;

另外,在您的库部分中,您还必须包含枚举,否则枚举不会导出到类型库:

library MyLib
{
    enum MyEnum;
...
};

【讨论】:

  • 啊...我不确定我是否有图书馆部分!
  • 对。我生成的 .IDL 文件中有一个库部分。该文件根本不包含枚举。如何将枚举放在 .IDL 文件中的正确位置?
  • 我不确定;它是由 Visual Studio 生成的吗?我已经完成了大部分 COM/IDL “艰难的方式”(VS 6),所以我对较新版本的 COM/IDL 工具不是很熟悉。如果它是一次生成的,您可以自己输入。如果它是由 VS 或其他工具生成的,那么该工具应该足够聪明,知道它需要库条目。
【解决方案2】:

这非常依赖于编译器,因为枚举没有固定的存储大小。

还有兼容性的角度——你会如何在 Visual Basic 或 C# 中表示该枚举?底层存储类似于整数,因此 COM 允许这样做。

【讨论】:

  • 这不是 C 或 C++。 COM 接口中的枚举具有由 COM 规则定义的大小。 VB 和 C# 都支持枚举(并且它们与 COM 枚举兼容)。这并不意味着每种语言都必须:例如,在 VBScript 中,枚举被静默映射到 Integer。
【解决方案3】:

你几乎已经明白了,但是 idl 编译器的语法比 cl.exe 更严格一些。你需要像这样在枚举之前有初始枚举名称。

typedef
[uuid("..."), v1_enum, helpstring("Enum")]
enum tagMyEnum
{
    value_a,
    value_b,
    value_c
} MyEnum;

如果您构建并注册您的 tlb,那么脚本语言应该能够在脚本和 .NET 中访问您的枚举。

【讨论】:

  • 在 idl 文件中为 COM 类定义的数据大小不依赖于编译器,而是标准化的。如果它们不是标准尺寸,COM 的互操作性就会被消除,这也是 COM 与它存在的主要原因之一。
  • 我之前尝试过使用标签,但在阅读了这样做的建议后将其删除。我得到一个不同的错误:错误1错误MIDL2011:未解析的类型声明:[过程'MyQuery'(接口'IMyCOMServer')的参数'outenum']这是我定义的函数:HRESULT MyQuery([in] BSTR instr,[out ,retval] 枚举 tagMyEnum* outenum);
猜你喜欢
  • 2018-08-18
  • 2016-03-21
  • 2011-01-03
  • 2011-03-10
  • 1970-01-01
  • 2017-11-17
  • 2020-02-29
  • 2011-04-10
  • 1970-01-01
相关资源
最近更新 更多