[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework.interop

Introspecting COM Object in C#

MichaelQuinlan

10/12/2007 12:54:00 PM

My C# program is being passed a COM object. I can successfully read and write
properties in the COM object by using code like this:

object tsFields = tsInterface.GetType().InvokeMember("TSFields",
BindingFlags.GetProperty, null, tsInterface, new object[] { });

What I would like to be able to do is get a list of the public properties
and methods defined in the COM object. When I use the statement

MemberInfo[] memberInfoArr = tsInterface.GetType().GetMembers();

The result contains 7 items:
+ [0] {System.Object GetLifetimeService()} System.Reflection.MemberInfo
{System.Reflection.RuntimeMethodInfo}
+ [1] {System.Object InitializeLifetimeService()}
System.Reflection.MemberInfo {System.Reflection.RuntimeMethodInfo}
+ [2] {System.Runtime.Remoting.ObjRef CreateObjRef(System.Type)}
System.Reflection.MemberInfo {System.Reflection.RuntimeMethodInfo}
+ [3] {System.Type GetType()} System.Reflection.MemberInfo
{System.Reflection.RuntimeMethodInfo}
+ [4] {System.String ToString()} System.Reflection.MemberInfo
{System.Reflection.RuntimeMethodInfo}
+ [5] {Boolean Equals(System.Object)} System.Reflection.MemberInfo
{System.Reflection.RuntimeMethodInfo}
+ [6] {Int32 GetHashCode()} System.Reflection.MemberInfo
{System.Reflection.RuntimeMethodInfo}

None of these are the actual properties and methods defined by the COM object.

Is there any way I can get a list of the properties and methods defined by
the COM object?

Thanks,
8 Answers

wawang

10/15/2007 6:21:00 AM

0

Hi Michael,

If the COM object implements IDispatch, we can use IDispatch.GetTypeInfo to
get its type information.

Please try following code:

1) Add reference to "CustomMarshalers", you should be able to find it at
%windir%\Microsoft.NET\Framework\v2.0.50727\CustomMarshalers.dll.

2) Use following code to test:

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Runtime.InteropServices.CustomMarshalers;

namespace ConsoleApplication1
{
[
ComImport,
Guid("00020400-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
public interface IDispatch
{
void Reserved();
[PreserveSig]
int GetTypeInfo(uint nInfo, int lcid,
[MarshalAs(
UnmanagedType.CustomMarshaler,
MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))]
out System.Type typeInfo);
}

class Program
{
static void Main(string[] args)
{
Type t1 = Type.GetTypeFromProgID("Scripting.FileSystemObject");
Object o1 = Activator.CreateInstance(t1);

IDispatch disp2 = o1 as IDispatch;
if (disp2 != null)
{
Type t3;
disp2.GetTypeInfo(0, 0, out t3);

MemberInfo[] mlist3 = t3.GetMembers();
}
}
}
}


References:

#.NET Remoting: Create a Custom Marshaling Implementation Using .NET
Remoting and COM Interop -- MSDN Magazine, September 2003
http://msdn.microsoft.com/msdnmag/issues/03/09/CustomM...


Hope this helps.


Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.


MichaelQuinlan

10/15/2007 4:33:00 PM

0

This is exactly what I need. Thanks!

""Walter Wang [MSFT]"" wrote:

> Hi Michael,
>
> If the COM object implements IDispatch, we can use IDispatch.GetTypeInfo to
> get its type information.
>
> Please try following code:
>
> 1) Add reference to "CustomMarshalers", you should be able to find it at
> %windir%\Microsoft.NET\Framework\v2.0.50727\CustomMarshalers.dll.
>
> 2) Use following code to test:
>
> using System;
> using System.Text;
> using System.Runtime.InteropServices;
> using System.Reflection;
> using System.Runtime.InteropServices.CustomMarshalers;
>
> namespace ConsoleApplication1
> {
> [
> ComImport,
> Guid("00020400-0000-0000-C000-000000000046"),
> InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
> ]
> public interface IDispatch
> {
> void Reserved();
> [PreserveSig]
> int GetTypeInfo(uint nInfo, int lcid,
> [MarshalAs(
> UnmanagedType.CustomMarshaler,
> MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))]
> out System.Type typeInfo);
> }
>
> class Program
> {
> static void Main(string[] args)
> {
> Type t1 = Type.GetTypeFromProgID("Scripting.FileSystemObject");
> Object o1 = Activator.CreateInstance(t1);
>
> IDispatch disp2 = o1 as IDispatch;
> if (disp2 != null)
> {
> Type t3;
> disp2.GetTypeInfo(0, 0, out t3);
>
> MemberInfo[] mlist3 = t3.GetMembers();
> }
> }
> }
> }
>
>
> References:
>
> #.NET Remoting: Create a Custom Marshaling Implementation Using .NET
> Remoting and COM Interop -- MSDN Magazine, September 2003
> http://msdn.microsoft.com/msdnmag/issues/03/09/CustomM...
>
>
> Hope this helps.
>
>
> Regards,
> Walter Wang (wawang@online.microsoft.com, remove 'online.')
> Microsoft Online Community Support
>
> ==================================================
> When responding to posts, please "Reply to Group" via your newsreader so
> that others may learn and benefit from your issue.
> ==================================================
>
> This posting is provided "AS IS" with no warranties, and confers no rights.
>
>
>

FredPetterPedersen

10/16/2007 9:20:00 AM

0

I dont really have an answer for you but is working with exactly the same. Would like to hear from you if you find any solution. I'll keep on working on this so I'll come back with my findings some time. Good luck! ;-)

EggHeadCafe - .NET Developer Portal of Choice
http://www.egghe...

fredpp

10/23/2007 6:19:00 AM

0

On 15 Okt, 08:20, waw...@online.microsoft.com ("Walter Wang [MSFT]")
wrote:
> Hi Michael,
>
> If the COM object implements IDispatch, we can use IDispatch.GetTypeInfotogetitstypeinformation.
>
> Please try following code:
>
> 1) Add reference to "CustomMarshalers", you should be able to find it at
> %windir%\Microsoft.NET\Framework\v2.0.50727\CustomMarshalers.dll.
>
> 2) Use following code to test:
>
> class Program
> {
> static void Main(string[] args)
> {
> Typet1 =Type.GetTypeFromProgID("Scripting.FileSystemObject");
> Object o1 = Activator.CreateInstance(t1);
>
> IDispatch disp2 = o1 as IDispatch;
> if (disp2 != null)
> {
> Typet3;
> disp2.GetTypeInfo(0, 0, out t3);
>
> MemberInfo[] mlist3 = t3.GetMembers();
> }
> }
> }
>
> }
>
> References:
>
> #.NET Remoting: Create a Custom Marshaling Implementation Using .NET
> Remoting and COM Interop -- MSDN Magazine, September 2003http://msdn.microsoft.com/msdnmag/issues/03/09/CustomM...
>
> Hope this helps.
>
> Regards,
> Walter Wang (waw...@online.microsoft.com, remove 'online.')
> Microsoft Online Community Support
>
> This posting is provided "AS IS" with no warranties, and confers no rights.

Hi

I'm trying to do the exactly same but the method:

disp2.GetTypeInfo(0, 0, out t3);

takes very long time to get finished, about 4 minutes, which is too
mutch of course. What can be the reason for this? I know that my COM-
object has very many interfaces, but I cant understand why this
shouldn't be handled....... My COM is written in Delphi and I have
access to the source, is there anything I can look at in the source to
make this faster?

Thanks in advance

- RightCoder

unknown

10/25/2007 9:57:00 PM

0

The reason that it is taking so long is because it's generating
in-memory interop assemblies behind the scenes. It's basically the same
thing as adding a reference to a type library in Visual Studio although
it seems to be slower than when you manually add the reference.

The faster but more difficult way to work with COM in .NET is to work
directly with the IDispatch interface. Here is a bit of code that I use
in one of my applications. The code listed below are 3 separate .cs
files. I also did not list my full source so not all functionality is
available in what I'm giving you but it should be enough to give you an
idea as to what's involved.

Once you have the code in place, you can use it something like:

Jason Newell
www.jasonnewell.net


/* Example Usage */
ComObject comObject = new
ComObject(Marshal.GetActiveObject("Word.Application"));
string[] propertyNames = comObject.GetPropertyNames();
foreach (string propertyName in propertyNames)
{
object property =
comObject.WrappedComObject.GetType().InvokeMember(propertyName,
System.Reflection.BindingFlags.GetProperty, null,
comObject.WrappedComObject, null);
}



