Source file: /~heha/hs/wmfview.zip/src/emf.c

#include "wmfview.h"
#include <stdarg.h>

static LPCSTR Enums[]={
 "ALTERNATE=1 WINDING",		//E0
 "TRANSPARENT=1 OPAQUE",	//E1
 "MM_TEXT=1 MM_LOMETRIC MM_HIMETRIC MM_LOENGLISH "
 "MM_HIENGLISH MM_TWIPS MM_ISOTROPIC MM_ANISOTROPIC",	//E2
 "AD_COUNTERCLOCKWISE=1 AD_CLOCKWISE",	//E3
 "RGN_AND=1 RGN_OR RGN_XOR RGN_DIFF RGN_COPY",	//E4
 "TA_LEFT TA_UPDATECP TA_RIGHT TA_CENTER=6 TA_TOP=0 TA_BOTTOM=8 TA_BASELINE=24",	//E5
 "R2_BLACK=1 R2_NOTMERGEPEN R2_MASKNOTPEN R2_NOTCOPYPEN "
 "R2_MASKPENNOT R2_NOT R2_XORPEN R2_NOTMASKPEN "
 "R2_MASKPEN R2_NOTXORPEN R2_NOP R2_MERGENOTPEN "
 "R2_COPYPEN R2_MERGEPENNOT R2_MERGEPEN R2_WHITE",	//E6
 "FW_DONTCARE FW_THIN=100 FW_EXTRALIGHT=200 FW_LIGHT=300 FW_NORMAL=400 "
 "FW_MEDIUM=500 FW_SEMIBOLD=600 FW_BOLD=700 FW_EXTRABOLD=800 FW_HEAVY=900",	//E7
 "FALSE TRUE",	//E8
 "ANSI_CHARSET DEFAULT_CHARSET SYMBOL_CHARSET "
 "MAC_CHARSET=77 "
 "SHIFTJIS_CHARSET=128 HANGEUL_CHARSET JOHAB_CHARSET "
 "GB2312_CHARSET=134 CHINESEBIG5_CHARSET=136 "
 "GREEK_CHARSET=161 TURKISH_CHARSET VIETNAMESE_CHARSET "
 "HEBREW_CHARSET=177 ARABIC_CHARSET "
 "BALTIC_CHARSET=186 RUSSIAN_CHARSET=204 THAI_CHARSET=222 EASTEUROPE_CHARSET=238 "
 "OEM_CHARSET=255",	//E9
 "OUT_DEFAULT_PRECIS OUT_STRING_PRECIS OUT_CHARACTER_PRECIS OUT_STROKE_PRECIS "
 "OUT_TT_PRECIS OUT_DEVICE_PRECIS OUT_RASTER_PRECIS OUT_TT_ONLY_PRECIS "
 "OUT_OUTLINE_PRECIS OUT_SCREEN_OUTLINE_PRECIS OUT_PS_ONLY_PRECIS",	//E10
 "CLIP_DEFAULT_PRECIS CLIP_CHARACTER_PRECIS CLIP_STROKE_PRECIS "
 "CLIP_LH_ANGLES=16 CLIP_TT_ALWAYS=32 CLIP_DFA_DISABLE=48 CLIP_EMBEDDED=64",	//E11
 "DEFAULT_QUALITY DRAFT_QUALITY PROOF_QUALITY NONANTIALIASED_QUALITY "
 "ANTIALIASED_QUALITY CLEARTYPE_QUALITY CLEARTYPE_NATURAL_QUALITY",	//E12
 "DEFAULT_PITCH FIXED_PITCH VARIABLE_PITCH MONO_FONT=8 "
 "FF_ROMAN=16 FF_SWISS=32 FF_MODERN=48 FF_SCRIPT=64 FF_DECORATIVE=80",	//E13
 "FLOODFILLBORDER FLOODFILLSURFACE",	//E14
 "BS_SOLID BS_NULL BS_HATCHED BS_PATTERN "
 "BS_INDEXED BS_DIBPATTERN BS_DIBPATTERNPT BS_PATTERN8X8 "
 "BS_DIBPATTERN8X8 BS_MONOPATTERN",	//E15
 "HS_HORIZONTAL HS_VERTICAL HS_FDIAGONAL HS_BDIAGONAL "
 "HS_CROSS HS_DIAGCROSS",		//E16
 "PS_SOLID PS_DASH PS_DOT PS_DASHDOT "
 "PS_DASHDOTDOT PS_NULL PS_INSIDEFRAME PS_USERSTYLE "
 "PS_ALTERNATE "
 "PS_ENDCAP_SQUARE=256 PS_ENDCAP_FLAT=512 "
 "PS_JOIN_BEVEL=4096 PS_JOIN_MITER=8192 "
 "PS_GEOMETRIC=65536",			//E17
};

