Programming - cpueblo.com

[강좌] Windows 95 프로그래밍 입문.txt


글쓴이 : 유광희 날짜 : 2002-05-13 (월) 21:24 조회 : 11262


Windows 95 프로그래밍 입문 (1)
--------------------------------------------------------------------------------
게 시 자 : yunix(유태웅)
게 시 일 : 96/10/28 00:24:37
수 정 일 :
크    기 : 8.4K
조회횟수 : 2785



???  윈도우즈'95 프로그래밍 입문 (1)  ???
                   
                            by SEO JIN-HO(ID:synabreu)

안녕하세요? 소동회 여러분
그동안 개인적으로 많이 바빠서 강좌를 한다고 말만 하고 미루어왔던 점
죄송하게 생각하고 비록 약속한 시간에 비해 늦었지만, 제가 아는 테두리
내에서 "윈도우즈16비트에서 32비트"로 옮겨가는 데, 필요한 이야기들을
모두어 이야기 할까 합니다.
이 글은 누구나 보시고 여러분이 32비트 프로그래밍 공부를 하시고자 하는
데에는 상관이 없으나, 다른 상용시(잡지 원고 투고 포함)할때에는 저에게
개인적으로 알려 주시기 바라며, 아울러 이 글에 대하여 어떠한 의무나
책임을 지지 않습니다. 그러나, 만일 이 글에 읽고 궁금한 점이 있으시면
아래와 같은 곳으로 메일을 주시면 아는데 까지 답변을 드리도록 하겠습니다.

하이텔, 천리안, 나우누리 ID : synabreu
인터넷 ID (E-MAIL) : synabreu@nuri.net
인터넷 웹 홈페이지 : http://sol.nuri.net/~synabreu

끝으로, 이글이 정말로 여러분께 윈도우즈95 프로그래밍 하는데 조금이나마
도움이 되었으면 합니다.

1. 32비트 윈도우즈의 소개
우선 제가 이야기할 범위에 대하여 여러분께 간략하게 소개해 올리겠습니다
저는 윈도우즈 16비트에서 32비트로 옮겨가는데 필요한 포팅 테크닉과
Win32s사용법과 다른 시스템간의 이식을 위한 썽크(thunks)와 Win32 API
의 개요까지 이야기하고자 합니다.
그 이후로, Win32 프로세스와 멀티 쓰레딩이나 SEH(예외처리)부분은 저 역
시 아직 초보자임에 불구하므로, 좀 더 제가 개념이 쓴 후에, 다시 여러분
께 글을 올리도록 하겠습니다.
앞으로 4-5회 정도로 이 이야기들은 여러분이 윈도우즈 32비트로 옮겨가는
데에, 많은 도움이 될 것입니다.

* 이 글에 대한 각종 예제 소스는 소동 자료실의 프로그래밍에 올려 놓겠습
  니다. 이 글과 예제 소스를 비교하시기를 바라며, 이 글들은 윈도우즈95
  에 비주얼 C++2.0 이상에서 실행되는 것을 기본으로 하고 있습니다.
 
======================================================================
 
  제 1 장  32비트 윈도우즈의 소개

1) 윈도우즈'95 프롤로그

윈도우즈 프로그래밍을 처음 공부하는 초보자님들은 한번쯤 무엇을 어떻게
공부해야 할까 고민한적이있을 겁니다. 시대의 부응에 따라 윈도우즈 프로
그래밍을 해야 하겠는데, 무엇을 어떻게 해야 할지 마치 법률을 변호하는
변호사처럼 육하원칙의 합당한 이유를 마련코자 열심히 애쓴 적이 있을겁니다.
윈도우즈 프로그래밍에 있어서 가장 요즘 핵심적인 기술로 부각되고 있는
비주얼 툴들을 이용한 비주얼 베이직이나 델파이로 할 것 인가 아니면,
정석대로 C/C++언어(MFC나 OWL모두포함)로써 개발할 것인가?
물론 그 답은 이글을 읽고 계신 여러분의 판단에 의존해야 할겁니다.
그러나, 제가 여러분께 감히 충고해 드리자면, 일단 여러분 스스로가 무엇
을 하기 위해 언어를 택하는 가에 대하여 곰곰히 생각할 필요성이 있습니다
그것은 왜냐하면, 예를들어 회사에 필요한 데이타 처리를 위한 자료관리나
소프트웨어 개발기간을 단축해서 개발하려면 C/C++은 한번도 다루어 보지
않은 여러분께는 분명히 그리 쉬운 것이 아닐겁니다. 그것은 이 언어들은
시스템 전반적인 것을 다루어야 하기 때문에 세세한 부분을 프로그래머가
직접 다루어야 하는 반면에, 델파이나 비주얼 베이직은 협소하지만 VBX라는
컴포넌트 틀(일종의 DLL형태)만 있다면 얼마든지 구현할 수 있기 때문입니
다.
필자의 개인 경험을 말씀 드리자면, 저는 한번도 도스용 프로그래밍을
해보지 않고 곧바로 윈도우즈 프로그래밍으로 넘어 왔습니다. 
많은 선배들이 정석대로 여러가지 도스용에서 필요한 한글구현 및 프로그래
밍적인 공부를 하지 않고, 새로운 것 만을 쫓차 간다는 비난하에 가감히 도
스용을 버리고 시작했습니다.
물론 상당히 용어와 더불어 개념 자체가 처음에는 상당히 힘들었으며,
도스용과 비교할 수 없는 재미있는 부분도 많이 배웠습니다.
그리고 저도 여러분들과 같이 초보자에 불과하며, 배워 나가야 참으로
많다는 것을 깨달았습니다.
이글을 보는 분들중에는 저보다 훨씬 실력이 월등히 좋은 분들도 많으리라
생각됩니다.
주제 넘게 우리나라 소프트웨어 현실에 대해 말하자면, 아직 우리나라는
도스용 프로그램이 주류를 이루고 있으며, 그나마 윈도우즈3.1용 프로그램
이 서서히 사용되었지만, 내달에 발표될 한글 윈도우즈95로 인하여
아마 윈도우즈'95 응용 프로그램이 더 많이 만들어 지는 것은 불을 보듯 뻔
한일입니다. 하지만 사용자들이 이 윈도우즈'95를 사용하기에는 시스템 업
그레이드(적어도 486DX2-66, RAM16메가)가 되어야 원활히 사용할 수 있기
때문에 아직은 미지수이지만, 2-3년안에 윈도우즈'95로 옮겨가는데에는
지변이 없는 한 그렇게 변경 될것라고 추측이 되어 집니다.
그렇다면, 응용 프로그램을 개발하고자 하는 여러분은 윈도우즈'95(Win32)
에 대하여 지금 연구할 필요가 있고, 윈도우즈'95에 포팅된 여러가지 기능
을 사용하여 좋은 프로그램을 작성할 수 있을 겁니다.
윈도우즈 3.1은 여러분도 잘 아시다시피, 사실상 도스에서 돌아가는 불완전
한 운영체제였지만, 윈도우즈'95는 그와 달리 Ms-Dos를 포함하고 있는 완전
한 운영체제로써 그 면모를 가지고 있습니다.

2) 윈32의 장점