/* IDispatch.cs */
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace SolidEdgeSpy.InteropServices
{
[Guid("00020400-0000-0000-c000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDispatch
{
int GetTypeInfoCount();
System.Runtime.InteropServices.ComTypes.ITypeInfo
GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo,
[MarshalAs(UnmanagedType.U4)] int lcid);
[PreserveSig]
int GetIDsOfNames(ref Guid riid,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]
string[] rgsNames, int cNames, int lcid,
[MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
[PreserveSig]
int Invoke(int dispIdMember, ref Guid riid,
[MarshalAs(UnmanagedType.U4)] int lcid, [MarshalAs(UnmanagedType.U4)]
int dwFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS
pDispParams, [Out, MarshalAs(UnmanagedType.LPArray)] object[]
pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO
pExcepInfo, [Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] pArgErr);
}
}

/* ComObject.cs */
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;

namespace SolidEdgeSpy.InteropServices
{
public class ComObject : IDisposable
{
private object _object;
private IDispatch _dispatch;
private IntPtr _pTypeAttr = IntPtr.Zero;
private System.Runtime.InteropServices.ComTypes.ITypeInfo
_typeInfo;
private string _typeName, _typeDescription, _typeHelpFile;
private int _typeHelpContext;
private SolidEdgeSpy.InteropServices.ComTypeLibrary
_comTypeLibrary;

public ComObject(object comObject)
{
System.Runtime.InteropServices.ComTypes.ITypeLib ppTLB = null;
int pIndex = 0;

_dispatch = comObject as IDispatch;

if (_dispatch != null)
{
_object = comObject;
_typeInfo = _dispatch.GetTypeInfo(0, 0);
_typeInfo.GetTypeAttr(out _pTypeAttr);
_typeInfo.GetDocumentation(-1, out _typeName, out
_typeDescription, out _typeHelpContext, out _typeHelpFile);
_typeInfo.GetContainingTypeLib(out ppTLB, out pIndex);
_comTypeLibrary = new ComTypeLibrary(ppTLB);
}
else
{
throw new InvalidComObjectException();
}
}

~ComObject()
{
Dispose();
}

public void Dispose()
{
try
{
if (_typeInfo != null)
{
_typeInfo.ReleaseTypeAttr(_pTypeAttr);
}

if (_object != null) {
Marshal.ReleaseComObject(_object); _object = null; }
if (_dispatch != null) {
Marshal.ReleaseComObject(_dispatch); _dispatch = null; }
}
catch
{
}
}

public string[] GetPropertyNames()
{
System.Collections.ArrayList list = new
System.Collections.ArrayList();

try
{
for (int i = 0; i < this.TypeAttr.cFuncs; i++)
{
IntPtr pFuncDesc = IntPtr.Zero;
System.Runtime.InteropServices.ComTypes.FUNCDESC
funcDesc;
string strName, strDocString, strHelpFile;
int dwHelpContext;

_typeInfo.GetFuncDesc(i, out pFuncDesc);
funcDesc =
(System.Runtime.InteropServices.ComTypes.FUNCDESC)Marshal.PtrToStructure(pFuncDesc,
typeof(System.Runtime.InteropServices.ComTypes.FUNCDESC));

switch (funcDesc.invkind)
{
case
System.Runtime.InteropServices.ComTypes.INVOKEKIND.INVOKE_PROPERTYGET:
_typeInfo.GetDocumentation(funcDesc.memid,
out strName, out strDocString, out dwHelpContext, out strHelpFile);
list.Add(strName);
break;
}
}
}
catch (System.Exception ex)
{
throw ex;
}

return (string[])list.ToArray(typeof(string));
}

public string TypeName { get { return this._typeName; } }
public string TypeFullName { get { return
this.ComTypeLibrary.Name + "." + this._typeName; } }
public string TypeDescription { get { return
this._typeDescription; } }
public int TypeHelpContext { get { return
this._typeHelpContext; } }
public string TypeHelpFile { get { return this._typeHelpFile; } }
public object WrappedComObject { get { return _dispatch; } }
public ComTypeLibrary ComTypeLibrary { get { return
_comTypeLibrary; } }
public System.Runtime.InteropServices.ComTypes.TYPEATTR
TypeAttr { get { return
(System.Runtime.InteropServices.ComTypes.TYPEATTR)Marshal.PtrToStructure(_pTypeAttr,
typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR)); } }
public string TypeVersion
{
get
{
string version = String.Empty;
try
{
version = TypeAttr.wMajorVerNum.ToString() + "." +
TypeAttr.wMinorVerNum.ToString();
}
catch
{
}
return version;
}
}
}
}

/* ComTypeLibrary.cs */
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;

namespace SolidEdgeSpy.InteropServices
{
public class ComTypeLibrary
{
private System.Runtime.InteropServices.ComTypes.ITypeLib _typeLib;
IntPtr _pTypeLibAttr = IntPtr.Zero;
string _Name, _Description, _HelpFile;
int _HelpContext;

public
ComTypeLibrary(System.Runtime.InteropServices.ComTypes.ITypeLib typeLib)
{
_typeLib = typeLib;
_typeLib.GetLibAttr(out _pTypeLibAttr);
_typeLib.GetDocumentation(-1, out _Name, out _Description,
out _HelpContext, out _HelpFile);
}

public string Name { get { return this._Name; } }
public string Description { get { return this._Description; } }
public int HelpContext { get { return this._HelpContext; } }
public string HelpFile { get { return this._HelpFile; } }
public System.Runtime.InteropServices.ComTypes.TYPELIBATTR
TypeLibAttr { get { return
(System.Runtime.InteropServices.ComTypes.TYPELIBATTR)Marshal.PtrToStructure(_pTypeLibAttr,
typeof(System.Runtime.InteropServices.ComTypes.TYPELIBATTR)); } }
public string TypeLibVersion
{
get
{
string version = String.Empty;
try
{
version = TypeLibAttr.wMajorVerNum.ToString() + "."
+ TypeLibAttr.wMinorVerNum.ToString();
}
catch
{
}
return version;
}
}

public Version Version
{
get
{
return new Version(TypeLibAttr.wMajorVerNum,
TypeLibAttr.wMinorVerNum, 0, 0);
}
}

public override int GetHashCode()
{
return this.TypeLibAttr.guid.GetHashCode() +
this.TypeLibAttr.wMajorVerNum.GetHashCode() +
this.TypeLibAttr.wMinorVerNum.GetHashCode();
}

public override bool Equals(object obj)
{
ComTypeLibrary comTypeLibrary = obj as ComTypeLibrary;
if (comTypeLibrary != null)
{
if
(this.TypeLibAttr.guid.Equals(comTypeLibrary.TypeLibAttr.guid))
{
if
(this.TypeLibAttr.wMajorVerNum.Equals(comTypeLibrary.TypeLibAttr.wMajorVerNum))
{
if
(this.TypeLibAttr.wMinorVerNum.Equals(comTypeLibrary.TypeLibAttr.wMinorVerNum))
{
return true;
}
}
}
return base.Equals(obj);
}
else
{
return base.Equals(obj);
}
}

public override string ToString()
{
return this.Name + " - " + this.Description;
}
}
}


fredpp@online.no wrote:
> On 15 Okt, 08:20, waw...@online.microsoft.com ("Walter Wang [MSFT]")
> wrote:
>> Hi Michael,
>>
>> If the COM object implements IDispatch, we can use IDispatch.GetTypeInfotogetitstypeinformation.
>>
>> Please try following code:
>>
>> 1) Add reference to "CustomMarshalers", you should be able to find it at
>> %windir%\Microsoft.NET\Framework\v2.0.50727\CustomMarshalers.dll.
>>
>> 2) Use following code to test:
>>
>> class Program
>> {
>> static void Main(string[] args)
>> {
>> Typet1 =Type.GetTypeFromProgID("Scripting.FileSystemObject");
>> Object o1 = Activator.CreateInstance(t1);
>>
>> IDispatch disp2 = o1 as IDispatch;
>> if (disp2 != null)
>> {
>> Typet3;
>> disp2.GetTypeInfo(0, 0, out t3);
>>
>> MemberInfo[] mlist3 = t3.GetMembers();
>> }
>> }
>> }
>>
>> }
>>
>> References:
>>
>> #.NET Remoting: Create a Custom Marshaling Implementation Using .NET
>> Remoting and COM Interop -- MSDN Magazine, September 2003http://msdn.microsoft.com/msdnmag/issues/03/09/CustomM...
>>
>> Hope this helps.
>>
>> Regards,
>> Walter Wang (waw...@online.microsoft.com, remove 'online.')
>> Microsoft Online Community Support
>>
>> This posting is provided "AS IS" with no warranties, and confers no rights.
>
> Hi
>
> I'm trying to do the exactly same but the method:
>
> disp2.GetTypeInfo(0, 0, out t3);
>
> takes very long time to get finished, about 4 minutes, which is too
> mutch of course. What can be the reason for this? I know that my COM-
> object has very many interfaces, but I cant understand why this
> shouldn't be handled....... My COM is written in Delphi and I have
> access to the source, is there anything I can look at in the source to
> make this faster?
>
> Thanks in advance
>
> - RightCoder
>

RightCoder

10/29/2007 10:12:00 AM

0

Hi Jason

Thank you for your response. I must admit I have not had a closer look at
your code because it seems to be a lot of work to be done before I'm there. I
have no experience with COM nor working with IDispatch so this looks like a
mountain for me. I dont have the time either to sit down and understand all
the details.

I may be asking for much here, but I'm looking for a complete solution and I
was hoping it was a matter of changing an input-parameter or doing another
methodcall. Is it really that difficult to introspect COM from .NET?

What else could be done to make this work without taking so long time? Could
I make the COMs TLB available on the client? There must be an easier way or a
workaround that is doable for a mere mortal like me (ASP.NET developer)? ;-)

"Jason Newell" wrote:

