메모장_Web
작은 주제
주제어 ; Google "Embedded browser C++ sample" or "웹브라우저 임베딩"
library
2 웹브라우저 #
2.1 uBrowser #

▷
http://ubrowser.com/
uBrowser는 Mozilla엔진을 통해 Firefox 1.5로 보이는 웹 페이지를 3차원으로 렌더링 할 수 있게 하는
OpenGL(tm) 프로그램이다. 웹페이지에 대한 좌우 크기 변경, 찌그리기, 파도형 등 다양한 인터페이스로 변형을 가능하게 만든다.
Callum은 3차원 가상 커뮤니티 소프트웨어를 개발하는
SecondLife의 개발자이기도 하다. (
SecondLife는 2006년 web2con에서 꽤 좋은 반응을 얻기도 했다.) 그는 이 프로그램을 만든 이유가 2-D 브라우저를 대체하고자 하는 게 아니라, 뭔가 좀 더 재밌고 혁신적인 걸 만들고 싶어 했다는 것이다.
2.2 게임속의 웹브라우저 Rogue #
Rogue는 Adobe AIR 기반의 게임 브라우저로 XP와 비스타에서 사용 할 수 있다. CSS, 자바스크립트, 플래시를 지원하며 탭은 물론 홈페이지 지정과 북마크도 가능하다.

