2

We have an ActiveX component that displays a Web page in an Internet Explorer window via SHDocVw. In the DocumentComplete event handler, we attempt to retrieve the value from one of the controls on the page. We know the control is on the page (it's visible via a Fiddler trace).

It's at this point that things get wonky. We receive the following error message at runtime:

Error Message:  
  Public member 'elements' on type 'DBNull' not found.
Error Routine Location:  
   at Microsoft.VisualBasic.CompilerServices.Symbols.Container.GetMembers(String& MemberName, Boolean ReportErrors)
   at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack)
   at Foo.AddinModule.m_internetExplorer_DownloadComplete(Object pDisp, Object& url)
Error Source:  
  Microsoft.VisualBasic
Error Site Location:  
  System.Reflection.MemberInfo[] GetMembers(System.String ByRef, Boolean)

The offending line of code is this one:

Me.IEInstance.Document.forms("frmRedirect").elements("redirectData").Value = outlookXML.OuterXml

So, essentially, Me.IEInstance.Document.forms("frmRedirect") is evaluating to DBNull.

We've eliminated case sensitivity issues. Tried moving the control around within the page, and verified that the HTML is well-formed. I have no idea why this is occurring. A sample of the generated HTML is below.

Can anyone suggest a cause and a possible resolution for this issue? I'm entertaining any and all suggestions at this point.

HTML Sample

<form id='frmRedirect' name='frmRedirect' action='pw_outlook/choosecontacts.aspx' method='POST'>
    <input type='hidden' name='redirectData'>
</form>

UPDATE 3/28/2012

We have determined that the code works fine under certain configurations. Then, mysteriously, it will succeed for some users if you change the code as follows:

Me.IEInstance.Document.forms("frmRedirect").Elements("redirectData").Value = outlookXML.OuterXml
                                            ^
                                            ^

That is, if you simply change the case of Elements. This, to me, smacks of a case sensitivity issue during a COM vtable lookup, but the mystery is that it doesn't occur for everyone. Just some users.

Also, please note that the form that is returned by .forms("frmRedirect") is a valid object; however, it doesn't appear to have an elements() method.

Mike Hofer
  • 16,477
  • 11
  • 74
  • 110
  • Just to note that it can be also Me.IEInstance.Document.forms("frmRedirect").elements("redirectData") evaluating to DbNull. Maybe some of the answers here heps too: http://stackoverflow.com/questions/840813/how-to-use-webbrowser-control-documentcompleted-event-in-c – Ignacio Soler Garcia Mar 28 '12 at 14:49
  • No, we have verified that it isn't evaluating to DBNull. Elements itself is null. For some reason, the browser evaluates that as DBNull, which always has exactly one instance, which produces the misleading error message. – Mike Hofer Mar 28 '12 at 15:09

3 Answers3

5

You are battling a bug in the DLR, the dynamic language runtime that was added in .NET 4. The code on the stack trace is related to the VB.NET binder to the DLR. This bug is almost certainly not triggered by the code you posted, it is likely to be some other code in your project that does something with a dbase query. Given the presence of DBNull in the exception message.

You'll need support from Microsoft to get to the bottom of this. They'll need your project to give them a repro to work on, given that the code snippet itself won't help them find it. You can contact Microsoft Support to get that started. They'll take a chunk out of your credit card but you'll almost certainly get it back, given that it is likely to be a bug in their code and not yours.

There is a possible workaround for this particular failure, although it isn't exactly guaranteed that the DLR corruption isn't going to cause some kind of problem later. You can write the exact same code without using the DLR by writing early bound code. Start that with Project + Add Reference, Browse tab, select c:\windows\system32\mshtml.tlb