> The reason that it is taking so long is because it's generating
> in-memory interop assemblies behind the scenes. It's basically the same
> thing as adding a reference to a type library in Visual Studio although
> it seems to be slower than when you manually add the reference.
>
> The faster but more difficult way to work with COM in .NET is to work
> directly with the IDispatch interface. Here is a bit of code that I use
> in one of my applications. The code listed below are 3 separate .cs
> files. I also did not list my full source so not all functionality is
> available in what I'm giving you but it should be enough to give you an
> idea as to what's involved.
>
> Once you have the code in place, you can use it something like:
>
> Jason Newell
> www.jasonnewell.net
>
>
> /* Example Usage */
> ComObject comObject = new
> ComObject(Marshal.GetActiveObject("Word.Application"));
> string[] propertyNames = comObject.GetPropertyNames();
> foreach (string propertyName in propertyNames)
> {
> object property =
> comObject.WrappedComObject.GetType().InvokeMember(propertyName,
> System.Reflection.BindingFlags.GetProperty, null,
> comObject.WrappedComObject, null);
> }
>
>
>
> /* IDispatch.cs */
> using System;
> using System.Collections.Generic;
> using System.Runtime.InteropServices;
> using System.Text;
>
> namespace SolidEdgeSpy.InteropServices
> {
> [Guid("00020400-0000-0000-c000-000000000046"),
> InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
> public interface IDispatch
> {
> int GetTypeInfoCount();
> System.Runtime.InteropServices.ComTypes.ITypeInfo
> GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo,
> [MarshalAs(UnmanagedType.U4)] int lcid);
> [PreserveSig]
> int GetIDsOfNames(ref Guid riid,
> [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]
> string[] rgsNames, int cNames, int lcid,
> [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
> [PreserveSig]
> int Invoke(int dispIdMember, ref Guid riid,
> [MarshalAs(UnmanagedType.U4)] int lcid, [MarshalAs(UnmanagedType.U4)]
> int dwFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS
> pDispParams, [Out, MarshalAs(UnmanagedType.LPArray)] object[]
> pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO
> pExcepInfo, [Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] pArgErr);
> }
> }
>
> /* ComObject.cs */
> using System;
> using System.Collections.Generic;
> using System.Runtime.InteropServices;
> using System.Runtime.InteropServices.ComTypes;
> using System.Text;
>
> namespace SolidEdgeSpy.InteropServices
> {
> public class ComObject : IDisposable
> {
> private object _object;
> private IDispatch _dispatch;
> private IntPtr _pTypeAttr = IntPtr.Zero;
> private System.Runtime.InteropServices.ComTypes.ITypeInfo
> _typeInfo;
> private string _typeName, _typeDescription, _typeHelpFile;
> private int _typeHelpContext;
> private SolidEdgeSpy.InteropServices.ComTypeLibrary
> _comTypeLibrary;
>
> public ComObject(object comObject)
> {
> System.Runtime.InteropServices.ComTypes.ITypeLib ppTLB = null;
> int pIndex = 0;
>
> _dispatch = comObject as IDispatch;
>
> if (_dispatch != null)
> {
> _object = comObject;
> _typeInfo = _dispatch.GetTypeInfo(0, 0);
> _typeInfo.GetTypeAttr(out _pTypeAttr);
> _typeInfo.GetDocumentation(-1, out _typeName, out
> _typeDescription, out _typeHelpContext, out _typeHelpFile);
> _typeInfo.GetContainingTypeLib(out ppTLB, out pIndex);
> _comTypeLibrary = new ComTypeLibrary(ppTLB);
> }
> else
> {
> throw new InvalidComObjectException();
> }
> }
>
> ~ComObject()
> {
> Dispose();
> }
>
> public void Dispose()
> {
> try
> {
> if (_typeInfo != null)
> {
> _typeInfo.ReleaseTypeAttr(_pTypeAttr);
> }
>
> if (_object != null) {
> Marshal.ReleaseComObject(_object); _object = null; }
> if (_dispatch != null) {
> Marshal.ReleaseComObject(_dispatch); _dispatch = null; }
> }
> catch
> {
> }
> }
>
> public string[] GetPropertyNames()
> {
> System.Collections.ArrayList list = new
> System.Collections.ArrayList();
>
> try
> {
> for (int i = 0; i < this.TypeAttr.cFuncs; i++)
> {
> IntPtr pFuncDesc = IntPtr.Zero;
> System.Runtime.InteropServices.ComTypes.FUNCDESC
> funcDesc;
> string strName, strDocString, strHelpFile;
> int dwHelpContext;
>
> _typeInfo.GetFuncDesc(i, out pFuncDesc);
> funcDesc =
> (System.Runtime.InteropServices.ComTypes.FUNCDESC)Marshal.PtrToStructure(pFuncDesc,
> typeof(System.Runtime.InteropServices.ComTypes.FUNCDESC));
>
> switch (funcDesc.invkind)
> {
> case
> System.Runtime.InteropServices.ComTypes.INVOKEKIND.INVOKE_PROPERTYGET:
> _typeInfo.GetDocumentation(funcDesc.memid,
> out strName, out strDocString, out dwHelpContext, out strHelpFile);
> list.Add(strName);
> break;
> }
> }
> }
> catch (System.Exception ex)
> {
> throw ex;
> }
>
> return (string[])list.ToArray(typeof(string));
> }
>
> public string TypeName { get { return this._typeName; } }
> public string TypeFullName { get { return
> this.ComTypeLibrary.Name + "." + this._typeName; } }
> public string TypeDescription { get { return
> this._typeDescription; } }
> public int TypeHelpContext { get { return
> this._typeHelpContext; } }
> public string TypeHelpFile { get { return this._typeHelpFile; } }
> public object WrappedComObject { get { return _dispatch; } }
> public ComTypeLibrary ComTypeLibrary { get { return
> _comTypeLibrary; } }
> public System.Runtime.InteropServices.ComTypes.TYPEATTR
> TypeAttr { get { return
> (System.Runtime.InteropServices.ComTypes.TYPEATTR)Marshal.PtrToStructure(_pTypeAttr,
> typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR)); } }
> public string TypeVersion
> {
> get
> {
> string version = String.Empty;
> try
> {
> version = TypeAttr.wMajorVerNum.ToString() + "." +
> TypeAttr.wMinorVerNum.ToString();
> }
> catch
> {
> }
> return version;
> }
> }
> }
> }
>
> /* ComTypeLibrary.cs */
> using System;
> using System.Collections.Generic;
> using System.IO;
> using System.Reflection;
> using System.Reflection.Emit;
> using System.Runtime.InteropServices;
> using System.Runtime.InteropServices.ComTypes;
> using System.Text;
>
> namespace SolidEdgeSpy.InteropServices
> {
> public class ComTypeLibrary
> {
> private System.Runtime.InteropServices.ComTypes.ITypeLib _typeLib;
> IntPtr _pTypeLibAttr = IntPtr.Zero;
> string _Name, _Description, _HelpFile;
> int _HelpContext;
>
> public
> ComTypeLibrary(System.Runtime.InteropServices.ComTypes.ITypeLib typeLib)
> {
> _typeLib = typeLib;
> _typeLib.GetLibAttr(out _pTypeLibAttr);
> _typeLib.GetDocumentation(-1, out _Name, out _Description,
> out _HelpContext, out _HelpFile);
> }
>
> public string Name { get { return this._Name; } }
> public string Description { get { return this._Description; } }
> public int HelpContext { get { return this._HelpContext; } }
> public string HelpFile { get { return this._HelpFile; } }
> public System.Runtime.InteropServices.ComTypes.TYPELIBATTR
> TypeLibAttr { get { return
> (System.Runtime.InteropServices.ComTypes.TYPELIBATTR)Marshal.PtrToStructure(_pTypeLibAttr,
> typeof(System.Runtime.InteropServices.ComTypes.TYPELIBATTR)); } }
> public string TypeLibVersion
> {
> get
> {
> string version = String.Empty;
> try
> {
> version = TypeLibAttr.wMajorVerNum.ToString() + "."
> + TypeLibAttr.wMinorVerNum.ToString();
> }
> catch
> {
> }
> return version;
> }
> }
>
> public Version Version
> {
> get
> {
> return new Version(TypeLibAttr.wMajorVerNum,
> TypeLibAttr.wMinorVerNum, 0, 0);
> }
> }
>
> public override int GetHashCode()
> {
> return this.TypeLibAttr.guid.GetHashCode() +
> this.TypeLibAttr.wMajorVerNum.GetHashCode() +
> this.TypeLibAttr.wMinorVerNum.GetHashCode();
> }
>
> public override bool Equals(object obj)
> {
> ComTypeLibrary comTypeLibrary = obj as ComTypeLibrary;
> if (comTypeLibrary != null)
> {
> if
> (this.TypeLibAttr.guid.Equals(comTypeLibrary.TypeLibAttr.guid))
> {
> if
> (this.TypeLibAttr.wMajorVerNum.Equals(comTypeLibrary.TypeLibAttr.wMajorVerNum))
> {
> if
> (this.TypeLibAttr.wMinorVerNum.Equals(comTypeLibrary.TypeLibAttr.wMinorVerNum))
> {
> return true;
> }
> }
> }
> return base.Equals(obj);
> }
> else
> {
> return base.Equals(obj);
> }
> }
>
> public override string ToString()

unknown

10/29/2007 1:31:00 PM

0

If there is an easier way to do it with existing .NET API's, then I
guess I've wasted a considerable amount of time developing a lot of
code. I always look for existing .NET API's before I dive off doing
things myself, but in this case, I found no other solution.

Fortunately for me, I do have a lot of COM experience so I'm able to
write the code. The API that I've written closely resembles the
existing System.Reflection namespace. Everything that I've done starts
with the name Com. i.e. ComType, ComObject, ComMethodInfo,
ComPropertyInfo, ComParameterInfo, etc.

The code that I posted is still very much a work in progress. It sounds
like it could be useful to others so I'll post a copy of the source onto
my website. Maybe even write a Code Project article about it.

Jason Newell
www.jasonnewell.net

RightCoder wrote:
> Hi Jason
>
> Thank you for your response. I must admit I have not had a closer look at
> your code because it seems to be a lot of work to be done before I'm there. I
> have no experience with COM nor working with IDispatch so this looks like a
> mountain for me. I dont have the time either to sit down and understand all
> the details.
>
> I may be asking for much here, but I'm looking for a complete solution and I
> was hoping it was a matter of changing an input-parameter or doing another
> methodcall. Is it really that difficult to introspect COM from .NET?
>
> What else could be done to make this work without taking so long time? Could
> I make the COMs TLB available on the client? There must be an easier way or a
> workaround that is doable for a mere mortal like me (ASP.NET developer)? ;-)
>
> "Jason Newell" wrote:
>
>> The reason that it is taking so long is because it's generating
>> in-memory interop assemblies behind the scenes. It's basically the same
>> thing as adding a reference to a type library in Visual Studio although
>> it seems to be slower than when you manually add the reference.
>>
>> The faster but more difficult way to work with COM in .NET is to work
>> directly with the IDispatch interface. Here is a bit of code that I use
>> in one of my applications. The code listed below are 3 separate .cs
>> files. I also did not list my full source so not all functionality is
>> available in what I'm giving you but it should be enough to give you an
>> idea as to what's involved.
>>
>> Once you have the code in place, you can use it something like:
>>
>> Jason Newell
>> www.jasonnewell.net
>>
>>
>> /* Example Usage */
>> ComObject comObject = new
>> ComObject(Marshal.GetActiveObject("Word.Application"));
>> string[] propertyNames = comObject.GetPropertyNames();
>> foreach (string propertyName in propertyNames)
>> {
>> object property =
>> comObject.WrappedComObject.GetType().InvokeMember(propertyName,
>> System.Reflection.BindingFlags.GetProperty, null,
>> comObject.WrappedComObject, null);
>> }
>>
>>
>>
>> /* IDispatch.cs */
>> using System;
>> using System.Collections.Generic;
>> using System.Runtime.InteropServices;
>> using System.Text;
>>
>> namespace SolidEdgeSpy.InteropServices
>> {
>> [Guid("00020400-0000-0000-c000-000000000046"),
>> InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
>> public interface IDispatch
>> {
>> int GetTypeInfoCount();
>> System.Runtime.InteropServices.ComTypes.ITypeInfo
>> GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo,
>> [MarshalAs(UnmanagedType.U4)] int lcid);
>> [PreserveSig]
>> int GetIDsOfNames(ref Guid riid,
>> [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]
>> string[] rgsNames, int cNames, int lcid,
>> [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
>> [PreserveSig]
>> int Invoke(int dispIdMember, ref Guid riid,
>> [MarshalAs(UnmanagedType.U4)] int lcid, [MarshalAs(UnmanagedType.U4)]
>> int dwFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS
>> pDispParams, [Out, MarshalAs(UnmanagedType.LPArray)] object[]
>> pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO
>> pExcepInfo, [Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] pArgErr);
>> }
>> }
>>
>> /* ComObject.cs */
>> using System;
>> using System.Collections.Generic;
>> using System.Runtime.InteropServices;
>> using System.Runtime.InteropServices.ComTypes;
>> using System.Text;
>>
>> namespace SolidEdgeSpy.InteropServices
>> {
>> public class ComObject : IDisposable
>> {
>> private object _object;
>> private IDispatch _dispatch;
>> private IntPtr _pTypeAttr = IntPtr.Zero;
>> private System.Runtime.InteropServices.ComTypes.ITypeInfo
>> _typeInfo;
>> private string _typeName, _typeDescription, _typeHelpFile;
>> private int _typeHelpContext;
>> private SolidEdgeSpy.InteropServices.ComTypeLibrary
>> _comTypeLibrary;
>>
>> public ComObject(object comObject)
>> {
>> System.Runtime.InteropServices.ComTypes.ITypeLib ppTLB = null;
>> int pIndex = 0;
>>
>> _dispatch = comObject as IDispatch;
>>
>> if (_dispatch != null)
>> {
>> _object = comObject;
>> _typeInfo = _dispatch.GetTypeInfo(0, 0);
>> _typeInfo.GetTypeAttr(out _pTypeAttr);
>> _typeInfo.GetDocumentation(-1, out _typeName, out
>> _typeDescription, out _typeHelpContext, out _typeHelpFile);
>> _typeInfo.GetContainingTypeLib(out ppTLB, out pIndex);
>> _comTypeLibrary = new ComTypeLibrary(ppTLB);
>> }
>> else
>> {
>> throw new InvalidComObjectException();
>> }
>> }
>>
>> ~ComObject()
>> {
>> Dispose();
>> }
>>
>> public void Dispose()
>> {
>> try
>> {
>> if (_typeInfo != null)
>> {
>> _typeInfo.ReleaseTypeAttr(_pTypeAttr);
>> }
>>
>> if (_object != null) {
>> Marshal.ReleaseComObject(_object); _object = null; }
>> if (_dispatch != null) {
>> Marshal.ReleaseComObject(_dispatch); _dispatch = null; }
>> }
>> catch
>> {
>> }
>> }
>>
>> public string[] GetPropertyNames()
>> {
>> System.Collections.ArrayList list = new
>> System.Collections.ArrayList();
>>
>> try
>> {
>> for (int i = 0; i < this.TypeAttr.cFuncs; i++)
>> {
>> IntPtr pFuncDesc = IntPtr.Zero;
>> System.Runtime.InteropServices.ComTypes.FUNCDESC
>> funcDesc;
>> string strName, strDocString, strHelpFile;
>> int dwHelpContext;
>>
>> _typeInfo.GetFuncDesc(i, out pFuncDesc);
>> funcDesc =
>> (System.Runtime.InteropServices.ComTypes.FUNCDESC)Marshal.PtrToStructure(pFuncDesc,
>> typeof(System.Runtime.InteropServices.ComTypes.FUNCDESC));
>>
>> switch (funcDesc.invkind)
>> {
>> case
>> System.Runtime.InteropServices.ComTypes.INVOKEKIND.INVOKE_PROPERTYGET:
>> _typeInfo.GetDocumentation(funcDesc.memid,
>> out strName, out strDocString, out dwHelpContext, out strHelpFile);
>> list.Add(strName);
>> break;
>> }
>> }
>> }
>> catch (System.Exception ex)
>> {
>> throw ex;
>> }
>>
>> return (string[])list.ToArray(typeof(string));
>> }
>>
>> public string TypeName { get { return this._typeName; } }
>> public string TypeFullName { get { return
>> this.ComTypeLibrary.Name + "." + this._typeName; } }
>> public string TypeDescription { get { return
>> this._typeDescription; } }
>> public int TypeHelpContext { get { return
>> this._typeHelpContext; } }
>> public string TypeHelpFile { get { return this._typeHelpFile; } }
>> public object WrappedComObject { get { return _dispatch; } }
>> public ComTypeLibrary ComTypeLibrary { get { return
>> _comTypeLibrary; } }
>> public System.Runtime.InteropServices.ComTypes.TYPEATTR
>> TypeAttr { get { return
>> (System.Runtime.InteropServices.ComTypes.TYPEATTR)Marshal.PtrToStructure(_pTypeAttr,
>> typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR)); } }
>> public string TypeVersion
>> {
>> get
>> {
>> string version = String.Empty;
>> try
>> {
>> version = TypeAttr.wMajorVerNum.ToString() + "." +
>> TypeAttr.wMinorVerNum.ToString();
>> }
>> catch
>> {
>> }
>> return version;
>> }
>> }
>> }
>> }
>>
>> /* ComTypeLibrary.cs */
>> using System;
>> using System.Collections.Generic;
>> using System.IO;
>> using System.Reflection;
>> using System.Reflection.Emit;
>> using System.Runtime.InteropServices;
>> using System.Runtime.InteropServices.ComTypes;
>> using System.Text;
>>
>> namespace SolidEdgeSpy.InteropServices
>> {
>> public class ComTypeLibrary
>> {
>> private System.Runtime.InteropServices.ComTypes.ITypeLib _typeLib;
>> IntPtr _pTypeLibAttr = IntPtr.Zero;
>> string _Name, _Description, _HelpFile;
>> int _HelpContext;
>>
>> public
>> ComTypeLibrary(System.Runtime.InteropServices.ComTypes.ITypeLib typeLib)
>> {
>> _typeLib = typeLib;
>> _typeLib.GetLibAttr(out _pTypeLibAttr);
>> _typeLib.GetDocumentation(-1, out _Name, out _Description,
>> out _HelpContext, out _HelpFile);
>> }
>>
>> public string Name { get { return this._Name; } }
>> public string Description { get { return this._Description; } }
>> public int HelpContext { get { return this._HelpContext; } }
>> public string HelpFile { get { return this._HelpFile; } }
>> public System.Runtime.InteropServices.ComTypes.TYPELIBATTR
>> TypeLibAttr { get { return
>> (System.Runtime.InteropServices.ComTypes.TYPELIBATTR)Marshal.PtrToStructure(_pTypeLibAttr,
>> typeof(System.Runtime.InteropServices.ComTypes.TYPELIBATTR)); } }
>> public string TypeLibVersion
>> {
>> get
>> {
>> string version = String.Empty;
>> try
>> {
>> version = TypeLibAttr.wMajorVerNum.ToString() + "."
>> + TypeLibAttr.wMinorVerNum.ToString();
>> }
>> catch
>> {
>> }
>> return version;
>> }
>> }
>>
>> public Version Version
>> {
>> get
>> {
>> return new Version(TypeLibAttr.wMajorVerNum,
>> TypeLibAttr.wMinorVerNum, 0, 0);
>> }
>> }
>>
>> public override int GetHashCode()
>> {
>> return this.TypeLibAttr.guid.GetHashCode() +
>> this.TypeLibAttr.wMajorVerNum.GetHashCode() +
>> this.TypeLibAttr.wMinorVerNum.GetHashCode();
>> }
>>
>> public override bool Equals(object obj)
>> {
>> ComTypeLibrary comTypeLibrary = obj as ComTypeLibrary;
>> if (comTypeLibrary != null)
>> {
>> if
>> (this.TypeLibAttr.guid.Equals(comTypeLibrary.TypeLibAttr.guid))
>> {
>> if
>> (this.TypeLibAttr.wMajorVerNum.Equals(comTypeLibrary.TypeLibAttr.wMajorVerNum))
>> {
>> if
>> (this.TypeLibAttr.wMinorVerNum.Equals(comTypeLibrary.TypeLibAttr.wMinorVerNum))
>> {
>> return true;
>> }
>> }
>> }
>> return base.Equals(obj);
>> }
>> else
>> {
>> return base.Equals(obj);
>> }
>> }
>>
>> public override string ToString()

RightCoder

10/29/2007 3:14:00 PM

0

Yes, I really think this would be a great article at Code Project. This is an
area that most of us have little or no experience with, I can say that
because I cant find much information about it on the Internet. Even MSDN have
litle documentation on topics like this.

I hope you'll share your code and experience with the rest of us either by
your own homepage/blog or Code Project. What would be great if you could make
a component/class that had some methods I could use that implemented all the
magic you are doing, but that I, as a user, really dont have to know anything
about. You could even earn some money on it ;-)

I'll try to learn some COM-programming the next few weeks and see how far
I'll come. Thanks anyway, Jason.

"Jason Newell" wrote:

> If there is an easier way to do it with existing .NET API's, then I
> guess I've wasted a considerable amount of time developing a lot of
> code. I always look for existing .NET API's before I dive off doing
> things myself, but in this case, I found no other solution.
>
> Fortunately for me, I do have a lot of COM experience so I'm able to
> write the code. The API that I've written closely resembles the
> existing System.Reflection namespace. Everything that I've done starts
> with the name Com. i.e. ComType, ComObject, ComMethodInfo,
> ComPropertyInfo, ComParameterInfo, etc.
>
> The code that I posted is still very much a work in progress. It sounds
> like it could be useful to others so I'll post a copy of the source onto
> my website. Maybe even write a Code Project article about it.
>
> Jason Newell
> www.jasonnewell.net
>
> RightCoder wrote:
> > Hi Jason
> >
> > Thank you for your response. I must admit I have not had a closer look at
> > your code because it seems to be a lot of work to be done before I'm there. I
> > have no experience with COM nor working with IDispatch so this looks like a
> > mountain for me. I dont have the time either to sit down and understand all
> > the details.
> >
> > I may be asking for much here, but I'm looking for a complete solution and I
> > was hoping it was a matter of changing an input-parameter or doing another
> > methodcall. Is it really that difficult to introspect COM from .NET?
> >
> > What else could be done to make this work without taking so long time? Could
> > I make the COMs TLB available on the client? There must be an easier way or a
> > workaround that is doable for a mere mortal like me (ASP.NET developer)? ;-)
> >
> > "Jason Newell" wrote:
> >
> >> The reason that it is taking so long is because it's generating
> >> in-memory interop assemblies behind the scenes. It's basically the same
> >> thing as adding a reference to a type library in Visual Studio although
> >> it seems to be slower than when you manually add the reference.
> >>
> >> The faster but more difficult way to work with COM in .NET is to work
> >> directly with the IDispatch interface. Here is a bit of code that I use
> >> in one of my applications. The code listed below are 3 separate .cs
> >> files. I also did not list my full source so not all functionality is
> >> available in what I'm giving you but it should be enough to give you an
> >> idea as to what's involved.
> >>
> >> Once you have the code in place, you can use it something like:
> >>
> >> Jason Newell
> >> www.jasonnewell.net
> >>
> >>
> >> /* Example Usage */
> >> ComObject comObject = new
> >> ComObject(Marshal.GetActiveObject("Word.Application"));
> >> string[] propertyNames = comObject.GetPropertyNames();
> >> foreach (string propertyName in propertyNames)
> >> {
> >> object property =
> >> comObject.WrappedComObject.GetType().InvokeMember(propertyName,
> >> System.Reflection.BindingFlags.GetProperty, null,
> >> comObject.WrappedComObject, null);
> >> }
> >>
> >>
> >>
> >> /* IDispatch.cs */
> >> using System;
> >> using System.Collections.Generic;
> >> using System.Runtime.InteropServices;
> >> using System.Text;
> >>
> >> namespace SolidEdgeSpy.InteropServices
> >> {
> >> [Guid("00020400-0000-0000-c000-000000000046"),
> >> InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
> >> public interface IDispatch
> >> {
> >> int GetTypeInfoCount();
> >> System.Runtime.InteropServices.ComTypes.ITypeInfo
> >> GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo,
> >> [MarshalAs(UnmanagedType.U4)] int lcid);
> >> [PreserveSig]
> >> int GetIDsOfNames(ref Guid riid,
> >> [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]
> >> string[] rgsNames, int cNames, int lcid,
> >> [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
> >> [PreserveSig]
> >> int Invoke(int dispIdMember, ref Guid riid,
> >> [MarshalAs(UnmanagedType.U4)] int lcid, [MarshalAs(UnmanagedType.U4)]
> >> int dwFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS
> >> pDispParams, [Out, MarshalAs(UnmanagedType.LPArray)] object[]
> >> pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO
> >> pExcepInfo, [Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] pArgErr);
> >> }
> >> }
> >>
> >> /* ComObject.cs */
> >> using System;
> >> using System.Collections.Generic;
> >> using System.Runtime.InteropServices;
> >> using System.Runtime.InteropServices.ComTypes;
> >> using System.Text;
> >>
> >> namespace SolidEdgeSpy.InteropServices
> >> {
> >> public class ComObject : IDisposable
> >> {
> >> private object _object;
> >> private IDispatch _dispatch;
> >> private IntPtr _pTypeAttr = IntPtr.Zero;
> >> private System.Runtime.InteropServices.ComTypes.ITypeInfo
> >> _typeInfo;
> >> private string _typeName, _typeDescription, _typeHelpFile;
> >> private int _typeHelpContext;
> >> private SolidEdgeSpy.InteropServices.ComTypeLibrary
> >> _comTypeLibrary;
> >>
> >> public ComObject(object comObject)
> >> {
> >> System.Runtime.InteropServices.ComTypes.ITypeLib ppTLB = null;
> >> int pIndex = 0;
> >>
> >> _dispatch = comObject as IDispatch;
> >>
> >> if (_dispatch != null)
> >> {
> >> _object = comObject;
> >> _typeInfo = _dispatch.GetTypeInfo(0, 0);
> >> _typeInfo.GetTypeAttr(out _pTypeAttr);
> >> _typeInfo.GetDocumentation(-1, out _typeName, out
> >> _typeDescription, out _typeHelpContext, out _typeHelpFile);
> >> _typeInfo.GetContainingTypeLib(out ppTLB, out pIndex);
> >> _comTypeLibrary = new ComTypeLibrary(ppTLB);
> >> }
> >> else
> >> {
> >> throw new InvalidComObjectException();
> >> }
> >> }
> >>
> >> ~ComObject()
> >> {
> >> Dispose();
> >> }
> >>
> >> public void Dispose()
> >> {
> >> try
> >> {
> >> if (_typeInfo != null)
> >> {
> >> _typeInfo.ReleaseTypeAttr(_pTypeAttr);
> >> }
> >>
> >> if (_object != null) {
> >> Marshal.ReleaseComObject(_object); _object = null; }
> >> if (_dispatch != null) {
> >> Marshal.ReleaseComObject(_dispatch); _dispatch = null; }
> >> }
> >> catch
> >> {
> >> }
> >> }
> >>
> >> public string[] GetPropertyNames()
> >> {
> >> System.Collections.ArrayList list = new
> >> System.Collections.ArrayList();
> >>
> >> try
> >> {
> >> for (int i = 0; i < this.TypeAttr.cFuncs; i++)
> >> {
> >> IntPtr pFuncDesc = IntPtr.Zero;
> >> System.Runtime.InteropServices.ComTypes.FUNCDESC
> >> funcDesc;
> >> string strName, strDocString, strHelpFile;
> >> int dwHelpContext;
> >>
> >> _typeInfo.GetFuncDesc(i, out pFuncDesc);
> >> funcDesc =
> >> (System.Runtime.InteropServices.ComTypes.FUNCDESC)Marshal.PtrToStructure(pFuncDesc,
> >> typeof(System.Runtime.InteropServices.ComTypes.FUNCDESC));
> >>
> >> switch (funcDesc.invkind)
> >> {
> >> case
> >> System.Runtime.InteropServices.ComTypes.INVOKEKIND.INVOKE_PROPERTYGET:
> >> _typeInfo.GetDocumentation(funcDesc.memid,
> >> out strName, out strDocString, out dwHelpContext, out strHelpFile);
> >> list.Add(strName);
> >> break;
> >> }
> >> }
> >> }
> >> catch (System.Exception ex)
> >> {
> >> throw ex;
> >> }
> >>
> >> return (string[])list.ToArray(typeof(string));
> >> }
> >>
> >> public string TypeName { get { return this._typeName; } }
> >> public string TypeFullName { get { return
> >> this.ComTypeLibrary.Name + "." + this._typeName; } }
> >> public string TypeDescription { get { return
> >> this._typeDescription; } }
> >> public int TypeHelpContext { get { return
> >> this._typeHelpContext; } }
> >> public string TypeHelpFile { get { return this._typeHelpFile; } }
> >> public object WrappedComObject { get { return _dispatch; } }
> >> public ComTypeLibrary ComTypeLibrary { get { return
> >> _comTypeLibrary; } }
> >> public System.Runtime.InteropServices.ComTypes.TYPEATTR
> >> TypeAttr { get { return
> >> (System.Runtime.InteropServices.ComTypes.TYPEATTR)Marshal.PtrToStructure(_pTypeAttr,
> >> typeof(System.Runtime.InteropServices.ComTypes.TYPEATTR)); } }
> >> public string TypeVersion
> >> {
> >> get
> >> {
> >> string version = String.Empty;
> >> try
> >> {
> >> version = TypeAttr.wMajorVerNum.ToString() + "." +
> >> TypeAttr.wMinorVerNum.ToString();
> >> }
> >> catch
> >> {
> >> }
> >> return version;
> >> }
> >> }
> >> }
> >> }
> >>
> >> /* ComTypeLibrary.cs */
> >> using System;
> >> using System.Collections.Generic;
> >> using System.IO;
> >> using System.Reflection;
> >> using System.Reflection.Emit;
> >> using System.Runtime.InteropServices;
> >> using System.Runtime.InteropServices.ComTypes;
> >> using System.Text;
> >>
> >> namespace SolidEdgeSpy.InteropServices
> >> {
> >> public class ComTypeLibrary
> >> {
> >> private System.Runtime.InteropServices.ComTypes.ITypeLib _typeLib;
> >> IntPtr _pTypeLibAttr = IntPtr.Zero;
> >> string _Name, _Description, _HelpFile;
> >> int _HelpContext;
> >>
> >> public
> >> ComTypeLibrary(System.Runtime.InteropServices.ComTypes.ITypeLib typeLib)
> >> {
> >> _typeLib = typeLib;
> >> _typeLib.GetLibAttr(out _pTypeLibAttr);
> >> _typeLib.GetDocumentation(-1, out _Name, out _Description,
> >> out _HelpContext, out _HelpFile);
> >> }
> >>
> >> public string Name { get { return this._Name; } }
> >> public string Description { get { return this._Description; } }
> >> public int HelpContext { get { return this._HelpContext; } }
> >> public string HelpFile { get { return this._HelpFile; } }
> >> public System.Runtime.InteropServices.ComTypes.TYPELIBATTR
> >> TypeLibAttr { get { return
> >> (System.Runtime.InteropServices.ComTypes.TYPELIBATTR)Marshal.PtrToStructure(_pTypeLibAttr,
> >> typeof(System.Runtime.InteropServices.ComTypes.TYPELIBATTR)); } }
> >> public string TypeLibVersion
> >> {
> >> get
> >> {
> >> string version = String.Empty;
> >> try
> >> {
> >> version = TypeLibAttr.wMajorVerNum.ToString() + "."
> >> + TypeLibAttr.wMinorVerNum.ToString();
> >> }
> >> catch
> >> {
> >> }
> >> return version;
> >> }
> >> }
> >>
> >> public Version Version
> >> {
> >> get
> >> {
> >> return new Version(TypeLibAttr.wMajorVerNum,
> >> TypeLibAttr.wMinorVerNum, 0, 0);