fail to get IHTMLElement from IHTMLFormElement
-
Hello all I am getting the form objects from internet explorer and want to get all the elements from each form. To do this, I get the form collection from the html document object, get an interface to each form element in the collection then try to get an IID_IHTMLElement interface from the IID_IHTMLFormElement interface in order to get all the elements in the form, as recommended by MS. It all works on my machine and all others I've tried, except that on my friend's pc, the QueryInterface call fails with E_NOINTERFACE. I'm not that proficient in COM, so I wonder if there is something I'm doing wrong here so that it only works on some systems. He assures me that he has IE7 installed so not an old cranky version. Code as follows:
bool ret = true; CComPtr<IHTMLElementCollection> spForms; long numForms = 0L; CComPtr<IDispatch> spDisp; // get collection of forms within web page HRESULT hr = spDoc->get\_forms(&spForms.p); if (FAILED(hr) || !spForms) { ret = false; } if (ret) { // get number of forms in collection HRESULT hr = spForms->get\_length(&numForms); if (FAILED(hr)) { ret = false; } } if (ret) { // process each form for (int formNumber = 0; ret && (formNumber < numForms); formNumber++) { BSTR bstr; CString formName; CComPtr<IHTMLElementCollection> spElements; CComPtr<IHTMLFormElement> spFormElement; CComPtr<IHTMLElement> spElement; long numElements = 0L; // get next form CComVariant vIdx(0, VT\_I4); HRESULT hr = spForms->item(CComVariant(formNumber), vIdx, &spDisp.p); if (FAILED(hr) || !spDisp) { ret = false; } if (ret) { // get form interface HRESULT hr = spDisp->QueryInterface( IID\_IHTMLFormElement, (void\*\*) &spFormElement.p); if (FAILED(hr) || !spFormElement) { ret = false; } } if (ret) { // get form name hr = spFormElement->get\_name(&bstr); if (FAILED(hr)) { ret = false; } } if (ret) { // need to call IHTMLElement::all() instead of IHTMLFormElement::item(), // otherwise will only get the controls and not all the elements in the form, // such as the labels HRESULT hr = spFormElement->QueryInterface(!!! IID\_IHTMLElement, (void\*\*) &spElement.p); if (FAILED(hr) || !spElement) { // FAILS HERE WITH hr == E\_NOINTERFACE!!! ret = false; }
-
Hello all I am getting the form objects from internet explorer and want to get all the elements from each form. To do this, I get the form collection from the html document object, get an interface to each form element in the collection then try to get an IID_IHTMLElement interface from the IID_IHTMLFormElement interface in order to get all the elements in the form, as recommended by MS. It all works on my machine and all others I've tried, except that on my friend's pc, the QueryInterface call fails with E_NOINTERFACE. I'm not that proficient in COM, so I wonder if there is something I'm doing wrong here so that it only works on some systems. He assures me that he has IE7 installed so not an old cranky version. Code as follows:
bool ret = true; CComPtr<IHTMLElementCollection> spForms; long numForms = 0L; CComPtr<IDispatch> spDisp; // get collection of forms within web page HRESULT hr = spDoc->get\_forms(&spForms.p); if (FAILED(hr) || !spForms) { ret = false; } if (ret) { // get number of forms in collection HRESULT hr = spForms->get\_length(&numForms); if (FAILED(hr)) { ret = false; } } if (ret) { // process each form for (int formNumber = 0; ret && (formNumber < numForms); formNumber++) { BSTR bstr; CString formName; CComPtr<IHTMLElementCollection> spElements; CComPtr<IHTMLFormElement> spFormElement; CComPtr<IHTMLElement> spElement; long numElements = 0L; // get next form CComVariant vIdx(0, VT\_I4); HRESULT hr = spForms->item(CComVariant(formNumber), vIdx, &spDisp.p); if (FAILED(hr) || !spDisp) { ret = false; } if (ret) { // get form interface HRESULT hr = spDisp->QueryInterface( IID\_IHTMLFormElement, (void\*\*) &spFormElement.p); if (FAILED(hr) || !spFormElement) { ret = false; } } if (ret) { // get form name hr = spFormElement->get\_name(&bstr); if (FAILED(hr)) { ret = false; } } if (ret) { // need to call IHTMLElement::all() instead of IHTMLFormElement::item(), // otherwise will only get the controls and not all the elements in the form, // such as the labels HRESULT hr = spFormElement->QueryInterface(!!! IID\_IHTMLElement, (void\*\*) &spElement.p); if (FAILED(hr) || !spElement) { // FAILS HERE WITH hr == E\_NOINTERFACE!!! ret = false; }
It doesn't sound as if there's anything wrong with your code.
E_NO_INTERFACE
is technically not a failure, it's a legal response in the COM world. I've had users 'assure me' that nothing out of the ordinary is installed or used when it proves not to be the case. Can you put in some checks in your code to test for the right version of IE or perhaps a version number or similar for the FormElement that you get theE_NOINTERFACE
from? Does it support some alternate interface, say IHTMLElementEx? I'm not saying there is such a thing as an IHTMLElementEx interface, it's just a possibility. -
It doesn't sound as if there's anything wrong with your code.
E_NO_INTERFACE
is technically not a failure, it's a legal response in the COM world. I've had users 'assure me' that nothing out of the ordinary is installed or used when it proves not to be the case. Can you put in some checks in your code to test for the right version of IE or perhaps a version number or similar for the FormElement that you get theE_NOINTERFACE
from? Does it support some alternate interface, say IHTMLElementEx? I'm not saying there is such a thing as an IHTMLElementEx interface, it's just a possibility.Hi I called him tonight and got him to check the IE version. It is version 7, same as mine. I also asked him to disable all add-ons temporarily but got the same problem. If we both have IE7 and add-ons are not the problem, what other difference could there be on his system that means he gets the E_NOINTERFACE and I don't?
-
Hi I called him tonight and got him to check the IE version. It is version 7, same as mine. I also asked him to disable all add-ons temporarily but got the same problem. If we both have IE7 and add-ons are not the problem, what other difference could there be on his system that means he gets the E_NOINTERFACE and I don't?
I suppose it depends on what he has loaded up in IE at the time. For any COM error such as E_NOINTERFACE you can look for extended error information that may have been set when the error was generated:
//Check for IErorrInfo and load it if it is present
IErrorInfo* pErrInfo = NULL;
HRESULT hr = GetErrorInfo(0, &pErrInfo);Then use the IErrorInfo methods to obtain details, though there may be no info set to retreive its worth a try. You may have the same IE7, but presumably you may not have the same forms or elements etc. All I can suggest is have the program get details of the object that returns E_NOINTERFACE to see if you can find anything out based on that information or establish a pattern. It may be that in an ideal world all objects would implement this interface but in reality it means that you have to accept that there are objects out there that don't for some reason. As a result you have to handle the ones that don't somehow. Currently your loop exits when 'ret' becomes false for any reason, maybe you need to skip that element and move on to the next (or something similar), storing its details etc.
-
I suppose it depends on what he has loaded up in IE at the time. For any COM error such as E_NOINTERFACE you can look for extended error information that may have been set when the error was generated:
//Check for IErorrInfo and load it if it is present
IErrorInfo* pErrInfo = NULL;
HRESULT hr = GetErrorInfo(0, &pErrInfo);Then use the IErrorInfo methods to obtain details, though there may be no info set to retreive its worth a try. You may have the same IE7, but presumably you may not have the same forms or elements etc. All I can suggest is have the program get details of the object that returns E_NOINTERFACE to see if you can find anything out based on that information or establish a pattern. It may be that in an ideal world all objects would implement this interface but in reality it means that you have to accept that there are objects out there that don't for some reason. As a result you have to handle the ones that don't somehow. Currently your loop exits when 'ret' becomes false for any reason, maybe you need to skip that element and move on to the next (or something similar), storing its details etc.
Thanks for that. I'll try the extended error info to see what it shows me. You're right - it should skip onto the next one if it fails instead of aborting completely. Both of us are using the same web page to test the program, specifically mailzone.onetel.net.uk which is a simple page containing a single form with a text input element and a password input element. It doesn't seem to matter what the page is though as mine always works and his always fails whatever web page I've chosen. It should be possible to get an interface to an IHTMLElement from the IHTMLFormElement according to the MS documentation, but it won't work on his pc.