FIX: Tlbimp.exe Generates Interface Wrappers that Cannot Be Used (318608)



The information in this article applies to:

  • Microsoft Windows .NET Framework 1.1
  • Microsoft .NET Framework 1.0

This article was previously published under Q318608

SYMPTOMS

In a .NET application, if you call a COM function that accepts a pointer to a COM interface as its parameter, and you then pass a .NET class that implements a wrapper interface that is created around the COM interface to the function, the function call is unsuccessful and you receive the following error message:
An unhandled exception of type 'System.NullReferenceException' occurred in YourApp.exe

Additional information: Object reference not set to an instance of an object.

CAUSE

The wrapper class that the Type Library Importer utility (Tlbimp.exe) generates for the COM interface changes the COM function definition so that the function accepts a .NET wrapper interface instead of the actual COM interface pointer. Note that Tlbimp.exe only does this for the default interface for coclasses. If you use an interface that is not the default interface for a coclass, the application works as expected.

RESOLUTION

To work around the problem, change the wrapper assembly so that the COM function takes a pointer to the actual COM interface instead of to a wrapper interface. To modify the wrapper, follow these steps:
  1. Follow these steps to use the MSIL Disassembler (Ildasm.exe) to disassemble the wrapper dynamic-link library (DLL):
    1. From a .NET command prompt, run ILDASM.
    2. On the File menu, click Open. Open the wrapper DLL that is created by using Tlbimp.exe.
    3. On the File menu, click Dump. Click OK in the dialog box that appears. Specify a file name, and then click OK.
  2. In a text editor, modify the contents of the intermediate language that is generated.
  3. Search for the function that you want, and then change the parameter list so that it takes the actual COM interface. In the intermediate language code, underscore characters (_) typically precede the name of the COM interfaces. Therefore, you must type an underscore (_) before the interface name in the function definition. For example, change the following
    function([in][out] class IBug.myinterface&  marshal( interface) func) runtime managed internalcall
    					
    to:
    function([in][out] class IBug._myinterface&  marshal( interface) func) runtime managed internalcall
    					
  4. Save the changes to the file.
  5. Run the following command from a .NET command prompt to use ILASM to reassemble the intermediate language as a DLL:
    ilasm /dll <.il file> /out=<output .dll file>
    					
  6. In your .NET application, remove the reference to the old DLL and add a reference to the new wrapper DLL that you just created.

STATUS

This bug was corrected in .NET Framework (2003|1.1).

MORE INFORMATION

Steps to Reproduce the Behavior

  1. Create a new class in a Microsoft Visual Basic DLL. Name the class MyInterface, and then paste the following code in the code window for the class:
    Public Function f() As String
       f = "MyInterface:f()"
    End Function
    					
  2. Create another class, name the class MyClass, and then paste the following code in the code window for the class: Note that the first parameter of the function is a pointer to the MyInterface class.
    Function answer(func As myinterface) As String
        answer = func.f + " ... answering from COM"
    End Function
    					
  3. On the File menu, click Make to build the DLL.
  4. Use Tlbimp.exe to generate a COM Interop assembly for the COM DLL that you just created. To do this, run the following from a .NET command prompt, where dll is the file that you just created:
    tlbimp <dll> /out=Bug.Interop.dll
    					
  5. Create a new Visual Basic .NET or Visual C# .NET Windows Application project.
  6. Add a reference to the COM Interop DLL, Bug.Interop.dll, that you just created.
  7. Create a new class that will implement the first COM wrapper interface. Name the class Class2, and then paste the following code in the code window for the new class:
    Public Class Class2
        Implements Bug.Interop.MyInterface
        Private mystring As String
    
        Public Sub setstring(ByVal astring As String)
            mystring = astring
        End Sub
    
        Function f() As String Implements Bug.Interop.MyInterface.f
            Return mystring
        End Function
    End Class
    					
  8. Add a command button to Form1. Double-click the command button to open the code window for Form1.
  9. Call the COM function on your newly-created object, and then pass the .NET class that implemented the first wrapper interface to the function. To do this, paste the following code in the Button1_Click event handler:
    Dim netimpl2 As New Class1()
    Dim com As New Bug.Interop.MyClass()
    
    netimpl2.setstring("I'm calling from .NET")
    
    'This line generates the error.
    MsgBox(com.answer(netimpl2))
    					
  10. Press F5 to run the application, and then click the command button to generate the error.

REFERENCES

For additional information, click the article numbers below to view the articles in the Microsoft Knowledge Base:

310674 HOW TO: Add References to a Managed Visual C++ Project

318466 Tlbimp.exe Cannot Handle Coclasses That List Source Interfaces That Are Defined in a Different Type Library


Modification Type:MinorLast Reviewed:5/28/2003
Keywords:kbfix kbbug KB318608