파일 입.출력


파일 입.출력은 앞으로도 매우 중요하게 쓰이는 부분이다.

어떤 파일로부터 데이터를 읽어들이고 또 데이터를 어떤 파일에 저장하는 것을 말한다.


데이터 저장과 불러오기 기능을 구현한것

읽기 / 쓰기 전용 , 읽기 / 쓰기 혼합 모드 기능

파일을 열고 닫는 작업이 쌍으로 존재한다.


[파일 오픈]


* FILE *fopen(const char *filename, const char *mode) ;    // 성공시 해당파일의 포인터. 실패시 NULL 포인터 리턴


- filename : 문자형 포인터로 사용할 파일 이름을 지정

- mode     : 파일에 대한 접근 방식

- 리턴값     : open 한 파일을 가리키는 파일 포인터


mode 에는 기본적으로 r, w, a 가 있고 세부적으로 바이너리 코드(이진모드)와 텍스트 모드로 분리



[파일 오픈 모드]


r   텍스트 모드이며 읽기 모드로 파일을 오픈

w  텍스트 모드이며 쓰기 모드로 파일을 오픈. 단 파일을 없으면 자동으로 생성. 있으면 내용을 전부 삭제하고 새로운 파일을 생성

a   텍스트 모드이며 쓰기 모드로 파일을 오픈. 단 파일이 없으면 자동으로 생성. 있으면 파일의 가장 끝부분에 이어 쓰기를 실행

b   바이너리 모드를 의미

+   읽기 / 쓰기의 혼합 모드가 가능함을 의미



[데이터 입.출력 모드]


t   텍스트 모드(text mode)

b   2진 모드(binary mode)


데이터의 읽기 / 쓰기를 텍스트 모드로 할건지 2진 모드로 할건지 정해주는 거이다.

문자열과 같은 텍스트 기반의 데이터는 텍스트 모드로 입. 출력 하는 것이 좋고 데이터 변환이 발생하면 안되는 경우 2진 모드로 데이터 입. 출력 하는 것이 좋다.


파일 접근 모드 + 데이터.입출력모드 = 파일 개방 모드     rt  ( r + t )  : 텍스트 모드의 읽기 전용



[일반적인 파일 열기 방법과 파일 오픈시 주의 사항]


FILE *fp ;                                                 // 파일을 오픈하기전에 반드시 파일포인터 선언

.......

fp = fopen( "test.txt" , "r" ) ;                        // 파일이름과 모드는 "와" 사이에 입력   test.txt 파일을 읽기 모드로 읽는 것이다.  

.......                                                        // 반드시 test.txt 파일이 폴더내에 있어야 한다.

if( fp == NULL )                                          // 파일이 제대로 열렸는지 반드시 체크

{

     ........

     return -1 ;

}



[파일 종결]


* int fclose(FILE *stream) ;


- stream : fopen() 함수를 통해 생성된 파일 포인터

- 현재 열린 파일을 닫을때 사용

- 출력 버퍼에 남아있는 데이터를 파일에 기록한 후 파일을 닫음


FILE *fp ;

.......

fp = fopen( "test.txt", "r" ) ;             // 파일 오픈

.......

fclose( fp ) ;                                  // 파일 닫음


동적할당에서 malloc 과 free 가 짝이 듯이 항상 파일을 오픈하면 종료를 해주어야 한다. fopen -> fclose



* 파일을 읽기 와 쓰기 에서 사용되는 함수들은 기존의 함수와 비슷하다. f 만 들어가면 된다.















<fputc() 함수>


하나의 문자를 파일에 저장

int fputc(int c, FILE *fp) ;

- c : 파일에 저장할 데이터

- fp : open 한 파일을 가리키는 포인터

- 리턴값 : fputc() 함수가 파일에 기록한 데이터


#include <stdio.h>

void main()

{

     FILE *fp ;

     fp = fopen( "text.txt", "w" ) ;                  // w 생성한다. test.txt   기존에 파일이 있으면 데이터 삭제 새로 사용.

     for( int i = 0 ; i < 128 ; i++ ){

          fputc( '\n', fp ) ;                           

          fputc( i, fp ) ;

     }

     fclose( fp ) ;

}


실행하면 아무것도 안나올 것이다.. 폴더에 가보면 test.txt 란 파일이 생기고  아스키 코드값 0번부터 128번의 문자들이 들어있다.


<fgetc() 함수>


* int fgetc( FILE *fp ) ;

- fp : fopen() 함수를 통해 생성된 파일 포인터

- 리턴값 : 문자

- fp 는 항상 NULL 이 될수 없음


폴더에 text.txt 안에 a b c 를 작성하고 종료.(저장. 공백 주의)


#include <stdio.h>

#include <stdlib.h>


void main()

{

     FILE* fp ;

     fp = fopen( "test.txt" , "r" ) ;

     if( fp == NULL){

          printf("Error\n") ;

          exit( 1 ) ;

     }

    

     while( !feof(fp) )                                  // 끝이 아니라면 실행

          printf( "%c", fgetc(fp) ) ;                   // 문자를 읽어들여 출력  a b c 출력

     

     fclose( fp ) ;

}


<feof() 함수>


* int feof( FILE *filepointer )

- fileopinter : fopen() 함수를 통해 생성된 파일 포인터

- 현재 가리키는 위치가 파일의 끝인가를 검사한다.

- 리턴값 : 현재 가리키는 위치가 파일의 끝인 경우 0 을. 아닌 경우에는 0 이 아닌 값을 리턴


<fputs() 함수>


문자열을 대상파일( 지정한 파일 포인터의 파일) 에 기록


* int *fputs( const char *buffer, FILE *fp ) ;

- buffer : 출력할 문자열의 포인터

- fp : 출력할 파일을 가리키는 포인터


#include <stdio.h>

#include <stdlib.h>


void main()

{

     FILE *fp ;

     fp = fopen( "test.txt", "w" ) ;


     fputs( "Hello" , fp ) ;                              // test.txt 에 Hello 가 저장된다.

     fclose( fp ) ;

}


<fgets() 함수>


파일 포인터로부터 원하는 양 만큼의 문자열 데이터를 읽어옴


* char *fgets( char *buffer, int n, FILE *fp ) ;

- buffer : 문자열을 저장하게 되는 영역

- n : 읽어드릴 양

- fp : open 한 파일을 가리키는 포인터


현재 test.txt 파일에는 Hello 가 저장되어 있다.


#include <stdio.h>

#include <stdlib.h>


void main()

{

     FILE *fp ;

     char str[20] ;

     fp = fopen( "test.txt", "r" ) ;

   

     fgets( str, sizeof(str), fp ) ;

     printf( "str : %s\n", str ) ;                     // Hello 출력

     fclose( fp ) ;

}


<fread() 함수>


파일로 부터 바이트 단위로 데이터를 읽어들인다.


* size_t fread( void *buffer, size_t size, FILE *fp ) ;

- buffer : 읽어올 데이터를 저장할 메몰리 영역의 포인터

- size : 읽어올 사이즈

- fp : 파일 포인터

- 파일 포인터 fp 에서 size 만큼의 데이터 n 개를 buffer 에 저장


<fwrite() 함수>


파일에 바이트 단위로 데이터 기록


* size_t fwrite( void *buffer, size_t size, size_t n, FILE *fp ) ;

- buffer : 파일에 기록할 데이터가 저장되어 있는 메모리 영역의 포인터

- size : 개별적인 데이터 항목의 크기

- n : 기록할 수

- fp : 파일 포인터

- buffer 에 있는 size 만큼의 데이터 n 개를 파일 포인터 fp 에 기록


#include <stdio.h>

#include <stdlib.h>


struct ADDS{

     char name[30] ;

     char number[30] ;

} ;


void main()

{

     FILE *fp ;

     int input, cnt ;

     ADDS *Juso ;


     while(1)

     {

          printf( "* [1] 입력  [2] 출력  [3] 종료 *\n" ) ;

          printf( "입력  : " ) ;

          scanf( "%d", &input ) ;


          if( input == 3 ){

               printf( "-Good Bye-\n" ) ;

               exit( 1 ) ;

          }

          if( input == 1 ){

               printf( "총 몇명 의 주소록을 입력할까요 ?" ) ;

               scanf( "%d", &cnt ) ;


               Juso = (ADDS*)malloc(sizeof(ADDS)*cnt) ;         

               fp = fopen( "test.txt", "w" ) ;


               for( int i = 0 ; i < cnt ; i++ ){

                    printf( "이름 : " ) ;

                    scanf( "%s", Juso[i].name ) ;

                    printf( "전화번호 : " ) ;

                    scanf( "%s", Juso[i].number ) ;

               }

               fwrite( &cnt, sizeof(int), 1, fp ) ;                       // fwrite cnt 변수값

               fwrite( Juso, sizeof(ADDS), cnt, fp ) ;                // fwrite Juso 구조체

               printf( "저장 완료\n" ) ;

               fclose( fp ) ;

               free( Juso ) ;

          }

          if( input == 2 ){

               fp = fopen( "test.txt", "r" ) ;            

               fread( &cnt, sizeof(int), 1, fp ) ;

          

               Juso = (ADDS*)malloc(sizeof(ADDS)*cnt)  ;          

               fread( Juso, sizeof(ADDS), cnt, fp ) ;

               printf( "\n" ) ;

     

               for( int i = 0 ; i < cnt ; i++ )

                    printf( "이름 : %s  전화 : %s\n", Juso[i].name, Juso[i].number ) ;


               printf( "\n" ) ;

               free( Juso ) ;

               fclose( fp ) ;

          }

     }

}


간단한 주소록 프로그램이다.  소스가 그다지 어렵지 않기 때문에 쉽게 이해 할수 있을 것이다.


<fprintf 와 fscanf>


fprintf 와 fscanf 함수는 printf 와 scanf 함수와 똑같다. 단지 파일이냐 모니터냐의 차이이다.  그리고 앞에 FILE 포인터 변수가 들어간다.


#include <stdio.h>

#include <stdlib.h>


void main()

{

     FILE *fp ;

     int Index ;    

     int Data ;


     fp = fopen( "test.txt", "w" ) ;

     for( Index = 0 ; Index < 9 ; Index++ )                            // 0 부터 9 까지 test.txt 에 저장

          fprintf( fp, "%d\n", Index ) ;


     fclose( fp ) ;


     fp = fopen( "test.txt", "r" ) ;

     for( Index = 0 ; Index < 9 ; Index++ ){                           // test.txt 에 있는 값을 9개 불러옴.. 0 부터 9 까지 출력

          fscanf( fp, "%d", &Data ) ;                            

          printf( "%d\n", Data ) ;

     }


     fclose( fp ) ;

}

'C/C++언어' 카테고리의 다른 글

여러 C++ 컴파일러  (0) 2007.09.06
함수포인터란 ?  (0) 2007.09.06
[본문스크랩] VC++ Article  (0) 2007.09.06
[강좌] MASM 6.0 사용법  (0) 2007.09.06
어셈블리 초급 기초 #1(정태식님)  (0) 2007.09.06

출처 : http://www.gosu.net/GosuWeb/ArticleBList.aspx?CateCode=0502000

 
• General (52) • Database (0)
• Command and Function (0) • Internet & Network (8)
• API/DLLs (1) • COM/DCOM/COM+ (5)
• Threads, Processes & IPC (2) • Shell Programming (1)
• Windows forms (0) • Doc/View/Printing (1)
• Files and Folders (2) • Dialog and Windows (6)
• TextBoxs/String (0) • Button Controls (0)
• Menus (0) • Tab/Toolbars/Status Bar (0)
• Edit Controls (0) • List/Combo Controls (1)
• ListView/TreeView (1) • Static Controls (0)
• Samples (0)
 
