Volleynerd Knowledge Base

Monday, June 30, 2003


MIDL and Enum Name-Mangling

I've gotten obscure build errors when building our SFP stuff with a bunch of dependent IDL (MIDL) files that contain ENUMs. A "deja" search finally set me straight - figured out how to avoid this name mangling issue...

We start with something like this in IDL:
typedef enum

{
SFP_STATE_IDLE = 0x00000000,
SFP_STATE_UPDATECHECK_BUSY = 0x00000001,
SFP_STATE_INSTALL_BUSY = 0x00000002
} SFP_STATE;
Then a method somewhere that uses this enum:
HRESULT State([out, retval] SFP_STATE *pVal);

The Problem
When calling code uses #import on this generated type library, you end up with something like this in the .TLH file:

typedef enum __MIDL___MIDL_itf_UpdateAdvisor_0257_0003 SFP_STATE;
enum __MIDL___MIDL_itf_UpdateAdvisor_0257_0003;
...
...
enum __MIDL___MIDL_itf_UpdateAdvisor_0257_0003
{
SFP_STATE_IDLE = 0,
SFP_STATE_UPDATECHECK_BUSY = 1,
SFP_STATE_INSTALL_BUSY = 2
};


If you use this #import statement in more than one client file/project, you may get multiply defined symbols. The trick to getting around this is to use the "exclude" modifier on the #import in subsequent files/projects. The problem I've had is what to exclude. The multiply defined symbol is really this enum with a big mangled name.

You can exclude by referring to this mangled name:
exclude( "__MIDL___MIDL_itf_vzInstall_0263_0003"),
but this is not optimal. You see, this symbol is *sometimes* mangled to slightly different numeric codes on different machines! I haven't pinpointed where the generated number comes from, especially the 0263 portion (the part that changes on various machines) in the above name. At work here, almost all machines come up with 0263, but then on a new laptop with a fresh install of the VS tools, it generates as 0264. So....how to avoid this constant chase of the mangled names...

The Solution
Thanks to this thread (search google with "#import" enum generated group:microsoft.public.* if the link doesn't work), I found a slightly different way to define the enums in IDL, to avoid the mangling all together.
typedef [public] enum eSfpState

{
SFP_STATE_IDLE = 0x00000000,
SFP_STATE_UPDATECHECK_BUSY = 0x00000001,
SFP_STATE_INSTALL_BUSY = 0x00000002
} SFP_STATE;
Notice the [public] enum eSfpState difference from the original way of describing.

This results in the .tlh having a nicer set of #defines:
typedef enum eSfpState SFP_STATE;

enum eSfpState;
...
...
enum eSfpState
{
SFP_STATE_IDLE = 0,
SFP_STATE_UPDATECHECK_BUSY = 1,
SFP_STATE_INSTALL_BUSY = 2
};


Now you leave the method signature the same in IDL:
HRESULT State([out, retval] SFP_STATE *pVal);
And the caller still uses SFP_STATE as the enum parameter type, and all is well in the world !!!

Wahoo!!




Comments: Post a Comment

Home