int CountBits(unsigned value) {
 int i=sizeof(value)*8,ret=0;
 do{
  if (value&1) ret++;
  value>>=1;
 }while(--i);
 return ret;
}

LPTSTR DecodeEnum(LPSTR CurEnum, unsigned input, LPTSTR buf, LPCTSTR end) {
 LPSTR Names[32],p,q;
 unsigned Values[32],v,bitsneeded;
 int i,j,k,best,bestcount;
// 1. Dekodiere Enum-String in Names[] und Values[]
 for(i=v=0; CurEnum; CurEnum=p, i++,v++) {
  if (i==elemof(Names)) break;
  Names[i]=CurEnum;
  p=StrChrA(CurEnum,' ');
  if (p) *p++=0;	// zerhacken
  q=StrChrA(CurEnum,'=');
  if (q) {
   *q++=0;
   v=StrToIntA(q);
  }
  Values[i]=v;
 }
// 2. Finde "Value" mit den meisten passenden Bits (aber keine zuviel)
 bitsneeded=input;
 do{
  best=-1;
  for (j=bestcount=0; j<i; j++) {
   if (Values[j]&~input) continue;	// ungeeignet, zu viele Bits
   k=CountBits(Values[j]&bitsneeded);	// mindestens 1 Bit ist beizusteuern
   if (bestcount<k) {bestcount=k; best=j;}
   if (Values[j]==bitsneeded) {best=j; break;}	// gefunden (ggf. auch die Null)
  }
  if (best<0) {
   if (!input) bitsneeded=TRUE;
   break;		// nichts gefunden: Zahl anhängen
  }
  ADDBUF SA,Names[best]);
  bitsneeded&=~Values[best];	// Erledigte Bits entfernen
  if (bitsneeded) ADDBUF T("|"));
 }while (bitsneeded);
 if (bitsneeded) ADDBUF T("%u"),input&bitsneeded);
 return buf;
}

LPTSTR DecodeE(LPCSTR EnumNummer, unsigned input, LPTSTR buf, LPCTSTR end) {
 LPSTR s;
 int Nummer;
 if (!IS_INTRESOURCE(EnumNummer)) Nummer=StrToIntA(EnumNummer);
 else Nummer=LOWORD(EnumNummer);
 if ((unsigned)Nummer>=elemof(Enums)) goto fail;
 s=StrDupA(Enums[Nummer]);	// besser: StackAlloc?
 if (!s) goto fail;
 buf=DecodeEnum(s,input,buf,end);
 LocalFree(s);
 return buf;
fail:
 ADDBUF T("%d"),input);
 return buf;
}

int _fltused;

LPTSTR FloatToStr(FLOAT x, int nk, LPTSTR buf, UINT buflen) {
 return buf+_sntprintf(buf,buflen,T("%.*G"),nk,x);
}

