웹, HTML

IHTMLDocument2 도큐먼트 파싱 함수

디버그정 2008. 9. 17. 03:49


/////////////////////////////////////////////////////////////////////////////////
//////// int ParseDoc(IHTMLDocument2 *, LPTSTR *) : 도큐먼트 파싱
/////////////////////////////////////////////////////////////////////////////////
// 인수 1: [in]  IHTMLDocument2 인터페이스 포인터
// 인수 2: [out] LPTSTR의 포인터
// 리턴값: [ret] 다큐먼트내 프레임의 수(에러면 0, 정상리턴이면 1이상의 값)
// 주의) 리턴 후 caller 측에서 두번째 인수 널값이 아니면 free로 반드시 해제
/////////////////////////////////////////////////////////////////////////////////
/* 사용법 샘플)
 LPTSTR lpszParsed;
 int iCount=ParseDoc(m_pDoc, &lpszParsed);
 if(iCount){
  ...
  ...
  ...
  free(lpszParsed);
 } else {
  ...  // 에러일 경우 처리
 }
*/
/////////////////////////////////////////////////////////////////////////////////

int ParseDoc(IHTMLDocument2 * pDoc, LPTSTR * ppszParsed);

/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
int ParseDocRecur(IHTMLDocument2 * pDoc, LPTSTR * ppszParsed);
int ParseDoc(IHTMLDocument2 * pDoc, LPTSTR * ppszParsed){
 if(pDoc ==0 || ppszParsed==0){ // 전달 인수 간단한 유효성 검사: 기본적 에러 처리
  MessageBox(NULL, _T("Parameter is invalid - ParseDoc"), _T("error"), MB_ICONERROR);
  return 0;
 }
 *ppszParsed = 0; // 초기화
 return ParseDocRecur(pDoc, ppszParsed);
}
int ParseDocRecur(IHTMLDocument2 * pDoc, LPTSTR * ppszParsed){
 LPTSTR p = *ppszParsed;
 int iFrameCount=0;
 BSTR bstrSource;
 
 HRESULT hr=pDoc->get_URL(&bstrSource);
 if(FAILED(hr)){MessageBox(NULL, _T("IHTMLDocument2::get_URL failed. - ParseDocReCur"), _T("error"), MB_ICONERROR); return 0;}
#if defined(UNICODE) || defined(_UNICODE)
 int iLen=lstrlen(p);
 int iTargetLen=lstrlen(bstrSource);
 p=(LPTSTR)realloc(p, (iLen+iTargetLen+5)*sizeof(TCHAR));
 lstrcpy(p+iLen, bstrSource);
 lstrcat(p,_T("\r\n\r\n"));
 iLen += iTargetLen+4;
#else
 int iNeedSize=WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,bstrSource,-1,0,0,0,0);
 int iLen=lstrlen(p);
 p=(LPTSTR)realloc(p, iLen+iNeedSize+4); // 참고) iNeedSize는 이미 널 포함된 길이값이다.
 if(NULL == p){MessageBox(NULL, _T("realloc failed. - ParseDocReCur"), _T("error"), MB_ICONERROR); return 0;}
 WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,bstrSource,-1,p+iLen,iNeedSize,0,0);
 lstrcat(p, _T("\r\n\r\n")); // 2번 개행
 iLen += iNeedSize+4-1;  // iNeedSize에 널이 포함되었으므로 1을 빼준다.
#endif
 SysFreeString(bstrSource);
 //*ppszParsed = p;

 IHTMLElement * pBodyEl=0, * pParentEl=0;
 hr=pDoc->get_body(&pBodyEl);
 if(FAILED(hr) || pBodyEl==0){MessageBox(NULL, _T("IHTMLDocument2::get_body failed. - ParseDocRecur"), _T("error"), MB_ICONERROR); return 0;}
 hr=pBodyEl->get_parentElement(&pParentEl);
 if(FAILED(hr) || pParentEl==0){MessageBox(NULL, _T("IHTMLDocument2::get_parentElement failed. - ParseDocRecur"), _T("error"), MB_ICONERROR); return 0;}
 pBodyEl->Release();
 hr=pParentEl->get_outerHTML(&bstrSource);
 if(FAILED(hr)){MessageBox(NULL, _T("IHTMLDocument2::get_outerHTML failed. - ParseDocRecur"), _T("error"), MB_ICONERROR); return 0;}
 pParentEl->Release();

#if defined(UNICODE) || defined(_UNICODE)
 iTargetLen=lstrlen(bstrSource);
 p=(LPTSTR)realloc(p, (iLen+iTargetLen+5)*sizeof(TCHAR)); // 개행+널 고려 5를 더해줌
 lstrcpy(p+iLen, bstrSource);
 lstrcat(p,_T("\r\n\r\n"));
 iLen += iTargetLen+4;
#else
 iNeedSize=WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,bstrSource,-1,0,0,0,0);
 p=(LPTSTR)realloc(p, iLen+iNeedSize+4);
 if(!p){MessageBox(NULL, _T("realloc failed. - ParseDocRecur"), _T("error"), MB_ICONERROR); return 0;}
 WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,bstrSource,-1,p+iLen,iNeedSize,0,0);
 lstrcat(p, _T("\r\n\r\n"));
 iLen += iNeedSize+4-1;
#endif
 SysFreeString(bstrSource);
 *ppszParsed = p; // 리얼록으로 할당주소 변경되었으므로 반영해 준다.

 iFrameCount++;

 // 프레임의 수를 검사하고 그 수만큼 재귀루프를 돌린다.(프레임 안에 또 프레임이 존재 가능)
 IHTMLFramesCollection2 * pFrameCol=0;
 hr=pDoc->get_frames(&pFrameCol);
 if(FAILED(hr) || pFrameCol==0){MessageBox(NULL, _T("IHTMLFramesCollection2::get_frames failed. - ParseDocRecur"), _T("error"), MB_ICONERROR); return 0;}
 long lFrameElCount=0;
 
 pFrameCol->get_length(&lFrameElCount);
 if(FAILED(hr)){MessageBox(NULL, _T("IHTMLFramesCollection2::get_length failed. - ParseDocRecur"), _T("error"), MB_ICONERROR); return 0;}

 VARIANT varIndex, varResult;
 varIndex.vt=VT_I4;
 long i;
 for(i=0; i<lFrameElCount ;i++){
  varIndex.lVal=i;
 
  hr=pFrameCol->item(&varIndex, &varResult);
  if(FAILED(hr)) continue;
 
  IHTMLWindow2 * pWin=0;
  hr=varResult.pdispVal->QueryInterface(IID_IHTMLWindow2, (void**)&pWin);
  if(FAILED(hr) || pWin==0) continue;
  varResult.pdispVal->Release();

  IHTMLDocument2 * pSubDoc=0;
  hr=pWin->get_document(&pSubDoc);
  if(FAILED(hr) || pSubDoc==0) continue;
  pWin->Release();
  iFrameCount += ParseDocRecur(pSubDoc, ppszParsed);
  pSubDoc->Release();
 }
 pFrameCol->Release();
 return iFrameCount;
}