제가 개인적으로 윈32로 옮겨 가는데 조금도 망설이지 않았던 것은
멀티쓰레딩 지원으로 인한 다중 프로그램 처리부분과 좀더 구현하기 쉬운
멀티미디어, 여러 컴퓨터를 원격적으로 할 수 네트워크와 단순한 인텔 뿐만
아니라, RISC와 MIPS 같은 멀티 클로스 플랫폼등에서 프로그램을 개발할 수
있다는 점등을 뽑을 수가 있겠습니다.
RTTI 제어와 RPC를 이용한 telephone api를 이용한다면, 이젠 어쩌면 삐삐
보다는 화상통신을 이용한 전자수첩(전자전화장치가 기억된)을 우리는 사용
할 수 있을지도 모르겠습니다.
그리고, 우리나라에 10%로 되지 않은 네트워크 분야에 사용될 프로그램들을
개발한다면 아마 차세대 소프트웨어의 흐름이 어딜갈지를 짐작할 수가 있을
겁니다.
그렇다면, 제가 이렇게 말하는 근거가 어디인가는 여러분이 이 글을 모두
읽게 되면 이해가 가리라 생각됩니다.
윈32의 시스템 특성을 이야기하자면, 윈16은 intel칩 바탕으로 인한 8086계
열을 기준으로 만들어 졌기 때문에, 6가지의 세그멘트 단위의 메모리 모델로
개발 되었지만, 윈32에서는 플랫 메모리라 불리우는 선형 프로그램 모델을
채택하여 4GB 주소 공간을 확보할 수 있게 되었습니다.
다시 말해서, 세그멘트 단위 메모리 모델은 64KB한계성으로 더 이상 메모리
를 불러 오기 위해서 우리는 EMS스펙이니, XMS스펙이니 하는 속임수를 사용
해 왔습니다. 하지만, 윈32에서는 이 모든 것은 사라지고 새로운 메모리 모
델이 탄생했습니다.
이것은 윈32부터는 intel칩 뿐만 아니라, RISC와 MIPS, ALPHA, PowerPC와
같은 프로세서를 염두해두었기 때문에, 사용자가 불러올수 있는 만큼 최대
의 크기로 불러 올수 있다는 것이 장점입니다.
사실 이런한 점 때문에 FAR와 NEAR 키워드가 쓸모 없게 되었고, VBX라는 int
el칩에 의존되어 있는 Dll을 버리고, OLE Custom Controls 라는 새로운 표
준 스펙을 발표하는 계기가 되었습니다.
그외의 특징은 윈32의 최적화하기 위한 여러가지 프로세스 및 쓰레딩 처리
지원이 있는데에, 이것은 이것만 이야기 해도 적어도 20페이지 이상 차지함
으로 다음에 이야기를 하도록 하겠습니다.
이 부분에 대해서는 이 글이 끝나는 마직막으로 참고문헌때에 밝힐게 될
"Advanced Windows : The Developer's Guide to the Win32 API for windows
NT 3.5 and Windows'95 by Jeffery Richter, 1995 microsoft press"책을
잠조하며 자세한 설명이 나와 있습니다.

3) 타입 크기 확장
위에서 말씀 드린 것 같이, 윈32는 기존의 윈16의 세그먼트 메모리 모델을
제거하고, 윈32의 플랫 메모리를 사용함으로써 더 빠른 메모리의 효율성을
가지게 되었습니다. 그리고 기본적인 타입들이 변경되었는데, 아래의 표를
보시면 그 변경된 것을 알수가 있으리라 생각됩니다.

-----------------------------------------------------------------
Type                      Size
-----------------------------------------------------------------
char                      8 bits(one bytes)
short                      16 bits
int                        32 bits
long                      32 bits
float                      32 bits (IEEE)
double                    64 bits (IEEE)
ULONG                      32 bits
USHORT                    16 bits
UCHAR                      8 bits
DWORD                32 bits
BOOL                      32 bits
BYTE                      8 bits
WORD                      16 bits
LONGLONG                  64 bits
DWORDLONG                  64 bits
LARGE_INTEGER              64 bits
-----------------------------------------------------------------

4) Calling Conventions

NT에서는 stdcall:_(_cdecl) 과 fastcall:(__fastcall)을 지원하며, 스탠
다드 콜은 디폴로로써 사용되었습니다. 윈16에서는 아시다시피 pascal
호출 예약가 있었지만, 윈32에서는 더 이상 이것들을 지원하지 않고 있습
니다. 따라서,

int PASCAL WinMain(...);

는,

int WINAPI WinMain(...);

로 바꾸어서 반드시 코딩을 해야 하며,
프로시져에서는

long far PASCAL _export MainWinProc(...)
는,

LRESULT CALLBACK MainWndProc(...)

입니다.
아직도 APIENTRY라는 표현하는 SDK예제는 버그가 일어날 염두가 있습니다.
이것은 os/2에서 스몰 모델용으로 사용되었지만, WINAPI로 고쳐서 사용하시
것이 훨씬 권장할 방법입니다.
왜냐하면, 최근에 VC++2.0이상의 컴파일러는 이키워드를 제공하지 않고
있기 때문에 그렇습니다.

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


Windows 95 프로그래밍 입문 (2)
--------------------------------------------------------------------------------
게 시 자 : yunix(유태웅)
게 시 일 : 96/10/28 00:25:28
수 정 일 :
크    기 : 13.7K
조회횟수 : 1363

< 윈도우즈'95 프로그래밍 입문 >

                        작성자 : 서진호(ID : synabreu)   
                        비고  : 두 번째 작성

안녕하세요? 서진호입니다.
두 번째 이야기를  새로히 작성함을 미리 밝혀 드립니다.  처음에 보시
는 분들은 상관없지만,  이미 제글을 보고 있는 분들은  죄송하다는 말
씀을 드립니다. 왜냐하면 제가 글을 올리면서 윈도우즈  NT와 95에 대
하여 착각을 하여 틀리게 오보를 한 것  같습니다. 이점을 보완 수정하
여 다시  올립니다. 다음부터는 더  정확하게 확인하고 글을  올리도록
하겠습니다. 그리고 이글을 쓰는데 틀린 부분을  지적해주시고 많은 관
심을 가져 주신  용주형(저번에 확장 MDI강좌를 하신분)께 감사  드립
니다. (수정한 부분  앞에 "*"를 해 놓았습니다. 저번의 글과  비교하여
보시면 잘못된 오보를 한 것을 알 수가 있을 겁니다.) 

1. 윈도우즈의 역사

여러분도 아시다시피,  MS-DOS로 시작한 마이크로  소프트는 종전의
텍스트 운영체제를 종식하고,  서서히 그래픽 유저 인터페이스(GUI)를
이용한 MS-Windows전략을 지금으로  부터 10전 부터 이것을 시작해
왔습니다. 그 당시에는  윈도우즈가 과연 살아남으리라는 것은  예상
도 못했을 뿐만  아니라,  10년후의 컴퓨터 산업에  대하여  "지금보다
는 급진적으로 발전하리라"라는 말만 했을 뿐, 예측을 못했습니다.
그러나, 90년초 윈도우즈3.0이 발표되고, 그에 따른 여러가지  응용 프
로그램이 개발되었을 때 부터,  매킨토시의 여러가지 GUI가 위축 당할
정도로 많은 성공을 거두었습니다. 그 이후로,  윈도우즈는 PC사용자들
의 그래픽 인터페이스 운영체제로 자리를 잡게  되었으며, 아울러 윈도
우즈 패밀리하여 새로운  기술을 부각한  UNIX 사용자  및 중대형 워
크 스테이션  급을  통합하려는 야심찬  윈도우즈NT를  발표함으로써
또한 한 번의 운좋은 성공을 하게 되었습니다.
*현재 PC 네트워크  분야에서는 노벨 네트웨어가 많이 사용되고  있습
니다만 앞으로  추의를 볼 때 NT사용자들이  지금 미미한 상태이지만
어떻게 변화가 될지 귀추가 주목 되고 있습니다. 
또한, 올해에 발표된  윈도우즈'95는 대대적인 선전 공세를 인하여 PC
와 네트워크를 연결하는 중간 결정체라 볼수 있습니다. 어쩌면 미래에
는 우리의 시스템이 더 향상되면  윈도우즈 NT와 95가 통합된 운영체
제로써 그야말로  "정보를 내손안에" 라는 그의 슬로건대로  전세계의
정보를 얻을 수 있는 획기적인 시대를 맞이할 것 으로 기대됩니다.

