FAQ: 如何动态创建并访问网页元素

——谨以怀念写邮件回答网友关于Internet Explorer编程问题的青春岁月

Posted by eagleboost on November 18, 2006

本文转载自我2006年在csdn发布的博客

你好:

在你的博客上看到了一些关于操作Internet Explorer的代码,有个问题请教

目的:在html页面中创建一个控件,程序动态创建。

我已经获得要创建页面的IHTMLDocument2指针,看msdn提示使用createElement函数调用后能够创建以及设置属性,创建为一个element我如何把它设置为一个对象或者applet对象或一个embed对象 我调用原有页面上的控件发现为一个applet对象,以下为动态创建的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void InsertElement(IHTMLDocument2 * pIHTMLDocument2)
{
  HRESULT hr;
  IHTMLElement *pHtmlElement = NULL;
  
  CComBSTR bstrTitle = L"applet";
 
  pIHTMLDocument2->createElement(bstrTitle, &pHtmlElement);
 
  //创建后不知道如何设置成一个applet的对象或者embed对象
 
  VARIANT  vRet;
  VariantInit(&vRet);
  CComBSTR bstrClassID = L"classid";  
  vRet.bstrVal = L"clsid:75B6E755-01FB-46C0-BA16-27350A1855B1";
  vRet.vt = VT_BSTR;
  hr = pHtmlElement->setAttribute(bstrClassID, vRet);
  if (FAILED(hr))
  {
    cout << _T("setAttribute错误") << endl;
    return;
  }
  
  CComBSTR bstrID = L"id";
  vRet.bstrVal = L"myocx1";
  vRet.vt = VT_BSTR;
 
  hr = pHtmlElement-> setAttribute (bstrID, vRet);
  if (FAILED(hr))
  {
    cout << _T("setAttribute错误") << endl;
    return;
  }
 
  CComBSTR bstrName = L"name";
  vRet.bstrVal = L"myocx1";
  hr = pHtmlElement-> setAttribute (bstrName, vRet);
  if (FAILED(hr))
  {
    cout << _T("setAttribute错误") << endl;
    return;
  }
  //如果创建applet对象,是否需要其他的属性或者设置,其他方法????
  ......
}

创建Element之后,应通过IHTMLDOMNode::insertBeforeIHTMLDOMNode::appendChild把元素添加到DOM树中去,所以代码本来应该是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
LPDISPATCH lpDisp = GetHtmlDocument();
if (lpDisp)
{ 
  CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2>  spDoc(lpDisp);
  if (spDoc)
  {
    CComPtr<IHTMLElement>  spElem;
    HRESULT hr = spDoc->createElement(L"applet", &spElem);
    if (FAILED(hr) || !spElem)
      return;
      
    CComPtr<IHTMLElement>  pBodyElem;
    hr = spDoc->get_body(&pBodyElem);
    if (FAILED(hr) || !pBodyElem)
      return;
      
    CComPtr<IHTMLDOMNode>  pBodyNode(pBodyElem);
    if (!pBodyNode)
      return;
      
    CComPtr<IHTMLDOMNode>  pNewChild(pElem);
    CComPtr<IHTMLDOMNode>  pRefChild;
    hr = pBodyNode->appendChild(pNewChild, &pRefChild);
    if (FAILED(hr) || !pRefChild)
      return;
      
    CComQIPtr<IHTMLObjectElement, &IID_IHTMLObjectElement> pObj(pRefChild);
    if (pObj)
    {
      //修改属性等等
    }
  }
}

但试验下来最后一步总是不能成功,从pRefChild得不到pObj,尽管类似的代码用脚本实现没有什么问题:

1
2
3
4
5
6
7
8
9
10
function createRadioButton(){
    // Create radio button object with value="First Choice" and then insert 
    // this element into the document hierarchy.
    var newRadioButton = document.createElement("<INPUT TYPE='RADIO' NAME='RADIOTEST' VALUE='First Choice'>")
    document.body.insertBefore(newRadioButton);
    // Create radio button object with value="Second Choice" and then insert 
    // this element into the document hierarchy. 
    newRadioButton = document.createElement("<INPUT TYPE='RADIO' NAME='RADIOTEST' VALUE='Second Choice'>")
    document.body.insertBefore(newRadioButton);
  }
1
2
3
4
5
6
<HTML>
<BODY>
  <INPUT TYPE="BUTTON" ONCLICK="createRadioButton()" VALUE="Create two Radio Buttons"><BR>
  <INPUT TYPE="BUTTON" ONCLICK="alert (document.body.outerHTML)" VALUE="Click here to see HTML">
<BODY>
</HTML>

看来我们只能用另外一种办法了——insertAdjacentHTML,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
LPDISPATCH lpDisp = GetHtmlDocument();
if (lpDisp)
{ 
  CComQIPtr<IHTMLDocument2, &IID_IHTMLDocument2>  spDoc(lpDisp);
  if (spDoc)
  {
    CComPtr<IHTMLElement>  spBodyElem;
    HRESULT hr = spDoc->get_body(&spBodyElem);
    if (FAILED(hr) || !spBodyElem)
      return;
    
    //我们先创建网页元素,注意给一个ID
    hr = spBodyElem->insertAdjacentHTML(L"beforeEnd", L"<applet code='RainbowText.class' ID='my applet' width='297' height='48' codebase='class/' name='rainbowText'><param name='TEXT' value='test' ></applet>");
    if (FAILED(hr))
      return;
    
    //再通过IHTMLDocument3来访问它
    CComQIPtr<IHTMLDocument3, &IID_IHTMLDocument3>  spDoc3(lpDisp);
    if (!spDoc3)
      return;
      
    CComQIPtr<IHTMLElement>  spElemTemp;
    hr = spDoc3->getElementById(L"my applet", &spElemTemp);
    if (FAILED(hr) || !spElemTemp)
      return;
    
    //把Applet作为IHTMLObjectElement来处理
    CComQIPtr<IHTMLObjectElement, &IID_IHTMLObjectElement> pApplet(spElemTemp);
    if (pApplet)
    {
      //这样就行了
    }
  }
}

能抓到老鼠就是好猫:)

参考资料

MSDN: createElement Method