Then rewrite your snippet to look like this:

    Dim doc = DirectCast(Me.IEInstance.ActiveXInstance, mshtml.IHTMLDocument2)
    Dim form = DirectCast(doc.forms("frmRedirect"), mshtml.IHTMLFormElement)
    If form IsNot Nothing Then
        Dim elem = DirectCast(form.elements("redirectData"), mshtml.IHTMLInputElement)
        If elem IsNot Nothing Then
            elem.value = outlookXML.OuterXml
        End If
    End If
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • This is what I'm afraid of, but we're accepting it. The truth of the matter is that it occurs only for a handful of users, and only sporadically, with the exact same page, and *what appears to be* the exact same data. If the code hasn't changed, it must be something external to the code. If the data hasn't changed, it must also be something external to the data. That leaves the platform. :( – Mike Hofer Apr 04 '12 at 15:25
  • Do encourage your users to keep Windows Update enabled. There are some odds that this bug was already fixed. There have been lots of updates to .NET 4 since it shipped. – Hans Passant Apr 04 '12 at 15:27
  • Our users are, unfortunately, end-users in corporations scattered across the world. Which service packs they are using tends to be dictated by their IT departments. As much as we'd like them to be updated, some of them are obstinately refusing to move forward. We have one client that refuses to move off of IE6. (They are not the culprit in this case, but they're a prime example of the corporate cultures we get to support.) – Mike Hofer Apr 04 '12 at 15:30
0

To try to help out other people that looking at this same issue ... I have been screen scraping stock data for many years. I like to see the web page that is being scraped since it makes it much easier to debug.
I run Windows 7 64 bit, Visual Studio 2010. When my computer automatically changed to IE9 - I started having a lot of problems with code that had been running for many years. The code in VB.NET is like:

Public WithEvents MyExplorer As SHDocVw.InternetExplorer
MyExplorer.Navigate("SomeURL")
While (MyExplorer.ReadyState <> SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE)
    Application.DoEvents()
    Thread.Sleep(500)
End While
Dim strHtml As String
strHtml = MyExplorer.Document.DocumentElement.innerHTML.Replace("&amp;", "&").replace("&nbsp;", " ")

I have had to make two significant changes since IE9 came out: 1. MyExplorer.ReadyState <> SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE 2. MyExplorer.Document.DocumentElement.innerHTML

In the first case I was doing something like While (MyExplorer.Document.readyState <> "complete") that no longer seems to work reliably. I changed to: While (MyExplorer.ReadyState <> SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE) which seems more reliable

In the second case I was getting the HTML of the web page by using: MyExplorer.Document.documentElement.innerhtml I kept getting exceptions that although MyExplorer.ReadyState was complete - documentElement was null (or DBNull). The interesting part was that in Intellisense and "Local Variables" of Visual Studio - I could see documentElement and innerhtml.
Based on what I saw in one answer above - I simply changed the capitalization of DocumentElement and it now seems to work reliably.
The huge advantage of VB.NET is that it is suppose to be case insensitive ...

Bubba
  • 192
  • 1
  • 3
  • 14
0

What do the following expressions evaluate to?

Me.IEInstance.Document.forms
Me.IEInstance.Document.forms("frmRedirect")
Me.IEInstance.Document.forms(0)

I don't know that the forms collection can be indexed by name, but maybe I am wrong on this. Please verify all the expressions.

What does the ActiveX-control have to do with your question? It seems that your question is only about that offending line of code. Am I mistaken here?

Edit: Here is a workaround: assign an ID to the hidden input and get the input element by id.

usr
  • 168,620
  • 35
  • 240
  • 369
  • They all return the expected form. But trying to invoke elements on it throws a COM interop exception. – Mike Hofer Mar 28 '12 at 15:42
  • Same exception occurs. In fact, it appears to occur for every method on the Form. Almost as if something about the case of the method names in the vtable has been changed. Perplexing. – Mike Hofer Mar 28 '12 at 16:03
  • 1) And different casing doesn't help? 2) What is the static and the runtime type of "IEInstance", "Document", and "forms"? btw, the vtable does not contain the names of the strings. The vtable only gets used for statically known method slots. – usr Mar 28 '12 at 16:09
  • I would normally agree with you regarding the VTable, except that I think that Don Box might disagree as well. When a method invocation is made during dynamic dispatch, the vtable is consulted to determine the address of the method by the method name. COM is case-sensitive; VB is not. I suspect that VB is providing one case, and COM demands the other. However, if I change the case, it breaks the app for the other half of its users. – Mike Hofer Mar 29 '12 at 14:46
  • Ok, if one of the two casings is guaranteed to succeed, you can try both and ignore one failure. This is, of course, the last resort... But if you don't have any other option you might need to do it. – usr Mar 29 '12 at 18:17