2. Win32 API 개요

그렇다면, 현재 발표가  되고 있는  윈도우즈'95와 NT  개발자들에 서
비스를 해주고 있는  이 Win32 API는 저번 이야기에서 말씀드렸듯이,
*16비트 API에 호완성을 기준으로  하지만, 세그먼트 단위의 64KB 메
모리 한계의 장벽을 넘어 폭ㄴ은  메모리를 사용하고 있습니다. Win32
API는 Windows'95와 MS-Windows NT에사용되는 응용 프로그램의
인터페이스 입니다.

1) Kernel : The Base Operating System
종전의 윈도우즈3.1에서  지원되지 않는 선점형  멀티태스킹이 (엄격히
말해서 멀티 쓰레딩 지원, 한 프로세스에 여러개의 쓰레드를 관리하여
한 시스템에서 여러개의  응용 프로그램을 실행시킬 수 있음)완벽하게
지원되고, 플랫 메모리라고 부르는 선형 메모리 구조 형식으로 종전의
세그먼트 단위보다  처리 속도가 빠르며, 4GB  메모리를 확보  할 수
있는 효율적인 페이지 가상 기법(paged virtual memory)기법을 이용하
고 있습니다. 또한 메모리 사상기법을 통하여 입출력  I/O 에 관한 여
러가지 서비스를 직접 할  수 있으며,  메모리 오류  (예를들어,  GPE)
등을 줄여 주는 장점을 가지고 있습니다.

2) GDI Improvements : Beziers, Paths, Transforms
종전의 윈도우즈3.1에서는 하드웨어 독립적인 디바이스 컨텍스트가 장
점으로 부각 되었다면,  윈도우즈'95 부터는 이젠 비트맵 뿐만  아니라,
*윤곽선(트루타입)처리를 좀더 원숙하게 구현해주고 있습니다.
(OpenGL은 윈도우즈  NT3.5x만 지원됨,  윈도우즈'95에서는 지원되지
않음. 필자가 비주얼 C++2.0이 윈도우즈'95와 NT둘다를 지원하는 것을
염두하지 않았음)
그것은 베지어  곡선이라 불리우는 기법을  통해 폴리베지어 기능성과
연속적으로 선과 곡선을 이용하여  결합시켜 놓았으며, Path API는 삼
각형과 사각형,  다각형과 같은 베이지  곡선의 인공적인 결합  형태로
구성  해놓았습니다. BeginPath는 Path를  시작하는  함수이며, 패스의 
길이와 크기등을  정의합니다. 또한, EndPath는  패스를 닫으며, 응용
프로그램은 그러한 형태들을 출력장치에 그리고,  칠하고, 클립하며, 번
역해줍니다.
 
3) The Windowing System and System Classes
* 윈도우즈3.1에서는 여러분도 아시다시피 시스템 기반  사항이 도스에
의존하고 있기 때문에,  하나의 운영체제로 부르기에는 뭔가  부족했지
만, 윈도우즈'95에서는 반대로  윈도우즈'95안에 도스7.0이 내장되어 있
는 폼으로 되었으며 무엇보다도  프로세스 처리와 멀티 쓰레딩 기법을
통한 여러개의 프로그램을 동시에 처리할 수 있게 되었습니다. 

4) Networking Extentions
아무래도 윈도우즈'95로  업그레이드됨으로써 그들은 표방하는 자랑거
리 하나 중에 네트워크에  관한 전모가 아닐  듯 싶습니다.  우선 사용
자들에게는 PC와 서버를 연결한 인터넷  서비스, MSN이 그렇고, 개발
자  및  시스템    엔지니어에게는  IPC  (Interprocess  Process
Communication) 메카니즘을 이용한  파일, 프린트, 파이프,  메일슬럿,
서버 브라우저, 머신 컨피그레이션를 지원해줍니다.
또한 WinNet API뿐만 아니라,  Win32 API는  원격 제어  호출(RPC,
Remote Process Control)를 가능하게 해주는 피어투피어 파이프,  메일
슬럿 기능들을 포함하고 있습니다.
* Win32 API의  장점 부분은 위에 있는 내용과  비슷함으로 생략했음 
 
3. Win32 포팅의 개요
자! 그러면, 이제  여러분의 Win16 코드를 하나씩 하나씩 Win32로  옮
겨 가보도록 합시다. * 여러분 이사할 짐은 다 꾸려 놓으셨습니까?

1) 두 개의 코드 기반하여 작성
두개의 코드를  작성하는 것을 말하는데,  하나는 Win16으로  만들며, 
또  하나는 Win32  코드를  새로 만들어  윈도우즈  95와 NT용으로
만드는 방법을 말합니다.

2) 세개의 코드 기반하여 작성
이것은 위와 마찬가지로 하나는 Win16으로 작성하지만, Win32는 두가
지로 더욱 더  세밀히  구분하여 각각  Windows95, nt용 으로 코드를
만드는 것을 말합니다. *왜냐하면, 윈도우즈'95에서는 아직 부분적으로
유니코드를 지원하며,  윈도우즈'95에 실행되는  프로그램이 NT에서는
사용할 수 없을  수도 있음을 주시해야 합니다.  예를들어, 윈도우즈'95
용 오피스는 NT에서는 사용하기가 힘듭니다.

3) 하나의 코드 기반하여 작성(1)
하나의 코드내에 win16과  win32를 둘다 목표로 하여 작성하는  것을
말합니다. 이것은 간단한  프로그램이며, 개발하는 사람의 수가 적었을
때 사용하면 많은 효율성을 가질 수 있습니다.

4) 하나의 코드 기반하여 작성(2)
이것은 아예 win32는  배제하고, 처음부터 win16을 Win32s로 작성하
는 방법을 말합니다. 그러나, win32s는  한계성이 있어 이 방법을 사
용한다면, 윈도우즈3.1사용자들은  이로우나, 윈도우즈'95와  NT에서
는 포터블 하지 않을 수도 있습니다.

* 바이너리 호완성  문제점(여기 글(강좌)의 문맥상 맞지  않기 때문에
삭제했음)

우선 윈도우즈3.1 응용프로그램이 Standard/Enhanced 모드를 동작해야
하며 문서화된 Win16의 구조체와API, 메시지들을 사용해야 할것입니
다. *그리고,  WIN.INI를 직접  제어하는 것보다  GetProfileString이나
WriteProfileString으로 하는 것이 나으며,  윈도우즈'95에서는 레지스터
리를 이용하는 방법을 권장하고 있습니다.
또한 Escape를  사용하는 것보다 특별한 프린터  드라이버 이스케이프
가 구현되었는지 안되었는지를 결정하는  QUERYESCSUPPORT를 사
용하는 것이 좋으며,  StartDoc과 EndDoc를 이용하는 방법을 권고  하
고 있습니다.
그리고 윈32에서도 윈16을 그대로 가져온것이 있는 데, 이것을 나열하
자면다음과 같습니다.

* 그대로 변경 되지 않은 부분

1) 다중문서인터페이스(MDI)지원과 디폴트 메시지 핸들링
2) 리소스화일 그대로
* 참고
WIN32의 리소스는  기본적으로 유니코드를 사용하고 있다는  점에 주
의 사용자가  3.1의 리소스 파일을 그대로  쓸 수 있다는 것은  리소스
컴파일러가 기존의 ANSI에서 유니코드로의 변환을 내부적으로 처리하
기 때문임. 만약 직접 사용자가 프로그램에서  리소스를 다루어야 한다
면 리소스가 유니코드라는 사실에 주의해야 함.

3) DDE 메시지와 이것을 유지하는 DDEML API
4) 윈도우즈와 호완하는  OLE2.0(이것은 32비트로 확충되며, OCX라는
컴포넌트 스펙과 연결되어 확장성을 보여주고 있습니다.)
5) 메타화일, 클립보드 기능

