InterOp interfaces must match Vtable layout for early binding to work (327116)



The information in this article applies to:

  • Microsoft Visual Studio 2005 Standard Edition
  • Microsoft Visual Studio 2005 Professional Edition
  • Microsoft Visual Studio .NET (2003), Professional Edition
  • Microsoft Visual Studio .NET (2003), Enterprise Architect Edition
  • Microsoft Visual Studio .NET (2003), Enterprise Developer Edition
  • Microsoft Visual Studio .NET (2002), Professional Edition
  • Microsoft Visual Studio .NET (2002), Enterprise Architect Edition
  • Microsoft Visual Studio .NET (2002), Enterprise Developer Edition
  • Microsoft Visual Basic 2005 Express Edition
  • Microsoft Visual Basic .NET (2003)
  • Microsoft Visual Basic .NET (2002)

This article was previously published under Q327116

SYMPTOMS

When you call a COM method through InterOp, you may receive the following error message:
An unhandled exception of type System.Exception occurred in ApplicationName.exe

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

CAUSE

This problem may occur when the order of the methods declaration in the InterOp interface does not match the order of the Vtable layout of the COM interface (which is determined by their layout in IDL). Because you perform early binding in most cases, the order of the methods is very important in this scenario.

RESOLUTION

Change the order of the methods declaration in the InterOp interface to verify that it matches the Vtable layout of the COM interface that you want to use.

STATUS

This behavior is by design.

MORE INFORMATION

Steps to Reproduce the Behavior

To reproduce the problem, follow these steps:

NOTE: The IOleCommandTarget interface appears in this example.
  1. Create a Visual Basic 2005 or Visual Basic .NET Windows Application. By default, Form1 is added.
  2. Add the following references to the project:
    • Microsoft Internet Control (shdocvw.dll)
    • Microsoft HTML Object Library (mshtml.tlb)
  3. Add a Button control and a Web Browser control to Form1. (Click to select the Microsoft Web Browser item in the Customize ToolBox window.)

    Note In Visual Studio 2005, click Tools, click Choose Toolbox Items, and then click to select Microsoft Web Brower on the COM Components tab.
  4. Add a Class to the project. By default, Class1.vb is added. Paste the following sample code to the class:
    Imports System
    Imports System.Runtime.InteropServices
    Public Class Class1
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
        Public Structure OLECMDTEXT
            Public cmdtextf As UInt32
            Public cwActual As UInt32
            Public cwBuf As UInt32
            <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=100)> _
            Public rgwz As Char
        End Structure
    
        <StructLayout(LayoutKind.Sequential)> _
        Public Structure OLECMD
            Public cmdID As UInt32
            Public cmdf As UInt32
        End Structure
    
        ' Interop definition for IOleCommandTarget. To reproduce the problem, the method order 
        ' here does not match the Vtable layout of IOleCommandTarget interface.
        ' For more information about the IOleCommandTarget interface, see the MSDN. 
    
        <ComImport(), Guid("b722bccb-4e68-101b-a2bc-00aa00404770"), _
            InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Public Interface IOleCommandTarget
    
            Sub Exec(ByRef pguidCmdGroup As Guid, _
            ByVal nCmdId As UInt32, ByVal nCmdExecOpt As UInt32, _
            ByRef pvaIn As Object, ByRef pvaOut As Object)
    					  Sub QueryStatus(ByRef pguidCmdGroup As Guid, _
            ByVal cCmds As UInt32, <MarshalAs(UnmanagedType.LPArray, _
            SizeParamIndex:=1)> ByVal prgCmds() As OLECMD, ByRef pCmdText As OLECMDTEXT)
        End Interface
    
    End Class
    					
  5. Open the Code View of the Form1.vb file, and then paste the following sample code after the Windows Form Designer generated code section of the class Form1:
       Private cmdGUID As New Guid(&HED016940, -17061, _
        &H11CF, &HBA, &H4E, &H0, &HC0, &H4F, &HD7, &H8, &H16)
    
        Private Enum MiscCommandTarget
            ViewSource = 2
        End Enum
    
        Private Sub Button1_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles Button1.Click
            Dim cmdt As IOleCommandTarget
            Dim o As Object
    
            Try
                cmdt = CType(GetDocument(), IOleCommandTarget)
                cmdt.Exec(cmdGUID, Convert.ToUInt32(MiscCommandTarget.ViewSource), _
                Convert.ToUInt32(SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER), o, o)
            Catch
                Throw (New Exception(Err.GetException().Message))
            End Try
        End Sub
    
        Private Function GetDocument() As mshtml.HTMLDocument
            Try
                Dim htm As mshtml.HTMLDocument = AxWebBrowser1.Document
                GetDocument = htm
            Catch
                Throw (New Exception("Cannot retrieve document from WebBrowser" + _
                "Control: " + Err.GetException().Message))
            End Try
        End Function
    
        Private Sub Form1_Load(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load
            AxWebBrowser1.Navigate("http://www.microsoft.com")
    
        End Sub
    
    					
  6. Run the application. When the page appears, click the Button.

RESOLUTION

To resolve this problem, change the order of the method definitions in interface IOleCommandTarget, as in the following example:
  <ComImport(), Guid("b722bccb-4e68-101b-a2bc-00aa00404770"), _
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IOleCommandTarget

        Sub QueryStatus(ByRef pguidCmdGroup As Guid, _
        ByVal cCmds As UInt32, <MarshalAs(UnmanagedType.LPArray, _
        SizeParamIndex:=1)> ByVal prgCmds() As OLECMD, _
        ByRef pCmdText As OLECMDTEXT)
        Sub Exec(ByRef pguidCmdGroup As Guid, _
        ByVal nCmdId As UInt32, ByVal nCmdExecOpt As UInt32, _
        ByRef pvaIn As Object, ByRef pvaOut As Object)
    End Interface
				

Modification Type:MajorLast Reviewed:2/1/2006
Keywords:kbvs2005applies kbvs2005swept kbCOMInterop kberrmsg kbpending kbprb KB327116