static LPCSTR FuncNames[]={
 NULL,
 "Header(RECTL rclBounds,RECTL rclFrame,FOURCC Signature,DWORD Version,Size,nRecords,nHandles,sDesc,DWORD oDesc,nPalEntries,POINT DevPixels,POINT DevMM)",
 "PolyBezier(RECTL rclBounds,nCount,POINT lpPoints[nCount])",
 "Polygon(RECTL rclBounds,nCount,POINT lpPoints[nCount])",
 "Polyline(RECTL rclBounds,nCount,POINT lpPoints[nCount])",
 "PolyBezierTo(RECTL rclBounds,nCount,POINT lpPoints[nCount])",
 "PolylineTo(RECTL rclBounds,nCount,POINT lpPoints[nCount])",
 "PolyPolyline(RECTL rclBounds,nCount,nPoints,nPolyPoints[nCount],POINT lpPoints[nPoints])",
 "PolyPolygon(RECTL rclBounds,nCount,nPoints,nPolyPoints[nCount],POINT pPoints[nPoints])",
 "SetWindowExtEx(nXExtent,nYExtent)",
 "SetWindowOrgEx(X,Y)",
 "SetViewportExtEx(nXExtent,nYExtent)",
 "SetViewportOrgEx(X,Y)",
 "SetBrushOrgEx(nXOrg,nYOrg)",
 "Eof(nPalEntries,offPalEntries,nSizeLast)",
 "SetPixelV(X,Y,COLORREF crColor)",
 "SetMapperFlags(unsigned dwFlag)",
 "SetMapMode(E2 fnMapMode)",
 "SetBkMode(E1 iBkMode)",
 "SetPolyFillMode(E0 iPolyFillMode)",
 "SetRop2(E6 fnDrawMode)",
 "SetStretchBltMode(iStretchMode)",
 "SetTextAlign(E5 fMode)",
 "SetColorAdjustment(COLORADJUSTMENT*lpca)",
 "SetTextColor(COLORREF crColor)",
 "SetBkColor(COLORREF crColor)",
 "OffsetClipRgn(nXOffset,nYOffset)",
 "MoveToEx(X,Y)",
 "SetMetaRgn()",
 "ExcludeClipRect(iLeft,iTop,iRight,iBottom)",
 "IntersectClipRect(iLeft,iTop,iRight,iBottom)",
 "ScaleViewportExtEx(XNum,XDenom,YNum,YDenom)",
 "ScaleWindowExtEx(XNum,XDenom,YNum,YDenom)",
 "SaveDC()",
 "RestoreDC(nSaveDC)",
 "SetWorldTransform(FLOAT eM11,FLOAT eM12,FLOAT eM21,FLOAT eM22,FLOAT eDx,FLOAT eDy)",
 "ModifyWorldTransform(FLOAT eM11,FLOAT eM12,FLOAT eM21,FLOAT eM22,FLOAT eDx,FLOAT eDy,iMode)",
 "SelectObject(OBJIDX objidx)",
 "CreatePen(OBJIDX objidx,E17 fnPenStyle,WidthX,WidthY,COLORREF crColor)",
 "CreateBrushIndirect(OBJIDX objidx,E15 lbStyle,COLORREF lbColor,E16 lbHatch)",
 "DeleteObject(OBJIDX objidx)",
 "AngleArc(X,Y,Radius,FLOAT StartAngle,FLOAT EndAngle)",
 "Ellipse(iLeft,iTop,iRight,iBottom)",
 "Rectangle(iLeft,iTop,iRight,iBottom)",
 "RoundRect(iLeft,iTop,iRight,iBottom,iWidth,iHeight)",
 "Arc(iLeft,iTop,iRight,iBottom,iXStart,iYStart,iXEnd,iYEnd)",
 "Chord(iLeft,iTop,iRight,iBottom,iXStart,iYStart,iXEnd,iYEnd)",
 "Pie(iLeft,iTop,iRight,iBottom,iXStart,iYStart,iXEnd,iYEnd)",
 "SelectPalette",
 "CreatePalette",
 "SetPaletteEntries",
 "ResizePalette",
 "RealizePalette",
 "ExtFloodFill(nXStart,nYStart,COLORREF crColor,E14 fuFillType)",
 "LineTo(X,Y)",
 "ArcTo(iLeft,iTop,iRight,iBottom,iXStart,iYStart,iXEnd,iYEnd)",
 "PolyDraw(POINT pPoints[],BYTE nPolyPoints[nCount],nCount)",
 "SetArcDirection(E3 ArcDirection)",
 "SetMiterLimit(FLOAT MiterLimit)",
 "BeginPath()",
 "EndPath()",
 "CloseFigure()",
 "FillPath(RECTL rclBounds)",
 "StrokeAndFillPath(RECTL rclBounds)",
 "StrokePath(RECTL rclBounds)",
 "FlattenPath()",
 "WidenPath()",
 "SelectClipPath(E4 iClipMode)",
 "AbortPath()",
 NULL,
 "GdiComment(cbSize,BYTE lpData[cbSize])",
 "FillRgn",
 "FrameRgn",
 "InvertRgn",
 "PaintRgn",
 "ExtSelectClipRgn",
 "BitBlt",
 "StretchBlt",
 "MaskBlt",
 "PlgBlt",
 "SetDIBitsToDevice",
 "StretchDIBits",
 "CreateFont(OBJIDX objidx,lfHeight,lfWidth,FIX1 lfEscapement,FIX1 lfOrientation,"
	"E7 lfWeight,EB8 lfItalic,EB8 lfUnderline,EB8 lfStrikeOut,EB9 lfCharSet,"
	"EB10 lfOutPrecision,EB11 lfClipPrecision,EB12 lfQuality,EB13 lfPitchAndFamily,"
	"WCHAR lfFaceName[32],"
	"WCHAR elfFullName[64],WCHAR elfStyle[32],DWORD elfVersion,elfStyleSize,"
	"elfMatch,elfReserved,DWORD elfVendorId,elfCulture,"
	"BYTE bFamilyType,BYTE bSerifStyle,BYTE bWeight,BYTE bProportion,"
	"BYTE bContrast,BYTE bStrokeVariation,BYTE bArmStyle,BYTE bLetterform,"
	"BYTE bMidline,BYTE bXHeight)",
 "ExtTextOutA",
 "ExtTextOutW(RECTL rclBounds,iGraphicsMode,FLOAT exScale,FLOAT eyScale,"
	"POINT ptlReference,nChars,offString,fOptions,RECTL rcl,offDx,"
	"WCHAR text[nChars],spacing[nChars])",
 "PolyBezier16(RECTL rclBounds,cPoints,POINTS points[cPoints])",
 "Polygon16(RECTL rclBounds,cPoints,POINTS points[cPoints])",
 "PolyLine16(RECTL rclBounds,cPoints,POINTS points[cPoints])",
 "PolyBezierTo16(RECTL rclBounds,cPoints,POINTS points[cPoints])",
 "PolylineTo16(RECTL rclBounds,cPoints,POINTS points[cPoints])",
 "PolyPolyline16",
 "PolyPolygon16",
 "PolyDraw16",
 "CreateMonoBrush(OBJIDX objidx,iUsage,offBmi,cbBmi,offBits,cbBits)",
 "CreateDIBPatternBrushPt",
 "ExtCreatePen(OBJIDX objidx,offBmi,cbBmi,offBits,cbBits,E17 elpPenStyle,elpWidth,E15 elpBrushStyle,COLORREF elpColor,E16 elpHatch,elpNumEntries,elpStyleEntry[1])",
 "PolyTextOutA",
 "PolyTextOutW",
 "SetICMMode",
 "CreateColorSpace",
 "SetColorSpace",
 "DeleteColorSpace",
 "GlsRecord",
 "GlsBoundedRecord",
 "PixelFormat",
 "Reserved_105",
 "Reserved_106",
 "Reserved_107",
 "Reserved_108",
 "Reserved_109",
 "Reserved_110",
 "ColorCorrectPalette",
 "SetICMProfileA",
 "SetICMProfileW",
 "AlphaBlend",
 "SetLayout",
 "TransparentBlt",
 "Reserved_117",
 "GradientFill",
 "Reserved_119",
 "Reserved_120",
 "ColorMatchToTargetW",
 "CreateColorSpaceW(LOGCOLORSPACE*colspace)"};

