// 깔끔하게 만들려고 노력했다.
// 에러처리 완벽하게 할려고 했다.
/*
// <사용방법>
LPWSTR lpszSource; // WCHAR 포인터(유니코드 문자열) 변수 할당
if(GetHtmlSource(pDoc, &lpszSource)){ // 성공여부 체크
//ClipBoardTextCopyW(lpszSource); // 필요한 작업~~~~
//.....
//....
//...
free(lpszSource); // ★ 작업이 끝나면 반드시 해제하자
}
*/
int __stdcall GetHtmlSource(IHTMLDocument2 *pDoc, LPWSTR *ppszText)
{
int iRunCount = 0; // 함수 실행 횟수 제한키 위해
int iSuccessCount = 0; // 성공적으로 프레임으로부터 소스 추출한 횟수
*ppszText = (LPWSTR)calloc(1, sizeof(WCHAR));
if(NULL == *ppszText){
MessageBox(NULL, _T("초기 2바이트 메모리 할당에 실패하였습니다."), _T("GetHtmlSource 에러"), MB_ICONERROR|MB_TOPMOST);
*ppszText = NULL;
return 0;
}
iSuccessCount = GetHtmlSourceRecur(pDoc, ppszText, &iRunCount); // 실질적인 재귀함수 실행
if(0 == iSuccessCount) free(*ppszText); // 성공카운트가 0이면 실패이므로 메모리 해제하자.
return iSuccessCount;
}
// 프레임안에 프레임이 있는 구조가 흔하므로 재귀함수로 구성한다.
// 재귀함수의 무한반복(스택 오버플로우 에러 가능)은 위험하므로 호출횟수 제한함.
// 정상적인 웹페이지에서 프레임이 20개 넘는 경우는 없을 것이므로 20으로 제한
// 리턴값은 프레임에서 소스 추출 성공횟수
int __stdcall GetHtmlSourceRecur(IHTMLDocument2 *pDoc, LPWSTR *ppszText, int *piRunCount)
{
// 호출횟수 검사
*piRunCount = *piRunCount+1;
if(*piRunCount > 20){
MessageBox(NULL, _T("GetHtmlSourceRecur 재귀함수 호출이 20회를 초과하였습니다."), _T("GetHtmlSource 에러"), MB_ICONERROR|MB_TOPMOST);
return 0;
}
BOOL bRes=FALSE;
int iSuccessCount = 0;
// 현재의 프레임의 URL 추출
LPCWSTR lpszPreStr=L"<!-- ◀◀◀ 프레임 주소: "; // 주석표시와 앞에 붙일 스트링
BSTR bstrUrl;
if(S_OK == pDoc->get_URL(&bstrUrl)){
*ppszText = (LPWSTR)realloc(*ppszText, (lstrlenW(*ppszText)+lstrlenW(bstrUrl)+lstrlenW(lpszPreStr)+5+1)*sizeof(WCHAR));
if(*ppszText){
lstrcatW(*ppszText, lpszPreStr);
lstrcatW(*ppszText, bstrUrl);
lstrcatW(*ppszText, L"-->\r\n"); // 주석 닫음과 개행(길이 5)
bRes = TRUE;
} else{
MessageBox(NULL, _T("URL을 위한 메모리 할당이 실패하였습니다."), _T("GetHtmlSource 에러"), MB_ICONERROR|MB_TOPMOST);
bRes = FALSE;
}
SysFreeString(bstrUrl);
}
if(!bRes){
MessageBox(NULL, _T("URL을 얻는 데 실패하였습니다."), _T("GetHtmlSource 에러"), MB_ICONERROR|MB_TOPMOST);
return 0;
}
// 현재의 프레임의 도큐먼트의 소스 추출... 구하는 원리는 <body>의 부모는 <html>이므로...
IHTMLElement * pBodyElem=NULL;
IHTMLElement * pParentElem=NULL;
BSTR bstrSource;
bRes=FALSE;
if(S_OK==pDoc->get_body(&pBodyElem)){
if(S_OK==pBodyElem->get_parentElement(&pParentElem)){
if(S_OK == pParentElem->get_outerHTML(&bstrSource)){
*ppszText = (LPWSTR)realloc(*ppszText, (lstrlenW(*ppszText)+lstrlenW(bstrSource)+8+1)*sizeof(WCHAR));
if(*ppszText){
lstrcatW(*ppszText, bstrSource);
lstrcatW(*ppszText, L"\r\n\r\n\r\n\r\n"); // 개행 4번(길이 8)
bRes = TRUE;
} else{
MessageBox(NULL, _T("소스를 위한 메모리 할당이 실패하였습니다."), _T("GetHtmlSource 에러"), MB_ICONERROR|MB_TOPMOST);
bRes = FALSE;
}
SysFreeString(bstrSource);
}
pParentElem->Release();
}
pBodyElem->Release();
}
if(!bRes){
MessageBox(NULL, _T("개별 도큐먼트 소스를 얻는 데 실패하였습니다."), _T("GetHtmlSource 에러"), MB_ICONERROR|MB_TOPMOST);
return 0;
}
++iSuccessCount;
// 내부에 존재하는 프레임의 수를 검사하고 있으면 재귀호출
long i, lFrameCount=0;
IHTMLFramesCollection2 *pFramesCollection = NULL;
IHTMLWindow2 * pWin=NULL;
IHTMLDocument2 * pDocFrame = NULL;
VARIANT varIndex; varIndex.vt=VT_I4;
VARIANT varDispWin; varDispWin.vt=VT_DISPATCH;
if(S_OK == pDoc->get_frames(&pFramesCollection)){
if(S_OK == pFramesCollection->get_length(&lFrameCount)){
for(i=0 ; i<lFrameCount ; i++){
varIndex.lVal=i;
if(S_OK == pFramesCollection->item(&varIndex, &varDispWin)){
if(S_OK == varDispWin.pdispVal->QueryInterface(IID_IHTMLWindow2,(void**)&pWin)){
if(S_OK == pWin->get_document(&pDocFrame)){ // 하위 doc이 구해지면 재귀시킨다.
iSuccessCount += GetHtmlSourceRecur(pDocFrame, ppszText, piRunCount);
pDocFrame->Release();
}
pWin->Release();
}
varDispWin.pdispVal->Release();
}
}
}
pFramesCollection->Release();
}
return iSuccessCount;
}