단축키...
F11 : Rogue와 게임간의 마우스/키보드 컨트롤 전환
F10 : Rogue를 덜 투명하게..
F9 : Rogue를 더 투명하게..
지원되는 게임 목록은...
. Age of Conan
. Battlefield 2
. Call of Duty
. Call of Duty 2 (not on menu screens)
. Civilization IV
. Counter-Strike: Source
. Counter-Strike 1.6
. Gears of War
. Guild Wars
. Half-Life 2
. Halo: Combat Evolved
. Neverwinter Nights
. Neverwinter Nights 2
. Portal
. Unreal Tournament III
. Warhammer 40,000
. Warhammer: Dawn of War
. World of Warcraft
지원하지 않는 게임목록...
. Call of Duty 4
. Diablo 2
. Doom 3
. Quake 4
. Starcraft
. Warcraft III
. Wolfenstein: Enemy Territory
게임하면서 블로그 댓글을 달거나 유튜브 비디오도 볼 수 있다.
IWebBrowser:
:Navigate Post 데이터 보내기
이것도 역시 좀 헤멨다.
IWebBrowser:
:Navigate 함수를 이용해 데이터를 Post 해야했다.
이것도 시작시는 엄청 간단할 것으로 생각했다.
근데 소스를 아무리 봐도 잘못된 점은 없는데 작동이 되질 않았다...
난감... Navigate 메서드를 호출할 때 파라미터중 Headers 항목이 있다.
이것은 웹서버에 HTTP 헤더를 포함하는 값이다.
나는 당연히 HTTP Post 값만 넣어주면 될것으로 생각했다.
"데이터 Post 할때는 반드시 헤더 내용도 넣어주어야 한다."
다음은 소스이다.
#include <Exdisp.h>
VARIANT vtHeader={0}, vtPost={0}, vtEmpty={0};
CString sHeader = "Content-Type: application/x-www-form-urlencoded\n";
vtHeader.vt = VT_BSTR;
vtHeader.bstrVal = sHeader.
AllocSysString();
LPCTSTR szPostData = "postdatatest";
int nPostLen = strlen(szPostData);
LPSAFEARRAY psa =
SafeArrayCreateVector(VT_
UI1, 0, nPostLen);
if (!psa) return;
LPSTR pPostData;
HRESULT hr =
SafeArrayAccessData(psa, (void**)&pPostData);
memcpy(pPostData, szPostData, nPostLen);
hr =
SafeArrayUnaccessData(psa);
V_VT(&vtPost) = VT_ARRAY|VT_
UI1;
V_ARRAY(&vtPost) = psa;
IWebBrowser2 *pWeb;
CoCreateInstance(CLSID_
InternetExplorer, NULL, CLSCTX_LOCAL_SERVER,
IID_
IWebBrowser2, (void**)&pWeb);
pWeb->Navigate(bstrUrl, &vtEmpty, &vtEmpty, &vtPost, &vtHeader);
pWeb->Release();
SafeArrayDestroy(psa);
SysFreeString(vtHeader.bstrVal);
SysFreeString(bstrUrl);
이상입니다.
#include <Exdisp.h>
우선
IWebBrowser2를 선언. 그 외 변수들 선언
IWebBrowser2* pWebBrowser = NULL;
BSTR bstrURL = NULL;
BSTR bstrHeader = NULL;
VARIANT vtPostData = {0};
VARIANT vtEmpty;
VARIANT vtHeader;
bstrURL하고, bstrHeader는 필요한 값으로 채우고...(Navigate 할 때 필요)
그 다음 생성.
hr = ::
CoCreateInstance( __uuidof(
InternetExplorer), NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
__uuidof(
IWebBrowser2), reinterpret_cast<LPVOID *>(&pWebBrowser) );
띄울 웹 브라우저의 크기를 설정
pWebBrowser->put_Left(200);
pWebBrowser->put_Top(300);
pWebBrowser->put_Width(578);
pWebBrowser->put_Height(298);
다른 값들도 설정 혹은 디폴트로 놓고 사용.
VariantInit( &vtEmpty );
VariantInit( &vtPostData );
VariantInit( &vtHeader );
V_VT( &vtHeader ) = VT_BSTR;
V_BSTR( &vtHeader ) = bstrHeader;
그 다음 브라우저에서 필요없는 것들 삭제.
pWebBrowser->put_
ToolBar(VARIANT_FALSE); // 익스플로어 툴바 없앰
pWebBrowser->put_
MenuBar(VARIANT_FALSE); // 메뉴바 없앰
pWebBrowser->put_
AddressBar(VARIANT_FALSE); // 주소창 없앰
pWebBrowser->put_
StatusBar(VARIANT_FALSE); // 상태바 없앰
pWebBrowser->put_Resizable(VARIANT_FALSE); //리사이즈 불가
pWebBrowser->put_Visible ( (VARIANT_BOOL) TRUE );
이렇게 하고 Navigate
hr = pWebBrowser->Navigate( bstrURL, &vtEmpty, &vtEmpty, &vtPostData, &vtHeader );
위 처럼 하면 툴바도 없고, 메뉴바도 없고, 주소창도 없고, 상태바도 없고, 리사이즈도 않되는 브라우저가 뜬다.
마지막으로...
HWND hIE;
hr=pWebBrowser->get_HWND((long *)&hIE);
::
SetWindowPos(hIE, HWND_TOPMOST, 0, 0,0 ,0 , SWP_NOMOVE | SWP_NOSIZE);
위 코드는 방금 전에 띄운 브라우저를 최상단에 띄우게 하는 코드이다.
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 )
{
}
if( pWebbrowser != NULL )
pWebbrowser->Quit();
SAFE_RELEASE( pHtmlElement );
SAFE_RELEASE( pHtmlDocument2 );
SAFE_RELEASE( pDispatch );
SAFE_RELEASE( pWebbrowser );
return result;
}
이 함수의 장점은 IE Control을 그대로 사용하기 때문에, 주소가 http, https 구분을 하지 않고, 잘 동작한다. 하지만 사용시 창의 포커스가 깜빡인다는 단점도 있긴 함.
LPBYTE
PostWebPage( LPCTSTR pszURL , LPBYTE pbPostData )
{
int result;
DWORD dwLength;
int nContentLength;
BYTE baBuffer[ 64 ];
DWORD dwServiceType;
INTERNET_PORT nPort;
HINTERNET hInternet = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
CString sServer, sObject;
CString strHeaders = _T( "Content-Type: application/x-www-form-urlencoded" );
LPBYTE pbContent = NULL;
CString sLicenseXML;
LPSTR pszFirst = NULL, pszLast = NULL;
CString sLog ;
DWORD dwFlags = 0 ;
CString ss;
//
// URL 호출
//
hInternet =
InternetOpen( _T( "Mozilla" ), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
if( hInternet == NULL )
{
result =
GetLastError();
goto finish;
}
result =
AfxParseURL( pszURL, dwServiceType, sServer, sObject, nPort );
if( result == FALSE )
{
result =
GetLastError();
goto finish;
}
hConnect =
InternetConnect( hInternet, sServer, nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, NULL );
if( hConnect == NULL )
{
result =
GetLastError();
goto finish;
}
//
// 반드시 포스트 방식으로
//
hRequest =
HttpOpenRequest( hConnect, _T( "POST" ), sObject, NULL, NULL, NULL,INTERNET_FLAG_NO_CACHE_WRITE , NULL );
if( hRequest == NULL )
{
result =
GetLastError();
goto finish;
}
//
// 웹서버에 데이타를 전송
//
result =
HttpSendRequest( hRequest, strHeaders, strHeaders.
GetLength(), (LPVOID)pbPostData, strlen( (LPSTR)pbPostData ) );
if( result == FALSE )
{
result =
GetLastError();
goto finish;
}
//
// HTTP STATUS 코드
//
dwLength = sizeof( baBuffer );
result =
HttpQueryInfo( hRequest, HTTP_QUERY_STATUS_CODE, (LPVOID)baBuffer, &dwLength, NULL );
if( result == FALSE )
{
result =
GetLastError();
goto finish;
}
if( strcmp( (LPCSTR)baBuffer, "200" ) != 0 )
{
//
// HTTP Request 가 실패했다. 왜???
//
/
/CString s = (LPCSTR)baBuffer;
result = ERROR_HTTP_INVALID_QUERY_REQUEST;
goto finish;
}
dwLength = sizeof( baBuffer );
result =
HttpQueryInfo( hRequest, HTTP_QUERY_CONTENT_LENGTH , (LPVOID)baBuffer, &dwLength, NULL );
if( result == FALSE )
{
result =
GetLastError();
goto finish;
}
nContentLength = atoi( (LPSTR)baBuffer );
pbContent = new BYTE[ nContentLength + 1 ];
if( pbContent == NULL )
{
result = ERROR_NOT_ENOUGH_MEMORY;
goto finish;
}
result =
InternetReadFile( hRequest, pbContent, nContentLength, &dwLength );
if( result == FALSE )
{
result =
GetLastError();
goto finish;
}
pbContent[ nContentLength ] = '\0';
result = 0;
finish:
if( hInternet != NULL )
InternetCloseHandle( hInternet );
if( hConnect != NULL )
InternetCloseHandle( hConnect );
if( hRequest != NULL )
InternetCloseHandle( hRequest );
return pbContent;
}
사용방법은 아래와 같이...
LPBTYEpbPostData = new BYTE[ 512 ];
CString strRes;
memset( pbPostData, 0, sizeof( BYTE ) * 512 );
sprintf( (char*)pbPostData, "id=%s&pw=%s", loginDlg.
GetID(), strPass64 );
strRes =
PostWebPage( 웹주소, pbPostData );
strRes에 Post방식으로 날린 웹페이지의 응답값이 들어온다. LPBYTE형을 리턴하지만, 자동형변환 되어 들어간다.
3.5 파일 받을 때 폴더 선택하는 창 #
출처 ;
http://intel.tistory.com/2460623
long
SelectDownloadFolder()
{
// TODO: Add your dispatch handler code here
int result;
TCHAR szDir[ 4096 ];
BROWSEINFO bi;
LPITEMIDLIST pidl = NULL;
ZeroMemory( &bi, sizeof( BROWSEINFO ) );
bi.hwndOwner = this->
GetSafeHwnd();
bi.lpfn = NULL;
bi.lParam = 0;
bi.lpszTitle = _T( "Choose download folder" );
bi.ulFlags = BIF_NEWDIALOGSTYLE;
pidl =
SHBrowseForFolder( &bi );
if( pidl != NULL )
{
//
// 사용자가 디렉토리를 선택했다
//
result =
SHGetPathFromIDList( pidl, szDir ); //szDir에 저장된 폴더가 들어감.
}
It is possible to render HTML in an ordinary Windows program with
MSHTML. This makes it possible to have a web look and feel in a program. Because I think this is quite interesting, I decided to write some C++ classes that make it possible to use MSHTML in an easy way. I found some ideas on how to do that with
Embed an HTML Control in your own window using plain C .
Test program
This test programm displays a simple HTML document in a window. The HTML document consists of three links. These links are fully operational.
MSHTMLTest.cpp
#include <windows.h>
#include "HTMLWindow.h"
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE /*unused__*/, LPSTR /*lpszCmdLine*/, int /*nCmdShow*/) {
HTMLWindow* html_window = new HTMLWindow (
// Parameter html_or_url:
"<html><head>"
"<title>MSHTMLTest</title>" // seems a little useless in this context
"</head><body>"
"<h1>This is a test</h1>"
"I offer the following links:"
"<ul>"
"<li><a href='http://www.google.com'>www.google.com</a>"
"<li><a href='http://www.adp-gmbh.ch'>www.adp-gmbh.ch</a>"
"<li><a href='http://www.yahoo.com'>www.yahoo.com</a>"
"</ul>"
"</body></html>",
// Parameter title
"MSHTMLTest",
hInstance,
false // indicates: this not an url, but html
);
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
TranslateMessage(&msg);
if (msg.message >= WM_KEYFIRST &&
msg.message <= WM_KEYLAST) {
::SendMessage(html_window->hwnd_, msg.message, msg.wParam, msg.lParam);
}
DispatchMessage(&msg);
}
return 0;
}
Displaying an HTML document
The following program displayes an URL. So, it can be called like:
DisplayHTML.exe www.your-favorite-url.zzz
If the URL happens to be an HTML file on the harddisk, call it like so:
DisplayHTML.exe file://c:/path/to/your/document.html
DisplayHTML.cpp
#include <windows.h>
#include "HTMLWindow.h"
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) {
if (__argc < 2) {
::MessageBox(0, "DisplayHTML.exe html-document", "Specify HTML document to be displayed", 0);
return -1;
}
HTMLWindow* html_window = new HTMLWindow (
__argv[1],
"DisplayHTML",
hInstance,
true // it is an url
);
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
TranslateMessage(&msg);
if (msg.message >= WM_KEYFIRST &&
msg.message <= WM_KEYLAST) {
::SendMessage(html_window->hwnd_, msg.message, msg.wParam, msg.lParam);
}
DispatchMessage(&msg);
}
return 0;
}
Downloading MSHTMLTest
The sources (including makefile) as well as the exes can be downloaded here:
MSHTMLTest.
I compiled it with the
mingw compiler.