* 그래픽 인터페이스
1) 트루타입과 트루타입 API
2) 현재 사용되는 윈도우즈3.1의 아이콘과 커서 포맷
* 참고 
윈도우즈 95에서는 기존의  아이콘외에 작은 아이콘(16x16)과 큰  아이
콘(48x48)이 추가되었음. 작은 아이콘은  시스템 메뉴가 나타나는 부분
에서 사용되고 큰 아이콘은 정확히 기억이 나지  않음. 만약 작은 아이
콘이 제공되지 않으면 윈95에서 기존의 아이콘을 줄여서 사용함.

3) 비트맵(BMP)와 장치-독립 비트맵(DIB)
4) 윈도우즈3.x 개발된 프린트 디바이스 드라어버

* 시스템 성능성
1) IPC에 대한 공유 메모리(Shared Memory)
2) NetBIOS 와 파이프라 불리는 MS-DOS용 LAN MANAGER

3. Win32 포팅 기본 규칙

윈도우즈 3.x 와 Win32 SDK를 지원하는 포터블한 코드임

* 한가지 여러분께 참고적으로 말씀 드릴 께 있습니다.
  영문 원서를 보면, "포팅(porting)"과 "호완가능한(portable)"
  용어가 있는데요. 이것은 어떻게 보면 똑같은 내용일 것 같지만,
  전혀 다른 뜻을 가지고 있습니다. 포팅이라는 말한 win16에서
  win32로 옮기는 과정을 말하며, 포터블이라는 말은 윈도우즈3.x
  와 윈도우즈 32비트용에 코드가 호완가능하다는 말입니다.
 
1) WndProc루틴에서 데이타 형태가 바뀌었므로 WParam 과 lParam
  인자를 점검하세요.
2) 호완가능한 API를 사용하십시요. 예를들어, MoveTo대신에
  MoveToEx를 사용하십시요.
3) GetFocus와 GetActiveWindows는 NULL값을 리턴하고 있지 
  점검하십시요.
4) 이젠 hPrevInstance값은 WinMain이 start-up밖에 지나지 않으므로
  그 값은 무관합니다. 따라서, FindWindows(또는 IPC)를 사용하여
  인스턴스를 추적하십시요.
5) GlobalLock 과 malloc는 세그먼트 단위의 메모리 모델을 지원하지
  않으므로 64KB 메모리 포인터를 리턴하지 않습니다.
6) 컬러 비트맵들을 초기화하는 DIB API를 사용하십시요.
7) GetInstanceDate를 사용하지  말고, IPC 메카니즘을 지원하는  것
  으로 변경하십시요.
8) 프로세스 사이에서 펜과 비트맵 같은 GDI를 더이상 공유하지 마십
시요. 왜냐하면, 그것들은 하나의  쓰레드에 종속되고, 아이콘은 GDI객
체가 아니라 시스템 객체로 변경되었다는 사실을 잊지 마십시요.
9) -w2 이상 -w3 경고 레벨 옵션으로 컴파일하십시요.
  이것은 컴파일러에 옵션메뉴에  잊지 않고,  프로젝트  화일을 불러
왔을때 오른쪽 퀵메뉴 부분에 있음을 유의 하십시요.(VC++2.0기준)
10) 모든 함수들에 대한 함수 프로토 타입을 생성하십시요.
11) 구조체 멤버 정렬(align)과 데이타 타입의 크기를 모두 점검하세요.
* 참고
중요한 문제이고 뜻하지 않은 에러가 발생할 수 있는 부분임.
비쥬얼 C++ 2.x에서는 자동적으로  8바이트 얼라인먼트를 사용하는 것
에 주의할 필요가 있음. 이는 16비트용  프로그램과 자료를 공유하려면
(마프 Q&A처럼  같은 자료파일을 공유하려 한다면)  구조체의 얼라인
먼트를 16비트에서 사용하는 1로 바꾸어  주어야 함. 이는 비쥬얼 C++
에서는
#pragma pack(1)
구조체...
#pragma pack()
와 같이 해줄 수  있음. 좀 더 자세한 사용법은 마프의  소스를 참조할
것. 볼랜드 C++에서는 32비트  환경에서도 1바이트 얼라인먼트가 기본
값임에 주의할 것. 따라서 비쥬얼  C++로 만들어진 DLL이 볼랜드에서
제대로 동작되지 않을 수도 있음. 이럴 경우에는  옵션을 수정해서 8바
이트 얼라인을 시켜주는 것이 안전한 방법임.

12) 파일명과 확장자가 8.3이 아닌  255개이므로 그것들을 모두 점검하
세요.
13) Windows.H를 사용자가 직접 만든 것 복사본을 사용하지 마세요.
    (문서화되지 않는 부분을 사용하지 마세요.)
14) HANDLE 이나  int와 같은 보통  형태가 아니라,  HPEN, HWND
와 같은 구체적인 타입들을 사용하세요.
15) UINT 나 WORD 처럼 호완가능한 typedef로 정의하세요.

7. 연습하기

우와~~ 벌써 200줄  넘어 버렸습니다. 그럼 여기서  백문이 불여일타
입니다. 헌번 여러분이 직접 win16코드를 저번 주제와 오늘 주제를 모
두 읽었다면 무난히 변경할 수 있을 겁니다.
아래의 예제 코드는 K&R(C 발명가) "Hello, World"입니다.
이것을 윈도우즈95에서 비주얼 C++2.0으로 한번 컴파일해보십시요.
그리고 다음 주제는 그외  중요한 여러가지 인터페이스 포팅법에 관한
정보를 여러분과 함께 나누도록 하겠습니다.
이글을 보시면  의문점이나 이해가 안가시는 점이  있으면 synabreu
로 연락주십시요. 히~ 여러분 안녕~

////////////////////////////////////////////////////////////////////
// HELLO.C

#include <windows.h>

// just prototype : Global functions
long FAR PASCAL  _export WndProc (HWND, UINT, UINT,LONG);

