나.MetaEnum

예제 다운로드

메타 레코드를 열거하는 방법에 대해 알아 보았는데 이 함수들을 응용하면 메타 파일의 구조를 상세히 살펴볼 수 있는 유틸리티 정도는 쉽게 만들 수 있다. 다음 예제는 메타 파일의 레코드를 순서대로 열거하면서 하나씩 출력해 보인다.

HWND hList;
int delay;
int count;
char arMetaRecord[][30]={"","Header", "PolyBezier","Polygon","PolyLine","PolyBezierTo",			// 0
	"PolyLineTo","PolyPolyLine","PolyPolygon","SetWindowExtEx","SetWindowOrgEx",				// 6
	"SetViewPortExtEx","SetViewportOrgEx","SetBrushOrgEx","EOF","SetPixelV",					// 11
	"SetMapperFlags","SetMapMode","SetBkMode","SetPolyFillMode","SetRop2",						// 16
	"SetStretchBltMode","SetTextAlign","SetColorAdjustment","SetTextColor","SetBkColor",		// 21
	"OffsetClipRgn","MoveToEx","SetMetaRgn","ExcldueClipRect","IntersectClipRect",				// 26
	"ScaleViewportExtEx","ScaleWindowExtEx","SaveDC","ResotreDC","SetWorldTransform",			// 31
	"ModifyWorldTransForm","SelectObject","CreatePen","CreateBrushIndirect","DeleteObject",		// 36
	"AngleArc","Ellipse","Rectangle","RoundRect","Arc",											// 41
	"Chord","Pie","SelectPalette","CreatePalette","SetPaletteEntries",							// 46
	"ResizePalette","RealizePalette","ExtFloodFill","LineTo","ArcTo",							// 51
	"PolyDraw","SetArcDirection","SetMiterLimit","BeginPath","EndPath",							// 56
	"CloseFigure","FillPath","StrokeAndFillPath","StrokePath","FlattenPath",					// 61
	"WidenPath","SelectClipPath","AboartPath","EMPTY","GdiComment",								// 66
	"FillRgn","FrameRgn","InvertRgn","PaintRgn","ExtSelectClipRgn",								// 71
	"BitBlt","StretchBlt","MaskBlt","PlgBlt","SetDibitsToDevice",								// 76
	"StretchDIBits","ExtCreateFontIndirectW","ExtTextOutA","ExtTextOutW","PolyBezier16",		// 81
	"Polygon16","PolyLine16","PolyBezierTo16","PolyLineTo16","PolyPolyLine16",					// 86
	"PolyPolygon16","PolyDraw16","CreateMonoBrush","CreateDINPatternBrushPt","ExtCreatePen",	// 91
	"PolyTextOutA","PolyTextOutW","SetICMMode","CreateColorSpace","SetColorSpace",				// 96
	"DeleteColorSpace","GLSRecord","GLSBoundedRecord","PixelFormat","DrawEscape",				// 101
	"ExtEscape","StartDoc","SmallTextOut","ForceUfiMapping","NamedEscape",						// 106
	"ColorCorrectPalette","SetICMProfileA","SetICMProfileW","AlphaBlend","AlphaDibBlend",		// 111
	"TransparentBlt","TransparentDIB","GradientFill","SetLinkedUfis","SetTextjustification"		// 116
};