General (52)
 
 
How to i386 32bit OS Kernel Compile in VC6 (0) / 작성자: bro / 작성일: 2004-10-14 / 평점: 4.56
본 문서는 VC6에서 어떻게 커널을 컴파일 할 수 있는가에 대한 간단한 소개를 하는 문서입니다. VC에서 OS를 만들기 위해서 생기는 특이한 사항과 간단한 컴파일 후 콘솔 커널을 띄우는 것의 데모까지 해보도록 합니다.
MFC DLL 간단 설명 (0) / 작성자: bro / 작성일: 2004-11-28 / 평점: 4.75
MFC DLL 과 관련된 여러 재미있는 내용들을 알아보았습니다. MSDN에서 본 영문 자료를 기반으로 이해를 위해 추가를 하거나 한 설명입니다.
프로그램내에서 한/영 전환하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-25 / 평점: 4.75
프로그램적으로 한영키를 제어 하는 방법으로 Imm*() 함수를 사용하시면 됩니다. 아래의 예제 코드는 한글키와 영문키로 바꾸는 두가지 함수를 설명하고 있습니다
프로그램 한번만 실행하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.75
프로그램의 중복 실행을 막는 방법에는 여러가지가 있겠지만, 공유 Data segment 를 사용하는 방법을 살펴보겠습니다.
MetaFile 사용 및 클립보드에 복사하기 (1) / 작성자: 하얀그림자 / 작성일: 2004-12-02 / 평점: 4.75
메타파일을 클립보드를 이용하여 다른 프로그램에 붙여넣을 수 있는 기능을 구현하자. 여기서는 윈도우메타파일이 아닌 확장 메타파일을 다루고 있다. 뭐, 그게 그것이지만,,,
트레이 아이콘(TrayIcon) 사라지는 버그 막기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-09 / 평점: 4.00
요즘 나오는 프로그램에서는 대부분 TrayIcon을 제공합니다. 단순히 프로그램 리스트(태스크 바)에 나오는 것보다는, TrayIcon이 사용자에게 보다 더 편리한 UI를 제공하기 때문입니다. 그런데, 익스플로어(인터넷 익스플로어가 아닙니다.)의 버그 때문에 <그림 1>과 같이 종종 TrayIcon이 Tray에서 사라지는 경우가 있습니다. 하지만, 몇몇의 프로그램은 사라지지 않고 계속 남아있는 경우도 볼 수 있습니다.
DLL, LIB 인텔리센스, Debug Step Trace되게 하기 (0) / 작성자: bro / 작성일: 2004-10-20 / 평점: 4.25
Static Lib나 DLL을 배포할때 DLL, LIB만 배포하면 쓰는 사람쪽(클라이언트)에서 인텔리센스와 스텝트레이스 디버깅을 제대로 할 수 없는 문제가 있습니다. 이 문서는 이를 위한 경험에 따른 팁입니다.
소스 세이프 ( Source Safe )의 간략한 소개와 설명 (1) / 작성자: 규서스 / 작성일: 2004-11-09 / 평점: 4.25
Visual Studio 에서 제공하는 공동 프로젝트 소스관리 툴인 소스세이프 (Source Safe)에 관하여 간략하게 설명합니다. 보다 세밀하고 어려운 기능은 많은 방법으로 테스트를 한 이후에 실제 프로젝트에 적용을 하면 보다 안전(Safe)한 프로젝트 소스와 리소스 관리가 되지 않을까 생각됩니다.
MFC DLL Debug/Release 구분해서 하기 (0) / 작성자: bro / 작성일: 2004-11-18 / 평점: 3.80
Release용 MFC42.dll 디버그용 MFC42d.dll 처럼 dll 만들때 디버그용 릴리즈용으로 세팅하는 방법에 대해서 알아봅니다.
CStringArray 정렬하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.67
CStringArray 객체를 정렬하기 위해서 아래에서 보여주는 소스코드를 사용하실 수 있습니다. main() 함수에서는 CStringArray 객체를 만들고, 내용들을 추가시킵니다. 그리고 나서 화면에 출력하고 sort() 함수를 호출하죠. 이제 sort()함수가 끝나고 난후 다시 화면에 출력해서 sort() 함수가 제대로 역할을 수행했는지 결과를 보여줍니다. sort() 함수는 Bubble Sort 알고리즘을 사용했으면 CompareAndSwap()라는 함수를 구현하여 CString 객체끼리 서로 위치를 바꿀 수 있도록 하고 있습니다.
일반적인 윈도우 소멸 순서 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.00
MFC framework에서, 사용자가 frame 윈도를 닫게되면, 윈도는 기본적으로 OnClose 핸들을 call 합니다. 그리고 OnClose 내부에서는 DestroyWindow를 호출하죠. 가장 마지막으로 호출되는 함수는 OnNcDestroy이다.
_ASSERTE 가 GetLastError()를 망친다 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-15 / 평점: 4.00
MFC 에서 제공하는 에러 방지용 매크로인 _ASSERTE 가 호출되면 MFC 는 Last Error 를 0 을 셋팅하게 되어 GetLastError() 가 무용지물이 되어 버립니다.
윈도우용 CVS 의 활용-클라이언트_WinCVS (1) / 작성자: nak / 작성일: 2004-11-12 / 평점: 4.00
WinCVS는 CVS명령을 쉽게 사용하게 하는 클라이언트 프로그램이다. 비슷한 프로그램으로 여러가지가 나와 있지만 Tortoise CVS 프로그램과 가장 많이 사용하는 CVS 클라이언트 이다. 역시 군더더기는 빼고 사용법만 설명하도록 하겠다.
tstring: string for TCHAR (0) / 작성자: bro / 작성일: 2004-10-20 / 평점: 3.75
MBCS 환경이나 UNICODE 환경에서도 stl::string과 stl::wstring을 자동으로 선택해서 사용할 수 있는 tstring에 대해서 알아보도록합니다.
파일 버전 구해서 비교하기... (1) / 작성자: 데미소다오렌지 / 작성일: 2004-11-16 / 평점: 4.33
요즘은 대부분의 파일을 인터넷을 통해서 배포하는 것이 일반적입니다. 이럴 경우 파일이 업데이트 되었는지 검사하기 위해서 버전 정보를 구하는 함수가 필요합니다. 이 문서에서는 Win32 PE 파일에 포함된 버전 정보를 구하는 함수와 함께 구해진 버전을 비교하는 함수의 구현 과정을 포함하고 있습니다.
자동 버전 증가 매크로 (0) / 작성자: 데미소다오렌지 / 작성일: 2004-11-28 / 평점: 4.33
이 문서는 VC++의 자동 버전 증가 매크로에 대한 설명과 좀 더 개선된 매크로의 소스를 포함하고 있습니다.
HBITMAP을 BMP 파일로 만들어 주는 함수 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-07 / 평점: 4.33
어떤 내용이 들어있는 HBITMAP 값과 파일이름을 넘겨주면 주어진 파일 이름으로 Bitmap 이미지 파일을 만드는 함수입니다.
디스크 복사 및 포맷 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.33
디스크 포맷 기능을 하는 API함수가 존재하는데 이건 Undocument된 내용으로 MSDN에 나오지않고 헤더에도 선언되어있지 않습니다. 함수 Prototype을 선언하면 사용할 수 있습니다.
친절한 메세지 ( benign message ) (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-23 / 평점: 3.25
특정 Thread 나 Window 에 아무런 영향을 끼치지 않으면서 단순히 그 Thread 나 Window 가 살아있는지를 확인하고 싶을때 '친절한 메세지' 를 사용하시면 됩니다.
Source Safe과 Project를 분리시키기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 3.67
Source Safe와 연결되어있는 Project는 자체적으로 이와 관련된 정보를 가지고 있습니다. 이 정보를 제거하는 방법을 알아보겠습니다.
재밌는(?) 시스템 강제로 다운시키기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 3.67
필요한 경우가 거의 없겠지만(바이러스가 아니고서야. ^^;;), 시스템을 강제로 다운시키고자 하는 경우가 있을 수 있습니다. 이런 경우 아래의 예제에서 처럼 어셈블리 코드를 사용하는 방법과 Thread 를 와장창 만들어서 thread 러쉬(?)를 통해서 다운시키는 방법이 있습니다. 아래의 예제를 참고 하세요.
SearchPath()의 리턴값 알아보기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.50
"Win32 Programmer's Reference"에서 "SearchPath()"는 다음과 같은 reture value를 갖고 있습니다. The length (in characters) of the string copied to the buffer. -or- 0 if the function fails [see "GetLastError()" in the "Win32 Programmer's Reference" for more information]. 하지만, 만약 찾고자 하는 파일을 찾을 수 없을때에도 0을 return 해주는데, 이때 GetLastError()로 error값을 살펴보아도 error값은 변경되어 있지 않다는 것을 알수 있습니다.
MFC UNICODE 컴파일 하기 (0) / 작성자: bro / 작성일: 2004-11-10 / 평점: 4.50
MFC에서 다국어 버전( 한프로그램에서 여러 국가의 문자를 표현하는 )을 만들때 유니코드를 사용하므로 유니코드 컴파일을 해야 합니다.
윈도우용 CVS 의 활용-서버편 (0) / 작성자: nak / 작성일: 2004-11-11 / 평점: 4.50
많은 사람들이 알지만 귀차니즘 혹은 정보의 부족으로 인해 하지 않았던 CVS를 아주 쉽게 따라하며 직접 설치하고 사용 할 수 있도록하는데 이 문서의 목적이 있다.
Hatch 가 밀려나오는 브러시 수정하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-15 / 평점: 4.50
Hatch 스타일이 적용된 브러시가 정상적으로 표시되지 않는 이유는 브러시 원점과 관련되어 있습니다.
IPicture를 이용한 JPG, GIF, BMP, WMF, EMF, ICO 보기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-15 / 평점: 4.50
JPG나 GIF 등의 이미지 파일포멧을 읽어올려면 직접구현하던가 아니면 해당 라이브러리(예, LeadTool,...)을 이용해야 됩니다. 그러나 윈도즈에서 제공하는 IPicture인터페이스로 간단하게 그림파일(JPG, GIF, BMP, WMF, EMF, ICO)을 불러오는 방법을 알아보겠습니다.
web session : MD5, RC4, base64 (0) / 작성자: bro / 작성일: 2004-12-24 / 평점: 4.50
웹 세션에 대해서알아본 후 md5, rc4, base64등을 사용하는 방법과 쉽게 사용 할 수 있는 md5, rc4, base64 소스를 얻어봅니당.
First-chance exception 에서 Stop 하도록 만들기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 4.50
가끔씩 Visaul C++의 Debug 창에 위의 문구가 출력되는 걸 볼 수 있습니다. 이 문구의 의미는 무엇이며, 어떻게 디버깅할 수 있는지 알아보겠습니다.
ISAPI필터dll Attach to Process로 디버깅하기 (0) / 작성자: bro / 작성일: 2004-11-17 / 평점: 3.00
VC의 Attach to Process를 하는 방법에 대해서 알아보고 예로 ISAPI 필터 dll을 디버깅하는 방법을 알아보았습니다.
스플리터 윈도우 위치 고정하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.00
스플리터 윈도우의 크기를 위치를 공정하는 방법을 설명한다. 스플릿바의 행동양식을 살펴보면 스플리터 윈도우의 크기를 고정하는 방법을 찾을 수 있다.
CDROM Insertion / Removal 감지하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-15 / 평점: 4.00
CDROM (or DVD) Insertion / Removal 감지하는 방법을 알아보겠습니다.
할당된 블록의 크기 구하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.00
new, malloc을 사용해서 메모리 블럭을 할당한 경우에, 포인터를 통해 메모리 블럭의 크기를 구하는 함수입니다. 물론 디버그 버전에서만 사용할 수 있습니다.
base pointer를 지정하자. (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-16 / 평점: 4.00
microsoft c++에서는 __base 키워드를 사용해서 base pointer를 지정할 수 있습니다.
CPList - CPtrList for non-MFC (0) / 작성자: bro / 작성일: 2005-01-02 / 평점: 4.00
MFC의 CPtrList를 대치할 수 있는 non-MFC 환경하의 PList 클래스를 소개합니다
Top 윈도우들의 핸들을 알수 없을까? (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-25 / 평점: 3.50
프로그램을 하다 보면, 현재 Windows System 에서 돌아가는 상위 윈도우들을 알아야 되는 경우가 있습니다. 어떻게 하면 쉬울까요?
소스로 바로가는 TRACE (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 3.50
ANSI CRT에는 TRACE와 같은 기능이 없지만 Visual C++에는 _RPTn 들과 _RPTFn 들이 있습니다. 여기서 _RPTFn 을 주목할 필요가 있는데 _RPTFn 은 다음과 같은 형태의 매크로들을 말합니다.
파일로 트레이스 하도록 바꾸기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 3.50
MFC에서 말입니다. 모든 트레이스를 파일로 하도록 바꿔봅시다. 예전에 어떻게 좀 해볼라고 하다가 실패했는데, 간단하고도 효과적인 방법이 무수히 많이 있습니다. 그중에 하나!
폴더내의 dll 한 번에 등록하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 3.50
쉘에서 for 명령을 지원하네요.
포인터 변수를 검증하기위한 매크로 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-16 / 평점: 3.50
포인터가 올바른 메모리 블럭을 가리키고 있는지 조사할 수 있는 API 들이 몇 가지 있습니다. ( IsBadWritePtr() 을 MSDN 에서 찾으시면 비슷한 친구들까지 모두 찾을실 수 있을겁니다 ) MFC 에는 이 API를 사용해서 간단한 매크로를 만들어 두었습니다.
COM 디버그 설정 (0) / 작성자: bro / 작성일: 2004-11-29 / 평점: 3.50
웹페이지에 붙은 COM 디버깅 VB 프로그램에 붙은 COM 디버깅 MTS COM+ 디버깅 참고 ISAPI DLL 디버깅
특정 파일의 Property 창 띄우기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 3.50
프로그래머가 직접 정보를 수정하지 않고 사용자가 정보를 수정하게 하고 싶은 경우에 파일의 Property 창을 띄울 수 있습니다. 그럴때 간단히 ShellExcute() 를 사용해 보시면 됩니다.
CTString - CString on non-MFC (0) / 작성자: bro / 작성일: 2005-01-02 / 평점: 5.00
CString만 사용하는 경우 MFC 라이브러리를 포함하기에는 무겁습니다. 이럴때 간단히 대치할 수 있는 클래스로 CTString을 소개합니다.
Watch 창에서 함수 실행하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 3.00
아시는 분은 다 아시겠지만, watch 창에서는 함수를 실행시킬 수 있습니다.
Floating-Point Error가 Exception을 발생하도록 만들기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 4.00
int대신 float를 사용했다면 Exception은 발생하지 않습니다. 어떻게하면 Exception이 발생하도록 만들 수 있을까요?
특정 컨트롤에서 한글을 입력받고 싶지 않을때 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-21 / 평점: 4.00
특정 컨트롤에서 영문만 입력 받고자 할때에는 IME의 사용을 중지하면 됩니다.
WaitCursor가 만들어지지 않는 경우 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-23 / 평점: 4.00
모래시계 커서를 만드는데 실패하셨던( 저처럼) 분들은 부디 유용하게 사용하시기 바랍니다.
트레이 메뉴가 사라지지 않을때 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 4.00
트레이 아이콘에서 메뉴를 띄울 때 메뉴의 특정 항목을 선택하지 않고 다른 윈도우를 선택하게 되면 메뉴가 사라지지 않습니다. 이 문제는 임의의 윈도우를 생성하여 메세지가 사라지도록 하는 것입니다.
MFC 라이브러리에 동적으로 링크된 정규 DLL (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 4.00
MFC 라이브러리에 DLL을 동적으로 링크하는 방법을 알아보도록 합니다.
연결 프로그램 찾기 다이얼로그 띄우기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.00
Explorer 에서 파일 아이콘을 더블클릭할 경우 파일의 확장명에 따라 연결되어 있는 프로그램이 동작하게 되어 있다. 하지만 연결되어 있는 프로그램이 없을 경우 "연결 프로그램 찾기" 다이얼로그가 화면에 나타나게 할 수 있습니다.
xmlite : simple xml parser (0) / 작성자: bro / 작성일: 2004-12-17 / 평점: 4.00
XMLite 는 DOM 기반의 사용하기 쉬운 c++ XML 파서입니다. 처음에는 간단히 엘리먼트만 파싱하도록 하였다가, 필요에 의해서 여러가지 기능이 추가되었습니다.
Capture가 되지 않는 경우 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-23 / 평점: 3.00
Capture가 되기 위해서는 마우스 버튼이 눌려져 있어야 한다는 사실을 아십니까?
간단한 LoadString (0) / 작성자: bro / 작성일: 2004-11-26 / 평점: 2.00
애플리케이션의 문자열 리소스를 가져다 쓰려면 LoadString을 호출해야 합니다. MFC에서는 그나마 편리하게 사용하라고 CString의 맴버 함수로 LoadString 맴버 함수를 제공 하고 있지만, 매번 CString 객체를 생성해서 사용해야 하므로 불편하기도 합니다. 게다가, 문자열 리소스에서 인자를 받게 하고 싶으면 더욱 불편합니다. 그래서 아래와 같은 방식으로 저는 간단한 LoadString 매크로를 만들어 사용하고 있습니다.
 

 
Internet & Network (8)
 
 
PHP나 ASP 코드 직접 호출하기 (2) / 작성자: 디버깅전문가 / 작성일: 2004-11-09 / 평점: 4.00
IE(Internet Explorer)같은 웹 브라우저를 이용하지 않고, 서버측에 있는 코드를 직접호출하는 방법에 대해서 알아보도록 합니다.
네트워크 정보 얻어오는 방법 (3) / 작성자: bro / 작성일: 2004-11-10 / 평점: 4.00
1. MAC Address 그냥 보는 방법 2. GetNetworkParams / GetAdaptersInfo 3. NIC 카드 랜카드 이름 얻기
HTML코드를 임시파일로 저장한 파일 URL얻기 (0) / 작성자: bro / 작성일: 2004-11-29 / 평점: 4.00
가끔가다보면 동적으로 HTML코드를 만들어서 이를 네비게이트해야하는 경우가 있습니다. about 을 사용하면 간단한 경우 해결되지만, 제약으로 인해 몇 K 이상되는 코드는 넣을수 없습니다.
인터넷에 연결되어 있는지 알아보기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-21 / 평점: 4.33
현재 컴퓨터가 인터넷에 연결되어 있는지를 확인하는 함수를 알아보도록 합니다.
mshtml 메모리 릭 최소화하기 (0) / 작성자: bro / 작성일: 2004-11-29 / 평점: 4.50
mshtml은 웹브라우저 컨트롤이나 CHtmlView를 사용할때 내부 HTML 다큐먼트 안의 엘리먼트 값을 보거나 수정하기 위해서 쓰는 HTML DOM Parser COM 라이브러리이다. 문제는 잘못사용하면 메모리릭이 많이 생긴다는 것이다.
HTML 스크립트 함수 ActiveX에서 호출하기 (0) / 작성자: bro / 작성일: 2004-11-30 / 평점: 4.50
IDocument 를 얻은 후 get_script로 스크립트 객체를 얻은 후 GetIDsOfNames( 함수명 ) 으로 해당 함수를 얻은 후 Invoke 할 수 있습니다.
HTML 리소스에 넣어 Navigate 하기 (0) / 작성자: bro / 작성일: 2004-11-29 / 평점: 4.00
HTML 페이지를 리소스로 EXE에 포함하여 이를 Navigate 하는 방법에 대해서 알아봅니다.
웹페이지가 이동될때 진입하는 함수 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-07 / 평점: 4.00
웹상에서 구동되는 ActiveX 컨트롤의 경우 웹페이지가 이동될때 진입하는 함수를 알아본다.
 

 
API/DLLs (1)
 
 
local folder에 있는 dll 사용하게 만들기 (2) / 작성자: 디버깅전문가 / 작성일: 2004-12-21 / 평점: 3.00
dll hell 을 방지하기 위한 방법 중 한가지로, local 폴더에 dll을 두고 혼자만 쓰는 방법을 들 수 있습니다. 그와 관련하여 재밌는 기능이 한 가지 있네요..
 

 
COM/DCOM/COM+ (5)
 
 
MS Script Control in MFC (0) / 작성자: bro / 작성일: 2004-11-20 / 평점: 5.00
MS VB Script Control을 MFC 에서 사용하는 방법에 대해서 간략하게 알아보았습니다.
Lite control에서 이벤트가 가능하게 하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 4.00
Lite control에서 이벤트가 가능하게 하기위해서는 IProvideClassInfo2Impl를 상속받게 하면 된다.
ATL Object가 한글 폴더에 있으면 등록이 안되는 버그 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 4.00
이 버그는 MS에서 인정하는 버그이고 해결책까지 나와있습니다. 아래 참조에서 MSDN 항목을 확인하실 수 있습니다. 시키는대로 했는데 잘 안되서, 독자적인 해결책을 제시합니다.
OLE를 이용한 Drag and Drop (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-25 / 평점: 4.00
Ole를 이용하여 간단하게 Window 사이에서 Drag and Drop하여 데이터를 교환하는 방법을 설명합니다.
다른 스레드에서 인터페이스 받아다 쓰기 마샬링하기 (0) / 작성자: bro / 작성일: 2004-11-30 / 평점: 2.00
같은 에러는 다른 스레드에서 인터페이스 포인터 받아와서 직접 메소드를 호출하려고 할때 나는 에러다. 이런 경우 해당 인터페이스를 스레드로 넘겨줄때는 마샬링을 해야 한다.
 

 
Threads, Processes & IPC (2)
 
 
멀티 프로세서 시스템에서 한개의 CPU만 사용하도록 하기. (3) / 작성자: nak / 작성일: 2004-11-10 / 평점: 4.80
멀티 프로세서 시스템에서 프로그램을 개발시 가장 좋은 방법은 생성한 스레드가 잘 분산되어 처리 되도록 하는것이다. 그러나 멀티 프로세서 시스템을 염두하지 않고 만들어진 프로그램에서 비정상적인 종료, dead lock 등으로 인한 pendig 현상등의 문제가 발생하면 당혹스러울 수 밖에 없다. 아주 간단한 팁이지만 실무에서 유용하게 사용할 수있는 팁을 소개한다.
Safe TerminateProcess() (0) / 작성자: snaiper / 작성일: 2004-10-20 / 평점: 4.50
Win32 API 에 보면 TerminateProcess 라는 함수가 있습니다. 함수명 그대로 Process 를 강제로 Kill 시키는 함수입니다. 하지만 권고하지 않는 함수이고, 여러가지 Side Effect 들이 존재합니다. 이를 피하고 안전하게 처리할 수 있는 방법을 소개합니다.
 

 
Shell Programming (1)
 
 
바탕화면, 즐겨찾기, 내 문서 등의 패스얻기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-09 / 평점: 4.67
Windows에서는 여러가지 특별한 폴더들이 있습니다. 내 문서도 그렇고 휴지통 등이 이에 속합니다. 이들 경로는 절대적인 경로가 아니기 때문에(대표적인 예가 Windows root 경로나 System 경로등이죠) 절대적인 경로를 사용하는 경우에는 낭패를 보기 쉽상입니다. 이 글에서는 SHGetSpecialFolderPath()를 이용하여 윈도우에서 사용하는 특별한 폴더들의 패스를 얻어오는 방법을 설명합니다.
 

 
Doc/View/Printing (1)
 
 
Doc/View 구조 없는 SDI에서 스플릿 윈도우 만들기 (0) / 작성자: bro / 작성일: 2004-11-28 / 평점: 4.00
Visual C++ 6 에서 새롭게 지원된 MFC App Wizard 옵션은 바로 다큐먼트 뷰 구조를 사용하지 않고 SDI나 MDI를 할 수 있다는 것입니다. 다큐먼트 뷰 구조가 아닐때 스플릿 윈도우를 만드는 방법을 간단히 알아보도록 합니다.
 

 
Files and Folders (2)
 
 
실행 파일(바이너리)에서 파일 이름 가져오기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-21 / 평점: 4.50
실행 파일의 헤더안에 저장되어 있는 정보를 읽는 것은 심볼릭 정보나 실행 파일에 대한 더 자세한 것을 얻을 수 있는 방법입니다.
파일 사이즈 별로 단위를 나누어서 출력하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-21 / 평점: 4.00
파일의 사이즈를 바이트 연산을 하여, 화면에 적당한 값으로 출력하는 함수를 알아보도록 합니다.
 

 
Dialog and Windows (6)
 
 
Dialog Box의 Control에 Tooltip넣기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.67
Tooltip은 CToolTipCtrl 클래스를 이용하면 쉽게 구현할 수 있습니다. 먼저 Create()를 호출해서 Tooltip 객체를 생성합니다. 그리고 나서 AddTool()을 호출해 각각의 컨트롤과 Tooltip 문자열을 연결해 줍니다. 여기서 Tooltip 문자열을 표시해 주는 함수는 ReplyEvent()이며, Tooltip 컨트롤 객체를 생성해 주고 컨트롤과 연결할 수 있는 가장 적당한 곳은 WM_INITDIALOG 메시지의 핸들러(OnInitDialog())입니다.
Dialog Base 프로그램을 Tray에 등록할 때 문제점 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 4.33
Dialog Base 프로그램을 Tray에 등록할 때 대부분 Window를 Hide시켜서 실행하게 된다. 그런데 Dialog Base로 프로그램 작성하면 프로그램이 처음 실행되면서 화면에 잠깐 나타났다가 사라지는 모습을 볼 수 있다. 이런 현상을 피할 수 있는 방법을 소개한다.
윈앰프처럼 TaskBar와 SystemTray 마음대로 주무루기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-15 / 평점: 4.50
윈앰프에서 보면 TaskBar와 SystemTray에 동시에 보여주는 모드 혹은 각각 보여주는 모드 그리고 모두 보여주지 않는 모드가 있습니다. 4가지의 기능을 모두 구현해 보도록 하겠습니다.
다이얼로그 리소스의 실제 크기 얻기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-15 / 평점: 5.00
VC++ 의 Resouce Editor 에서 작성한 다이얼로그의 크기는 실제 화면의 pixel 단위와 맞지 않기 때문에 종종 컨트롤 배치시에 어려움을 겪게 됩니다. 아래의 함수는 리소스에서 작성한 다이얼로그의 실제 크기를 구하는 함수입니다.
모달 다이알로그 시작시 숨기기 (0) / 작성자: 데미소다오렌지 / 작성일: 2004-11-30 / 평점: 4.00
이 문서는 MFC의 모달 다이알로그의 생성시 초기 상태를 숨김 상태로 하는 방법을 설명하고 있습니다.
Brush 의 패턴을 사용하여 스킨 구현하기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-12-19 / 평점: 4.00
브러시의 패턴을 설정할 수 있다는 점과 브러시의 원점을 설정할 수 있다는 점에서 착안하여 만들어본 스킨 예제입니다.
 

 
List/Combo Controls (1)
 
 
List Control 에 다른 Control 넣기 (0) / 작성자: 디버깅전문가 / 작성일: 2004-11-28 / 평점: 5.00
특정 Column에서 다른 Control 을 띄우는 방법 설명. 여기서 사용한 방법은 현재 Cursor가 있는 위치를 파악한후 그 위치에 적당한 크기의 Edit Control를 생성 시킨다.
 

 
ListView/TreeView (1)
 
 
리스트 컨트롤 몇가지 팁 (0) / 작성자: bro / 작성일: 2004-10-20 / 평점: 4.86
1. 특정 ROW 포커스 주기 2. 특정 ROW로 가기 3. 헤더 컬럼수 얻어오기 4. 컬럼의 너비를 이쁘게 주기 5. 한줄 쭉 선택되게 하기, 그리드 라인 주기 6. 선택한 아이템(ROW)를 지우기 7. 두 아이템을 스왑 하기 8. 기존에 선택되어있는 것을 해체하기
 

'C/C++언어' 카테고리의 다른 글

함수포인터란 ?  (0) 2007.09.06
[본문스크랩] 파일 입.출력  (0) 2007.09.06
[강좌] MASM 6.0 사용법  (0) 2007.09.06
어셈블리 초급 기초 #1(정태식님)  (0) 2007.09.06
어셈블리 초급 기초 #2(정태식님)  (0) 2007.09.06

소스파일입니다.


우선..
"stdafx.h" 파일을 만들고
==================================================================
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once


#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#ifndef DWORD
#define DWORD unsigned long
#endif
// TODO: reference additional headers your program requires here
==================================================================
를 써줍니다.

다음.. 소스가 들어갈 파일..
파일명은 "LaunchBrowser.cpp" 로 해줍니다.
==================================================================

#include "stdafx.h"
#include <comutil.h>
#include <exdisp.h>
#include <process.h>    /* _beginthread, _endthread */
#include <stddef.h>

#pragma comment(lib, "comsupp.lib")

// Get a string from the registry
BOOL GetRegistryString(HKEY rootKey, const char *pzPath, const char *pzKey, char *zBuf, int nBufSize)
{
  HKEY hKey = NULL;
  LONG lReturnValue = RegOpenKeyEx (rootKey, pzPath, 0L, KEY_QUERY_VALUE, &hKey);
  if(lReturnValue != ERROR_SUCCESS)
    return FALSE;
  DWORD dwType = 0;
  DWORD dwSize = nBufSize;
  lReturnValue = RegQueryValueEx (hKey, pzKey, NULL, &dwType, (BYTE *) zBuf, &dwSize);
  RegCloseKey (hKey);
  if (lReturnValue != ERROR_SUCCESS)
    return FALSE;
  return TRUE;
}

// Determine if the version of MSIE is version 7
BOOL IsIE7()
{
  char szVersion[128];
  BOOL bRet = GetRegistryString(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Internet Explorer", "Version", szVersion, sizeof(szVersion));
  if (bRet == TRUE && szVersion[0] == '7')
    return TRUE;
  return FALSE;
}

// simple data structure for our browser settings
typedef struct
{
  char zUrl[1024];
  int nWidth;
  int nHeight;
 HICON hIcon;
}BROWSER_INFO;

BROWSER_INFO g_BrowserInfo;

// This thread demonstrates how to initialize OLE such that we have an exclusive COM apartment for this
// thread separate from the main thread.
//
// It also shows how to manipulate the IWebBrowser interface to do some interesting things such as:
//   1.  Make the IE window resizable or static (non-resizable) based on IE version number.
//  2.  Turn off the address bar, menu bar, status bar, and tool bar buttons.
//  3.  Set the width and height of the resulting window.
//  4.  Change the icon of the MSIE window to one of your own.
//
void BrowserThread( void* pParams )
{
  OleInitialize(NULL);
  BROWSER_INFO *pBrowserInfo = (BROWSER_INFO *)pParams;
   IWebBrowser2* m_pInetExplorer;

    HRESULT hr;
  HICON hIcon;
    CLSID clsid;
    LPUNKNOWN punk=NULL;
    CLSIDFromProgID (OLESTR("InternetExplorer.Application"), &clsid);
    hr = CoCreateInstance (clsid, NULL, CLSCTX_SERVER, IID_IUnknown, (LPVOID *) &punk);
    if (SUCCEEDED(hr))
   {
    punk->QueryInterface (IID_IWebBrowser2, (LPVOID *) &m_pInetExplorer);
    punk->Release();
    VARIANT vars[4];
        memset(vars,0,sizeof(vars));
        BSTR BStrURL = _com_util::ConvertStringToBSTR((const char *)(pBrowserInfo->zUrl));
    if (IsIE7())
      m_pInetExplorer->put_Resizable(VARIANT_TRUE);
    else
      m_pInetExplorer->put_Resizable(VARIANT_FALSE);
        m_pInetExplorer->put_ToolBar(FALSE);
        m_pInetExplorer->put_AddressBar(VARIANT_FALSE);
        m_pInetExplorer->put_MenuBar(VARIANT_FALSE);
        m_pInetExplorer->put_StatusBar(VARIANT_FALSE);
        m_pInetExplorer->put_Width(pBrowserInfo->nWidth);
        m_pInetExplorer->put_Height(pBrowserInfo->nHeight);

        m_pInetExplorer->put_Visible(VARIANT_TRUE);
        HRESULT hrie = m_pInetExplorer->Navigate(BStrURL,vars,vars+1,vars+2,vars+3);
        SysFreeString(BStrURL);
    if (SUCCEEDED(hrie))
    {
      VARIANT_BOOL bBusy = VARIANT_TRUE;
      while(bBusy == VARIANT_TRUE)
      {
        Sleep(500);
        m_pInetExplorer->get_Busy(&bBusy);
      }
       HWND hWnd = NULL;
      m_pInetExplorer->get_HWND ((long*)(&hWnd));
      if (IsWindow(hWnd) && pBrowserInfo->hIcon != NULL)
      {
        hIcon = pBrowserInfo->hIcon;
        SendMessage(hWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
      }
  // Do other interesting IE stuff here while the window is valid.
  //   while(IsWindow(hWnd))
  //   {
  //     Sleep(500);
  //     m_pInetExplorer->get_HWND ((long*)(&hWnd));
  //   }
    }
    m_pInetExplorer->Release();
   }
    OleUninitialize();
  // thread exiting.
}

/*
 * Spawn the M browser
 */
void spawn_browser(
  const char *uri, // URL
  int nWidth,    // Window Width
  int nHeight,   // Window Height
 HICON hIcon)   // Handle to the icon
{
  g_BrowserInfo.nWidth = nWidth;
  g_BrowserInfo.nHeight = nHeight;
  memset(g_BrowserInfo.zUrl,0,(sizeof(g_BrowserInfo.zUrl)*sizeof(char)));
  strncpy(g_BrowserInfo.zUrl,uri,min(strlen(uri),(sizeof(g_BrowserInfo.zUrl)*sizeof(char))));
  g_BrowserInfo.hIcon = hIcon;
  HANDLE hThread = (HANDLE) _beginthread( BrowserThread, 0, &g_BrowserInfo );

  // Wait until IE is done loading before we return.
    WaitForSingleObject( hThread, INFINITE );
}

==================================================================

해줍니다..

구조상...
spawn_browser으로 구동시키며,
이거 쓰레드를 사용합니다... 허...
어쨋든..

spawn_browser("http://www.codeproject.com", 800, 600, hIcon);
식으로 쓰면, codeproject.com 웹을  800,600 크기, hIcon 이미지를 가진 대화상자를 만들어
거기에 띄워줍니다.

음...
이거.. 소스찾는데 애먹었습니다..허.. 조금만 수정하면 다용도로 사용가능할꺼 같네요

/* CWebPage.c
 
This is a Win32 C application (ie, no MFC, WTL, nor even any C++ -- just plain C) that demonstrates
how to embed a browser "control" (actually, an OLE object) in your own window (in order to display a
web page, or an HTML file on disk).

This is very loosely based upon a C++ example written by Chris Becke. I used that to learn the minimum
of what I needed to know about hosting the browser object. Then I wrote this example from the ground up
in C.
*/



#include <windows.h>
#include <exdisp.h>  // Defines of stuff like IWebBrowser2. This is an include file with Visual C 6 and above
#include <mshtml.h>  // Defines of stuff like IHTMLDocument2. This is an include file with Visual C 6 and above
#include <crtdbg.h>  // for _ASSERT()




// A running count of how many windows we have open that contain a browser object
unsigned char WindowCount = 0;

// The class name of our Window to host the browser. It can be anything of your choosing.
static const TCHAR ClassName[] = "Browser Example";

// This is used by DisplayHTMLStr(). It can be global because we never change it.
static const SAFEARRAYBOUND ArrayBound = {1, 0};



// Our IStorage functions that the browser may call
HRESULT STDMETHODCALLTYPE Storage_QueryInterface(IStorage FAR* This, REFIID riid, LPVOID FAR* ppvObj);
HRESULT STDMETHODCALLTYPE Storage_AddRef(IStorage FAR* This);
HRESULT STDMETHODCALLTYPE Storage_Release(IStorage FAR* This);
HRESULT STDMETHODCALLTYPE Storage_CreateStream(IStorage FAR* This, const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm);
HRESULT STDMETHODCALLTYPE Storage_OpenStream(IStorage FAR* This, const WCHAR * pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
HRESULT STDMETHODCALLTYPE Storage_CreateStorage(IStorage FAR* This, const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg);
HRESULT STDMETHODCALLTYPE Storage_OpenStorage(IStorage FAR* This, const WCHAR * pwcsName, IStorage * pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg);
HRESULT STDMETHODCALLTYPE Storage_CopyTo(IStorage FAR* This, DWORD ciidExclude, IID const *rgiidExclude, SNB snbExclude,IStorage *pstgDest);
HRESULT STDMETHODCALLTYPE Storage_MoveElementTo(IStorage FAR* This, const OLECHAR *pwcsName,IStorage * pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags);
HRESULT STDMETHODCALLTYPE Storage_Commit(IStorage FAR* This, DWORD grfCommitFlags);
HRESULT STDMETHODCALLTYPE Storage_Revert(IStorage FAR* This);
HRESULT STDMETHODCALLTYPE Storage_EnumElements(IStorage FAR* This, DWORD reserved1, void * reserved2, DWORD reserved3, IEnumSTATSTG ** ppenum);
HRESULT STDMETHODCALLTYPE Storage_DestroyElement(IStorage FAR* This, const OLECHAR *pwcsName);
HRESULT STDMETHODCALLTYPE Storage_RenameElement(IStorage FAR* This, const WCHAR *pwcsOldName, const WCHAR *pwcsNewName);
HRESULT STDMETHODCALLTYPE Storage_SetElementTimes(IStorage FAR* This, const WCHAR *pwcsName, FILETIME const *pctime, FILETIME const *patime, FILETIME const *pmtime);
HRESULT STDMETHODCALLTYPE Storage_SetClass(IStorage FAR* This, REFCLSID clsid);
HRESULT STDMETHODCALLTYPE Storage_SetStateBits(IStorage FAR* This, DWORD grfStateBits, DWORD grfMask);
HRESULT STDMETHODCALLTYPE Storage_Stat(IStorage FAR* This, STATSTG * pstatstg, DWORD grfStatFlag);

// Our IStorage VTable. This is the array of pointers to the above functions in our C
// program that someone may call in order to store some data to disk. We must define a
// particular set of functions that comprise the IStorage set of functions (see above),
// and then stuff pointers to those functions in their respective 'slots' in this table.
// We want the browser to use this VTable with our IStorage structure (object).
IStorageVtbl MyIStorageTable = {Storage_QueryInterface,
Storage_AddRef,
Storage_Release,
Storage_CreateStream,
Storage_OpenStream,
Storage_CreateStorage,
Storage_OpenStorage,
Storage_CopyTo,
Storage_MoveElementTo,
Storage_Commit,
Storage_Revert,
Storage_EnumElements,
Storage_DestroyElement,
Storage_RenameElement,
Storage_SetElementTimes,
Storage_SetClass,
Storage_SetStateBits,
Storage_Stat};

// Our IStorage structure. NOTE: All it contains is a pointer to our IStorageVtbl, so we can easily initialize it
// here instead of doing that programmably.
IStorage   MyIStorage = { &MyIStorageTable };



// Our IOleInPlaceFrame functions that the browser may call
HRESULT STDMETHODCALLTYPE Frame_QueryInterface(IOleInPlaceFrame FAR* This, REFIID riid, LPVOID FAR* ppvObj);
HRESULT STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR* This);
HRESULT STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR* This);
HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR* This, HWND FAR* lphwnd);
HRESULT STDMETHODCALLTYPE Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR* This, BOOL fEnterMode);
HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR* This, LPRECT lprectBorder);
HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths);
HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths);
HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(IOleInPlaceFrame FAR* This, IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName);
HRESULT STDMETHODCALLTYPE Frame_InsertMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR* This, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject);
HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared);
HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR* This, LPCOLESTR pszStatusText);
HRESULT STDMETHODCALLTYPE Frame_EnableModeless(IOleInPlaceFrame FAR* This, BOOL fEnable);
HRESULT STDMETHODCALLTYPE Frame_TranslateAccelerator(IOleInPlaceFrame FAR* This, LPMSG lpmsg, WORD wID);

