Getting a COM dll's version from it's COM registry entries

We currently have some code that goes like this:

object savePath = null;

// get smartconnect type from prog id of COM component SmartConnect.dll

Type smartConnectType = Type.GetTypeFromProgID("SmartConnect.CSmartConnect");

// create instance of smartconnect

Object smartConnectObject = Activator.CreateInstance(smartConnectType);

// get the save path

savePath = smartConnectType.InvokeMember("GetFullSmartPath", BindingFlags.InvokeMethod, null, smartConnectObject, new object[] { clientPolicyReference, branchReference, diaryKey });

So basically we're late binding to a COM dll

Now there's a try catch block around this and we handle any exceptions as an indication that the .dll doesn't exist or hasn't been registered (i.e. that this particular component hasn't been installed) and we log this to the event log and skip this particular functionality.

Now it turns out that there's more than one version of this .dll and we can't use any version older than v. 2.0. We're able to fudge around this issue as we know where the dll will be so we can use FileVersionInfo (on System.Diagnostics) to get the version of the file. But I'm not mad keen on this approach as you can imagine.

What I'd like to do is somehow get the file's path dynamically from it's COM registry entries but I can't work out how to do this.

There was an unsupported COM .dll called TypeLibInfo from MS that I used to use for this from VB6, is there an equivalent in the framework library Tthe Type object I get from GetTypeFromProgID doesn't seem to return anything useful unfortunately and I really don't want to have to manually search the registry using the registry handling in the Microsoft.Win32 namespace.

Anyway TIA for any answers.




Answer this question

