Microsoft KB Archive/828986

From BetaArchive Wiki

Article ID: 828986

Article Last Modified on 4/19/2007



APPLIES TO

  • Microsoft .NET Framework 1.1
  • Microsoft .NET Framework 1.0
  • Microsoft Visual Studio .NET 2003 Enterprise Architect
  • Microsoft Visual Studio .NET 2003 Enterprise Developer
  • Microsoft Visual Studio .NET 2003 Professional Edition
  • Microsoft Visual Studio .NET 2003 Academic Edition
  • Microsoft Visual Studio .NET 2002 Enterprise Architect
  • Microsoft Visual Studio .NET 2002 Enterprise Developer
  • Microsoft Visual Studio .NET 2002 Professional Edition
  • Microsoft Visual Studio .NET 2002 Academic Edition
  • Microsoft Visual C++ .NET 2003 Standard Edition
  • Microsoft Visual C++ .NET 2002 Standard Edition



SYMPTOMS

When you try to add a project reference to a Component Object Model (COM) DLL in Microsoft Visual Studio .NET, you may receive an error message that is similar to the following:

A reference to 'C:\MyCOMDLL\Debug\MyCOMDLL.dll' could not be added. Converting the type library to a .NET assembly failed. Could not load type MyCOMDLLLib.MyClassClass from assembly Interop.MyCOMDLLLib, Version=1.0.0.0.


Additionally, when you try to convert the type definitions that are found in a COM DLL by using Microsoft Type Library Importer (Tlbimp.exe) from a command prompt, you may receive an error message that is similar to the following:


TlbImp error: System.TypeLoadException - Could not load type MyCOMDLLLib.MyClassClass from assembly MyCOMDLLLib, Version=1.0.0.0.

CAUSE

You may notice the behavior that is mentioned in the "Symptoms" section when the following conditions are true:

  • Your DLL contains a class (such as MyClass) that implements an interface (such as IMyClass) that in turn derives from a base interface (such asIBaseClass).
  • The IMyClass interface contains a method (such as Test) that has the same name as a property that the IBaseClass interface has.

You notice this behavior because of the mechanism that Tlbimp.exe uses to disambiguate member names. Under the previous conditions, when the Microsoft .NET Framework tries to create a method implementation to associate the Test method of the MyClass class with the corresponding interface method, the .NET Framework does not know the name of the corresponding interface method. Therefore, Tlbimp.exe generates a System.TypeLoadException error, and then you receive the error message that is mentioned in the "Symptoms" section.

When you try to add a project reference to a COM DLL, Visual Studio .NET internally runs Tlbimp.exe and then handles any generated exceptions. Therefore, under the previous conditions, Visual Studio .NET handles the generated System.TypeLoadException, and then you receive the error message that is mentioned in the "Symptoms" section.

WORKAROUND

To work around the behavior that is mentioned in the "Symptoms" section, modify your COM DLL so that the method in the derived interface (IMyClass) and the property in the base interface (IBaseClass) have different names. To do this, follow these steps.

Note The following procedure is based on the sample that is mentioned in the "More Information" section. Therefore, the code and the file names in this procedure may differ from your code and from your file names.

  1. Quit Visual Studio .NET after you receive an error message.
  2. Start Visual Studio .NET, and then open the MyCOMDLL solution.
  3. Locate the following code in the MyCOMDLL.idl file:

    [id(2), helpstring("method Test")] HRESULT Test([in] CHAR Param1);
  4. Replace the code that you located in the previous step with the following code:

    [id(2), helpstring("method ModifiedTest")] HRESULT ModifiedTest([in] CHAR Param1);
  5. Locate the following code in the MyClass.h file:

    STDMETHOD(Test)(CHAR Param1);
  6. Replace the code that you located in the previous step with the following code:

    STDMETHOD(ModifiedTest)(CHAR Param1);
  7. Locate the following code in the MyClass.cpp file:

    STDMETHODIMP CMyClass::Test(CHAR Param1)
  8. Replace the code that you located in the previous step with the following code:

    STDMETHODIMP CMyClass::ModifiedTest(CHAR Param1)
  9. On the Build menu, click Build MyCOMDLL to build the MyCOMDLL.dll file.
  10. In the Solution Explorer window, click ConsoleApplication1.

    Try to add a project reference to the MyCOMDLL.dll file that you built in step 7. Notice that you do not receive the error message that is mentioned in the "Symptoms" section.
  11. From a Visual Studio .NET command prompt, change the directory path of the directory where the MyCOMDLL.dll file exists, and then run the following command:

    Tlbimp MyCOMDLL.dll

    Notice that you do not receive the error message that is mentioned in the "Symptoms" section.

The previous steps demonstrate how to work around the behavior that is mentioned in the "Symptoms" section by changing the name of the method in the IMyClass interface. You can also work around this behavior by similarly changing the name of the property in the IBaseClass interface.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft .NET Framework 1.1 and in the Microsoft .NET Framework 1.0.

MORE INFORMATION