int    PASCAL    WinMain
(HANDLE hInstance, HANDLE hPrevInstance,
 LPSTR lpszCmdParam, int nCmdShow)
{
    static char szAppName[] = "HelloWin";
    HWND    hWnd;
    MSG    msg;
    WNDCLASS wc;
   
    if (!hPrevInstance)
    {
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WndProc;
      wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = GetStockObject(WHITE_BRUSH);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = szAppName;
       
        RegisterClass (&wndclass);
    }
   
    hWnd = CreateWindow (szAppName, "The Hello Program",
                        WS_OVERLAPPEDWINDOW,
              CW_USEDEFAULT,
                        CW_USERDEFAULT,
                        CW_USERDEFAULT,
                        CW_USERDEFAULT, NULL, NULL,
                        hPrevInstance, NULL);
                       
    ShowWindow (hWnd, nCmdShow);
    UpdateWindow(hWnd);
   
    while (GetMessage (&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatechMessage(&msg);
    }
    return msg.Param;
}

long  FAR  PASCAL  _export 
WndProc 
(HWND  hWnd, UINT uMessage, UINT wParam, LONG lParam)
{
    HDC    hDC;
    PAINTSTRUCT ps;
    RECT    rect;
   
    switch (uMessage)
    {
        case WM_PAINT:
            hdc = BeginPaint (hWnd, &ps);
           
            GetClientRect (hWnd, &rect);
           
            DrawText (hDC, "Hello, Windows!", -1, &rect,
                      DT_SINGLE        |        DT_CENTER       
|
DT_VCENTER);
            EndPaint(hWnd, &ps);
            return 0;
           
        case WM_DESTROY:
            PostQuitMessage (0);
            return 0;
    }
   
    return DefWindowProc (hWnd, uMessage, wParam, lParam);
}

HELLO.DEF
;-----------------------------------------------------
;  HELLO.DEF module definition File
;-----------------------------------------------------

NAME            HELLO
DESCRIPTION      'Hello Windows Program'
EXETYPE          WINDOWS
STUB            'WINSTUB.EXE'
CODE            PRELOAD MOVEABLE DISCARDABLE
DATA            PRELOAD MOVEABLE MULTIPLE
HEAPSIZE        1024
STACKSIZE        8192
                                                                 




Windows 95 프로그래밍 입문 (3)
--------------------------------------------------------------------------------
게 시 자 : yunix(유태웅)
게 시 일 : 96/10/28 00:26:26
수 정 일 :
크    기 : 8.9K
조회횟수 : 1069

안녕하세요? 서진호입니다.

"윈도우즈'95 프로그래밍  입문"라는 이야기로  이제 세번째로  만나게
되었네요. 참으로 반갑습니다.  어떻게 저번에 내었던 숙제를 해보셨는
지요? 어렵던가요?  쉽던가요? 히~ 그럼  오늘은 본격적으로 포팅하는
이야기를 한번 해보도록 하겠습니다. (답은 이글 마직막에 있습니다.)

1. 윈도우즈3.1과  윈도우즈'95, NT를 한 코드내에서  호완가능한 포팅
방법
    1) 조건적 컴파일
      컴파일시 상수를 정의하는 방법
     
      switch (uMsg) {
        // message command from application menu
        case WM_COMMAND:
       
        #if defined (_WIN16 || defined(WIN16)
            wmId = uParam;
            wmEvent = HIWORD(lParam);
        #else
            wmId = LOWORD(uParam);
            wmEvent = HIWORD(uParam);
        #endif
       
    2) SDK에서 준비한 매크로 사용 - 메시지 크랙커 이용
        * 이방법은 사실 상당히 권장되는 방법이다. 다음번 강의에서
          자세히 다루어 설명하겠지만, 여러분들이여, 메시지크랙커를
  이용하십시오.

        하나를 간단히 예를들자면,
       
        < Win32 Code (not included message cracker)>
       
 LRESULT  WndProc(HWND  hWnd,  UINT  uMsg,  WPARAM
wParam, LPARAM lParam)
 {
    switch(uMsg)
    { 
          case WM_COMMAND:
          // WM_COMMAND 처리 
          case WM_PAINT:
          // WM_PAINT 처리
          case WM_DESTROY:
          // WM_DESTROY 처리
          default:
              return  (DefWindowProc  (hWnd,  uMsg,  wParam,
lParam));
    }
}

로 선언 되어 있으며,  각각 메시지를 처리한다고 할때, 메시지 크랙커
를 이용하는 방법으로 바꾼다면,

LRESULT WndProc (...)
{
    switch (uMsg)
    {
        HANDLE_MSG          (hWnd,        WM_COMMAND,
Cls_OnCommand);
        HANDLE_MSG (hWnd, WM_PAINT, Cls_OnPaint);
        HANDLE_MSG (hWnd, WM_DESTROY, Cls_OnDestroy);
       
        default:
            return (....);
    }
}

해주고, WM_* 메시지 처리를 함수로 사용하여  처리해주면 간단히 해
결수 할 수 있습니다.
 
void Cls_OnCommand(HWND hWnd, int id, HWND  hwndCtl, UINT
codeNotify)
{
    switch (id)
    {
        case ID_SOMELISTBOX:
            // list Box 명령 처리
    }
}

* 메시지 크랙커 장점과 차일드 컨트롤 매크로와  API매크로는 다음에
이야기 할때, 더 자세히 다루도록 하겠습니다. 여러분은 아마 환상적인
메시지처리를 할수 있을겁니다.  아차, 반드시 #include <windowsx.h>
를  포함시켜야  합니다.(참고적으로  다음번  이야기를  예고하자면,
message cracker 와 Win32s 1.30, thunks 를 설명하도록 하겠습니다.)

좀 더 유저 인터페이스 코드에 대하여  알아보도록 하겠습니다. 메시지
인자 팩킹에 대하여  우선 설명 드리자면, wParam 과  lParam이 32비
트(DWORD)로 확장 되었기 때문에  WM_COMMAND에서 wParam과
lParam에 인자가 변경되었습니다.

WM_COMMAND

Win 3.x :
    wParam == id of the window controls
    lParma == hwnd, command
   
Win 32:
    wParam == id of the window controls, command
    lParam == hwnd
   
예를 든다면,

Existing Code :

    switch (uMsg)
    {
        case WM_COMMAND:
            switch (wParam) {
                case ID_OK:
                ...
            }
    }
   
Portable Code:

    switch (message)
    {
        case WM_COMMAND:
            switch (LOWORD (wParam)) {
                case ID_OK:
            }
    }

이러한 경우에는 Windows 3.x와 Win32에서 둘다 사용할수 있는 코드
가 될 수 있습니다. LOWORD(wParam)는 Windows 3.x와 Win32에서
저급(lower)  16비트    메시지  인자를사용할    수  있습니다.
WM_COMMAND메시지 인자로  부터 핸들됨으로써  윈도우즈 코드는
다음과 같이 구성되어 사용하고 합니다.

hwnd = LOWORD (lParam);
notification = HIWORD(lParam);

하나의    윈도우    핸들로    부터  발췌하는    포터블    방법은
WM_COMMAND의 lParam인자를 다음과 같이 사용하면 됩니다.

hwnd = (HWND) (UINT) lParam;

UINT는 아래와 이야기한것 같이  새로운 타입입니다. UINT는 윈도우
즈3.x에서는 16비트 값을 lParam으로 캐스트(cast)하지만  win32에서는
32비트로  캐스트됩니다. WM_COMMAND  표기(notification)  코드의
발췌를 핸들링하는 것은 다음과 같은 코드가 요구 됩니다.

#ifdef WIN32
    notification = HIWORD(lParam);
#else
    notification = HIWORD(wParam);
#endif

사실 결론부터 말해놓는다면,  다시 말해서 인자들을 팩킹하는  효과를
극대화 시키려면  메시지 인자들의 매크로(메시지 크랙커)를  사용하는
것이 훨씬  좋은 방법입니다. 이러한  방법들을 사용하는 것은  독특한
메시지  핸들링 코드가  있거나 C  컴파일러인  #ifdef 지정자들  없이
Windows 3.x나 Win32 코드를 컴파일할 때 사용할 수 있습니다.
그러나, 메시지 크래커를  이용하거나 C컴파일러에서 지정자를 사용하
는 방법을 우리는 때때로 둘다  알아야 할 필요가 있을때 적절히 사용
하는 게 현명한 프로그래머라고 생각됩니다.

요약해서 말씀드리자면, 인자들의 팩킹을 변경하는 메시지를 위하여,
그 메시지를 계속해서  핸들링하면서 즉시 wParam/lParam 정보를  넣
어주십시요. 그리고 이러한 정보를 포함한 지역 변수를 사용하시고, 레
퍼런스를 참조할 뿐만 아니라, wParam  또는 lParam으로 부터 발췌하
여 그러한  지역변수를 사용하는 그  데이타를 참조하십시요. wParam
과  lParam  그 자체뿐만  아니라,  wParam과  lParam으로부터 발췌
(extract)한 변수들을 통과(pass)하십시요.

우리가  만일  범죄자를  수사한다고  가정할때,  항상  LOWORD 와
HIWORD는 용의 자임을 잊지 마십시요. 우리가 실행시킬 코드에서 각
각 그것들을 검사하고, 그것들이 잘 포팅이  되어있는지를 항상 주시하
십시요.

MESSAGE

Win 3.x (Existing form)
    wParam: 16 bits
    lParam: Least Significant 16-bits, Most Significant16-bits
   
Win32: (Widened form)
    wParam: Least Significant 16-bits, Most Significant 16-bits
    lParam: 32-bits
   
다음에 따라 오는 메시지들은 이러한 인자들을 팩킹(packing)하는데
도움이 될만할 것들입니다. 조금이나마 도움이 되었으면 합니다.