#define MAXARGS 40
#if 0
// volle Unicode-Unterstützung!
static LPTSTR escapestr(LPTSTR buf, LPCTSTR end, LPCWSTR s, int slen, bool ZeroTerminated) {
 WCHAR c;
 for(;slen;slen--,s++) {
  LPTSTR fmt;
  switch (c=*s) {
   case 0: if (ZeroTerminated) return buf; goto p; // nullterminiert (anzeigen)
   case '\r': c='r'; goto o;
   case '\n': c='n'; goto o;
   case '\a': c='a'; goto o;
   case '\v': c='v'; goto o;
   case '\t': c='t'; goto o;
   case '"':
   case '\\':
o:  fmt=T("\\%c"); break;
   default: if (c<0x20) {
p:  fmt=T("\\x%02X");
#ifndef UNICODE
   }else if (c>=256) {
    fmt=T("\\u%04X");
#endif
   }else fmt=T("%c");
  }
  ADDBUF fmt,c);
 }
 return buf;
}
#endif

void _stdcall EmfDecodeFunc(DECODEINFO*di, TVINSERTSTRUCT*pChildInsert, LPTSTR buf, LPCTSTR end) {
 LPSTR p,q,pType,pName,pArray,pNext,s=NULL;
 LPTSTR pBuf=buf;
 CHAR pointertype;
 DWORD hexval, *pParam=di->emr.dParm, *pParamEnd;
 int i,/*ParmIdx=0,*/ArgIdx,ArrIdx,ArrLen;
 LPSTR aNames[MAXARGS];	// Merker für INT-Argumente (=Längen)
 long aValues[MAXARGS];

 if (di->emr.iType<elemof(FuncNames)) {
  s=(LPSTR)FuncNames[di->emr.iType];
  if (s) s=StrDupA(s);	// denn StrDup() liefert "" für NULL (anders als strdup())
 }
 if (!s) {
  if (!pChildInsert) ADDBUF T("unknown: nSize=0x%X iType=0x%X"),
    di->emr.nSize,di->emr.iType);
 }else{
  p=StrChrA(s,'(');
  if (p) {
   *p++=0;	// jetzt ist <s>=Funktionsname und <p> Parameterliste
   q=StrChrA(p,')');
   if (q) *q++=0;	// q zeigt hinter die schließende Klammer (= künftig Extra-Info)
  }
  if (pChildInsert) {
   if (Config.fopt&optRecordHead) {
    ADDBUF T("nSize=0x%X, iType=0x%X (") SA T(")"),di->emr.nSize,di->emr.iType,s);
    TreeView_InsertItem(hContent,pChildInsert); buf=pBuf;
   }
  }else{
   ADDBUF SA T("("),s);
  }
  for (pType=p,ArgIdx=0; pType && *pType; pType=pNext,ArgIdx++) {
   pNext=StrChrA(pType,',');
   if (pNext) *pNext++=0;	// zerhacken
   pName=StrPBrkA(pType,"* ");
   if (pName) {
    pointertype=*pName;		// '*' == Zeiger
    *pName++=0;			// zerhacken, pName zeigt auf Name
   }else{
    pName=pType;		// ohne Typangabe nur Name
    pType=NULL;			// Typ immer <int>
    pointertype=0;		// kein Zeiger
   }
   pArray=StrChrA(pName,'[');
   if (pArray) {
    *pArray++=0;		// zerhacken, pArray zeigt auf Längen-Name
    pointertype='*';		// immer Zeigertyp
    p=StrChrA(pArray,']');
    if (p) *p=0;		// ohne ']' geht die Welt nicht
   }
   aNames[ArgIdx]=pName;
   aValues[ArgIdx]=*pParam;
   ArrLen=1;
   if (pointertype=='*') {
    ArrLen=StrToIntA(pArray);	// für feste Längen
    if (!ArrLen) {		// dann muss es ein Name sein, der vorher vorkam
     for (i=0; i<ArgIdx; i++) {	// der eigene Arrayname kommt nicht in Betracht!
      if (!lstrcmpA(pArray,aNames[i])) {
       ArrLen=aValues[i];	// da ist die Länge!
       break;
      }
     }
    }
   }
   for (ArrIdx=0; ArrIdx<ArrLen; ArrIdx++) {
    pBuf=buf;		// für ChildInsert, aber auch bei langen Listen immer von vorn anfangen
    if (pChildInsert){
     ADDBUF
       pointertype=='*' && lstrcmpA(pType,"WCHAR") ? SA T("[%d] = ") : SA T(" = "),
       pName,ArrIdx);	// Name oder Name+Index ausgeben
    }else if (!lstrcmpA(pType,"RECTL")) {
// verwirrende BoundingBox mancher Funktionen gar nicht ausgeben!
     pParam+=4;
     goto ignoreparam;
    }
    if (!lstrcmpA(pType,"COLORREF")) {
     COLORREF cr=*pParam++;
     ADDBUF T("#%02X%02X%02X"),GetRValue(cr),GetGValue(cr),GetBValue(cr));
    }else if (!lstrcmpA(pType,"FLOAT")) {
     hexval=*pParam++;
     buf=FloatToStr(*(const FLOAT*)&hexval,3,buf,260);
     goto AddHex;
    }else if (!lstrcmpA(pType,"RECTL")) {
     VADDBUF T("(%d,%d,%d,%d)"),(va_list)pParam);
     pParam+=4;
    }else if (pType && *pType=='E') {
     pType++;
     if (*pType=='B') {
      pType++;
      hexval=*((PBYTE)pParam)++;
     }else{
      hexval=*(PDWORD)pParam++;
     }
     buf=DecodeE(pType,hexval,buf,end);
// Enum zusätzlich als Hexzahl ausgeben
     goto AddHex;
    }else if (!lstrcmpA(pType,"POINT")) {
     if (!di->nPoints) {	// ersten Punkt gefunden: Punktliste einbauen
      di->nPoints=ArrLen;
      di->PointList.pl=(POINTL*)pParam;
     }
     VADDBUF T("(%d,%d)"),(va_list)pParam);
     pParam+=2;
    }else if (!lstrcmpA(pType,"POINTS")) {
     if (!di->nPoints) {	// ersten Punkt gefunden: Punktliste einbauen
      di->nPoints=ArrLen;
      di->PointList.ps=(POINTS*)pParam;
      di->Flags|=DI_POINTS;
     }
     ADDBUF T("(%d,%d)"),(short)LOWORD(*pParam),(short)HIWORD(*pParam));
     pParam++;
    }else if (!lstrcmpA(pType,"DWORD")) {	// hexadezimal ausgeben
     ADDBUF T("0x%X"),*pParam);
     pParam++;
    }else if (!lstrcmpA(pType,"BYTE")) {
     hexval=*((PBYTE)pParam)++;
     ADDBUF T("%d"),hexval);	// nur positiv
     goto AddHex2;
    }else if (!lstrcmpA(pType,"WCHAR")) {
     ADDBUF T("\""));
     buf=EscapeStr(buf,end,(LPCSTR)pParam,ArrLen,ES_WIDECHAR);
     ADDBUF T("\""));
     pParam+=(ArrLen+1)>>1;
     ArrLen=1;
    }else if (!lstrcmpA(pType,"FOURCC")) {
     ADDBUF T("'"));
     *((LPDWORD)buf)++=*pParam++;
     ADDBUF T("'"));
