How to programmatically register (set correct path

2019-02-26 08:30发布

问题:

Using .NET 4.0, I have made a COM-enabled DLL (let's call it example.dll), and I have registered it and generated the respective type library using regasm.exe (regasm.exe /tlb /codebase example.dll); the type library is called example.tlb. The assembly is strongly named.

This works so far, and I can use the DLL and the TLB from within VBA.

But for certain reasons, I need to make my own utility which does the DLL registration and TLB generation. Basically, this utility will be in the same directory as the DLL and should register the DLL which it finds in that directory as well as generate the TLB file from the DLL which it finds in that directory.

DLL registration and TLB generation seem to work, but there is the following problem: I have not found any acceptable means to set the correct path to the TLB file from within .NET 4.0, and that's the point where I would be very grateful for any help.

To reproduce and illustrate, imagine the following situation:

  • I have c:\test_1\example.dll, change directory into c:\test_1 and run regasm.exe /tlb /codebase example.dll. This does at least these things as far as I have understood: It registers the DLL, creates the TLB (c:\test_1\example.tlb) and somehow registers the TLB itself (see below what I mean by that).

  • Now I move the DLL to c:\test_2, put my registration and TLB generation utility into c:\test_2, change directory into c:\test_2 and run my utility. Apparently, the DLL gets registered correctly, and the TLB is generated. But the TLB is not registered (see below).

My question now is how I could register the TLB from within .NET.

By registering a TLB, I mean the following: When using regasm.exe like shown above, it obviously puts the path to the TLB into the registry (at least, I have found it there). When you use oleview.exe to view the respective type library, it shows that path. When I use my own utility for registration and TLB generation, this path is not updated - the path is always the one which has been set when lastly running regasm.exe.

This leads to the situation that the TLB cannot be found e.g. by Excel after moving the DLL and my utility to another directory and running the utility.

This is the relevant part of the utilities source code (VB.net, error handling and user interface stripped out):

sub Register()

  Dim s_Path As String
  Dim asm_DLL As [Assembly]
  Dim rs_DLL As RegistrationServices
  Dim tlc_DLL As TypeLibConverter
  Dim ns_DLL As cls_TLBCreatorNotifySink
  Dim tlb_DLL As UCOMICreateITypeLib

  s_Path = Application.StartupPath & "\example.dll"

  asm_DLL = Assembly.LoadFrom(s_Path)

  rs_DLL = New RegistrationServices()
  rs_DLL.RegisterAssembly(asm_DLL, AssemblyRegistrationFlags.SetCodeBase)

  s_Path = Application.StartupPath & "\example.tlb"
  ns_DLL = New cls_TLBCreatorNotifySink
  tlc_DLL = New TypeLibConverter
  tlb_DLL = CType(tlc_DLL.ConvertAssemblyToTypeLib(asm_DLL, s_Path, TypeLibExporterFlags.None, ns_DLL), UCOMICreateITypeLib)
  tlb_DLL.SaveAllChanges()

end sub


Public Class cls_TLBCreatorNotifySink

  Implements ITypeLibExporterNotifySink

  Public Sub ReportEvent(eventKind As System.Runtime.InteropServices.ExporterEventKind, eventCode As Integer, eventMsg As String) Implements System.Runtime.InteropServices.ITypeLibExporterNotifySink.ReportEvent

  End Sub

  Public Function ResolveRef(assembly As System.Reflection.Assembly) As Object Implements System.Runtime.InteropServices.ITypeLibExporterNotifySink.ResolveRef

    Return Nothing

  End Function

End Class

I hope I have been able to express the problem clearly enough. My question boils down to whether there is a reasonable method within .NET which enables me to set the path to the TLB in the registry or if I have to manipulate the respective entries in the registry directly (which would be silly because nobody knows if the next windows version uses the same entries); a bonus would be to know how regasm.exe does it.

回答1:

You should call RegisterTypeLib with the result of ConvertAssemblyToTypeLib, something like this:

RegisterTypeLib(tlc_DLL.ConvertAssemblyToTypeLib(asm_DLL, s_Path, TypeLibExporterFlags.None, Nothing), s_Path, Nothing)

<DllImport("oleaut32.dll")> _
Private Shared Function RegisterTypeLib(<MarshalAs(UnmanagedType.Interface)> ByVal ptlib As Object, <MarshalAs(UnmanagedType.LPWStr)> ByVal szFullPath As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal szHelpDir As String) As Integer
End Function