1) WM_ACTIVATE:

  Win 3.x : wParam - state / lParam - fMinimized, hwnd
  Win 32  : wParam - state, fMinimized / lParam - hwnd
 
2) WM_CHARTOITEM:

  Win 3.x : wParam - char / lParam - pos, char
  Win 32  : wParam - char, pos / lParam - hwnd
 
3) WM_COMMAND:

    Win 3.x : wParam - id / lParam - hwnd, cmd
    Win 32  : wParam - id, cmd / lParam - hwnd
   
4) WM_CTLCOLOR

    Win 3.x : wParam - hdc / lParam - hwnd, type
    Win 32  :
                WM_CTLCOLORBTN
                WM_CTLCOLORDLG
                WM_CTLCOLORLISTBOX
                WM_CTLCOLORMSGBOX
                WM_CTLCOLORSCROLLBAR
                WM_CTLCOLORSTATIC
                WM_CTLCOLOREDIT
                    wParam :hdc / lParam : hwnd
                   
    주의 -> WM_CTLCOLOR 포팅은 특별한 컨트롤 클래스 칼라 메
시지를 핸들링하는 것을 요구합니다. 물론 포터블  코드는 이러한 차이
점을 #ifdef 지정자로 해주어야 겠지요?
           
5) WM_MENUSELECT

    Win 3.x : wParam - cmd / lParam - flags, hMenu
    Win 32  : wParam - cmd, flags / lParam - hMenu
   
6) WM_MDIACTIVATE
  : 메시지가 MDI 클라이언트 윈도우를 보낼때 메시지이지만, 아무런
인자도 변경되지 않습니다.
   
7) WM_MDIACTVATE(클라이언트  윈도우가 MDI  차일드에 메시지
를 보낼때)
   
    Win  3.x :  wParam  -  fActive /  lParam  -  hwndDeactivate,
hwndActivate
    Win 32  : wParam - hwndActivate / lParam - hwndDeactivate
   
8) WM_MDISETMENU

    Win  3.x  :  wParam  -  0  /  lParam  -  hMenuFrame,
hMenuWindow
    Win 32  : wParam - hMenuFrame / lParam - hMenuWindow
   
9) WM_MENUCHAR

    Win 3.x : wParam - char / lParam - hMenu, fMenu
    Win 32  : wParam - char, fMenu / lParam - hMenu

10) WM_PARENTNOTIFY (두가지 경우가 있음)

    case #1
    Win 3.x : wParam - msg / lParam - id, hwndChild
    Win 32  : wParam - msg, id / lParam - hwndChild
   
    case #2
    Win 3.x : wParam - msg / lParam - x, y
    Win 32  : wParam - msg / lParam - x, y
   
11) WM_VKEYTOITEM

    Win 3.x : wParam - code / lParam - item, hwnd
    Win 32  : wParam - code, item / lParam - hwnd
   
12) EM_GETSEL

    Win 3.x
        return (wStart, wEnd)
        wParam - NULL / lParam - NULL
       
    Win 32:
        return (wStart, wEnd)
        wParam - lpdwStart or NULL / lParam - NULL
       
13) EM_LINESCROLL

    Win 3.x : wParam - 0 / lParam - nLinesVert, nLinesHorz
    Win 32  : nLinesVert, nLinesHorz
   
14) EM_SETSEL

    Win 3.x : wParam - 0 / lParam - wStart, wEnd
    Win 32  : wParam - wStart / lParam - wEnd
   
15) EM_HSCROLL & EM_VSCROLL

    Win 3.x : wParam - code / lParam - pos, hwnd
    Win 32  : wParam - code, pos / lParam -hwnd
         
3번째 이야기를 끝내면서

호~ 메시지만 이야기해도 이거 엄청나네요. 히~ 난 막내니깐,
보는 사람들에게 엄살 좀 피워야징~~ (호~~ 아꾸 손가락이야~~)
히~ 그렇다고 생색내는 거 아님..그냥 귀여운 눈초리 봐주세요 :)
다음번에는요, 윈도우와 클래스 외부(Extra) 워드들이랑
요번에는 말했던 메시지 크랙킹 방법에 대하여 알아 보도록
하겠습니다. 아차~ 포팅하는 예제 정답도 다음에 넣겠습니다.
왜~ 글이 너무 길면 안 읽어니깐~~~ 안뇽~~
긴글  끝까지  읽어 주셔서  감사합니다.  계속해서  마니  봐주세요~~         
                                                                 
                                                                 
         



Windows 95 프로그래밍 입문 (4)
--------------------------------------------------------------------------------
게 시 자 : yunix(유태웅)
게 시 일 : 96/10/28 23:20:12
수 정 일 :
크    기 : 8.1K
조회횟수 : 923

안녕하세요? 서진호입니다.

오늘 이야기는 저번에  약속한 것부터 시작하도록 하겠습니다.  그동안
개인적으로 바빠서 이 글들을  적지 못해서 대단히 죄송하게 생각합니
다. 그럼 긴 글 갈무리를 하여 읽어셔서 부디 윈도우즈'95로 포팅하는
데 도움이 되시기를 바랍니다.

1. 메시지 크랙킹의 모든것

1) 메시지 크랙커
저번에 이야기한 메시지 크랙킹에  대하여 이번에 좀더 자세히 설명해
드리도록 하겠습니다. 우선 이 메시지 크랙킹을  하려면 여러분의 소스
코드에서 #include  "windowsx.h"를 포함 시켜  주신 다음 사용하시면
됩니다.
메시지 크랙킹은 한마디로 말해서  바로 switch문에서 분기한 여러 갈
래의 메시지 처리 방법이 아닌 일종의 매크로와 함수로 처리하는 방법
을 말합니다.
이것은 여러분이 코드를 보기에 좀더 쉽게 읽을수  있고, 많은 양의 코
드를  줄일 뿐  아니라, Win16에서  32로  옮기는 데  쉽게  도와주며, 
HIWORD와 LOWORD등의 여러가지  규칙성을 배제하고 간단히 해결
할 수 있습니다.
첫째, 메인 프로시져에서  아래와 같이 "HANDLE_MSG" 라는 매크로
선언하여 "Cls_OnCommand" 함수에서 호출하게 만듭니다. 

BOOL CALLBACK Dlg_Proc (HWND hDlg, UINT uMsg,
  WPARAM wParam, LPARAM lParam) {

  BOOL fProcessed = TRUE;

  switch (uMsg) {
      HANDLE_MSG(hDlg, WM_INITDIALOG, Dlg_OnInitDialog);
      HANDLE_MSG(hDlg, WM_COMMAND, Dlg_OnCommand);

      default:
        fProcessed = FALSE;
        break;
  }
  return(fProcessed);
}

둘째, HANDLE_MSG로 정의한  Dlg_OnCommand함수를 아래와 같이
구해주면 됩니다.

void Dlg_OnCommand (HWND hwnd, int id, HWND hwndCtl,
  UINT codeNotify) {

  TCHAR szLogDrive[100];

  switch (id) {
      case IDC_LOGDRIVES:
        if (codeNotify != CBN_SELCHANGE)
            break;

        ComboBox_GetText(hwndCtl, szLogDrive,
            ARRAY_SIZE(szLogDrive));
        Dlg_FillDriveInfo(hwnd, szLogDrive);
        break;

      case IDCANCEL:
        EndDialog(hwnd, id);
        break;
  }
}

만일 OnCommand의 DefWndProc의 디폴트 옵션을 나타내고자하면,

void Cls_OnCommand (...)
{
  // 보통 메시지 처리

        // 디폴트 메시지 처리
        FORWORD_WM_COMMAND    (hWnd,    id,    hWndCtl,
codeNotify, DefWindowProc);
}
로 하면 됩니다.

2) 차일드 컨트롤 매크로