AddHex:		// Hexzahl auch dann ausgeben, wenn <10 (dann ohne Präfix)
     if (pChildInsert && hexval<10) ADDBUF T(" (%d)"),hexval);
     goto AddHex2;
    }else{	// Integer blank (dezimal)
     hexval=*pParam++;
     ADDBUF T("%d"),hexval);
AddHex2:	// Hexzahl ausgeben, wenn >=10
     if (pChildInsert && hexval>=10) ADDBUF T(" (0x%X)"),hexval);
    }
// Einsame X/Y-Koordinate als Punkt (später)
    if (pChildInsert) {	// Zeile ausgeben
     TreeView_InsertItem(hContent,pChildInsert); buf=pBuf;
    }else{	// anhängen (wenn's nicht zu viel ist)
     if (ArrLen>4) buf=pBuf;
    }
   }/* Skalar oder Array abgearbeitet */
   if (!pChildInsert) {
    if (ArrLen>4) ADDBUF T("..."));	// ausgelassene Zahlen
    if (pNext && *pNext) ADDBUF T(","));// nächstes Argument
   }
ignoreparam:;
  }/* Parameterliste abgearbeitet */
  if (!pChildInsert) ADDBUF T(")"));
  LocalFree(s);
 }
// "Halbe" DWORDs ignorieren (übergehen) - hier: immer /4 teilbare Adressen!
 pParam=(PDWORD)(((ULONG_PTR)pParam+3)&~3);