// Our IOleInPlaceFrame VTable. This is the array of pointers to the above functions in our C
// program that the browser may call in order to interact with our frame window that contains
// the browser object. We must define a particular set of functions that comprise the
// IOleInPlaceFrame set of functions (see above), and then stuff pointers to those functions
// in their respective 'slots' in this table. We want the browser to use this VTable with our
// IOleInPlaceFrame structure.
IOleInPlaceFrameVtbl MyIOleInPlaceFrameTable = {Frame_QueryInterface,
Frame_AddRef,
Frame_Release,
Frame_GetWindow,
Frame_ContextSensitiveHelp,
Frame_GetBorder,
Frame_RequestBorderSpace,
Frame_SetBorderSpace,
Frame_SetActiveObject,
Frame_InsertMenus,
Frame_SetMenu,
Frame_RemoveMenus,
Frame_SetStatusText,
Frame_EnableModeless,
Frame_TranslateAccelerator};

// We need to pass an IOleInPlaceFrame struct to the browser object. And one of our IOleInPlaceFrame
// functions (Frame_GetWindow) is going to need to access our window handle. So let's create our own
// struct that starts off with an IOleInPlaceFrame struct (and that's important -- the IOleInPlaceFrame
// struct *must* be first), and then has an extra data field where we can store our own window's HWND.
//
// And because we may want to create multiple windows, each hosting its own browser object (to
// display its own web page), then we need to create a IOleInPlaceFrame struct for each window. So,
// we're not going to declare our IOleInPlaceFrame struct globally. We'll allocate it later using
// GlobalAlloc, and then stuff the appropriate HWND in it then, and also stuff a pointer to
// MyIOleInPlaceFrameTable in it. But let's just define it here.
typedef struct _IOleInPlaceFrameEx {
 IOleInPlaceFrame frame;  // The IOleInPlaceFrame must be first!

 ///////////////////////////////////////////////////
 // Here you add any variables that you need
 // to access in your IOleInPlaceFrame functions.
 // You don't want those functions to access global
 // variables, because then you couldn't use more
 // than one browser object. (ie, You couldn't have
 // multiple windows, each with its own embedded
 // browser object to display a different web page).
 //
 // So here is where I added my extra HWND that my
 // IOleInPlaceFrame function Frame_GetWindow() needs
 // to access.
 ///////////////////////////////////////////////////
 HWND    window;
} IOleInPlaceFrameEx;