차일드 콘트롤  매크로는 메시지들을 차일드  컨트롤에 보내는데 쉽게
도와줍니다. 위에서 본 FORWORD_WM_*와 비슷한 방법을 사용할 수
있습니다. <Windowsx.H>에 정의된 선언을 보면 다음과 같습니다.

#define ListBox_GetCount(hwndCtl)
  ((int)(DWORD)SendMessage((hwndCtl), LB_GETCOUNT, 0, 0L))

ListBox_GetCount 매크로는 단지 하나만의 hwndCtl 인자(리스트 박스
의  윈도우  핸들)만 가지며,  LB_GETCOUNT  메시지는  wParam과
lParam를 무시하기 때문에,  SendMessage로 리턴할때 int형으로 던지
는(cast) 것을 알수 있을 겁니다. 예를들어 보통 메시지 코드는  다음과
같을 겁니다.

int n = (int) SendMessage (hwndCtl, LB_GETCOUNT, 0, 0);
만일 이와같이 16비트에서  했다면, 상위 비트값을 잃어버리질도  모른
다(Maybe you  might lose significant  digits)는 무서운  경고 옵션을
만나게  될겁니다.  왜냐하면  SendMessage에서  돌려  받는  값은
DWORD이기 때문에 그렇습니다. 따라서, 그것을 간단히 나타낸다면

int n = ListBox_GetCount (hwndCtl);

와 같습니다. 위의  코드보다는 더 간단 명료하다는 것을  여러분도 잘
아실 겁니다. 대부분 여러분이 필요한 메시지를  보내는 컨트롤은 다이
얼로그 박스의 차일드입니다.  그래서 GetDlgItem을 항상 사용하여 메
시지를 호출하게 되어 있는데,

int n = ListBox_GetCount(GetDlgItem(hDlg, ID_LISTBOX);

그러나, 이것은 GetDlgItem함수가 반복적으로 사용되기 때문에속도가
느리기 때문에 아래와 같이 코딩을 해주는 것이 바람직합니다.

HWND hwndCtl = GetDlgItem (hDlg, ID_LISTBOX);
int n = ListBox_GetCount(hwndCtl);
ListBox_AddString(hwndCtl, "Another String");

3) API 매크로
API 매크로는 보통 새로운 폰트를 생성하거나, 그 폰트를 장치 컨트롤
에서 선언하거나,  또는 예전의 폰트의 핸들을  저장할 때 사용됩니다. 
예를들어, 아래와 같은 코드가 있다면,

HFONT  hFontDlg  =  (HFONT)  SelectObject(hDC,  (HGDIOBJ)
hFontNew);

이렇게 바꾸어 주기만 하면 됩니다.

HFONT hFontOrig = SelectFont (hDC, hFontNew);

더 자세한 것은 <windowsx.h>에 정의  되어 있으니, 사용하고자 하는
메시지에 따라 그 내용들을 참조하시기 바랍니다.
 
2. 윈도우와 클래스 외부 워드

1) Index word and API's

16비트  API에서  사용되어  왔던,  GetClassWord, GetWindowWord,
SetClassWord, SetWindowWord와 같은  함수 들은 더 이상한 32비트
에서는  호환될  수가  없습니다.  따라서,  이것들은  GetClassLong,
GetWindowLong, SetClassLong,  SetWindowLong로 모두 바뀌었습니
다.
자료들을 접근하는 색인 변수들로  호환가능하도록 바뀌었는데, 예를들
면 아래와 같습니다.

GCW_CURSOR              --->    GCL_CURSOR
GCW_HBRBACKGROUND    --->    GCL_HBRBACKGROUND
GCW_HICON                --->    GCL_HICON
GWW_HINSTANCE          --->    GWL_HINSTANCE
GWW_HWNDPARENT      --->    GWL_HWNDPARENT
GWW_ID                    --->    GWL_ID
GWW_USERDATA          --->    GWL_USERDATA

따라서, 윈도우즈3.1과 윈32로 둘다 컴파일할 수 있는 코드를 수정하려
면 #ifdef지정자를 사용해야  됩니다. 이것이 바로 한  코드내에 두가지
플랫폼을 사용할 수 있는 방법입니다.

#ifdef WIN32
hwndParent      =      (HWND)    GetWindowLong      (hwnd,
GWL_HWNDPARENT);
#else
hwndParent      =    (HWND)      GetWindowWord      (hwnd,
GWW_HWNDPARENT);

부가적으로, 페어런트 윈도우 핸들를  포함하는 알려진 API는 이미 호
환가능하도록 해야 합니다.

불호환적 :
hwndParent        =      (HWND)        GetWindowWord(hWnd,
GWW_HWNDPARENT);

호환적:
hwndParent = GetParent (hwnd);

2) 하드웨어 접근을 직접적으로 할때

윈도우즈'95는  NT에서처럼 사용자  모드로부터 하드웨어를  제어하는
것은 보완성 문제로 발생하는 것 외 모두 직접적으로 접근할 수있습니
다. 이것은 BIOS, DMA 또는 컴포트와 같은 시리얼 포트를 읽고 쓸수
가 있습니다. 만일  여러분이 이러한 하드웨어를 직접적으로  사용하려
면, 장치 구동(Device)  드라이버를 써야 할 겁니다. 디바이스  드라이
버를 사용하는 것이 비록  어렵지만(DDK라는 툴로 만듦) 예를들어 간
단히 코딩하는 방법을 아래에 설명해 보이겠습니다.

sprintf(Drive, "\\\\\\\\.\\\\%s", driveName);
hdrive = CreateFile(Drive,
                  GENERIC_READ | GENERIC_WRITE,
                  0,
                  NULL,
                  OPEN_EXISTING,
                  0,
                  NULL));
                 
if (hDrive == INVALID_HANDLE_VALU)
{
  MessageBox (NULL, "Open Failed", "Open Device", MB_OK);
  return;
}

3) WIN.INI 와 SYSTEM.INI를 직접 제어할 때
윈도우즈3.x에서 Win.ini를 직접으로 제어하는 것은 OpenFile을 이용해
서  해왔다.  물론  이러한  처리는  문서화된  WriteProfileString과
GetProfileString 함수를 사용하는  것 보다 처리속도가 느리지만  말이
다. 하지만 윈도우즈'95에서는  레지스트리 데이터 베이스 연결하는 방
법을 권장하고  있으며, CreateFile(  ... OPEN_EXISTING을 사용하는
게 더 호완적이라고 권장하고 있다. 따라서 이  부분을 제어할 ㄸ 주의
하시기 바랍니다.

4) 사용자가 입력을 받을 때 (local input)
윈32에서는 사용자가 입력을 받을 때 윈16과는  다르다. 입력이 생성될
때시스템으로부터 파일을 읽어  지고 각각 쓰레드들은 마우스 캡쳐나
활성화된 윈도우를 가지게 된다. 이것은 프로세스가  하나의 응용 프로
그램을 실행시키는 병목현상을  줄여주는데 상당한 효과를 거둔다.  다
음은 이러한 사용자가 입력을 받을 때 사용하는 함수들이다.

SetFocus(HWND)
GetFocus(VOID)
SetActiveWindow(HWND)
GetActiveWindow(VOID)
GetCapture(VOID)
ReleaseCapture(VOID)

짐작하건대 대부분 Get으로  시작하는 API는 현재 사용자가  입력하는
쓰레드 동기며, Set은 사용자가 입력 받은  윈도우생성자 쓰레드를 설
정해주는 API들이다. 만일  이러한 쓰레드 동기가 생성되지  않았다면,
이러한 API는 NULL값을 가지게 될  것이다. 따라서 GetFocus로 사용
자가 입력한 메시지는  NULL으로 이루어지며, 이것은 SetFocus에  의
한 핸들로 설정되어 지게 되는 것이다. 그러나 윈도우3.x에서는 시스템
에서  한  윈도우가 키보드  포커스를  GetFocus로써  가지기  때문에
NULL로 할 수가 없었다.   
               