// Überschüssige DWORDs listen!
 pParamEnd=(PDWORD)((PBYTE)&di->emr+di->emr.nSize);
// ArrLen=(long)((di->mr.nSize-8)>>2);
 if (pChildInsert) for (; pParam<pParamEnd; pParam++) {
  ADDBUF T("dParm[%d] = %d (0x%X)"),pParam-di->emr.dParm,*pParam,*pParam);
  TreeView_InsertItem(hContent,pChildInsert); buf=pBuf;
 }
// Zu lange Daten anzeigen!
 if (pParam>pParamEnd) {
  if (pChildInsert) {
   ADDBUF T("!!! nSize too short by %X DWORDs !!!"),pParam-pParamEnd);
   TreeView_InsertItem(hContent,pChildInsert);
  }else ADDBUF T(" !"));
 }
}


// Füllt die Baumansicht mit Items (ohne String-Generierung) und hinterlegt
// jedes Element mit einer Kopie des Meta-Records (anders geht es nicht,
// wenn man EnumMetaFile() verwendet!)
// Alles weitere ist Sache von Callback-Routinen
int _stdcall EmfEnumProc(HDC dc, HANDLETABLE *ht, const ENHMETARECORD *mr,
  int cObj, LPARAM lParam) {
 DWORD nSize=mr->nSize;
 if (nSize<8) nSize=8;		// trotzdem listen!
 return MfEnumInternal(EMF_RECORD,mr,nSize);
}

