Preserving 'hidden' elements in a COM interop assembly

If you are shipping interop assemblies or PIAs of COM type libraries, you may have some elements in your type library marked as hidden.  But, C# and VB Intellisense show these hidden elements anyway.  This problem can be fixed with some low level work.  This information may help you with the task.

 

To create interop assemblies, Tlbimp.exe takes as input your COM type libraries.  Tlbimp.exe does preserve the "hidden" flag in the interop assembly it generates, in fact, the VS 2008 Object Browser correctly interprets the flag but C# and VB Intellisense doesn't.

 

To fix this problem we must add an attribute to any members in the interop assembly that shouldn’t appear in IntelliSense.  Here is the attribute: [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)].

By modifying the interop assembly, we can add this attribute to the interop assembly.  Editing an interop assembly is called ‘round-tripping’ the Interop assembly.

 

‘Round-tripping’ the Interop assembly is accomplished by modifying the IL code of your interop assembly.  The IL is generated by feeding ILDASM the interop assembly.  Next, add the EditorBrowsable attribute on hidden members in the IL code.  Finally re-assemble the IL code into the Interop assembly again.  This is quickly described by the authority, Adam Nathan, in this blog, Tricks for Modifying Interop Assemblies and described in detail in the book .NET and COM: The Complete Interoperability Guide by Adam Nathan.

 

 

The hidden flag is manifested in interop assembly metadata as a  System.Runtime.InteropServices.TypeLibFuncAttribute(64)]where 64 == FUNCFLAGS Enumeration value of  FUNCFLAG_FHIDDEN

 

Like this:

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(6), TypeLibFunc((short) 0x40)]

void Draw([In] IntPtr hdc);

 

Here's what I've discovered with my own investigation using the ShapeAppMFC sample:

 

[Note: the source  files -- ShapeAppMFC.idl,  ShapeAppMFC.tlb, ShapeAppMFC.interop.dll are all available in the VSTA 2.0 SDK]

 

1.  The ShapeAppMFC sample in the VSTA SDK includes a COM typelibrarywith an interface that has a hidden method marked in the ShapeAppMFC.idl file:

 

    [id(6), helpstring("method Draw"), hidden] HRESULT Draw([in] PVOID hdc);

  This method is defined in IDL interface IShape : IDispatch{

[
    object,
    uuid(AA4B9334-63A0-4C8B-AEE1-A759C0E66209),
    dual,
    nonextensible,
    helpstring("IShape Interface"),
    pointer_default(unique)
]
interface IShape : IDispatch{
    [propget, id(1), helpstring("property Color")] HRESULT Color([out, retval] IColorInfo** pVal);
    [propput, id(1), helpstring("property Color")] HRESULT Color([in] IColorInfo* newVal);
    [propget, id(2), helpstring("property Size")] HRESULT Size([out, retval] ISizeInfo** pVal);
    [propput, id(2), helpstring("property Size")] HRESULT Size([in] ISizeInfo* newVal);
    [propget, id(3), helpstring("property Location")] HRESULT Location([out, retval] IPointInfo** pVal);
    [propput, id(3), helpstring("property Location")] HRESULT Location([in] IPointInfo* newVal);
    [propget, id(4), helpstring("property Name")] HRESULT Name([out, retval] BSTR* pVal);
    [id(5), helpstring("method ContainsPoint")] HRESULT ContainsPoint([in] IPointInfo* p, [out,retval] VARIANT_BOOL* retVal);
    [id(6), helpstring("method Draw"), hidden] HRESULT Draw([in] PVOID hdc);
    [id(7), helpstring("method Load")] HRESULT Load(SAFEARRAY(BYTE) savedState);
    [id(8), helpstring("method Save")] HRESULT Save([out, retval] SAFEARRAY(BYTE) *savedState);
    [id(9), helpstring("method Clone")] HRESULT Clone([out, retval] IShape **ppNewShape);
};

 

2. ShapeAppMFC.idl is used to generate the typelibrary, "ShapeAppMFC.tlb" which I've also attached.

 

3. ShapeAppMFC.tlb is consumed by tlbimp to generate a PIA, ShapeAppMFC.interop.dll :

call "%WindowsSDKPath%bin\tlbimp" "%ShapeAppDir%\ShapeAppMFC.exe" /out:"%PIADir%\ShapeAppMFC.interop.dll" /keyfile:"%KeyPath%" /primaryI

4. Using .Net Reflector, I open ShapeAppMFC.interop.dll and disassemble the method IShape.Draw, Tools

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(6), TypeLibFunc((short) 0x40)]

void Draw([In] IntPtr hdc);

5.  I noticed that there was a unique TypeLibFunc((short)0x40) in the .NET Reflector dissassembly for ISharp.Draw.

 

6.  This typlibfunc attribute also shows up in VS2008 Object Browser:

 

void Draw(IntPtr hdc)

    Member of ShapeApp.Proxy.IShape

Summary:

method Draw

Attributes:

[System.Runtime.InteropServices.DispIdAttribute(6),

System.Runtime.InteropServices.TypeLibFuncAttribute(64)]

 

Notice that VS 2008 Object Browser correctly interprets System.Runtime.InteropServices.TypeLibFuncAttribute(64) as a hidden member, and hides the 'Draw()' method unless 'Show Hidden Types and Members' is switched on in the Object Browser Settings.  When the 'Draw()' method  is shown, it is gray colored

7. MSDN (http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.funcflags(VS.71).aspx)

documents the FUNCFLAGS Enumeration value of '60' as the FUNCFLAG_FHIDDEN


Posted Feb 06 2009, 03:42 PM by Gary
Copyright Summit Software Company, 2008. All rights reserved.