如何在COM服务器中使用用户定义类型(UDT)?

时间:2022-10-11 06:51:08

I have a COM server with a method currently returning an integer:

我有一个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);
};

This compiles fine, but I'd rather return an enum: (this code is actually above the interface definition)

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

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

Which again compile fine of its own right, but as soon as I change the int* to MyEnum* in the interface and implementation, I get linker errors:

这再次编译自己的权利,但是一旦我在接口和实现中将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"

Whichever way I do it, I can't get it to compile.

无论我采用哪种方式,我都无法进行编译。


Thanks to Euro Micelli it turns out that the real problem is that my User Defined Type (the enum) wasn't making it into the generated .IDL file. Judging by forum queries online, this seems to be a common problem.

感谢Euro Micelli,事实证明真正的问题是我的用户定义类型(枚举)没有进入生成的.IDL文件。通过在线论坛查询判断,这似乎是一个常见问题。

A blog article Star Tech: UDT (User Defined Types) and COM guided me down the right path. It seems that a workaround is needed when using attributed ATL.

博客文章Star Tech:UDT(用户定义类型)和COM引导我走正确的道路。在使用属性ATL时,似乎需要一种解决方法。

In summary, I made the following changes:

总之,我做了以下更改:

Created 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;
}

Added the following line prior to the module attribute in the main .cpp file so that the above IDL gets imported into the generated file:

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

[importidl("udt.idl")];

3 个解决方案

#1


(This is adapted from an actual IDL, so I know it works)

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

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

Plus, in your Library section you must include the enum as well, or the enum won't be exported to the type library:

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

library MyLib
{
    enum MyEnum;
...
};

#2


This is very compiler-dependent, since enums don't have a fixed storage size.

这与编译器有关,因为枚举没有固定的存储大小。

There's also the compatibility angle - how would you represent that enum in, say, Visual Basic, or C#? The underlying storage is something like an integer, so that's what COM allows.

还有兼容性角度 - 你会如何在Visual Basic或C#中表示枚举?底层存储就像一个整数,所以这就是COM允许的。

#3


You've almost got it, but the idl compiler has a little stricter syntax than the cl.exe. You need to have the initial enum name before the enum like this.

你几乎得到它,但idl编译器的语法比cl.exe更严格。你需要在enum之前有这样的初始枚举名称。

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

If you build and register your tlb then scripting languages should be able to access your enum in scripts and .NET.

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

#1


(This is adapted from an actual IDL, so I know it works)

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

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

Plus, in your Library section you must include the enum as well, or the enum won't be exported to the type library:

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

library MyLib
{
    enum MyEnum;
...
};

#2


This is very compiler-dependent, since enums don't have a fixed storage size.

这与编译器有关,因为枚举没有固定的存储大小。

There's also the compatibility angle - how would you represent that enum in, say, Visual Basic, or C#? The underlying storage is something like an integer, so that's what COM allows.

还有兼容性角度 - 你会如何在Visual Basic或C#中表示枚举?底层存储就像一个整数,所以这就是COM允许的。

#3


You've almost got it, but the idl compiler has a little stricter syntax than the cl.exe. You need to have the initial enum name before the enum like this.

你几乎得到它,但idl编译器的语法比cl.exe更严格。你需要在enum之前有这样的初始枚举名称。

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

If you build and register your tlb then scripting languages should be able to access your enum in scripts and .NET.

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