// Our IOleClientSite functions that the browser may call
HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR* This, REFIID riid, void ** ppvObject);
HRESULT STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_Release(IOleClientSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR* This, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk);
HRESULT STDMETHODCALLTYPE Site_GetContainer(IOleClientSite FAR* This, LPOLECONTAINER FAR* ppContainer);
HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR* This, BOOL fShow);
HRESULT STDMETHODCALLTYPE Site_RequestNewObjectLayout(IOleClientSite FAR* This);

// Our IOleClientSite VTable. This is the array of pointers to the above functions in our C
// program that the browser may call in order to interact with our frame window that contains
// the browser object. We must define a particular set of functions that comprise the
// IOleClientSite set of functions (see above), and then stuff pointers to those functions
// in their respective 'slots' in this table. We want the browser to use this VTable with our
// IOleClientSite structure.
IOleClientSiteVtbl MyIOleClientSiteTable = {Site_QueryInterface,
Site_AddRef,
Site_Release,
Site_SaveObject,
Site_GetMoniker,
Site_GetContainer,
Site_ShowObject,
Site_OnShowWindow,
Site_RequestNewObjectLayout};




// Our IOleInPlaceSite functions that the browser may call
HRESULT STDMETHODCALLTYPE Site_GetWindow(IOleInPlaceSite FAR* This, HWND FAR* lphwnd);
HRESULT STDMETHODCALLTYPE Site_ContextSensitiveHelp(IOleInPlaceSite FAR* This, BOOL fEnterMode);
HRESULT STDMETHODCALLTYPE Site_CanInPlaceActivate(IOleInPlaceSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_OnInPlaceActivate(IOleInPlaceSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_OnUIActivate(IOleInPlaceSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_GetWindowContext(IOleInPlaceSite FAR* This, LPOLEINPLACEFRAME FAR* lplpFrame,LPOLEINPLACEUIWINDOW FAR* lplpDoc,LPRECT lprcPosRect,LPRECT lprcClipRect,LPOLEINPLACEFRAMEINFO lpFrameInfo);
HRESULT STDMETHODCALLTYPE Site_Scroll(IOleInPlaceSite FAR* This, SIZE scrollExtent);
HRESULT STDMETHODCALLTYPE Site_OnUIDeactivate(IOleInPlaceSite FAR* This, BOOL fUndoable);
HRESULT STDMETHODCALLTYPE Site_OnInPlaceDeactivate(IOleInPlaceSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_DiscardUndoState(IOleInPlaceSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_DeactivateAndUndo(IOleInPlaceSite FAR* This);
HRESULT STDMETHODCALLTYPE Site_OnPosRectChange(IOleInPlaceSite FAR* This, LPCRECT lprcPosRect);

// Our IOleInPlaceSite VTable. This is the array of pointers to the above functions in our C
// program that the browser may call in order to interact with our frame window that contains
// the browser object. We must define a particular set of functions that comprise the
// IOleInPlaceSite set of functions (see above), and then stuff pointers to those functions
// in their respective 'slots' in this table. We want the browser to use this VTable with our
// IOleInPlaceSite structure.
IOleInPlaceSiteVtbl MyIOleInPlaceSiteTable =  {Site_QueryInterface, // This gives a compiler warning because we're using
               // the same function as the MyIOleClientSiteTable uses.
               // And the first arg to that Site_QueryInterface() is
               // a pointer to a IOleClientSite. What we really should
               // have here is a separate function with its first arg
               // as a pointer to a IOleInPlaceSite (even though what
               // will really get passed to it is a _IOleClientSiteEx *).
               // But it's easier to use one function for QueryInterface()
               // in order to support "inheritance". ie, Sometimes, the
               // browser may call your IOleClientSite's QueryInterface
               // in order to get a pointer to your IOleInPlaceSite, or
               // vice versa. This is because these two structs will be
               // passed to the browser inside of a single struct. And
               // that makes them "interconnected" as far as
               // QueryInterface is concerned.
Site_AddRef,    // Ditto as above.
Site_Release,    // Ditto as above.
Site_GetWindow,
Site_ContextSensitiveHelp,
Site_CanInPlaceActivate,
Site_OnInPlaceActivate,
Site_OnUIActivate,
Site_GetWindowContext,
Site_Scroll,
Site_OnUIDeactivate,
Site_OnInPlaceDeactivate,
Site_DiscardUndoState,
Site_DeactivateAndUndo,
Site_OnPosRectChange};

// The structure we need to pass to the browser object must contain an IOleClientSite structure. The
// IOleClientSite struct *must* be first. Our IOleClientSite's QueryInterface() may also be asked to
// return a pointer to our IOleInPlaceSite struct. So we'll need to have that object handy. Plus,
// some of our IOleClientSite and IOleInPlaceSite functions will need to have the HWND to our window,
// and also a pointer to our IOleInPlaceFrame struct. So let's create a single struct that has both
// the IOleClientSite and IOleInPlaceSite structs inside it, and also has an extra data field to
// store a pointer to our IOleInPlaceFrame struct. (The HWND is stored in the IOleInPlaceFrame
// struct, so we can get at it there). As long as the IOleClientSite struct is the first thing, it's
// all ok. We'll call this new struct a _IOleClientSiteEx.
//
// And because we may want to create multiple windows, each hosting its own browser object (to
// display its own web page), then we need to create IOleClientSite and IOleInPlaceSite structs for
// each window. (ie, Each window needs its own _IOleClientSiteEx struct). So, we're not going to
// declare this struct globally. We'll allocate it later using GlobalAlloc, and then store the
// appropriate IOleInPlaceFrame struct pointer then.

typedef struct __IOleInPlaceSiteEx {
 IOleInPlaceSite  inplace;  // My IOleInPlaceSite object. Must be first.

 ///////////////////////////////////////////////////
 // Here you add any variables that you need
 // to access in your IOleInPlaceSite functions.
 // You don't want those functions to access global
 // variables, because then you couldn't use more
 // than one browser object. (ie, You couldn't have
 // multiple windows, each with its own embedded
 // browser object to display a different web page.
 //
 // So here is where I added my extra pointer to my
 // IOleInPlaceFrame struct.
 ///////////////////////////////////////////////////
 IOleInPlaceFrameEx *frame;
} _IOleInPlaceSiteEx;

typedef struct __IOleClientSiteEx {
 IOleClientSite  client;   // My IOleClientSite object. Must be first.
 _IOleInPlaceSiteEx inplace;  // My IOleInPlaceSite object.

 ///////////////////////////////////////////////////
 // Here you add any variables that you need
 // to access in your IOleClientSite functions.
 ///////////////////////////////////////////////////

} _IOleClientSiteEx;



// This is a simple C example. There are lots more things you can control about the browser object, but
// we don't do it in this example. _Many_ of the functions we provide below for the browser to call, will
// never actually be called by the browser in our example. Why? Because we don't do certain things
// with the browser that would require it to call those functions (even though we need to provide
// at least some stub for all of the functions).
//
// So, for these "dummy functions" that we don't expect the browser to call, we'll just stick in some
// assembly code that causes a debugger breakpoint and tells the browser object that we don't support
// the functionality. That way, if you try to do more things with the browser object, and it starts
// calling these "dummy functions", you'll know which ones you should add more meaningful code to.
#define NOTIMPLEMENTED _ASSERT(0); return(E_NOTIMPL)



////////////////////////////////////// My IStorage functions  /////////////////////////////////////////
// NOTE: The browser object doesn't use the IStorage functions, so most of these are us just returning
// E_NOTIMPL so that anyone who *does* call these functions knows nothing is being done here.

HRESULT STDMETHODCALLTYPE Storage_QueryInterface(IStorage FAR* This, REFIID riid, LPVOID FAR* ppvObj)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_AddRef(IStorage FAR* This)
{
 return(1);
}

HRESULT STDMETHODCALLTYPE Storage_Release(IStorage FAR* This)
{
 return(1);
}

HRESULT STDMETHODCALLTYPE Storage_CreateStream(IStorage FAR* This, const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_OpenStream(IStorage FAR* This, const WCHAR * pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_CreateStorage(IStorage FAR* This, const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_OpenStorage(IStorage FAR* This, const WCHAR * pwcsName, IStorage * pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_CopyTo(IStorage FAR* This, DWORD ciidExclude, IID const *rgiidExclude, SNB snbExclude,IStorage *pstgDest)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_MoveElementTo(IStorage FAR* This, const OLECHAR *pwcsName,IStorage * pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_Commit(IStorage FAR* This, DWORD grfCommitFlags)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_Revert(IStorage FAR* This)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_EnumElements(IStorage FAR* This, DWORD reserved1, void * reserved2, DWORD reserved3, IEnumSTATSTG ** ppenum)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_DestroyElement(IStorage FAR* This, const OLECHAR *pwcsName)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_RenameElement(IStorage FAR* This, const WCHAR *pwcsOldName, const WCHAR *pwcsNewName)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_SetElementTimes(IStorage FAR* This, const WCHAR *pwcsName, FILETIME const *pctime, FILETIME const *patime, FILETIME const *pmtime)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_SetClass(IStorage FAR* This, REFCLSID clsid)
{
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Storage_SetStateBits(IStorage FAR* This, DWORD grfStateBits, DWORD grfMask)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Storage_Stat(IStorage FAR* This, STATSTG * pstatstg, DWORD grfStatFlag)
{
 NOTIMPLEMENTED;
}





///////////////////////////////// My IOleClientSite/IOleInPlaceSite functions  /////////////////////////////////

/************************* Site_QueryInterface() *************************
 * The browser object calls this when it wants a pointer to one of our
 * IOleClientSite or IOleInPlaceSite structures. They are both in the
 * _IOleClientSiteEx struct we allocated in EmbedBrowserObject() and
 * passed to DoVerb() and OleCreate().
 *
 * This =  A pointer to whatever _IOleClientSiteEx struct we passed to
 *    OleCreate() or DoVerb().
 * riid =  A GUID struct that the browser passes us to clue us as to
 *    which type of struct (object) it would like a pointer
 *    returned for.
 * ppvObject = Where the browser wants us to return a pointer to the
 *    appropriate struct. (ie, It passes us a handle to fill in).
 *
 * RETURNS: S_OK if we return the struct, or E_NOINTERFACE if we don't have
 * the requested struct.
 */

HRESULT STDMETHODCALLTYPE Site_QueryInterface(IOleClientSite FAR* This, REFIID riid, void ** ppvObject)
{
 // It just so happens that the first arg passed to us is our _IOleClientSiteEx struct we allocated
 // and passed to DoVerb() and OleCreate(). Nevermind that 'This' is declared is an IOleClientSite *.
 // Remember that in EmbedBrowserObject(), we allocated our own _IOleClientSiteEx struct, and lied
 // to OleCreate() and DoVerb() -- passing our _IOleClientSiteEx struct and saying it was an
 // IOleClientSite struct. It's ok. An _IOleClientSiteEx starts with an embedded IOleClientSite, so
 // the browser didn't mind. So that's what the browser object is passing us now. The browser doesn't
 // know that it's really an _IOleClientSiteEx struct. But we do. So we can recast it and use it as
 // so here.

 // If the browser is asking us to match IID_IOleClientSite, then it wants us to return a pointer to
 // our IOleClientSite struct. Then the browser will use the VTable in that struct to call our
 // IOleClientSite functions. It will also pass this same pointer to all of our IOleClientSite
 // functions.
 //
 // Actually, we're going to lie to the browser again. We're going to return our own _IOleClientSiteEx
 // struct, and tell the browser that it's a IOleClientSite struct. It's ok. The first thing in our
 // _IOleClientSiteEx is an embedded IOleClientSite, so the browser doesn't mind. We want the browser
 // to continue passing our _IOleClientSiteEx pointer wherever it would normally pass a IOleClientSite
 // pointer.
 //
 // The IUnknown interface uses the same VTable as the first object in our _IOleClientSiteEx
 // struct (which happens to be an IOleClientSite). So if the browser is asking us to match
 // IID_IUnknown, then we'll also return a pointer to our _IOleClientSiteEx.

 if (!memcmp(riid, &IID_IUnknown, sizeof(GUID)) || !memcmp(riid, &IID_IOleClientSite, sizeof(GUID)))
  *ppvObject = &((_IOleClientSiteEx *)This)->client;

 // If the browser is asking us to match IID_IOleInPlaceSite, then it wants us to return a pointer to
 // our IOleInPlaceSite struct. Then the browser will use the VTable in that struct to call our
 // IOleInPlaceSite functions.  It will also pass this same pointer to all of our IOleInPlaceSite
 // functions (except for Site_QueryInterface, Site_AddRef, and Site_Release. Those will always get
 // the pointer to our _IOleClientSiteEx.
 //
 // Actually, we're going to lie to the browser. We're going to return our own IOleInPlaceSiteEx
 // struct, and tell the browser that it's a IOleInPlaceSite struct. It's ok. The first thing in
 // our IOleInPlaceSiteEx is an embedded IOleInPlaceSite, so the browser doesn't mind. We want the
 // browser to continue passing our IOleInPlaceSiteEx pointer wherever it would normally pass a
 // IOleInPlaceSite pointer. My, we're really playing dirty tricks on the browser here. heheh.
 else if (!memcmp(riid, &IID_IOleInPlaceSite, sizeof(GUID)))
  *ppvObject = &((_IOleClientSiteEx *)This)->inplace;

 // For other types of objects the browser wants, just report that we don't have any such objects.
 // NOTE: If you want to add additional functionality to your browser hosting, you may need to
 // provide some more objects here. You'll have to investigate what the browser is asking for
 // (ie, what REFIID it is passing).
 else
 {
  *ppvObject = 0;
  return(E_NOINTERFACE);
 }

 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Site_AddRef(IOleClientSite FAR* This)
{
 return(1);
}

HRESULT STDMETHODCALLTYPE Site_Release(IOleClientSite FAR* This)
{
 return(1);
}

HRESULT STDMETHODCALLTYPE Site_SaveObject(IOleClientSite FAR* This)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Site_GetMoniker(IOleClientSite FAR* This, DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Site_GetContainer(IOleClientSite FAR* This, LPOLECONTAINER FAR* ppContainer)
{
 // Tell the browser that we are a simple object and don't support a container
 *ppContainer = 0;

 return(E_NOINTERFACE);
}

HRESULT STDMETHODCALLTYPE Site_ShowObject(IOleClientSite FAR* This)
{
 return(NOERROR);
}

HRESULT STDMETHODCALLTYPE Site_OnShowWindow(IOleClientSite FAR* This, BOOL fShow)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Site_RequestNewObjectLayout(IOleClientSite FAR* This)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Site_GetWindow(IOleInPlaceSite FAR* This, HWND FAR* lphwnd)
{
 // Return the HWND of the window that contains this browser object. We stored that
 // HWND in our _IOleInPlaceSiteEx struct. Nevermind that the function declaration for
 // Site_GetWindow says that 'This' is an IOleInPlaceSite *. Remember that in
 // EmbedBrowserObject(), we allocated our own _IOleInPlaceSiteEx struct which
 // contained an embedded IOleInPlaceSite struct within it. And when the browser
 // called Site_QueryInterface() to get a pointer to our IOleInPlaceSite object, we
 // returned a pointer to our _IOleClientSiteEx. The browser doesn't know this. But
 // we do. That's what we're really being passed, so we can recast it and use it as
 // so here.
 *lphwnd = ((_IOleInPlaceSiteEx FAR*)This)->frame->window;

 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Site_ContextSensitiveHelp(IOleInPlaceSite FAR* This, BOOL fEnterMode)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Site_CanInPlaceActivate(IOleInPlaceSite FAR* This)
{
 // Tell the browser we can in place activate
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Site_OnInPlaceActivate(IOleInPlaceSite FAR* This)
{
 // Tell the browser we did it ok
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Site_OnUIActivate(IOleInPlaceSite FAR* This)
{
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Site_GetWindowContext(IOleInPlaceSite FAR* This, LPOLEINPLACEFRAME FAR* lplpFrame, LPOLEINPLACEUIWINDOW FAR* lplpDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
 // Give the browser the pointer to our IOleInPlaceFrame struct. We stored that pointer
 // in our _IOleInPlaceSiteEx struct. Nevermind that the function declaration for
 // Site_GetWindowContext says that 'This' is an IOleInPlaceSite *. Remember that in
 // EmbedBrowserObject(), we allocated our own _IOleInPlaceSiteEx struct which
 // contained an embedded IOleInPlaceSite struct within it. And when the browser
 // called Site_QueryInterface() to get a pointer to our IOleInPlaceSite object, we
 // returned a pointer to our _IOleClientSiteEx. The browser doesn't know this. But
 // we do. That's what we're really being passed, so we can recast it and use it as
 // so here.
 //
 // Actually, we're giving the browser a pointer to our own IOleInPlaceSiteEx struct,
 // but telling the browser that it's a IOleInPlaceSite struct. No problem. Our
 // IOleInPlaceSiteEx starts with an embedded IOleInPlaceSite, so the browser is
 // cool with it. And we want the browser to pass a pointer to this IOleInPlaceSiteEx
 // wherever it would pass a IOleInPlaceSite struct to our IOleInPlaceSite functions.
 *lplpFrame = (LPOLEINPLACEFRAME)((_IOleInPlaceSiteEx FAR*)This)->frame;

 // We have no OLEINPLACEUIWINDOW
 *lplpDoc = 0;

 // Fill in some other info for the browser
 lpFrameInfo->fMDIApp = FALSE;
 lpFrameInfo->hwndFrame = ((IOleInPlaceFrameEx FAR*)*lplpFrame)->window;
 lpFrameInfo->haccel = 0;
 lpFrameInfo->cAccelEntries = 0;

 // Give the browser the dimensions of where it can draw. We give it our entire window to fill
 GetClientRect(lpFrameInfo->hwndFrame, lprcPosRect);
 GetClientRect(lpFrameInfo->hwndFrame, lprcClipRect);

 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Site_Scroll(IOleInPlaceSite FAR* This, SIZE scrollExtent)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Site_OnUIDeactivate(IOleInPlaceSite FAR* This, BOOL fUndoable)
{
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Site_OnInPlaceDeactivate(IOleInPlaceSite FAR* This)
{
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Site_DiscardUndoState(IOleInPlaceSite FAR* This)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Site_DeactivateAndUndo(IOleInPlaceSite FAR* This)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Site_OnPosRectChange(IOleInPlaceSite FAR* This, LPCRECT lprcPosRect)
{
 return(S_OK);
}




////////////////////////////////////// My IOleInPlaceFrame functions  /////////////////////////////////////////

HRESULT STDMETHODCALLTYPE Frame_QueryInterface(IOleInPlaceFrame FAR* This, REFIID riid, LPVOID FAR* ppvObj)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Frame_AddRef(IOleInPlaceFrame FAR* This)
{
 return(1);
}

HRESULT STDMETHODCALLTYPE Frame_Release(IOleInPlaceFrame FAR* This)
{
 return(1);
}

HRESULT STDMETHODCALLTYPE Frame_GetWindow(IOleInPlaceFrame FAR* This, HWND FAR* lphwnd)
{
 // Give the browser the HWND to our window that contains the browser object. We
 // stored that HWND in our IOleInPlaceFrame struct. Nevermind that the function
 // declaration for Frame_GetWindow says that 'This' is an IOleInPlaceFrame *. Remember
 // that in EmbedBrowserObject(), we allocated our own IOleInPlaceFrameEx struct which
 // contained an embedded IOleInPlaceFrame struct within it. And then we lied when
 // Site_GetWindowContext() returned that IOleInPlaceFrameEx. So that's what the
 // browser is passing us. It doesn't know that. But we do. So we can recast it and
 // use it as so here.
 *lphwnd = ((IOleInPlaceFrameEx FAR*)This)->window;
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Frame_ContextSensitiveHelp(IOleInPlaceFrame FAR* This, BOOL fEnterMode)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Frame_GetBorder(IOleInPlaceFrame FAR* This, LPRECT lprectBorder)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Frame_RequestBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Frame_SetBorderSpace(IOleInPlaceFrame FAR* This, LPCBORDERWIDTHS pborderwidths)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Frame_SetActiveObject(IOleInPlaceFrame FAR* This, IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
{
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Frame_InsertMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Frame_SetMenu(IOleInPlaceFrame FAR* This, HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
{
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Frame_RemoveMenus(IOleInPlaceFrame FAR* This, HMENU hmenuShared)
{
 NOTIMPLEMENTED;
}

HRESULT STDMETHODCALLTYPE Frame_SetStatusText(IOleInPlaceFrame FAR* This, LPCOLESTR pszStatusText)
{
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Frame_EnableModeless(IOleInPlaceFrame FAR* This, BOOL fEnable)
{
 return(S_OK);
}

HRESULT STDMETHODCALLTYPE Frame_TranslateAccelerator(IOleInPlaceFrame FAR* This, LPMSG lpmsg, WORD wID)
{
 NOTIMPLEMENTED;
}





/*************************** UnEmbedBrowserObject() ************************
 * Called to detach the browser object from our host window, and free its
 * resources, right before we destroy our window.
 *
 * hwnd =  Handle to the window hosting the browser object.
 *
 * NOTE: The pointer to the browser object must have been stored in the
 * window's USERDATA field. In other words, don't call UnEmbedBrowserObject().
 * with a HWND that wasn't successfully passed to EmbedBrowserObject().
 */

void UnEmbedBrowserObject(HWND hwnd)
{
 IOleObject **browserHandle;
 IOleObject *browserObject;

 // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
 // we initially attached the browser object to this window.
 if ((browserHandle = (IOleObject **)GetWindowLong(hwnd, GWL_USERDATA)))
 {
  // Unembed the browser object, and release its resources.
  browserObject = *browserHandle;
  browserObject->lpVtbl->Close(browserObject, OLECLOSE_NOSAVE);
  browserObject->lpVtbl->Release(browserObject);

  GlobalFree(browserHandle);

  return;
 }

 // You must have called this for a window that wasn't successfully passed to EmbedBrowserObject().
 // Bad boy!
 _ASSERT(0);
}




/******************************* DisplayHTMLStr() ****************************
 * Takes a string containing some HTML BODY, and displays it in the specified
 * window. For example, perhaps you want to display the HTML text of...
 *
 * <P>This is a picture.<P><IMG src="mypic.jpg">
 *
 * hwnd =  Handle to the window hosting the browser object.
 * string =  Pointer to nul-terminated string containing the HTML BODY.
 *    (NOTE: No <BODY></BODY> tags are required in the string).
 *
 * RETURNS: 0 if success, or non-zero if an error.
 *
 * NOTE: EmbedBrowserObject() must have been successfully called once with the
 * specified window, prior to calling this function. You need call
 * EmbedBrowserObject() once only, and then you can make multiple calls to
 * this function to display numerous pages in the specified window.
 */

long DisplayHTMLStr(HWND hwnd, LPCTSTR string)
{
 IWebBrowser2 *webBrowser2;
 LPDISPATCH  lpDispatch;
 IHTMLDocument2 *htmlDoc2;
 IOleObject  *browserObject;
 SAFEARRAY  *sfArray;
 VARIANT   myURL;
 VARIANT   *pVar;
 BSTR   bstr;

 // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
 // we initially attached the browser object to this window.
 browserObject = *((IOleObject **)GetWindowLong(hwnd, GWL_USERDATA));

 // Assume an error.
 bstr = 0;

 // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
 // object, so we can call some of the functions in the former's table.
 if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2))
 {
  // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
  // webBrowser2->lpVtbl.

  // Before we can get_Document(), we actually need to have some HTML page loaded in the browser. So,
  // let's load an empty HTML page. Then, once we have that empty page, we can get_Document() and
  // write() to stuff our HTML string into it.
  VariantInit(&myURL);
  myURL.vt = VT_BSTR;
  myURL.bstrVal = SysAllocString(L"about:blank");

  // Call the Navigate2() function to actually display the page.
  webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0);

  // Free any resources (including the BSTR).
  VariantClear(&myURL);

  // Call the IWebBrowser2 object's get_Document so we can get its DISPATCH object. I don't know why you
  // don't get the DISPATCH object via the browser object's QueryInterface(), but you don't.
  if (!webBrowser2->lpVtbl->get_Document(webBrowser2, &lpDispatch))
  {
   // We want to get a pointer to the IHTMLDocument2 object embedded within the DISPATCH
   // object, so we can call some of the functions in the former's table.
   if (!lpDispatch->lpVtbl->QueryInterface(lpDispatch, &IID_IHTMLDocument2, (void**)&htmlDoc2))
   {
    // Ok, now the pointer to our IHTMLDocument2 object is in 'htmlDoc2', and so its VTable is
    // htmlDoc2->lpVtbl.

    // Our HTML must be in the form of a BSTR. And it must be passed to write() in an
    // array of "VARIENT" structs. So let's create all that.
    if ((sfArray = SafeArrayCreate(VT_VARIANT, 1, (SAFEARRAYBOUND *)&ArrayBound)))
    {
     if (!SafeArrayAccessData(sfArray, (void**)&pVar))
     {
      pVar->vt = VT_BSTR;
#ifndef UNICODE
      {
      wchar_t  *buffer;
      DWORD  size;

      size = MultiByteToWideChar(CP_ACP, 0, string, -1, 0, 0);
      if (!(buffer = (wchar_t *)GlobalAlloc(GMEM_FIXED, sizeof(wchar_t) * size))) goto bad;
      MultiByteToWideChar(CP_ACP, 0, string, -1, buffer, size);
      bstr = SysAllocString(buffer);
      GlobalFree(buffer);
      }
#else
      bstr = SysAllocString(string);
#endif
      // Store our BSTR pointer in the VARIENT.
      if ((pVar->bstrVal = bstr))
      {
       // Pass the VARIENT with its BSTR to write() in order to shove our desired HTML string
       // into the body of that empty page we created above.
       htmlDoc2->lpVtbl->write(htmlDoc2, sfArray);

       // Normally, we'd need to free our BSTR, but SafeArrayDestroy() does it for us
//       SysFreeString(bstr);
      }
     }

     // Free the array. This also frees the VARIENT that SafeArrayAccessData created for us,
     // and even frees the BSTR we allocated with SysAllocString
     SafeArrayDestroy(sfArray);
    }

    // Release the IHTMLDocument2 object.
bad:   htmlDoc2->lpVtbl->Release(htmlDoc2);
   }

   // Release the DISPATCH object.
   lpDispatch->lpVtbl->Release(lpDispatch);
  }

  // Release the IWebBrowser2 object.
  webBrowser2->lpVtbl->Release(webBrowser2);
 }

 // No error?
 if (bstr) return(0);

 // An error
 return(-1);
}




/******************************* DisplayHTMLPage() ****************************
 * Displays a URL, or HTML file on disk.
 *
 * hwnd =  Handle to the window hosting the browser object.
 * webPageName = Pointer to nul-terminated name of the URL/file.
 *
 * RETURNS: 0 if success, or non-zero if an error.
 *
 * NOTE: EmbedBrowserObject() must have been successfully called once with the
 * specified window, prior to calling this function. You need call
 * EmbedBrowserObject() once only, and then you can make multiple calls to
 * this function to display numerous pages in the specified window.
 */

long DisplayHTMLPage(HWND hwnd, LPTSTR webPageName)
{
 IWebBrowser2 *webBrowser2;
 VARIANT   myURL;
 IOleObject  *browserObject;

 // Retrieve the browser object's pointer we stored in our window's GWL_USERDATA when
 // we initially attached the browser object to this window.
 browserObject = *((IOleObject **)GetWindowLong(hwnd, GWL_USERDATA));

 // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
 // object, so we can call some of the functions in the former's table.
 if (!browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2))
 {
  // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
  // webBrowser2->lpVtbl.

  // Our URL (ie, web address, such as "http://www.microsoft.com" or an HTM filename on disk
  // such as "c:\myfile.htm") must be passed to the IWebBrowser2's Navigate2() function as a BSTR.
  // A BSTR is like a pascal version of a double-byte character string. In other words, the
  // first unsigned short is a count of how many characters are in the string, and then this
  // is followed by those characters, each expressed as an unsigned short (rather than a
  // char). The string is not nul-terminated. The OS function SysAllocString can allocate and
  // copy a UNICODE C string to a BSTR. Of course, we'll need to free that BSTR after we're done
  // with it. If we're not using UNICODE, we first have to convert to a UNICODE string.
  //
  // What's more, our BSTR needs to be stuffed into a VARIENT struct, and that VARIENT struct is
  // then passed to Navigate2(). Why? The VARIENT struct makes it possible to define generic
  // 'datatypes' that can be used with all languages. Not all languages support things like
  // nul-terminated C strings. So, by using a VARIENT, whose first field tells what sort of
  // data (ie, string, float, etc) is in the VARIENT, COM interfaces can be used by just about
  // any language.
  VariantInit(&myURL);
  myURL.vt = VT_BSTR;

#ifndef UNICODE
  {
  wchar_t  *buffer;
  DWORD  size;

  size = MultiByteToWideChar(CP_ACP, 0, webPageName, -1, 0, 0);
  if (!(buffer = (wchar_t *)GlobalAlloc(GMEM_FIXED, sizeof(wchar_t) * size))) goto badalloc;
  MultiByteToWideChar(CP_ACP, 0, webPageName, -1, buffer, size);
  myURL.bstrVal = SysAllocString(buffer);
  GlobalFree(buffer);
  }
#else
  myURL.bstrVal = SysAllocString(webPageName);
#endif
  if (!myURL.bstrVal)
  {
badalloc: webBrowser2->lpVtbl->Release(webBrowser2);
   return(-6);
  }

  // Call the Navigate2() function to actually display the page.
  webBrowser2->lpVtbl->Navigate2(webBrowser2, &myURL, 0, 0, 0, 0);

  // Free any resources (including the BSTR we allocated above).
  VariantClear(&myURL);

  // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it,
  // so we can release our hold on it). Note that we'll still maintain our hold on the browser
  // object.
  webBrowser2->lpVtbl->Release(webBrowser2);

  // Success
  return(0);
 }

 return(-5);
}



/***************************** EmbedBrowserObject() **************************
 * Puts the browser object inside our host window, and save a pointer to this
 * window's browser object in the window's GWL_USERDATA field.
 *
 * hwnd =  Handle of our window into which we embed the browser object.
 *
 * RETURNS: 0 if success, or non-zero if an error.
 *
 * NOTE: We tell the browser object to occupy the entire client area of the
 * window.
 *
 * NOTE: No HTML page will be displayed here. We can do that with a subsequent
 * call to either DisplayHTMLPage() or DisplayHTMLStr(). This is merely once-only
 * initialization for using the browser object. In a nutshell, what we do
 * here is get a pointer to the browser object in our window's GWL_USERDATA
 * so we can access that object's functions whenever we want, and we also pass
 * pointers to our IOleClientSite, IOleInPlaceFrame, and IStorage structs so that
 * the browser can call our functions in our struct's VTables.
 */

long EmbedBrowserObject(HWND hwnd)
{
 IOleObject   *browserObject;
 IWebBrowser2  *webBrowser2;
 RECT    rect;
 char    *ptr;
 IOleInPlaceFrameEx *iOleInPlaceFrameEx;
 _IOleClientSiteEx *_iOleClientSiteEx;

 // Our IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame functions need to get our window handle. We
 // could store that in some global. But then, that would mean that our functions would work with only that
 // one window. If we want to create multiple windows, each hosting its own browser object (to display its
 // own web page), then we need to create a unique IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame
 // structs for each window. (Actually, the IOleClientSite and IOleInPlaceSite must be allocated as a
 // single struct, with the IOleClientSite embedded first). And we'll put an extra field at the end of those
 // structs to store our extra data such as a window handle. Remember that a pointer to our IOleClientSite we
 // create here will be passed as the first arg to every one of our IOleClientSite functions. Ditto with the
 // IOleInPlaceFrame object we create here, and the IOleInPlaceFrame functions. So, our functions are able to
 // retrieve the window handle we'll store here, and then, they'll work with all such windows containing a
 // browser control. Of course, that means we need to GlobalAlloc the structs now. We'll just get all 3 with
 // a single call to GlobalAlloc, but you could do them separately if desired.
 //
 // Um, we're not actually allocating a IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame structs. Because
 // we're appending our own fields to them, we're getting an IOleInPlaceFrameEx and an _IOleClientSiteEx (which
 // contains both the IOleClientSite and IOleInPlaceSite. But as far as the browser is concerned, it thinks that
 // we're giving it the plain old IOleClientSite, IOleInPlaceSite, and IOleInPlaceFrame.
 //
 // One final thing. We're going to allocate extra room to store the pointer to the browser object.
 if (!(ptr = (char *)GlobalAlloc(GMEM_FIXED, sizeof(IOleInPlaceFrameEx) + sizeof(_IOleClientSiteEx) + sizeof(IOleObject *))))
  return(-1);
 
 // Initialize our IOleInPlaceFrame object with a pointer to our IOleInPlaceFrame VTable.
 iOleInPlaceFrameEx = (IOleInPlaceFrameEx *)(ptr + sizeof(IOleObject *));
 iOleInPlaceFrameEx->frame.lpVtbl = &MyIOleInPlaceFrameTable;

 // Save our HWND (in the IOleInPlaceFrame object) so our IOleInPlaceFrame functions can retrieve it.
 iOleInPlaceFrameEx->window = hwnd;

 // Initialize our IOleClientSite object with a pointer to our IOleClientSite VTable.
 _iOleClientSiteEx = (_IOleClientSiteEx *)(ptr + sizeof(IOleInPlaceFrameEx) + sizeof(IOleObject *));
 _iOleClientSiteEx->client.lpVtbl = &MyIOleClientSiteTable;

 // Initialize our IOleInPlaceSite object with a pointer to our IOleInPlaceSite VTable.
 _iOleClientSiteEx->inplace.inplace.lpVtbl = &MyIOleInPlaceSiteTable;

 // Save a pointer to our IOleInPlaceFrameEx object so that our IOleInPlaceSite functions can retrieve it.
 _iOleClientSiteEx->inplace.frame = iOleInPlaceFrameEx;

 // Get a pointer to the browser object and lock it down (so it doesn't "disappear" while we're using
 // it in this program). We do this by calling the OS function OleCreate().
 //
 // NOTE: We need this pointer to interact with and control the browser. With normal WIN32 controls such as a
 // Static, Edit, Combobox, etc, you obtain an HWND and send messages to it with SendMessage(). Not so with
 // the browser object. You need to get a pointer to its "base structure" (as returned by OleCreate()). This
 // structure contains an array of pointers to functions you can call within the browser object. Actually, the
 // base structure contains a 'lpVtbl' field that is a pointer to that array. We'll call the array a 'VTable'.
 //
 // For example, the browser object happens to have a SetHostNames() function we want to call. So, after we
 // retrieve the pointer to the browser object (in a local we'll name 'browserObject'), then we can call that
 // function, and pass it args, as so:
 //
 // browserObject->lpVtbl->SetHostNames(browserObject, SomeString, SomeString);
 //
 // There's our pointer to the browser object in 'browserObject'. And there's the pointer to the browser object's
 // VTable in 'browserObject->lpVtbl'. And the pointer to the SetHostNames function happens to be stored in an
 // field named 'SetHostNames' within the VTable. So we are actually indirectly calling SetHostNames by using
 // a pointer to it. That's how you use a VTable.
 //
 // NOTE: We pass our _IOleClientSiteEx struct and lie -- saying that it's a IOleClientSite. It's ok. A
 // _IOleClientSiteEx struct starts with an embedded IOleClientSite. So the browser won't care, and we want
 // this extended struct passed to our IOleClientSite functions.

 if (!OleCreate(&CLSID_WebBrowser, &IID_IOleObject, OLERENDER_DRAW, 0, (IOleClientSite *)_iOleClientSiteEx, &MyIStorage, (void**)&browserObject))
 {
  // Ok, we now have the pointer to the browser object in 'browserObject'. Let's save this in the
  // memory block we allocated above, and then save the pointer to that whole thing in our window's
  // USERDATA field. That way, if we need multiple windows each hosting its own browser object, we can
  // call EmbedBrowserObject() for each one, and easily associate the appropriate browser object with
  // its matching window and its own objects containing per-window data.
  *((IOleObject **)ptr) = browserObject;
  SetWindowLong(hwnd, GWL_USERDATA, (LONG)ptr);

  // We can now call the browser object's SetHostNames function. SetHostNames lets the browser object know our
  // application's name and the name of the document in which we're embedding the browser. (Since we have no
  // document name, we'll pass a 0 for the latter). When the browser object is opened for editing, it displays
  // these names in its titlebar.
  //
  // We are passing 3 args to SetHostNames. You'll note that the first arg to SetHostNames is the base
  // address of our browser control. This is something that you always have to remember when working in C
  // (as opposed to C++). When calling a VTable function, the first arg to that function must always be the
  // structure which contains the VTable. (In this case, that's the browser control itself). Why? That's
  // because that function is always assumed to be written in C++. And the first argument to any C++ function
  // must be its 'this' pointer (ie, the base address of its class, which in this case is our browser object
  // pointer). In C++, you don't have to pass this first arg, because the C++ compiler is smart enough to
  // produce an executable that always adds this first arg. In fact, the C++ compiler is smart enough to
  // know to fetch the function pointer from the VTable, so you don't even need to reference that. In other
  // words, the C++ equivalent code would be:
  //
  // browserObject->SetHostNames(L"My Host Name", 0);
  //
  // So, when you're trying to convert C++ code to C, always remember to add this first arg whenever you're
  // dealing with a VTable (ie, the field is usually named 'lpVtbl') in the standard objects, and also add
  // the reference to the VTable itself.
  //
  // Oh yeah, the L is because we need UNICODE strings. And BTW, the host and document names can be anything
  // you want.

  browserObject->lpVtbl->SetHostNames(browserObject, L"My Host Name", 0);

  GetClientRect(hwnd, &rect);

  // Let browser object know that it is embedded in an OLE container.
  if (!OleSetContainedObject((struct IUnknown *)browserObject, TRUE) &&

   // Set the display area of our browser control the same as our window's size
   // and actually put the browser object into our window.
   !browserObject->lpVtbl->DoVerb(browserObject, OLEIVERB_SHOW, NULL, (IOleClientSite *)_iOleClientSiteEx, -1, hwnd, &rect) &&

   // Ok, now things may seem to get even trickier, One of those function pointers in the browser's VTable is
   // to the QueryInterface() function. What does this function do? It lets us grab the base address of any
   // other object that may be embedded within the browser object. And this other object has its own VTable
   // containing pointers to more functions we can call for that object.
   //
   // We want to get the base address (ie, a pointer) to the IWebBrowser2 object embedded within the browser
   // object, so we can call some of the functions in the former's table. For example, one IWebBrowser2 function
   // we intend to call below will be Navigate2(). So we call the browser object's QueryInterface to get our
   // pointer to the IWebBrowser2 object.
   !browserObject->lpVtbl->QueryInterface(browserObject, &IID_IWebBrowser2, (void**)&webBrowser2))
  {
   // Ok, now the pointer to our IWebBrowser2 object is in 'webBrowser2', and so its VTable is
   // webBrowser2->lpVtbl.

   // Let's call several functions in the IWebBrowser2 object to position the browser display area
   // in our window. The functions we call are put_Left(), put_Top(), put_Width(), and put_Height().
   // Note that we reference the IWebBrowser2 object's VTable to get pointers to those functions. And
   // also note that the first arg we pass to each is the pointer to the IWebBrowser2 object.
   webBrowser2->lpVtbl->put_Left(webBrowser2, 0);
   webBrowser2->lpVtbl->put_Top(webBrowser2, 0);
   webBrowser2->lpVtbl->put_Width(webBrowser2, rect.right);
   webBrowser2->lpVtbl->put_Height(webBrowser2, rect.bottom);

   // We no longer need the IWebBrowser2 object (ie, we don't plan to call any more functions in it
   // right now, so we can release our hold on it). Note that we'll still maintain our hold on the
   // browser object until we're done with that object.
   webBrowser2->lpVtbl->Release(webBrowser2);

   // Success
   return(0);
  }

  // Something went wrong!
  UnEmbedBrowserObject(hwnd);
  return(-3);
 }

 GlobalFree(ptr);
 return(-2);
}




/****************************** WindowProc() ***************************
 * Our message handler for our window to host the browser.
 */

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 if (uMsg == WM_CREATE)
 {
  // Embed the browser object into our host window. We need do this only
  // once. Note that the browser object will start calling some of our
  // IOleInPlaceFrame and IOleClientSite functions as soon as we start
  // calling browser object functions in EmbedBrowserObject().
  if (EmbedBrowserObject(hwnd)) return(-1);

  // Another window created with an embedded browser object
  ++WindowCount;

  // Success
  return(0);
 }

 if (uMsg == WM_DESTROY)
 {
  // Detach the browser object from this window, and free resources.
  UnEmbedBrowserObject(hwnd);

  // One less window
  --WindowCount;

  // If all the windows are now closed, quit this app
  if (!WindowCount) PostQuitMessage(0);

  return(TRUE);
 }

 // NOTE: If you want to resize the area that the browser object occupies when you
 // resize the window, then handle WM_SIZE and use the IWebBrowser2's put_Width()
 // and put_Height() to give it the new dimensions.

 return(DefWindowProc(hwnd, uMsg, wParam, lParam));
}



/****************************** WinMain() ***************************
 * C program entry point.
 *
 * This creates a window to host the web browser, and displays a web
 * page.
 */

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hInstNULL, LPSTR lpszCmdLine, int nCmdShow)
{
 MSG   msg;

 // Initialize the OLE interface. We do this once-only.
 if (OleInitialize(NULL) == S_OK)
 {
  WNDCLASSEX  wc;

  // Register the class of our window to host the browser. 'WindowProc' is our message handler
  // and 'ClassName' is the class name. You can choose any class name you want.
  ZeroMemory(&wc, sizeof(WNDCLASSEX));
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.hInstance = hInstance;
  wc.lpfnWndProc = WindowProc;
  wc.lpszClassName = &ClassName[0];
  RegisterClassEx(&wc);

  // Create a window. NOTE: We embed the browser object duing our WM_CREATE handling for
  // this window.
/*  if ((msg.hwnd = CreateWindowEx(0, &ClassName[0], "An HTML string", WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
       HWND_DESKTOP, NULL, hInstance, 0)))
  {
   // For this window, display a string in the BODY of a web page.
   DisplayHTMLStr(msg.hwnd, "<H2><CENTER>HTML string test</CENTER></H2><P><FONT COLOR=RED>This is a <U>HTML string</U> in memory.</FONT>");

   // Show the window.
   ShowWindow(msg.hwnd, nCmdShow);
   UpdateWindow(msg.hwnd);
  }
*/
  // Create another window with another browser object embedded in it.
  if ((msg.hwnd = CreateWindowEx(0, &ClassName[0], "Microsoft's web site", WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
      HWND_DESKTOP, NULL, hInstance, 0)))
  {
   // For this window, display a URL. This could also be a HTML file on disk such as "c:\\myfile.htm".
   DisplayHTMLPage(msg.hwnd, "http://www.naver.com/");

   // Show the window.
   ShowWindow(msg.hwnd, nCmdShow);
   UpdateWindow(msg.hwnd);
  }

  // Do a message loop until WM_QUIT.
  while (GetMessage(&msg, 0, 0, 0))
  {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }

  // Free the OLE library.
  OleUninitialize();

  return(0);
 }

 MessageBox(0, "Can't open OLE!", "ERROR", MB_OK);
 return(-1);
}


코드 구루였나.. 거기서 가져온겁니다...
문제는 C언어라.. C++로 돌리면 컴파일 에러가 난다는거...
음... C++로 돌려야 할텐데..

+ Recent posts