#define WIN32_LEAN_AND_MEAN
#include "wmfview.h"
HINSTANCE hInst; // da kommen die Ressourcen her (notfalls externe DLL!)
HMENU hMenu; // Menü des Hauptfensters
HWND hMainWnd; // Gesamt-Containerfenster
HWND hContent; // Baumdiagramm (erst mal nur 2 Ebenen) für Metadatei-Inhalt
HWND hObjects; // Baumdiagramm für Metadatei-Objekte
HWND hShow; // Skalierbare Metadatei-Anzeige
HWND hStatus; // Statuszeile
HWND hToolbar; // Werkzeugleiste
cRECT DiviV; // Vertikaler Teilungsstrich (keine Fenster??)
cRECT DiviH; // Horizontaler Teilungsstrich
POINT OldPos;
UINT DragWhat;
TCHAR MBoxTitle[64];
LPBYTE pLoadedMeta; // Zeiger geladene Metadaten
DWORD lLoadedMeta; // Länge geladene Metadaten
CONFIG Config; // In Registry speicherbare Einstellungen
bool EmfMode;
bool ClipboardMode;
#define WM_CONTINUEINIT (WM_USER+0)
#define WM_OPENFILE (WM_USER+1) // lParam=Dateiname (wParam=Mehrfach-Flag)
#define WM_LOADED (WM_USER+2)
#if !defined(_M_AXP64) && !defined(_M_IA64)
UINT _declspec(naked) _fastcall InitStr(UINT len/*ecx*/, LPVOID buf/*edx*/) {
_asm{ mov eax,ecx
xchg edx,edi
stosd
shr ecx,2
xor eax,eax
dec ecx
rep stosd
xchg edi,edx
ret
}
}
#endif
#ifdef _DEBUG
void _cdecl DebugOut(const char*t, ...) {
char s[256];
lstrcpyA(s+_vsnprintf(s,sizeof(s)-3,t,(va_list)(&t+1)),"\r\n");
OutputDebugStringA(s);
}
#endif
int vMBox(HWND Wnd, LPCTSTR id, UINT style, va_list arglist) {
TCHAR buf1[256],buf2[1024];
if (IS_INTRESOURCE(id)) {
LoadString(hInst,(UINT)(ULONG_PTR)id,buf1,elemof(buf1));
id=buf1;
}
_sntprintf(buf2,elemof(buf2),buf1,arglist);
return MessageBox(Wnd,buf2,MBoxTitle,style);
}
int _cdecl MBox(HWND Wnd, LPCTSTR id, UINT style,...) {
return vMBox(Wnd,id,style,(va_list)(&style+1));
}
static void SetOpt(BYTE NewOpt,BYTE Change=0) {
Change|=Config.fopt^NewOpt; // Sich ändernde Flags merken
Config.fopt=NewOpt; // alle Flags setzen
if (Change&optRecordHead) {
CheckMenuItem(hMenu,0x121,NewOpt&optRecordHead?MF_CHECKED:MF_UNCHECKED);
InvalidateRect(hContent,NULL,TRUE); // Baum neu zeichnen
}
if (Change&optRaw) {
CheckMenuItem(hMenu,0x122,NewOpt&optRaw?MF_CHECKED:MF_UNCHECKED);
PostMessage(hMainWnd,WM_LOADED,0,0); // Alles neu zeichnen
}
}
static void GetReducedClientRect(cRECT*r) {
int yStatus, yToolbar;
GetWindowRect(hStatus,r);
yStatus=r->Height();
GetWindowRect(hToolbar,r);
yToolbar=r->Height();
GetClientRect(hMainWnd,r);
r->top+=yToolbar;
r->bottom-=yStatus;
}
static BYTE ShiftRect(int*r, const int*r2) {
// Hilfsfunktion, schiebt horizontal bzw. vertikal
int ax,dx; // jaja, Assembler
ax=r2[0]-r[0]; // Differenz links bzw. oben
if (!ax) return 0;
if (ax<0) {
dx=r2[2]-r[2]; // Differenz rechts bzw. unten
if (dx>=0) return 0;
if (ax<dx) ax=dx; // die kleinere Zahl
}
r[0]+=ax;
r[2]+=ax;
return ax<0?(BYTE)4:(BYTE)1; // rechts=4, links=1
}
BYTE MoveRectIntoRect(RECT*R, const RECT*R2) {
// Falls R in R2 teilweise oder vollständig außerhalb liegt,
// wird R verschoben und TRUE zurückgeliefert, um maximale Sichtbarkeit
// zu realisieren.
// Dient zum Hineinholen von außerhalb liegenden Fenstern in den Desktop.
return (BYTE)(ShiftRect((PINT)&R->left,(PINT)&R2->left)
+(ShiftRect((PINT)&R->top, (PINT)&R2->top)<<1));
}
static void ReposWindows(bool OnWmSize=false) {
cRECT r;
GetReducedClientRect(&r);
if (OnWmSize) {
static POINT OldSize;
POINT NewSize={r.Width(),r.Height()};
// Teilungsstriche werden auf 1/3 und 1/2 festgelegt, ODER
// Teilungsstriche behalten ihr relatives Maß
if ((unsigned)OldSize.x<10) DiviV.left=NewSize.x/3;
else DiviV.left=r.left+MulDiv(DiviV.left-r.left,NewSize.x,OldSize.x);
if ((unsigned)OldSize.y<10) DiviH.top=NewSize.y/2;
else DiviH.top=r.top+MulDiv(DiviH.top-r.top,NewSize.y,OldSize.y);
DiviV.right=DiviV.left+3;
DiviV.top=r.top;
DiviV.bottom=r.bottom;
DiviH.left=r.left;
DiviH.right=DiviV.left;
DiviH.bottom=DiviH.top+3;
OldSize=NewSize;
}
MoveRectIntoRect(&DiviV,&r);
DiviH.right=DiviV.left;
MoveRectIntoRect(&DiviH,&r);
HDWP hdwp=BeginDeferWindowPos(3);
hdwp=DeferWindowPos(hdwp,hContent,0,r.left,r.top,DiviV.left-r.left,DiviH.top-r.top,SWP_NOZORDER);
hdwp=DeferWindowPos(hdwp,hObjects,0,r.left,DiviH.bottom,DiviV.left,r.bottom-DiviH.bottom,SWP_NOZORDER);
hdwp=DeferWindowPos(hdwp,hShow,0,DiviV.right,r.top,r.right-DiviV.left,r.Height(),SWP_NOZORDER);
EndDeferWindowPos(hdwp);
InvalidateRect(hMainWnd,&DiviV,FALSE);
InvalidateRect(hMainWnd,&DiviH,FALSE);
}
/*
DECODEINFO*GetSelected(void) {
TVITEM item;
item.mask=TVIF_PARAM;
item.hItem=TreeView_GetSelection(hContent);
if (!item.hItem) return NULL;
TreeView_GetItem(hContent,&item);
return (DECODEINFO*)item.lParam;
}
*/
// EMF in Speicher laden
bool LoadEmf(HENHMETAFILE hEMF) {
bool ret=false;
UINT NeedBytes=GetEnhMetaFileBits(hEMF,0,NULL);
if (NeedBytes) {
if (pLoadedMeta) GlobalFree(pLoadedMeta);
pLoadedMeta=(BYTE*)GlobalAlloc(GMEM_FIXED,NeedBytes);
if (pLoadedMeta) {
if (GetEnhMetaFileBits(hEMF,NeedBytes,pLoadedMeta)==NeedBytes) ret=true;;
PostMessage(hMainWnd,WM_LOADED,0,0);
}else MBox(hMainWnd,MAKEINTRESOURCE(6),MB_OK,NeedBytes);
}else MBox(hMainWnd,MAKEINTRESOURCE(5),MB_OK);
return ret;
}
// Datei-Öffnen-Dialog und WM_OPENFILE versenden
void OpenFileDlg() {
OPENFILENAME ofn;
TCHAR FileName[MAX_PATH];
TCHAR Filter[256];
Filter[LoadString(hInst,2,Filter,elemof(Filter)-1)+1]=0;
InitStruct(&ofn,sizeof(ofn));
ofn.hwndOwner=hMainWnd;
ofn.lpstrFilter=Filter;
ofn.lpstrFile=FileName;
ofn.nMaxFile=elemof(FileName);
FileName[0]=0;
ofn.Flags|=OFN_HIDEREADONLY|OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn)) {
HCURSOR hPrevCursor=SetCursor(LoadCursor(0,IDC_WAIT));
SendMessage(hMainWnd,WM_OPENFILE,0,(LPARAM)(LPCTSTR)FileName);
SetCursor(hPrevCursor);
}
}
// Toolbar buttons
static const TBBUTTON buttons[]={
{0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
{STD_FILEOPEN, 0x111, TBSTATE_ENABLED, TBSTYLE_BUTTON,{0,0},0,201},
{STD_PASTE, 0x112, TBSTATE_ENABLED, TBSTYLE_BUTTON},
{0, 0, TBSTATE_ENABLED, TBSTYLE_SEP},
{STD_HELP, 299, TBSTATE_ENABLED, TBSTYLE_BUTTON}
};
static void InitZoomMenu() {
MENUITEMINFO mii;
mii.cbSize=sizeof(mii);
mii.fMask=MIIM_FTYPE|MIIM_STATE;
mii.fType=MFT_RADIOCHECK;
switch (CurZoom) {
case ZOOM_BBOX:
case ZOOM_FRAME: mii.fState=MFS_CHECKED; break;
case ZOOM_BBOX_A:
case ZOOM_BBOX_W:
case ZOOM_FRAME_A:
case ZOOM_FRAME_W: mii.fState=0; break;
case ZOOM_TEXT: mii.fState=MFS_DISABLED; break;
default: mii.fState=MFS_CHECKED|MFS_DISABLED;
}
SetMenuItemInfo(hMenu,0x141,FALSE,&mii);
switch (CurZoom) {
case ZOOM_BBOX_A:
case ZOOM_FRAME_A: mii.fState=MFS_CHECKED; break;
case ZOOM_BBOX:
case ZOOM_BBOX_W:
case ZOOM_FRAME:
case ZOOM_FRAME_W: mii.fState=0; break;
case ZOOM_TEXT: mii.fState=MFS_CHECKED|MFS_DISABLED; break;
default: mii.fState=MFS_DISABLED;
}
SetMenuItemInfo(hMenu,0x142,FALSE,&mii);
switch (CurZoom) {
case ZOOM_BBOX_W:
case ZOOM_FRAME_W: mii.fState=MFS_CHECKED; break;
case ZOOM_BBOX_A:
case ZOOM_BBOX:
case ZOOM_FRAME_A:
case ZOOM_FRAME: mii.fState=0; break;
default: mii.fState=MFS_DISABLED;
}
SetMenuItemInfo(hMenu,0x143,FALSE,&mii);
switch (CurZoom) {
case ZOOM_BBOX:
case ZOOM_BBOX_A:
case ZOOM_BBOX_W: mii.fState=MFS_CHECKED; break;
default: mii.fState=0;
}
SetMenuItemInfo(hMenu,0x144,FALSE,&mii);
switch (CurZoom) {
case ZOOM_FRAME:
case ZOOM_FRAME_A:
case ZOOM_FRAME_W: mii.fState=MFS_CHECKED; break;
default: mii.fState=0;
}
SetMenuItemInfo(hMenu,0x145,FALSE,&mii);
mii.fState=CurZoom==ZOOM_TEXT?MFS_CHECKED:0;
SetMenuItemInfo(hMenu,0x146,FALSE,&mii);
mii.fState=CurZoom==1000?MFS_CHECKED:0;
SetMenuItemInfo(hMenu,0x147,FALSE,&mii);
mii.fState=CanZoom(hShow,ZOOM_UD+1)?0:MFS_DISABLED;
SetMenuItemInfo(hMenu,0x148,FALSE,&mii);
mii.fState=CanZoom(hShow,ZOOM_UD-1)?0:MFS_DISABLED;
SetMenuItemInfo(hMenu,0x149,FALSE,&mii);
mii.fState=CanZoom(hShow,ZOOM_PREV)?0:MFS_DISABLED;
SetMenuItemInfo(hMenu,0x14A,FALSE,&mii);
mii.fState=CanZoom(hShow,ZOOM_NEXT)?0:MFS_DISABLED;
SetMenuItemInfo(hMenu,0x14B,FALSE,&mii);
}
static void HandleZoomMenu(UINT id) {
int zoom=ZOOM_UD; // Kode für: Zoom nicht setzen (nichts tun)
switch (id) {
case 0x141: switch (CurZoom) {
case ZOOM_BBOX_A:
case ZOOM_BBOX_W: zoom=ZOOM_BBOX; break;
case ZOOM_FRAME_A:
case ZOOM_FRAME_W: zoom=ZOOM_FRAME; break;
}break;
case 0x142: switch (CurZoom) {
case ZOOM_BBOX:
case ZOOM_BBOX_W: zoom=ZOOM_BBOX_A; break;
case ZOOM_FRAME:
case ZOOM_FRAME_W: zoom=ZOOM_FRAME_A; break;
}break;
case 0x143: switch (CurZoom) {
case ZOOM_BBOX:
case ZOOM_BBOX_A: zoom=ZOOM_BBOX_W; break;
case ZOOM_FRAME:
case ZOOM_FRAME_A: zoom=ZOOM_FRAME_W; break;
}break;
case 0x144: switch (CurZoom) {
case ZOOM_BBOX_A: break;
case ZOOM_FRAME_A:
case ZOOM_TEXT: zoom=ZOOM_BBOX_A; break;
case ZOOM_BBOX_W: break;
case ZOOM_FRAME_W: zoom=ZOOM_BBOX_W; break;
default: zoom=ZOOM_BBOX;
}break;
case 0x145: switch (CurZoom) {
case ZOOM_FRAME_A: break;
case ZOOM_BBOX_A:
case ZOOM_TEXT: zoom=ZOOM_FRAME_A; break;
case ZOOM_FRAME_W: break;
case ZOOM_BBOX_W: zoom=ZOOM_FRAME_W; break;
default: zoom=ZOOM_FRAME;
}break;
case 0x146: zoom=ZOOM_TEXT; break;
case 0x147: zoom=1000; break;
case 0x148: zoom=ZOOM_UD+1; break;
case 0x149: zoom=ZOOM_UD-1; break;
case 0x14A: zoom=ZOOM_PREV; break;
case 0x14B: zoom=ZOOM_NEXT; break;
}
SetZoom(hShow,zoom);
}
LRESULT CALLBACK MainWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case WM_CREATE: {
LPCREATESTRUCT cs=(LPCREATESTRUCT)lParam;
hMenu=cs->hMenu;
hMainWnd=Wnd;
hContent=CreateWindowEx(WS_EX_CLIENTEDGE,WC_TREEVIEW,NULL,
WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT,
0,0,0,0,Wnd,(HMENU)1,hInst,NULL);
// TreeView_SetUnicodeFormat(hContent,FALSE);
hObjects=CreateWindowEx(WS_EX_CLIENTEDGE,WC_TREEVIEW,NULL,
WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT,
0,0,0,0,Wnd,(HMENU)2,hInst,NULL);
hShow=CreateWindowEx(WS_EX_CLIENTEDGE,T("show"),NULL,
WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|WS_HSCROLL|WS_VSCROLL|WS_CLIPCHILDREN,
0,0,0,0,Wnd,(HMENU)3,hInst,NULL);
hStatus=CreateStatusWindow(WS_CHILD|WS_VISIBLE,NULL,Wnd,4);
static const int widths[]={100,200,350,500,-1};
SendMessage(hStatus,SB_SETPARTS,elemof(widths),(LPARAM)widths);
hToolbar=CreateToolbarEx(Wnd,WS_CHILD|WS_VISIBLE|TBSTYLE_TOOLTIPS,5,
11,HINST_COMMCTRL,IDB_STD_SMALL_COLOR,buttons,elemof(buttons),0,0,0,0,sizeof(TBBUTTON));
SetOpt(3,0xFF);
if (cs->lpCreateParams && *(LPTSTR)cs->lpCreateParams)
SendMessage(Wnd,WM_OPENFILE,0,(LPARAM)cs->lpCreateParams);
}break;
case WM_SIZE:
SendMessage(hStatus,Msg,wParam,lParam);
SendMessage(hToolbar,Msg,wParam,lParam);
if (wParam!=SIZE_MINIMIZED) {
ReposWindows(true);
}break;
case WM_SETCURSOR: if (LOWORD(lParam)==HTCLIENT) {
DWORD p=GetMessagePos();
POINT pt={GET_X_LPARAM(p),GET_Y_LPARAM(p)};
ScreenToClient(Wnd,&pt);
if (PtInRect(&DiviV,pt)) {
SetCursor(LoadCursor(0,IDC_SIZEWE));
return TRUE;
}
if (PtInRect(&DiviH,pt)) {
SetCursor(LoadCursor(0,IDC_SIZENS));
return TRUE;
}
}break;
case WM_LBUTTONDOWN: {
MessageBeep(-1);
POINT NewPos={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
if (PtInRect(&DiviV,NewPos)) {
SetCapture(Wnd);
OldPos=NewPos;
DragWhat=1;
}
if (PtInRect(&DiviH,NewPos)) {
SetCapture(Wnd);
OldPos=NewPos;
DragWhat=2;
}
}break;
case WM_MOUSEMOVE: if (wParam&MK_LBUTTON && GetCapture()==Wnd) {
POINT NewPos={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
switch (DragWhat) {
case 1: {
OffsetRect(&DiviV,NewPos.x-OldPos.x,0);
DiviH.right=DiviV.left;
}break;
case 2: {
OffsetRect(&DiviH,0,NewPos.y-OldPos.y);
}
}
ReposWindows();
OldPos=NewPos;
}break;
case WM_LBUTTONUP: {
ReleaseCapture();
DragWhat=0;
}break;
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(Wnd,&ps);
FillRect(ps.hdc,&DiviV,GetSysColorBrush(COLOR_3DFACE));
FillRect(ps.hdc,&DiviH,GetSysColorBrush(COLOR_3DFACE));
// r.left+=DiviV.right;
// FillRect(ps.hdc,&r,GetStockBrush(WHITE_BRUSH));
EndPaint(Wnd,&ps);
}return FALSE;
case WM_OPENFILE: {
if (Config.fopt&optRaw) {
HANDLE f=CreateFile((LPCTSTR)lParam,
GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0);
if (f==INVALID_HANDLE_VALUE) break;
lLoadedMeta=GetFileSize(f,NULL);
if (pLoadedMeta) GlobalFree(pLoadedMeta);
ClipboardMode=false;
pLoadedMeta=/*new BYTE[lLoadedMeta]; */(BYTE*)GlobalAlloc(GPTR,lLoadedMeta);
if (!pLoadedMeta) {
MBox(Wnd,MAKEINTRESOURCE(6),MB_OK,lLoadedMeta);
break;
}
ReadFile(f,pLoadedMeta,lLoadedMeta,&lLoadedMeta,NULL);
CloseHandle(f);
}else{
HENHMETAFILE hMeta;
hMeta=GetEnhMetaFile((LPCTSTR)lParam);
if (hMeta) {
LoadEmf(hMeta);
DeleteEnhMetaFile(hMeta); // schließt die Datei
}else{
HMETAFILE hMeta;
hMeta=GetMetaFile((LPCTSTR)lParam);
// geht im allgemeinen schief, weil's praktisch nur Placeable Metafiles gibt
if (!hMeta) {
// probieren, ab Dateioffset 22 die Metadatei einzulesen
HANDLE f=CreateFile((LPCTSTR)lParam,
GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,0);
if (f!=INVALID_HANDLE_VALUE) {
DWORD fsize=GetFileSize(f,NULL);
if (fsize>30) {
HANDLE fm=CreateFileMapping(f,NULL,PAGE_READONLY,0,0,NULL);
if (fm) {
const BYTE *p=(const BYTE*)MapViewOfFile(fm,FILE_MAP_READ,0,0,0);
if (p && *(DWORD*)p==0x9AC6CDD7) {
hMeta=SetMetaFileBitsEx(fsize-22,p+22);
}
CloseHandle(fm);
}
}
CloseHandle(f);
}
}
if (hMeta) {
lLoadedMeta=GetMetaFileBitsEx(hMeta,0,NULL);
if (pLoadedMeta) GlobalFree(pLoadedMeta);
ClipboardMode=false;
pLoadedMeta=(BYTE*)GlobalAlloc(GPTR,lLoadedMeta);
if (!pLoadedMeta) {
MBox(Wnd,MAKEINTRESOURCE(6),MB_OK,lLoadedMeta);
break;
}
GetMetaFileBitsEx(hMeta,lLoadedMeta,pLoadedMeta);
DeleteMetaFile(hMeta); // schließt die Datei?
}else MBox(Wnd,MAKEINTRESOURCE(7),MB_OK,lParam);
}
}
PostMessage(Wnd,WM_LOADED,0,0);
}break;
case WM_LOADED: {
// RECT r;
union{
const BYTE *b;
const WORD *w;
const METARECORD *wmr;
const METAHEADER *wmh;
const PLACEABLE_HEADER *pmh;
const METAFILEPICT *mfp;
const ENHMETARECORD *emr;
const ENHMETAHEADER *emh;
}pMetaStart;
const BYTE *pMetaEnd;
SetWindowRedraw(hContent,FALSE);
SetWindowRedraw(hObjects,FALSE);
TreeView_DeleteAllItems(hContent);
TreeView_DeleteAllItems(hObjects);
pMetaStart.b=pLoadedMeta;
pMetaEnd=pLoadedMeta+lLoadedMeta;
if (!pMetaStart.b) break;
EmfMode = pMetaStart.emh->dSignature==ENHMETA_SIGNATURE;
// Typ (WMF, Platzierbares WMF, EMF, EMFplus, SPL, CLP) herausfinden
if (EmfMode) {
rcFrame=pMetaStart.emh->rclBounds;
#if 1
dpi.x=MulDiv(pMetaStart.emh->szlDevice.cx,254,pMetaStart.emh->szlMillimeters.cx*10);
dpi.y=MulDiv(pMetaStart.emh->szlDevice.cy,254,pMetaStart.emh->szlMillimeters.cy*10);
#else
dpi.x=MulDiv(pMetaStart.emh->rclBounds.right-pMetaStart.emh->rclBounds.left,2540,
pMetaStart.emh->rclFrame .right-pMetaStart.emh->rclFrame .left);
dpi.y=MulDiv(pMetaStart.emh->rclBounds.bottom-pMetaStart.emh->rclBounds.top,2540,
pMetaStart.emh->rclFrame .bottom-pMetaStart.emh->rclFrame .top);
#endif
if (Config.fopt&optRaw) { // Hand-Enumeration
for (; pMetaStart.b<pMetaEnd; pMetaStart.b+=pMetaStart.emr->nSize) {
DWORD nSize=pMetaStart.emr->nSize;
if (nSize<8) nSize=8; // trotzdem listen!
MfEnumInternal(EMF_RECORD,pMetaStart.b,nSize);
}
}else{ // Windows enumeriert (reicht _nicht_ die Zeiger durch!)
HENHMETAFILE hMeta;
hMeta=SetEnhMetaFileBits(lLoadedMeta,pLoadedMeta);
EnumEnhMetaFile(0,hMeta,EmfEnumProc,NULL,NULL);
DeleteEnhMetaFile(hMeta);
}
}else{ // WMF - mit diversen Headern
if (ClipboardMode) { // nur für WMF, nicht für EMF
rcFrame.left=0;
rcFrame.top=0;
rcFrame.right=pMetaStart.mfp->xExt;
rcFrame.bottom=pMetaStart.mfp->yExt;
switch (pMetaStart.mfp->mm) {
case MM_HIENGLISH: dpi.y=dpi.x=1000; break;
case MM_HIMETRIC: dpi.y=dpi.x=2540; break;
case MM_LOENGLISH: dpi.y=dpi.x=100; break;
case MM_LOMETRIC: dpi.y=dpi.x=254; break;
case MM_TWIPS: dpi.y=dpi.x=1440; break;
}
MfEnumInternal(WMF_METAFILEPICT,pMetaStart.mfp++,sizeof(METAFILEPICT));
}else if (pMetaStart.pmh->id==PLACEABLE_HEADER_ID) {
rcFrame=pMetaStart.pmh->rcArea;
dpi.y=dpi.x=pMetaStart.pmh->inch;
MfEnumInternal(WMF_PLACEABLE_HEADER,pMetaStart.pmh,sizeof(PLACEABLE_HEADER));
pMetaStart.pmh++;
}
if (Config.fopt&optRaw) { // Hand-Enumeration
MfEnumInternal(WMF_METAHEADER,pMetaStart.wmh,sizeof(METAHEADER));
pMetaStart.wmh++;
for (; pMetaStart.b<pMetaEnd; pMetaStart.w+=pMetaStart.wmr->rdSize) {
DWORD nSize=pMetaStart.wmr->rdSize<<1;
if (nSize<6 || nSize>(size_t)(pMetaEnd-pMetaStart.b)) { // Murks, Rest listen!
MfEnumInternal(WMF_GARBAGE,pMetaStart.b,pMetaEnd-pMetaStart.b);
break;
}
MfEnumInternal(WMF_RECORD,pMetaStart.wmr,nSize);
}
}else{ // Windows enumeriert (als WMF, keine Konvertierung zu EMF)
HMETAFILE hMeta;
hMeta=SetMetaFileBitsEx((UINT)(pMetaEnd-pMetaStart.b),pMetaStart.b);
EnumMetaFile(0,hMeta,WmfEnumProc,0);
DeleteMetaFile(hMeta);
}
}
TCHAR s[32];
s[_sntprintf(s,elemof(s)-1,dpi.x!=dpi.y?T("%d/%d dpi"):T("%d dpi"),dpi.x,dpi.y)]=0;
SendMessage(hStatus,SB_SETTEXT,2,(LPARAM)s);
SetWindowRedraw(hContent,TRUE);
SetWindowRedraw(hObjects,TRUE);
CopyRect(&rcBBox,&rcFrame);
SetZoom(hShow,ZOOM_FRAME); // neu zeichnen lassen
}break;
case WM_DROPFILES: {
TCHAR FileName[MAX_PATH];
HDROP hDrop=(HDROP)wParam; // der Compiler optimiert's schon!
UINT nFiles=DragQueryFile(hDrop,(UINT)-1,NULL,0);
DragQueryFile(hDrop,0,FileName,elemof(FileName));
if (nFiles!=1) MBox(Wnd,MAKEINTRESOURCE(1),MB_OK,FileName);
SendMessage(Wnd,WM_OPENFILE,0,(LPARAM)(LPCTSTR)FileName);
DragFinish(hDrop);
}break;
case WM_COMMAND: switch (LOWORD(wParam)) {
case 0x111: OpenFileDlg(); break;
case 0x112: { // Clipboard WMF
if (OpenClipboard(Wnd)) {
HGLOBAL hMFP;
hMFP=GetClipboardData(CF_METAFILEPICT);
if (hMFP) {
METAFILEPICT *pMFP;
UINT NeedBytes;
pMFP=(METAFILEPICT*)GlobalLock(hMFP);
NeedBytes=GetMetaFileBitsEx(pMFP->hMF,0,NULL);
if (NeedBytes) {
if (pLoadedMeta) GlobalFree(pLoadedMeta);
ClipboardMode=true; // am Anfang ein METAFILEPICT-Header
pLoadedMeta=(BYTE*)GlobalAlloc(GMEM_FIXED,sizeof(METAFILEPICT)+NeedBytes);
if (pLoadedMeta) {
METAFILEPICT *p2=(METAFILEPICT*)pLoadedMeta;
*p2++=*pMFP; // Ganzen Header kopieren
GetMetaFileBitsEx(pMFP->hMF,NeedBytes,p2);
PostMessage(Wnd,WM_LOADED,0,0);
}else MBox(Wnd,MAKEINTRESOURCE(6),MB_OK,sizeof(METAFILEPICT)+NeedBytes);
}else MBox(Wnd,MAKEINTRESOURCE(5),MB_OK);
GlobalUnlock(hMFP);
}else MBox(Wnd,MAKEINTRESOURCE(4),MB_OK);
CloseClipboard();
}else MBox(Wnd,MAKEINTRESOURCE(3),MB_OK);
}break;
case 0x113: { // Clipboard EMF
if (OpenClipboard(Wnd)) {
HENHMETAFILE hEMF;
hEMF=(HENHMETAFILE)GetClipboardData(CF_ENHMETAFILE);
if (hEMF && LoadEmf(hEMF)) ClipboardMode=true;
else MBox(Wnd,MAKEINTRESOURCE(4),MB_OK);
CloseClipboard();
}else MBox(Wnd,MAKEINTRESOURCE(3),MB_OK);
}break;
case 0x11F: SendMessage(Wnd,WM_CLOSE,0,0); break;
case 0x121: SetOpt(Config.fopt^optRecordHead); break;
case 0x122: SetOpt(Config.fopt^optRaw); break;
case 0x123: { // Konvertieren WMF<->EMF mittels SetWinMetafileBits
HENHMETAFILE hMeta;
UINT BytesNeeded;
union{
const BYTE *b;
const METARECORD *wmr;
const METAHEADER *wmh;
const PLACEABLE_HEADER *pmh;
const METAFILEPICT *mfp;
const ENHMETAHEADER *emh;
}pMetaStart;
const BYTE *pMetaEnd=pLoadedMeta+lLoadedMeta;
pMetaStart.b=pLoadedMeta;
if (!pMetaStart.b) break;
if (pMetaStart.emh->dSignature==ENHMETA_SIGNATURE) {
// EMF->WMF:
HDC dc=GetDC(Wnd);
hMeta=SetEnhMetaFileBits(lLoadedMeta,pLoadedMeta);
BytesNeeded=GetWinMetaFileBits(hMeta,0,NULL,MM_ANISOTROPIC,dc);
if (BytesNeeded) {
GlobalFree(pLoadedMeta);
pLoadedMeta=(BYTE*)GlobalAlloc(GMEM_FIXED,BytesNeeded);
GetWinMetaFileBits(hMeta,BytesNeeded,pLoadedMeta,MM_ANISOTROPIC,dc);
lLoadedMeta=BytesNeeded;
}
DeleteEnhMetaFile(hMeta);
ReleaseDC(Wnd,dc);
}else{
// WMF->EMF
METAFILEPICT mfp={MM_ANISOTROPIC,1000,1000};
if (ClipboardMode) {
mfp=*pMetaStart.mfp++;
}else if (pMetaStart.pmh->id==PLACEABLE_HEADER_ID) {
mfp.xExt=pMetaStart.pmh->rcArea.right-pMetaStart.pmh->rcArea.left;
mfp.yExt=pMetaStart.pmh->rcArea.bottom-pMetaStart.pmh->rcArea.top;
pMetaStart.pmh++;
}
hMeta=SetWinMetaFileBits((UINT)(pMetaEnd-pMetaStart.b),pMetaStart.b,0,&mfp);
if (hMeta) {
LoadEmf(hMeta); // macht PostMessage
DeleteEnhMetaFile(hMeta);
}else MBox(Wnd,MAKEINTRESOURCE(8),MB_OK);
}
}break;
case 0x141:
case 0x142:
case 0x143:
case 0x144:
case 0x145:
case 0x146:
case 0x147:
case 0x148:
case 0x149:
case 0x14A:
case 0x14B: HandleZoomMenu(LOWORD(wParam)); break;
}break;
case WM_INITMENU: {
EnableMenuItem(hMenu,0x112,IsClipboardFormatAvailable(CF_METAFILEPICT)?MF_ENABLED:MF_GRAYED);
EnableMenuItem(hMenu,0x113,IsClipboardFormatAvailable(CF_ENHMETAFILE)?MF_ENABLED:MF_GRAYED);
InitZoomMenu();
}break;
case WM_MENUSELECT: {
debug(("MenuSelect: %d",LOWORD(wParam)));
UINT ids[2]={0,LOWORD(wParam)};
if (ids[1]<0x10) ids[1]=(ids[1]<<4)+0x100;
MenuHelp(Msg,wParam,lParam,hMenu,hInst,hStatus,ids);
}break;
#if 1
case WM_NOTIFY: {
#define hdr ((LPNMHDR)lParam)
switch (hdr->idFrom) {
case 1: switch (hdr->code) {
case TVN_GETDISPINFO: {
LPNMTVDISPINFO tvdi=(LPNMTVDISPINFO)lParam;
DECODEINFO*di=(DECODEINFO*)tvdi->item.lParam;
if (EmfMode) {
if (tvdi->item.mask&TVIF_TEXT) {
#ifdef UNICODE
TCHAR buffer[1600];
#else
TCHAR buffer[2048];
#endif
EmfDecodeFunc(di,NULL,buffer,buffer+tvdi->item.cchTextMax);
lstrcpyn(tvdi->item.pszText,buffer,tvdi->item.cchTextMax);
}
if (tvdi->item.mask&TVIF_CHILDREN)
tvdi->item.cChildren=Config.fopt&optRecordHead||di->emr.nSize>8 ? 1 : 0;
}else{
if (tvdi->item.mask&TVIF_TEXT) WmfDecodeFunc(di,NULL,tvdi->item.pszText,tvdi->item.pszText+tvdi->item.cchTextMax);
if (tvdi->item.mask&TVIF_CHILDREN)
tvdi->item.cChildren=Config.fopt&optRecordHead||di->wmr.rdSize>3 ? 1 : 0;
}
}break;
case TVN_ITEMEXPANDING: {
LPNMTREEVIEW tv=(LPNMTREEVIEW)lParam;
if (tv->action==TVE_EXPAND) {
DECODEINFO*di=(DECODEINFO*)tv->itemNew.lParam;
TVINSERTSTRUCT tvis;
TCHAR buf[64];
if (!di) break;
tvis.hParent=tv->itemNew.hItem;
tvis.hInsertAfter=TVI_LAST;
tvis.item.mask=TVIF_TEXT;
tvis.item.pszText=buf;
if (EmfMode) EmfDecodeFunc(di,&tvis,buf,buf+elemof(buf)); // trägt alle Sub-Zeilen ein
else WmfDecodeFunc(di,&tvis,buf,buf+elemof(buf));
}
}break;
case TVN_ITEMEXPANDED: {
LPNMTREEVIEW tv=(LPNMTREEVIEW)lParam;
if (tv->action==TVE_COLLAPSE) {
DECODEINFO*di=(DECODEINFO*)tv->itemNew.lParam;
HTREEITEM Child=TreeView_GetChild(hContent,tv->itemNew.hItem);
HTREEITEM Sibling;
if (!di) break;
for(;Sibling=TreeView_GetNextSibling(hContent,Child),Child;Child=Sibling)
TreeView_DeleteItem(hContent,Child);
}
}break;
case TVN_SELCHANGED: {
LPNMTREEVIEW tv=(LPNMTREEVIEW)lParam;
RECT r;
DECODEINFO *di;
di=(DECODEINFO*)tv->itemOld.lParam;
if (di) di->Flags&=~DI_SELECTED;
di=(DECODEINFO*)tv->itemNew.lParam;
if (di) di->Flags|=DI_SELECTED;
GetClientRect(Wnd,&r);
r.left=DiviV.right;
InvalidateRect(Wnd,&r,TRUE);
}break;
case NM_CUSTOMDRAW: {
NMTVCUSTOMDRAW*cd=(NMTVCUSTOMDRAW*)lParam;
switch (cd->nmcd.dwDrawStage) {
case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW;
case CDDS_ITEMPREPAINT: return CDRF_NOTIFYPOSTPAINT;
case CDDS_ITEMPOSTPAINT: {
TCHAR s[256],*p;
TVITEMEX tv;
tv.mask=TVIF_TEXT;
tv.hItem=(HTREEITEM)cd->nmcd.dwItemSpec;
tv.pszText=s;
tv.cchTextMax=elemof(s);
if (SendMessage(hdr->hwndFrom,TVM_GETITEM,0,(LPARAM)&tv)
&& (p=StrChr(s,'#'))) {
int i;
COLORREF cr;
HBRUSH br,obr;
*--p='0';
p[1]='x';
p[8]=0;
StrToIntEx(p,STIF_SUPPORT_HEX ,&i);
cr=RGB(i>>16,i>>8,i);
br=CreateSolidBrush(cr);
obr=SelectBrush(cd->nmcd.hdc,br);
i=cd->nmcd.rc.bottom-cd->nmcd.rc.top; // Höhe
// Kreis mit Farbfüllung am rechten Rand (besser hinter dem Text, noch besser vor der Farbangabe)
Ellipse(cd->nmcd.hdc,cd->nmcd.rc.right-i+1,cd->nmcd.rc.top+1,cd->nmcd.rc.right-1,cd->nmcd.rc.bottom-1);
SelectBrush(cd->nmcd.hdc,obr);
DeleteBrush(br);
}
}break;
}
}break;
}break;
case 5: // Toolbar
debug(("code=%d",hdr->code));
switch (hdr->code) {
case TBN_GETINFOTIP: {
LPNMTBDISPINFO di=(LPNMTBDISPINFO)lParam;
LoadString(hInst,di->idCommand,di->pszText,di->cchText);
}break;
}break;
}
}break;
#endif
case WM_DESTROY: {
PostQuitMessage(0);
}break;
}
return DefWindowProc(Wnd,Msg,wParam,lParam);
}
void WINAPI WinMainCRTStartup() {
MSG Msg;
WNDCLASSEX wc;
InitStruct(&wc,sizeof(wc));
wc.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
wc.lpfnWndProc=ShowProc;
wc.hInstance=hInst=GetModuleHandle(NULL);
wc.hCursor=LoadCursor(0,IDC_CROSS);
wc.hbrBackground=(HBRUSH)(COLOR_APPWORKSPACE+1);
wc.lpszClassName=T("show");
RegisterClassEx(&wc);
wc.style=CS_DBLCLKS;
wc.lpfnWndProc=MainWndProc;
wc.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(100));
wc.hCursor=LoadCursor(0,IDC_ARROW);
wc.hbrBackground=0;
wc.lpszMenuName=MAKEINTRESOURCE(100);
wc.lpszClassName=T("WmfView");
RegisterClassEx(&wc);
InitCommonControls();
LoadString(hInst,100,MBoxTitle,elemof(MBoxTitle));
hMainWnd=CreateWindowEx(
WS_EX_ACCEPTFILES,
T("WmfView"),MBoxTitle,WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,CW_USEDEFAULT,0,0,0,hInst,
PathGetArgs(GetCommandLine()));
ShowWindow(hMainWnd,SW_SHOWDEFAULT);
while (GetMessage(&Msg,0,0,0)) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
ExitProcess((UINT)Msg.wParam);
}
Detected encoding: ANSI (CP1252) | 4
|
|