2014년 10월 27일 월요일

POST 방식으로 웹페이지를 읽어오기.

int WINAPI PostPageUseIE( IN LPCTSTR pszURL, IN LPBYTE pbPostData, IN LPCTSTR pszRes )
{
 int     result;
 IWebBrowser2*  pWebbrowser = NULL;
 COleVariant   vtURL;
 COleVariant   vtEmpty;
 IDispatch*   pDispatch = NULL;
 IHTMLDocument2*  pHtmlDocument2 = NULL;
 int     i;
 IHTMLElement*  pHtmlElement = NULL;
 BSTR    bstrText;
 CString    sText;
 READYSTATE   rs;
 VARIANT    vtPostData;
 SAFEARRAY*   psa = NULL;
 LPBYTE    pbValue = NULL;
 COleVariant   vtHeader( _T( "Content-Type: application/x-www-form-urlencoded" ) );
 CString    strRes = pszRes/*_T("Status=Success")*/;
 CString    sURL = pszURL;

 //
 // IE 객체 생성
 //
 result = CoCreateInstance( CLSID_InternetExplorer,
  NULL,
  CLSCTX_LOCAL_SERVER,
  IID_IWebBrowser2,
  (LPVOID*)&pWebbrowser );
 if( FAILED( result ) )
 {
  result = ERRORMSG( result, _T( "Can not create Webbrowser control" ) );
  STACKTRACE( _T( "CoCreateInstance()" ) );
  goto finish;
 }

 //
 // 호출되는 브라우저 화면을 볼려면 TRUE 로 설정
 //
 pWebbrowser->put_Visible( FALSE );

 //
 // 바이너리 POST DATA 를 전달하기 위해서 SAFEARRAY를 생성한다
 //
 psa = SafeArrayCreateVector( VT_UI1, 0, strlen( (LPSTR)pbPostData ) );
 if( psa == NULL )
 {
  result = ERRORMSG( ERROR_NOT_ENOUGH_MEMORY, NULL );
  DEBUGINFO( _T( "mem size = %d" ), strlen( (LPSTR)pbPostData ) );
  STACKTRACE( _T( "SafeArrayCreateVector()" ) );
  goto finish;
 }

 SafeArrayAccessData( psa, (LPVOID*)&pbValue );
 CopyMemory( pbValue, pbPostData, strlen( (LPSTR)pbPostData ) );
 SafeArrayUnaccessData( psa );

 vtPostData.vt = VT_ARRAY;
 vtPostData.parray = psa;

 //
 // URL 설정
 //
 vtURL = sURL;

 //
 // NULL 값 설정
 //
 vtEmpty.Clear();

 //
 // HTTP 요청
 //
 result = pWebbrowser->Navigate2( vtURL, vtEmpty, vtEmpty, &vtPostData, vtHeader );
 if( FAILED( result ) )
 {
  result = ERRORMSG( result, _T( "Can not navigate license issue url" ) );
  STACKTRACE( _T( "IWebBrowser2::Navigate2()" ) );
  goto finish;
 }

 //
 // 10초동안 브라우저가 모든 일을 할 때까지 대기
 //
 rs = READYSTATE_UNINITIALIZED;
 for( i = 0; i < 100; i++ )
 {
  pWebbrowser->get_ReadyState( &rs );
  if( rs == READYSTATE_COMPLETE )
  {
   break;
  }

  Sleep( 100 );
 }

 if( rs != READYSTATE_COMPLETE )
 {
  //
  // 문서를 다 받지 못함.
  //
  result = ERRORMSG( ERROR_CAN_NOT_COMPLETE, _T( "Can not download license issuer url" ) );
  goto finish;
 }

 //
 // 성공했는지 실패했는지 알기 위해서 HTML 내용을 봐야 한다
 //
 result = pWebbrowser->get_Document( &pDispatch );
 if( FAILED( result ) )
 {
  result = ERRORMSG( result, _T( "Can not get document of IWebbrowser2" ) );
  STACKTRACE( _T( "IWebbrowser2::get_Document()" ) );
  goto finish;
 }

 result = pDispatch->QueryInterface( IID_IHTMLDocument2, (void**)&pHtmlDocument2 );
 if( result != 0 )
 {
  result = ERRORMSG( result, _T( "Can not query IHtmlDocument2 interface from IDispatch" ) );
  STACKTRACE( _T( "IDispatch::QueryInterface()" ) );
  goto finish;
 }

 result = pHtmlDocument2->get_body( &pHtmlElement );
 if( result != 0 )
 {
  result = ERRORMSG( result, _T( "Can not get body html" ) );
  STACKTRACE( _T( "IHTMLDocument2::get_body()" ) );
  goto finish;
 }

 result = pHtmlElement->get_innerText( &bstrText );
 if( result != 0 )
 {
  result = ERRORMSG( result, _T( "Can not get inner text of html" ) );
  STACKTRACE( _T( "IHTMLElement::get_innerText()" ) );
  goto finish;
 }

 sText = bstrText;

 //
 // HTML 문서 내용 중에서 성공 메세지가 있는지 확인
 //
 if( sText.Find( strRes ) < 0 )
 {
  result = ERRORMSG( ERROR_INTERNAL_ERROR, _T( "invalid response." ) );
  DEBUGINFO( sText );
  goto finish;
 }

 result = 0;

finish:
 if( result != 0 )
 {
  STACKTRACE( _T( "PostPageUseIE()" ) );
 }

 if( psa != NULL )
 {
  SafeArrayDestroy( psa );
 }

 if( pWebbrowser != NULL )
  pWebbrowser->Quit();

 SAFE_RELEASE( pHtmlElement );
 SAFE_RELEASE( pHtmlDocument2 );
 SAFE_RELEASE( pDispatch );
 SAFE_RELEASE( pWebbrowser );

 return result;
}

이 함수의 장점은 IE Control을 그대로 사용하기 때문에, 주소가 http, https 구분을 하지 않고, 잘 동작한다. 하지만 사용시 창의 포커스가 깜빡인다는 단점도 있긴 함.

댓글 없음: