자료구조, 알고리즘 둘러보다가 퍼뜩 떠올라서 구성해 보았다.
스택을 이용하니 노재귀형태로 구성할 수 있었다.
재귀의 오버플로우는 뭐 요즘같이 스레드에 할당되는 기본 스택이 1메가? 정도되는 상태에서
웬만큼 흘리는 코딩을 하지 않으면 거의 발생할 일이 없겠지만서두,,,
이와 별도로 하나의 함수에서 기타 처리를 모두 할 수 있으니 깔끔해진 듯 하다.
이전에 재귀 형태로 돌리는 경우 기타 처리를 하려면
보통 재귀함수 + 기타처리를 하는 함수,,, 2개로 구성하는 경우가 많았다.
// 재귀함수 사용하지 않고 스택으로 해결
// 연결리스트 스택으로 구성한다.
// 이 함수 성공시 호출부에서는 사용하고 난 후 결과값을 잊지말고 free해줘야 된다.
LPWSTR __stdcall GetHtmlSourceNoRecur(IHTMLDocument2 *pDoc)
{
// 스택 구조상 pPre로 하는 것이 pop시 새로운 top 접근이 용이.
struct Node{
IHTMLDocument2 *pDoc;
Node *pPre;
};
Node *pTop=NULL, *pNew=NULL, *pTemp=NULL;
IHTMLDocument2 *pRootDoc=pDoc; // 밑의 루프에서 해제 방지
//pDoc->AddRef(); // 옆 방식은 해제 전 에러나서 리턴해 버린 경우 +1이 되므로 부적합
LPWSTR lpszBuf;
BOOL bSuc=FALSE;
// 전달된 인수 검사
if(!pDoc) return NULL;
// 노드 할당 및 첫번째 요소 push
pTop=(Node*)malloc(sizeof(Node));
if(!pTop){
MessageBox(NULL, _T("Node 메모리 할당이 실패하였습니다."), _T("GetHtmlSourceNoRecur 에러"), MB_ICONERROR|MB_TOPMOST);
return NULL;
}
pTop->pDoc=pDoc;
pTop->pPre=NULL;
// 소스버퍼 할당,,, 밑의 루프에서 일관성 있는 코드를 위해 한 글자 할당
lpszBuf=(LPWSTR)malloc(sizeof(WCHAR));
if(!lpszBuf){
MessageBox(NULL, _T("초기 메모리 할당이 실패하였습니다."), _T("GetHtmlSourceNoRecur 에러"), MB_ICONERROR|MB_TOPMOST);
return NULL;
}
memset(lpszBuf, 0, sizeof(WCHAR));
////////// pTop->pDoc 소스 추출 후 pop하고 하위 프레임 검사해서 push 그리고 Release한다.
////////// pTop가 NULL이면 스택이 빈 상태이므로 빠져나간다.
while(pTop){
// 참고로 팝하면 변수가 없어지므로 Release 과정을 위해 아래처럼 저장해놔야 된다.
pDoc=pTop->pDoc;
// 각각의 프레임을 구분하기 쉽게 URL에 아래와 같이 스트링을 붙여준다.
LPCWSTR lpszUrlPreStr=L"<!-- ############################### URL ############################### \r\n"; // 주석시작 표시와 앞에 붙일 스트링
LPCWSTR lpszUrlPostStr=L"\r\n######################################################################## -->\r\n"; // 주석끝 표시와 뒤에 붙일 스트링
BSTR bstrUrl;
bSuc=FALSE;
if(S_OK == pDoc->get_URL(&bstrUrl)){
lpszBuf = (LPWSTR)realloc(lpszBuf, (lstrlenW(lpszBuf)+lstrlenW(bstrUrl)+lstrlenW(lpszUrlPreStr)+lstrlenW(lpszUrlPostStr)+1)*sizeof(WCHAR));
if(lpszBuf){
lstrcatW(lpszBuf, lpszUrlPreStr);
lstrcatW(lpszBuf, bstrUrl);
lstrcatW(lpszBuf, lpszUrlPostStr);
bSuc = TRUE;
} else{
MessageBox(NULL, _T("URL을 위한 메모리 할당이 실패하였습니다."), _T("GetHtmlSourceNoRecur 에러"), MB_ICONERROR|MB_TOPMOST);
}
SysFreeString(bstrUrl);
}
if(!bSuc){
free(lpszBuf);
MessageBox(NULL, _T("URL을 얻는 데 실패하였습니다."), _T("GetHtmlSourceNoRecur 에러"), MB_ICONERROR|MB_TOPMOST);
return NULL;
}
// 도큐먼트의 소스 추출,,, <body>의 부모는 <html> 원리 이용
IHTMLElement *pBodyElem=NULL;
IHTMLElement *pParentElem=NULL;
BSTR bstrSource;
LPCWSTR lpszSourcePostStr=L"\r\n\r\n\r\n\r\n"; // 뒤에 붙일 스트링,,, 보기 좋게 개행 좀 해 준다.
bSuc=FALSE;
if(S_OK==pDoc->get_body(&pBodyElem)){
if(S_OK==pBodyElem->get_parentElement(&pParentElem)){
if(S_OK == pParentElem->get_outerHTML(&bstrSource)){
lpszBuf = (LPWSTR)realloc(lpszBuf, (lstrlenW(lpszBuf)+lstrlenW(bstrSource)+lstrlenW(lpszSourcePostStr)+1)*sizeof(WCHAR));
if(lpszBuf){
lstrcatW(lpszBuf, bstrSource);
lstrcatW(lpszBuf, lpszSourcePostStr);
bSuc = TRUE;
} else{
MessageBox(NULL, _T("소스를 위한 메모리 할당이 실패하였습니다."), _T("GetHtmlSourceNoRecur 에러"), MB_ICONERROR|MB_TOPMOST);
bSuc = FALSE;
}
SysFreeString(bstrSource);
}
pParentElem->Release();
}
pBodyElem->Release();
}
if(!bSuc){
free(lpszBuf);
MessageBox(NULL, _T("도큐먼트 소스를 얻는 데 실패하였습니다."), _T("GetHtmlSourceNoRecur 에러"), MB_ICONERROR|MB_TOPMOST);
return NULL;
}
// 스택에서 pop
pTemp=pTop;
if(pTop->pPre){pTop=pTop->pPre;} // 이전 노드가 있는 경우
else{pTop=NULL;} // 이전 노드가 없는 경우
free(pTemp);
// 하위 프레임 검사
IHTMLFramesCollection2 *pFramesCol=NULL;
IHTMLWindow2 *pWin=NULL;
IDispatch *pDisp=NULL;
IHTMLDocument2 *pSubDoc=NULL;
long i, cFrame=0;
VARIANT varIndex; varIndex.vt=VT_I4;
VARIANT varDisp; varDisp.vt=VT_DISPATCH;
HRESULT hr;
if(S_OK == pDoc->get_frames(&pFramesCol)){
if(S_OK == pFramesCol->get_length(&cFrame)){
for(i=cFrame-1 ; i>=0 ; i--){ // 뒤부터 얻어야 보기좋게 출력됨
varIndex.lVal=i;
if(S_OK == pFramesCol->item(&varIndex, &varDisp)){
if(S_OK == varDisp.pdispVal->QueryInterface(IID_IHTMLWindow2,(void**)&pWin)){
if(S_OK == (hr=pWin->get_document(&pSubDoc))){
// 스택에 push
if(pNew=(Node*)malloc(sizeof(Node))){
pNew->pDoc=pSubDoc;
pNew->pPre=pTop;
pTop=pNew;
} else {
MessageBox(NULL, _T("Node 메모리 할당이 실패하였습니다."), _T("GetHtmlSourceNoRecur 에러"), MB_ICONERROR|MB_TOPMOST);
}
// 아래 주의) 도메인이 다른 경우 등은 아래와 같은 에러메시지를 뱉는다.
// 이 경우는 해당 프레임과 연결된 웹브라우져 컨트롤을 구해야 한다.
} else if(hr == E_ACCESSDENIED){
IServiceProvider *pSP=NULL;
IWebBrowser2 *pSubWB=NULL;
if(S_OK == pWin->QueryInterface(IID_IServiceProvider, (void**)&pSP)){
if(S_OK == pSP->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, (void**)&pSubWB)){
if(S_OK == pSubWB->get_Document(&pDisp)){
if(S_OK == pDisp->QueryInterface(IID_IHTMLDocument2,(void**)&pSubDoc)){
// 스택에 push
if(pNew=(Node*)malloc(sizeof(Node))){
pNew->pDoc=pSubDoc;
pNew->pPre=pTop;
pTop=pNew;
} else {
MessageBox(NULL, _T("Node 메모리 할당이 실패하였습니다."), _T("GetHtmlSourceNoRecur 에러"), MB_ICONERROR|MB_TOPMOST);
}
}
pDisp->Release();
}
pSubWB->Release();
}
pSP->Release();
}
}
pWin->Release();
}
varDisp.pdispVal->Release();
}
}
}
pFramesCol->Release();
}
// 루트 도큐먼트가 아니면 해제
if(pRootDoc != pDoc) pDoc->Release();
}
return lpszBuf;
}
'자료구조, 알고리즘' 카테고리의 다른 글
퍼옴) STL에서 채택한 정렬방식 (2) | 2009.11.14 |
---|---|
각 알고리즘 복잡도(Complexity),,, 정확한 수식들 (0) | 2009.11.14 |
Introspective Sorting and Selection Algorithms --- 고안자 발표 자료 (0) | 2009.11.14 |
Intro Sort(Introspective Sort),,, 다큐먼트 (2) | 2009.11.14 |
기존 퀵소트 코드의 문제점 수정 및.... 중복 비교 제거 (1) | 2009.11.13 |
퀵소트 함수, 재귀와 노재귀(Non-Recursive) 형태,,, 동적배열 스택 이용 (2) | 2009.11.13 |
연결리스트 큐 이용 파일 탐색,,, No 재귀호출 (0) | 2009.11.12 |