다음 이야기를 준비하면서
호~ 이번에는 조금 빨리 끝내었지요?  너무 길며 지루할 까 싶어서 여
기서 짜르드록 하겠습니다. 저번에  변경하시라는 hello.c는요? 이곳 자
료실에 올려 놓을테니, 한 번 컴파일 해보시고  소스를 보면 이해가 저
절로 가실겁니다. 궁금한 사항이 있으시면 저(ID : synabreu)한테 메일
을 주시고요. 다음번에는 GDI와  그래픽 출력 부분을 포팅하는 방법에
대하여 알려 드리도록 하겠습니다. 추운 날씨에 감기 조심하시고, 이제
부터 쓸 쓸 크리스마스를 카운트할까 봅니다. 호~~~
 




Windows 95 프로그래밍 입문 (5)
--------------------------------------------------------------------------------
게 시 자 : yunix(유태웅)
게 시 일 : 96/10/28 23:21:12
수 정 일 :
크    기 : 7.3K
조회횟수 : 891

안녕하세요? 서진호입니다.

계속해서 보잘 없는  글들을 많은 분들이 읽어 주셔서  감사하고, 오늘
은 GDI 코드들은 어떻게 포팅되는가를 한 번 알아 보도록 하겠습니다.

1. GDI API 함수 부분
 1) WIN32 API 호환 가능한 코드 만들기
GDI API 함수  부분도 예외없이 16비트에서 32비트로 확장해야  한다.
이것은 리턴 값에 의해 수정하는 것과 시스템 정보를 유지하는 정보들
을 수정하는 두가지 차원에서 이루어져야 한다.
다시 말해서 모든 함수는 에러 상태가 발생하는 지 안하는지를 확인하
는 값을 돌려주워야한다. 그러나 16비트에서 그러지 하지  못하기 때
문에 32비트는 이를 확장적으로 지원해주어야 한다. 예를들어,

HDC hdc;
MoveTo(hdc, 10, 20);



HDC hdc;
MoveToEx(hdc, 10, 20, NULL);

로 변경해야 주워야 한다.  각각 핸들을 받아 오며 10과 20을  x, y 위
치점이다. 그리고  한가지 변한  것은 앞으로 여러분은  모든 API에서
"Ex"가 마직막에 붙는 신드롬을  보게 될 것이다. 그리고 위에서 말한
에러코드를 돌려주는 인자 부분을 추가해야 한다.  그러면 우리가 16비
트에서 32비트로 확장하는 데  이러한 경우에 적용되는 함수를 알아보
도록 하자.

MoveToEx,
OffSetViewportOrgEx,
OffSetWindowOrgEx,
ScaleViewportExtEx,
ScaleWindowExtEx,
SetBitmapDimensionEx,
SetMetaFileBitsEx,
SetViewportExtEx,
SetViewportOrgEx,
SetWindowExtEx,
SetWindowOrgEx

위의 함수들은  돌려지는 값들이 무시되거나 초기화(NULL)로  되지만,
다음 함수들은 그 값들을 돌려주어야 한다.

GetAspectRatioFilterEx,
GetBitmapDimensionEx,
GetBrushOrgEx,
GetCurrentPositionEx,
GetTextExtentPoint,
GetTextExtentPointEx,
GetTextViewportExtEx,
GetWindowExtEx,
GetWindowOrgEx

그런데 여기서 한가지 의문점을 생길 것이다. 윈도우즈 3.x에서 사용되
었던 GetTextExtentEx는 어떻게  변경하라는 말인가?? 그것은 아래의
코드를 보면 쉽게 이해가 가리라 생각됩니다.

GetTextExtent      --->  GetTextExtentPoint
GetTextExtenEx    --->  GetTextExtentPointEx

Win32는 또한 많은 구조체에  의해 의존하기 때문에, 임시의 사용자가
만든 구조체를 요구하여 변경한다. 다음의 코드를 보기 바란다.

Nonportable:

dwXY = GetTextExtent (hDC, szFoo, strlen(szFoo));
rect.left = 0;    rect.bottom = 0;
rect.right = LOWORD(dwXY);  rect.top = HIWORD(dwXY);
InvertRect(hDC, &rect);

Portable:
{
SIZE sizeRect;

GetTextExtentPoint(hDC, szFoo, strlen(szFoo), &SizeRect);
rect.left = 0; rect.bottom = 0;
rect.right = sizeRect.cx; rect.top = sizeRect.cy;
InvertRect( hDC, &rect);
}

데이터를 돌려받을 때 버퍼의  크기들을 지정한 인자를 준비하지 않는
API들은 변환할 때 주의해야 한다. 만일 그렇지 않고 32비트에서 실행
했다면 여러분의 아주  보기 좋은 에러들을 만나게 될  것이다. 그러한
함수들은 다음과 같다.

DlgDirSelectEx,
DlgDirSelectComboBoxEx,

ex) Win 3.x :
    DlgDirSelect(hDlg, lpString, nIDListBox);

    Portable:
    DlgDirSelectEx (hDlg, lpString, sizeof(lpstring), nIDListBox);
 
2) DIB vs DDBs
DDB(BMP)와 DIB는 장치에 의존하는 비트맵이냐 장치에 독립하는 비
트맵이냐 하는  차이점을 가지고 있습니다.  초창기 도스 바탕에  의한
윈도우즈 버전들에 의해 사용된  DDB는 이제 다시 DIB로 변환되어야
호환가능하다. 왜냐하면 그것들증에  선, 면, 컬러, 팔렛트 정보가 일부
변경되어거나  추가  되어진  것이    있기  때문이다.  예를들어
SetDIBitmapBits 와  GetDIBitmapBits를 사용해야 한다. Win32에서는
더 이상 CreateBitmap은 사용되지 않는다.

3) 그래픽 객체 공유에서
윈도우즈3.x 에서는 모든 프로그램을  서로 공유하였다. 데이터도 직접
자료를 유지하고, 윈도우즈 프로세스는 시스템이 생성될  때 직접 만들
어 지기도 했다.  이러한 구조들은 펜이나 비트맵와 같은  하나의 그래
픽 객체(Object)들을  생성하는 어떤 응용  프로그램에 의해 증가되고,
비트맵을 그리거나 펜을 사용하는 프로세스를 분류하는 허락해준다.
그러나, Win32 응용프로그램은  주소 공간이 분류되어 있으므로,  반대
로 그래픽 객체들이 그것들을  생성하고 프로세스에 의해 실행되어 진
다. 따라서 그것들을 공유하려면 IPC와 같은 방법을 사용하는 게 훨씬
더 낮다. 
     
2. Base System Support
1) 문서화되지 않은 함수나 내부 명령어를 사용할 때
윈도우즈 NT  차기버젼은 지금  많은 흥미를 자극시키며,  문서화되지
않는 호출과 윈도우즈 응용  프로그램이 NT에서 올바르게 작동되는지
작동되지 않은 지에  대해 모두 궁금히 여기고 있다.  사실 문서화되지
않은 함수를 사용한다는  것은 그 자체가 기분이 매우  집집하다. 그러
나 이러한 문서화되지 않는 함수들은 차기 윈도우 버전(현재 윈도우즈
'95용)에서는 공식화되어 지는 것도 있다. 예를들어, ShellAbout라는 것
은 문서화된 함수로 사용되어 진다. 심지어 윈도우즈'95에서는 모든 문
서화되지 않는 함수들의 인자를 패스할 수 있다고 한다.

ShellAbout(m_hWnd, "JIN-HO wasn't handsome",
          "From Myself voice : but nick named synabreu",
          "\\r\\nby JIN-HO SEO",   
          LoadIcon(AfxGetInstanceHandle(), "jinho"));