#if 0
typedef union{
 struct{
  DWORD key;
  WORD hmf;
  POINTS bbox[2];
  WORD inch;
  DWORD reserved;
  WORD checksum;
 };
 WORD xorwords[10];
}PMF;	// Platzierbare Metadatei

LPCTSTR PathFindExtensionNoBug(LPCTSTR p) {
 LPCTSTR r=PathFindExtension(p);
 if (r==PathFindFileName(p)) r=p+lstrlen(p);
 return r;
}

int mainCRTStartup(void) {
 OPENFILENAME ofn;
 TCHAR fname[MAX_PATH];
// HANDLE h;
 HENHMETAFILE hMeta;
// LPMETAFILEPICT mfp;
// HFILE hf;
// PMF pmf;
 HDC dc=NULL;
// int i;
// LPTSTR p;
// DWORD cb;
 
 hStdOut=GetStdHandle(STD_OUTPUT_HANDLE);
 InitStruct(&ofn,sizeof(ofn));
 ofn.lpstrFile=fname;
 ofn.nMaxFile=elemof(fname);
 ofn.Flags=OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
 while (GetOpenFileName(&ofn)) {
  hMeta=GetEnhMetaFile(fname);
  EnumEnhMetaFile(dc,hMeta,EnumProc,NULL,NULL);
  DeleteEnhMetaFile(hMeta);
#if 0
   h=(HANDLE)GetMetaFileBitsEx(CloseMetaFile(dc),(UINT)GlobalSize(clip),mfp);
   pmf.bbox[1].x=(short)mfp->xExt;
   pmf.bbox[1].y=(short)mfp->yExt;
   switch (mfp->mm) {
    case MM_LOMETRIC:  pmf.inch= 254; break;	//10 Punkte pro mm = 254 pro Zoll}
    case MM_HIMETRIC:  pmf.inch=2540; break;	//100 Punkte pro mm = 2540 pro Zoll}
    case MM_LOENGLISH: pmf.inch= 100; break;	//100 Punkte pro Zoll}
    case MM_HIENGLISH: pmf.inch=1000; break;	//1000 Punkte pro Zoll}
    case MM_TWIPS:     pmf.inch=1440; break;	//1/20 von 1/72 Zoll = 1440 pro Zoll}
    case MM_ANISOTROPIC:			//WinWord...???}
    case MM_ISOTROPIC: pmf.inch=MulDiv(pmf.inch,254,10);
   }
   pmf.checksum=0;
   for (i=0; i<elemof(pmf.xorwords); i++) {
    pmf.checksum^=pmf.xorwords[i];
   }
   GlobalUnlock(clip);
   hf=_lcreat(fname,0);
   _lwrite(hf,(LPCCH)&pmf,sizeof(pmf));
   _hwrite(hf,GlobalLock(h),GlobalSize(h));
   _lclose(hf);
   GlobalUnlock(h);
   GlobalFree(h);
   if (MessageBox(0,"Gespeichert.\nWiederholung?","OK",
     MB_ICONQUESTION|MB_YESNO)!=IDYES) return 0;
  }else{
   MessageBox(0,"Keine Metadatei in der Zwischenablage!",NULL,0);
  }
  CloseClipboard();
#endif
 }
 return 0;
}

#endif
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded