Win32 시스템의 원칙
Win32에는 기억을 해두어야 할 몇 가지 기본 원칙이 있다. 또, Win32 API는 UNIX 프로그래머들이 친숙한 POSIX API 같은 다른 API들과는 여러 면에서 다소간 차이를 보이고 있다. Win32가 원래 어려운 것은 아니지만, 코딩하는 스 타일과 기술면에서 어느 정도 변화를 요구한다.
• 거의 모든 시스템 자원은 핸들(handle)에 의해 식별되고 참조되는 커널(kernel) 객체이다.
• 커 널 객 체는 반 드 시 W i n 3 2 A P I에 의 해 서 만 다 루 어 져 야 한 다. 다 른 뒷 문 은 없다. W i n 3 2 가 객 체 지 향 은 아 니 지 만 , 이 규 약 은 객 체 지 향 프로 그 래 밍 에 서의 데이터 추상화 원칙과 일치한다.
• 객 체 는 파 일 , 프로 세 스 , 쓰 레 드 , 프로 세 스 간 통 신을 위 한 파 이 프 , 메 모 리 맵 핑,이 벤트 등을 포함한다. 객체들은 보안 속성 (security attribute)을 갖는다.
• W i n 3 2 는 다 양 하 고 융 통 성 있는 인 터 페 이 스 이 다. 첫 째 , 같은 또 는 유 사 한 동 작을 수 행 하 는 함 수 들 이 다 양 한 형 태로 제 공 되고 있다. 특 히 , 자 주 사 용 되는 함 수 호 출 의 연 속을 하 나 의 함 수로 모 아 서 제 공 한 다. 둘째 , 대 개 의 경 우 , 하 나 의 함 수 내에 도 많은 인 자 와 플 래 그 ( f l a g )가 있 으 며 , 이 들 대 부 분 은 보 통의 경우 무시될 수 있다. 이 책에서는 백과사전처럼 모든 것을 다루지는 않고, 가장 중요한 함수들과 선택 사양들에 만 초점을 맞추도록 한다•
• W i n 3 2 는 서로 다 른 요 구사 항에 맞추 어 진 많은 동 기 화 및 통 신 방 법 을 제 공한다.
• 수행의 기본 단위는 UNIX에서처럼 프로세스가 아니라 Win32 쓰레드가 된 다. 프로세스는 하나 이상의 스레드를 포함할 수 있다.
• Win32 함수명은 길고 설명적이다. 예를 들어,아래와 같은 함수명들은
WaitForSingleObject
WaitForS丄ngleObjectEx
WaitForMultipleObject
WaitNamedPipe
W i n 3 2 의 다 양 성 은 물 론 함 수 명의 관 례 를 보 여 주 고 있다. 마 찬 가 지로 , 타 입 명(type name)에도 몇 가지 관례가 있다.
• API가 필요로 하는 미리 정의된 데이터 타입들은 대문자이며 또 설명적이 다. 다음은 자주 사용되는 대표적인 타입들이다.
BOOL (하나의 논리값을 저장하는 32비트 객체로 정의된다)
HANDLE
DWORD (32비트 부호가 없는(unsigned) 정수)
LPTSTR
LPSECURITY_ATTRIBUTES
다른 많은 데이터 타입들은 필요에 따라 소개될 것이다.
• 변수명도 최소한 함수 프로토타입(prototype)에서는 사용 관례가 있다. 예를 들 어 , l p s z F i l e N a m e 은 파 일 명 을 나 타 내 는 0 으 로 끝 나 는 스 트 링에 대 한 long 타입 포인터가 된다. 마찬가지로, fdwAccess는 파일의 접근 플래그를 담 고 있는 3 2 비 트 더 블 워 드 를 나 타 낸 다. 이 와 같은 방 법 을 혼 히 헝 가 리 식 명명법이라 부르는데, 이 책에서는 프로그램 변수로는 일반적으로 사용하지 않는다.
끝으로 Win32는 처음부터 새로 짜진 것이기는 하지만, 윈도우 3.1의 Winl6 A P I와 호 환 성을 유 지 하 고 있다. 이 사 실 은 3 2 비 트 프로 그 램을 하 는 사 람 을 짜 증나게 하는 몇 가지 부작용을 일으킨다.
• 타입에 있어서 시대착오적인 면이 있다. 예를 들어, L P S T R 이나 L P V O I D는 “long pointer"를 의미하는데, 이는 단순히 32비트 포인터를 의미한다. 다른 포인터 타입이 전혀 필요하지 않다.
• 호환성을 유지하기 위해,이 책에서는 사용되지 않는 많은 16비트 함수들이 포함되어 있다. .론 이들도 때에 따라 중요할 수 있다. 예를 들면, OpenFile과 같은 함수가 이에 해당하는데, 이 책에서는 파일을 열 때, CreateRle을 항상 사용
한다.
표준 C 라이브러리: 언제 사용하는가?
Win32만의 유일한 특징이 있기는 하지만, 익숙한 C 프로그래밍언어와 ANSI 표준 C 라이브러리를 이용해서 많은 작업을, 특히 파일 I/O를, 하는 것은 여전 히 가능하다.
그 렇 다 면 , 언 제 C 라 이 브 러 리 가 적 당 하 고 , 언 제 W i n 3 2 시 스 템 콜 을 반 드 시 사 용 하 여 야 하 는 가? 대 답 은 간 단 하 지 안 다. 그 러 나 , 많은 프로 그 래 머 들 은 c 라 이 브 러 리 가 언 제 적 당 하 며 , 언 제 는 적 당 하 지 안 은 가에 대 해 나 름 대 로 ᄂ 지 침을 갖고 있으 며 , 따 라 서 , 같은 지 짐 이 W i n 3 2에 도 적 용 된 다. 또 한 , W i n 3 2 가 기 능 성 능 및 융 통 성 면에 서 개 선 된 것 을 감 안 한 다 면 , c 라 이 브 러 리 를 뛰 어 너무 는 것 이 편리하고 때로는 필수적이라고 할 수 있다.
표 준 C 라 이 브 러 리 는 파 일 과 같은 운 영 체 제 자 원을 관 리 하 는 제 한 된 능 력 을 갖는 함수들을 포함하고 있다. 이 함수들은 간단한 프로그램을 작성하는 데는 대개 적당하다. C 라이브러리를 이용하면 Win32를 배우지 않고도 이식성있는 응용을 작성하는 것이 가능하다. 그러나, 그 이상의 선택의 여지가 별로 없다, 예를 들어,6장에서는 성능과 프로그램의 편의를 위해 메모리에 맵핑된 (memory mapped) 파일을 살펴볼 예정인데, 이와 같은 기능이 C 라이브러리에는 없다.
이 제 부 터 는 간 단 한 순 차 파 일 을 복 사 하 는 프로 그 램을 다 음과 같은 네 개 의 다른 방법으로 구현하는 작은 프로그램들을 살펴보도록 한다.
예제) 순차파일의 복사
순 차 파 일 의 처 리는 어 떤 파 일 시 스 템에 서 도 가 장 간 단 하 고 , 자 주 나 오 며 , 가 장 기 본 적 인 기 능 이 며 , 웬 만 큼 큰 프로 그 램 은 거 의 모 든 경 우 최 소 한몇 개 의 파 일을 순차적으로 처리한다.
파 일 을 갱 신 하 면 서 복 사 하 는 것 과 , 정 렬 된 파 일 을 병 합 하 는 것 은 순 차 파 일 의 처 리 에 서 흔히 나 오 는 것 이 다. 컴 파 일 러 와 문 자 처 리 도 구 들 은 파 일 을 순 차 적으로 접근하는 응용들의 또 다른 예이다.
순 차 파 일 의 처 리 가 개 념 적 으 로 는 간 단 하 지 만 최 적 의 속 도를 보 이 는 효 율 적 인 처 리 를 달 성 하 는 것 은 매 우 어 려 운 일이 다. 왜 냐 하 면 , 이 를 위 해 서는 중 첩 (ovelapped) I/O, 메모리 맵핑,스레드 및 다른 기술들이 필요하기 때문이다.
간 단 한 파 일 복 사 는 그 자 체 만 으 로 는 흥 미 로 운 것 이 아 니 다. 그 러 나 이 프로그램을 비교해 보는 것은 다른 시스템들과 대비하면서 Win32를 소개하는 빠른 방법이 된다. 앞으로 나올 프로그램 예들은 제한된 형태의 UNIX cp 명령을구 현한다. 즉, 명령의 인자로 지정되는 파일명에 따라 하나의 파일을 다른 파일로 복 사 한 다 오 류 검 사 는 최 소 한 으 로 이 루 어 지 며 , 파 일 이 이 미 존 재 하 는 경 우에 는 단순히 덮어쓴다. 뒤에 나오는 Win32 구현 프로그램과 다른 프로그램에서는 이 문제 및 다른 단점들을 해결한다.
UNIX에서의 파일 복사
int main(int argc, char *argv[])
{
int input—fd, output_fd;
ssize_t bytes_in, bytes_out;
char rec[BUF__SIZE];
if (argc != 3) {
printf("Usage: cp filel file2\n"); return 1;
}
input一fd = open(argv[1], O_RDONLY);
if (input_fd == -1) {
perror(argv[1]); return 2;
}
output一fd = open(argv[2], O_WRONLY | 0 CREAT, 0666);
if (output_fd == -1){
perror(argv[2]); return 3;
}
while ((bytes_in = read(input_fd, &rec, BUF_SIZE)) > 0) {
bytes_out = write(output_fd, &rec t bytes_in);
if (bytes_out != bytes_in) {
perror("Fatal write error."); return 4;
}
}
close(input__fd);
close(output_fd);
return 0;
}
이 간단한 프로그램은,Win32에서는 해당되지 않는,UNIX 프로그래밍에서 자주 나오는 가정과 관례들을 어느 정도 보여 주고 있다.
• 오 픈 된 파 일 이 라 는 객 체 를 나 타 내 는 파 일 기 술 자는 단 순 한 정 수 이 다. - 1 은 오류 값으로서 open 작업이 실패했음을 나타낸다.
• r e a d 와 w r i t e 함 수는 처 리 된 바 이 트 수 를 인 자 중 의 하 나로서 가 아 니 라 리턴 값으로 직접 리턴한다. 이것은 프로그램 논리에 있어 중요한 사항이다. 음수가 아닌 값은 성공적인 읽기를 나타내며,0은 파일 끝을 나타낸다.
• c l o s e 함 수 는 I / O 객 체 에 대 해 서 만 적 용 되며 프로 세 스 와 같은 다른 U N I X 객체에 대해서는 적용되지 않는다.
• I / O 는 동 기 식 으 로 이 루 어 지 므로 프로 그 램 은 I / O 작 업 이 완 료 될 때 까 지 진 행 하지 않고 기다린다. UNIX의 비동기 I/O는 시스템 V Release 4와 4.3+ B S D 사 이 에 차 이 가 있다. 동 기 I / O는 큰 파 일 을 처 리 하 는 데는 매 우 비 효 율 적이다.
• 오 류 처 리 는 C 라 이 브 러 리의 p e r r o r 함 수 에 의 존 하 고 있는 데 , 이 함 수는 e r r n o 라는 전 역 변 수 를 읽어 서 U N I X 시 스 템 콜 이 실 패 한 이 유에 대 한 정 보를 얻어낸다.
• C 라 이 브 러 리 의 p r i n t f I / O 함 수는 오 류 메 시 지 를 처 리 하 는 데 유 용 하 며 , Win32 예제에서도 사용한다.
표준 c 라이브러리를 이용한 파일 복사
#include <errno.h>
#define BUF_SIZE 256
int main(int argc, char *argv(1)
{
FILE *in_file, *out_file; char rec[BUF_SIZE);
size_t bytes_in, bytes_out;
if (argc != 3)
{
printf("Usage: cp filel file2\n");
return 1;
}
in_file = fopen(argv[1], "rb");
if (in_file == NULL)
{
perror(argv[1]);
return 2;
}
out_file = fopen(argv[2], "b");
if (out_file == NULL)
{
perror(argy[2]);
return 3;
}
/* Process the input file a record at a time. */
while ((bytes in - fread(rec, 1, BUF_SIZE, in_file)) > 0)
{
bytes_out = fwrite(rec, bytes_in, out_file);
if (bytes_out != bytes_in) {
perror("Fatal write error.");
return 4;
}
}
fclose(in_file);
fclose(out_file);
return 0;
}
UNIX와 C 라이브러리 사이에는 다옴과 같은 세 가지 주요 차이점이 있다.
1. 오 픈 된 파 일 객 체 는 정 수 형 파 일 기 술 자에 의 해 서 가 아 니 라 F I L E 구조 에 대한 포인터에 의해 지정된다. NULL은 부적격(invalid) 값을 나타낸다. 실제에 있어서는 포인터는 열린 파일 객체에 대한 핸들의 형태라고 볼 수 있다.
2. fopen을 호출할 띠ᅵ,파일을 문자 파일로 취급할지 이진 파일로 취급합 지륜 규 정한다. 문자 파일은 줄끝(end of line)과 같은 상황 올 나타내는 시스램 문자들 도 포함한다. 윈도즈를 포함한 많은 시스템에서, 문자 파일에 대한 I/O 작업은 줄 끝 문 자 열 을 C에 서 스 트 링의 끝을 나 타 내 는 n u l l 문 자로 변 환 한 다. 예에 서는 두 파일 모두를 이진 모드로 오픈하였다.
3. 오 류 는 여 기 서는 p e r r o r를 통 해 표 시 된 다. 다 른 방 법 으 로 는 f e r r o r를 사 용 할 수 있는 데 , 이 함 수는 시 스 템 보 다 는 F I L E과 관련 된 오 류 코 드 를 리 턴 하여 준다.
Win32를 이용한 파일 복사
#include <windows.h>
#include <stdio.h>
#define BUF_SIZE 256
int main (int argc, LPTSTR argv)
{
HANDLE hin, hout;
DWORD nin, nout;
CHAR Buffer(BUF_SIZE);
if (argc != 3)
{
printf("Usage: cp filel file2\n");
return 1;
}
hin = CreateFile(argv[1], GENERIC_READ, O, NULL, OPEN EXISTING, NULL);
if (hIn == INVALID_HANDLE_VALUE)
{
printf("Cannot open input file. Error: %x\n", GetLastError();
return 2;
}
hout = CreateFile(argv(2), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hout == INVALID_HANDLE_VALUE)
{
printf("Cannot open output file. Error: %x\n", GetLastError();
return 3;
}
while (ReadFile(hin, Buffer, BUF_SIZE, &nIn, NULL) && non > 0)
{
WriteFile(hout, Buffer, nIn, &nout, NULL);
if (nIn != nout)
{
printf("Fatal write error: $x\n", GetLastError return 4;
}
}
closeHandle(hIn);
closeHandle(hout);
return 0;
}
1. 모든 Win32 함수 정의와 데이터 타입을 포함하는〈windows.h〉는 항상 인클르드된다.
2. 모든 Win32 객체는 HANDLE 타입 변수에 의해 지정되며,하나의 포괄 (generic) 함수인 CloseHandle 함수가 대부분의 객체에 적용된다.
3. Win32는 많은 기호형(symbolic) 상수와 플래그를 정의하고 있다. 그들의
이름은 대개 매우 길며 많은 경우 사용 목적을 기술하고 있다. INVALID_HANDLE_ VALUE와 GENERIC_READ가 대표적 예이다.
4. R e a d F i l e과 W r i t e F i l e 과 같은 함 수는 바 이 트 수 가 아 니 라 이 진 논 리 (Boolean) 값을 리턴하며,바이트 수는 인자 값으로 리턴된다. 이 점이 순환 문의 논 리 를 약 간 변 화 시켰 다.
C r e a t e F i l e 파 일 의 끝 은 바 이 트 수 가 0 인 경우로 감지되며, 작업 실패는 아니다.
5. 시스템 오류 코드는 어느 시점에서나 GetLastError ()를 통해 DWORD로 얻을 수 있다.
6. UNIX에서 접근 허용(permission)을 통해 파일 접근을 제어하는 것은 비교적 간 단 하 다. 윈 도 우 N T는 보 다 강 력 한 보 안 시 스 템을 갖추 고 있 으 며 , 따 라 서, 이를 프로그램하는 것은 좀 더 복잡하다.
7. CreateFile과 같은 함수는 매우 많은 선택 사항을 갖고 있다. 예에서는 디폴트(default) 값을 사용하였다.
'IT & 프로그래밍 > Win32시스템프로그래밍' 카테고리의 다른 글
Win32 파일 시스템과 문자 I/O 사용 (0) | 2022.03.10 |
---|---|
윈도우NT와 윈도우95 (0) | 2022.03.09 |
댓글