int CALLBACK EnhMetaFileProc(HDC hDC, HANDLETABLE *lpHTable, CONST ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData)
{
	char str[255], sParm[128];
	POINT pt;
	int idx, i;

	// 메타 레코드 출력
	wsprintf(str,"%d-%s(%d), 인수=",
		count,arMetaRecord[lpEMFR->iType], lpEMFR->nSize);

	// 인수를 조사하되 최대 6개까지만 조사한다.
	// nSize가 DWORD 단위이므로 4로 나누어 주었고 iType,nSize의 길이도 포함되므로 2를 빼주었다.
	for (i=0;i<int(lpEMFR->nSize)/4-2;i++) {
		if (i == 6)
			break;
		wsprintf(sParm,"%d,",lpEMFR->dParm[i]);
		strcat(str,sParm);
	}
	str[lstrlen(str)-1]=0;

	// 리스트 박스에 메타 레코드 출력
	idx=SendMessage(hList,LB_ADDSTRING,0,(LPARAM)str);
	SendMessage(hList,LB_SETCURSEL,idx,0);
	UpdateWindow(hList);
	count++;

	// 메타 레코드 재생
	PlayEnhMetaFileRecord(hDC,lpHTable,lpEMFR,nObj);
	Sleep(delay);

	// 커서가 0,0으로 이동하면 중지한다.
	GetCursorPos(&pt);
	if (pt.x==0 && pt.y==0) {
		if (MessageBox(hWndMain,"메타 파일 열거를 중지하시겠습니까?","질문",MB_YESNO) == IDYES) {
			return 0;
		} else {
			return 1;
		}
	} else {
		return 1;
	}
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	OPENFILENAME ofn;
	TCHAR szFileName[MAX_PATH];
	HENHMETAFILE hEnh;
	RECT rt;

	switch(iMessage) {
	case WM_CREATE:
		hList=CreateWindow("listbox",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER | 
			LBS_NOTIFY | WS_VSCROLL,10,50,400,600,hWnd,(HMENU)0,g_hInst,NULL);
		CreateWindow("button","파일 열기",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
			20,10,100,25,hWnd,(HMENU)1,g_hInst,NULL);
		CreateWindow("static","지연시간",WS_CHILD | WS_VISIBLE,
			140,13,100,25,hWnd,(HMENU)-1,g_hInst,NULL);
		CreateWindow("edit",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NUMBER,
			220,10,100,25,hWnd,(HMENU)2,g_hInst,NULL);
		SetDlgItemInt(hWnd,2,1,FALSE);
		return 0;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case 1:
			hdc=GetDC(hWnd);
			// 출력하고자 하는 메타 파일의 핸들을 구한다.
			szFileName[0]=0;
			memset(&ofn, 0, sizeof(OPENFILENAME));
			ofn.lStructSize=sizeof(OPENFILENAME);
			ofn.hwndOwner=hWnd;
			ofn.lpstrFilter="Meta File\0*.?MF\0";
			ofn.nFilterIndex=1;
			ofn.lpstrFile=szFileName;
			ofn.nMaxFile=MAX_PATH;

			if (GetOpenFileName(&ofn) != 0) {
				// 32비트 메타 파일의 핸들을 구해 재생한다.
				hEnh=ReadMeta(szFileName);
				if (hEnh==NULL)
					return 0;
				GetClientRect(hWnd, &rt);
				rt.left += 420;
				SendMessage(hList,LB_RESETCONTENT,0,0);
				count=1;
				delay=GetDlgItemInt(hWnd,2,NULL,FALSE);
				InvalidateRect(hWnd,NULL,TRUE);
				UpdateWindow(hWnd);
				//PlayEnhMetaFile(hdc, hEnh, &rt);
				EnumEnhMetaFile(hdc,hEnh,EnhMetaFileProc,NULL,&rt);
				DeleteEnhMetaFile(hEnh);
			}
			ReleaseDC(hWnd, hdc);
			break;
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

 

앞에서 작성한 ReadMeta 함수와 포맷 변경 함수들이 포함되어 있으며 arMetaRecord 배열에는 메타 레코드의 목록을 문자열로 작성해 놓았다. WndProc에서는 메타 열거에 필요한 컨트롤을 생성하고 파일 열기 버튼을 눌렀을 때 메타 파일을 열어 열거를 시작한다. 이때 메타 레코드를 출력할 영역은 리스트 박스의 오른쪽 영역으로 지정하였다.
콜백 함수에서는 메타 레코드를 분석하여 문자열 형태로 바꾼 후 그 인수와 함께 리스트 박스로 출력해 준다. 단, 인수의 수가 무한정 많을 수 있으므로 인수는 최대 6개까지만 조사한다. 그리고 PlayEnhMetaRecord 함수로 방금 읽은 메타 레코드를 출력하되 Sleep문으로 적당히 시간을 끌어 개별 레코드가 출력되는 모양을 천천히 살펴볼 수 있도록 하였다. 실행중의 모습은 다음과 같다.



특별히 어려운 기술이 포함된 예제는 아니므로 분석하거나 응용하기에 큰 무리는 없을 것이다. 메타 레코드 재생중에 레코드의 사본을 만들어 살짝 변경한 후 출력한다거나 특정한 타입의 레코드만 제외하는 것도 물론 가능하다. 그러나 이 예제는 그런 용도보다는 단순히 메타 파일의 구조를 좀 더 비주얼하게 살펴볼 수 있다는 데 의미가 있는 것 같다. 메타 파일의 구조를 좀 더 상세하게 보고 싶다면 일러스트레이터같은 전문 그래픽 툴의 도움을 받을 수도 있다.


목록 보기  다음 강좌            written by http://www.winapi.co.kr