Getting a COM dll's version from it's COM registry entries

  • Guy Burstein

    Peter Huang - MSFT wrote:

    BTW: I think you may try to write a simple VB6 application to call the SmartConnect.CSmartConnect with ITypeInfo related code.

    Peter, I think I'm missing your meaning here. The only way I know to get at the ITypeInfo interface is via the TypeLibInfo dll (as I said supplied by MS but unsupported by them but very useful nonetheless). I tried that and was able to get at the ITypeLibInfo interface but then that's doing everything inside COM so I'd be very confused if I couldn't.

    What I have also done is create a trivial COM component and tried using that with the code you posted. I got the same error as I noted above. I'm pretty sure Misys won't mind me posting the source to the trivial component so the VB6 code is below (The class is called TrivialClass)

    Option Explicit

    Public Function DoSomethingTrivial(factorOne As Integer, FactorTwo As Integer)

    Dim product As Long

    product = factorOne * FactorTwo

    DoSomethingTrivial = product

    End Function

    (The containing project is an activex dll project called Trivial)

    The C# code is the same as before:

    Type t = Type.GetTypeFromProgID("Trivial.TrivialClass");

    ITypeInfo pTypeInfo = Marshal.GetTypedObjectForIUnknown(Marshal.GetITypeInfoForType(t), typeof(ITypeInfo)) as ITypeInfo;

    The problem is occuring (as before) on the GetITypeInfoForType call. The exception raised is:

    The specified type must be visible from COM.
    Parameter name: t

    As I said before I can see this class in OLEView so I'm stumped. Hopefully with the above you might be able to repro this and work out where I'm going wrong.

    Once again, thanks for all your help Peter



  • Arterius

    Ah...Well that'd explain it then!

    I'm late binding to the smart connect.dll with reflection so I really didn't want to add a reference to it in the project.

    Given the fact that I'm late binding is there a way to get the version from the progid without trawling through the registry

    edit:

    I thought I'd give using the interop for the Trivial COM dll a go anyway to see what happened and it solves the 't must be visible to com' problem

    but

    when I get to the call to GetDocumentation on the ITypeInfo interface I get the following COM exception:

    Element not found. (Exception from HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND))

    Is this down to the index (the first param on the call) not being correct   I've tried 0 and 1 (covering both 0 and 1 based collection styles) but I get the error on both.

    Or is it something deeper, something that VB6 com dlls don't implement or expose



  • Railmonkey

    Hi Weevie,

    Based on my understanding, you have more than one version COM dll on one machine, and you want to bind to certain version.

    If I misunderstood, please feel free to post here.

    Commonly a COM DLL will have special version progid.
    e.g.
    Lib.Class.1

    Also from .NET 2.0 we have a new interface ITypeInfo,

    Here is code for your reference.

    static void Main(string[] args)
    {
    Type t = Type.GetTypeFromProgID("Excel.Application");
    ITypeInfo pTypeInfo = Marshal.GetTypedObjectForIUnknown(Marshal.GetITypeInfoForType(t), typeof(ITypeInfo)) as ITypeInfo;
    string strName;
    string strDocString;
    int dwHelpIndex;
    string strHelpFile;
    pTypeInfo.GetDocumentation(1, out strName, out strDocString, out dwHelpIndex, out strHelpFile);
    Console.WriteLine("{0}\n{1}\n{2}\n{3}", strName, strDocString, dwHelpIndex, strHelpFile);
    }

    Thanks!

    Best regards,
    Peter Huang



  • ch1p

    Hi,

    Yes, because we have no document associate with the DLL.
    I call the GetDocumentation just for testing.

    Or we can try to call the code below.
    ITypeInfo pTypeInfo = Marshal.GetTypedObjectForIUnknown(Marshal.GetITypeInfoForType(ttt), typeof(ITypeInfo)) as ITypeInfo;
    string strName;
    string strDocString;
    int dwHelpIndex;
    string strHelpFile;
    ITypeLib pITypeLib;
    int index;
    pTypeInfo.GetContainingTypeLib(out pITypeLib, out index);
    Console.WriteLine(pITypeLib.GetTypeInfoCount().ToString());

    Also if you do not want to use the .NET ITypeInfo approach which need the wrap class.
    We have to turn to the unmanaged TypeLibInfo library which is not supported just as you said in the first post.

    Or, I think you may have to turn to the Registry class in .NET to query the registry directly.

    If you still have any concern, please feel free to post here.

    Best regards,
    Peter Huang



  • Capella_student

    Hi,

    Thanks for you information.
    Based on my research, to use the method, we need the help of the Interop Assembly.
    If we debug through the application, we will find that the Excel PIA is loaded when we instance the Excel type.
    So for your scenario, we need to add a reference to the COM, so that we have an interop assembly and then run the code below.
    static void TestATL()
    {
    Assembly *** = Assembly.LoadFrom(@"Interop.CPPITypeInfoLib.dll");
    Type ttt = ***.GetType("CPPITypeInfoLib.TestObjClass");
    Console.WriteLine(Marshal.IsTypeVisibleFromCom(ttt));
    Marshal.GetITypeInfoForType(ttt);
    }

    If you still have any concern, please feel free to post here.


    Best regards,
    Peter Huang



  • woodced

    Hi Weevie,

    Thanks for your posting!

    So far to isolate the problem, I think you may try to Get the ITypeInfo interface from the type in VB6. That is to say, do the same job from VB6 to see if that works.

    I just wonder if the SmartConnect.CSmartConnect has exposed such an interface.

    If that works in VB6 but not in .NET, can you provide a simple reproduce sample together with the source code and send to me via remove "online" from my email address, so that we can do further troubleshooting.

    Thanks!

    Best regards,
    Peter Huang



  • Leandro Pardo

    I assume you meant getting the TypeInfos using the unsupported TypeLibInfo .dll.

    Just done that and I have no problem getting an instance of TypeLibInfo from the file (using GetTypeLibInfoFromFile). I can see three TypeInfos

    _CSmartConnect

    CSmartConnect

    CSMartConnect___v0

    They all seem to have the expected interfaces and members on those interfaces.

    Unfortunately you'd need the SmartConnect.dll and since that's a commercial product I'm not sure my company would view kindly me sending it out

    What I'll do tho' is build a simple VB6 COM .dll and try that in .Net and if that doesn't work I can send you that as a kind of stand-in for the SmartConnect .dll!

    Thanks again for all your help Peter



  • PeterTretP

    Yeah I think I'll go directly to the registry.

    I mean I like the TypeLibInfo library but as this is production code I can't see the PM agreeing!

    Thanks for all your help Peter, I do appreciate it

    Cheers

    Steve



  • Ehrick

    Cheers Peter, that was looking hopeful but when I attempt to run the code using the progid SmartConnect.CSmartConnect I get an ArgumentException relating to the type param t on the method call to GetITypeInfoForType

    "The specified type must be visible from COM."

    Looking at the Marshal.GetITypeInfoForType Method help this is one of the specified exceptions (no specific help on this particlar flavour of ArgumentException tho')

    Don't quite understand why SmartConnect.CSmartConnect wouldn't be visible to COM as it's registered (I checked in OLEView) and I can early bind to and instantiate it from a little test VB6 app.

    SmartConnect is a VB6 COM dll, but it's pretty straightforward and doesn't do anything exotic. I don't know if there's any relevant differences between a VB6 COM dll and a C++ COM dll that might be a problem. I know VB6 handles all the interface stuff and we are using the default interface in this case but I'm getting out to the margins of my knowledge here!

    Anyway thanks for your help so far and anything else you can suggest.



  • Morten Andersen

    Hi Weevie,

    I appreciate your prompt response. : )

    I understand your situation and please take your time to perform the steps you mentioned. If there is anything unclear, please feel free to post back. I am always very happy to be of assistance.

    BTW: I think you may try to write a simple VB6 application to call the SmartConnect.CSmartConnect with ITypeInfo related code.

    Have a nice day!

    Best regards,
    Peter Huang



  • Getting a COM dll's version from it's COM registry entries