Steps to Reproduce the Behavior

  1. Start Visual Studio .NET.
  2. Use Microsoft Visual C++ .NET to create an Active Template Library (ATL) project that is named MyCOMDLL.

    Note In the ATL Project Wizard dialog box, follow these steps on the Application Settings page:
    1. Click to clear the Attributed check box.
    2. Click the Dynamic-link library (DLL) option under Server type.
  3. Add an ATL Simple Object class that is named MyClass to the MyCOMDLL project.
  4. In Solution Explorer, right-click MyCOMDLL.idl, and then click Open.
  5. Replace the existing code in the MyCOMDLL.idl file with the following code:

    // MyCOMDLL.idl : IDL source for MyCOMDLL
    //
    
    // This file will be processed by the MIDL tool to
    // produce the type library (MyCOMDLL.tlb) and marshalling code.
    
    import "oaidl.idl";
    import "ocidl.idl";
    
    // The IBaseClass interface is a base interface that derives from the IDispatch interface.
    // The IBaseClass interface has a property that is named Test.
    [
        object,
        uuid(B6A5C077-6EFD-465C-A305-2025D5832D26),
        dual,
        nonextensible,
        helpstring("IBaseClass Interface"),
        pointer_default(unique)
    ]
    interface IBaseClass : IDispatch{
        [propget, id(1), helpstring("property Test")] HRESULT Test([out, retval] LONG* pVal);
        [propput, id(1), helpstring("property Test")] HRESULT Test([in] LONG newVal);
    };
    
    // The IMyClass interface is an interface that derives from the IBaseClass base interface.
    // The IMyClass interface has a method that is named Test.
    [
        object,
        uuid(63B49AA4-9BC2-41AC-A460-9C91E3976FC4),
        dual,
        nonextensible,
        helpstring("IMyClass Interface"),
        pointer_default(unique)
    ]
    interface IMyClass : IBaseClass{
        [id(2), helpstring("method Test")] HRESULT Test([in] CHAR Param1);
    };
    
    // The MyClass class is a COM class that implements the IMyClass interface.
    [
        uuid(C89325EB-9143-4FC5-ADFE-0FC6EF0FB8F5),
        version(1.0),
        helpstring("MyCOMDLL 1.0 Type Library")
    ]
    library MyCOMDLLLib
    {
        importlib("stdole2.tlb");
        [
            uuid(40CB04DA-89B2-48DB-A90F-4BB0AE3888CD),
            helpstring("MyClass Class")
        ]
        coclass MyClass
        {
            [default] interface IMyClass;
        };
    };
  6. In the MyClass.h file, add the following code to the public section that is located after the FinalRelease method:

    STDMETHOD(get_Test)(LONG* pVal);
    STDMETHOD(put_Test)(LONG newVal);
    STDMETHOD(Test)(CHAR Param1);
  7. Locate the following code in the MyClass.cpp file:

    // CMyClass
  8. Add the following code after the code that you located in the previous step:

    STDMETHODIMP CMyClass::get_Test(LONG* pVal)
    {
        // TODO: Add your implementation code here
    
        return S_OK;
    }
    
    STDMETHODIMP CMyClass::put_Test(LONG newVal)
    {
        // TODO: Add your implementation code here
    
        return S_OK;
    }
    
    STDMETHODIMP CMyClass::Test(CHAR Param1)
    {
        // TODO: Add your implementation code here
    
        return S_OK;
    }
  9. On the Build menu, click Build MyCOMDLL to build the MyCOMDLL.dll file.
  10. Use Microsoft Visual C# .NET or Visual Basic .NET to add a new console application project to your MyCOMDLL solution.
  11. Try to add a project reference to the MyCOMDLL.dll file that you built in step 9. You receive the following error message:

    A reference to 'DLLPath\MyCOMDLL.dll' could not be added. Converting the type library to a .NET assembly failed. Could not load type MyCOMDLLLib.MyClassClass from assembly Interop.MyCOMDLLLib, Version=1.0.0.0.


    Note DLLPath is a placeholder for the file path of the MyCOMDLL.dll file.
  12. From a Visual Studio .NET command prompt, change the directory path of the directory where the MyCOMDLL.dll file exists, and then run the following command:

    Tlbimp MyCOMDLL.dll

    You receive the following error message:

    TlbImp error: System.TypeLoadException - Could not load type MyCOMDLLLib.MyClassClass from assembly MyCOMDLLLib, Version=1.0.0.0.


REFERENCES

For additional information about adding and about removing project references, visit the following Microsoft Developer Network (MSDN) Web site:

For additional information about Type Library Importer (Tlbimp.exe), visit the following MSDN Web site:

For additional information about the TypeLoadException class, visit the following MSDN Web site:

For additional information about interface definitions and about type libraries, visit the following MSDN Web site:

Keywords: kbvs2002sp1sweep kbinheritance kbidl kbideproject kbdll kbcominterop kbmisctools kbinterop kbprogramming kbcode kbsample kberrmsg kbbug KB828986