| /* |
| * Copyright 1998 Douglas Ridgway |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <windows.h> |
| #include <commdlg.h> |
| #include "resource.h" |
| |
| #include <stdio.h> |
| |
| static HINSTANCE hInst; |
| static HWND hMainWnd; |
| static WCHAR szAppName[5] = {'V','i','e','w',0}; |
| static WCHAR szTitle[MAX_PATH]; |
| static WCHAR szFileTitle[MAX_PATH]; |
| |
| static HMETAFILE hmf; |
| static HENHMETAFILE enhmf; |
| static int deltax = 0, deltay = 0; |
| static int width = 0, height = 0; |
| static BOOL isAldus, isEnhanced; |
| |
| #include "pshpack1.h" |
| typedef struct |
| { |
| DWORD key; |
| WORD hmf; |
| SMALL_RECT bbox; |
| WORD inch; |
| DWORD reserved; |
| WORD checksum; |
| } APMFILEHEADER; |
| #include "poppack.h" |
| |
| #define APMHEADER_KEY 0x9AC6CDD7l |
| |
| |
| static BOOL FileOpen(HWND hWnd, WCHAR *fn, int fnsz) |
| { |
| static const WCHAR filter[] = {'M','e','t','a','f','i','l','e','s','\0','*','.','w','m','f',';','*','.','e','m','f','\0',0}; |
| OPENFILENAMEW ofn = { sizeof(OPENFILENAMEW), |
| 0, 0, NULL, NULL, 0, 0, NULL, |
| fnsz, NULL, 0, NULL, NULL, |
| OFN_SHOWHELP, 0, 0, NULL, 0, NULL }; |
| ofn.lpstrFilter = filter; |
| ofn.hwndOwner = hWnd; |
| ofn.lpstrFile = fn; |
| if( fnsz < 1 ) |
| return FALSE; |
| *fn = 0; |
| return GetOpenFileNameW(&ofn); |
| } |
| |
| static BOOL FileIsEnhanced( LPCWSTR szFileName ) |
| { |
| ENHMETAHEADER enh; |
| HANDLE handle; |
| DWORD size; |
| |
| handle = CreateFileW( szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, |
| NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); |
| if (handle == INVALID_HANDLE_VALUE) |
| return FALSE; |
| |
| if (!ReadFile( handle, &enh, sizeof(ENHMETAHEADER), &size, NULL ) || size != sizeof(ENHMETAHEADER) ) |
| { |
| CloseHandle( handle ); |
| return FALSE; |
| } |
| CloseHandle( handle ); |
| |
| /* Is it enhanced? */ |
| return (enh.dSignature == ENHMETA_SIGNATURE); |
| } |
| |
| static BOOL FileIsPlaceable( LPCWSTR szFileName ) |
| { |
| APMFILEHEADER apmh; |
| HANDLE handle; |
| DWORD size; |
| |
| handle = CreateFileW( szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, |
| NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); |
| if (handle == INVALID_HANDLE_VALUE) |
| return FALSE; |
| |
| if (!ReadFile( handle, &apmh, sizeof(APMFILEHEADER), &size, NULL ) || size != sizeof(APMFILEHEADER)) |
| { |
| CloseHandle( handle ); |
| return FALSE; |
| } |
| CloseHandle( handle ); |
| |
| /* Is it placeable? */ |
| return (apmh.key == APMHEADER_KEY); |
| } |
| |
| static HMETAFILE GetPlaceableMetaFile( LPCWSTR szFileName ) |
| { |
| LPBYTE lpData; |
| METAHEADER mfHeader; |
| APMFILEHEADER APMHeader; |
| HANDLE handle; |
| DWORD size; |
| HMETAFILE hmf; |
| WORD checksum, *p; |
| HDC hdc; |
| int i; |
| |
| handle = CreateFileW( szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, |
| NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); |
| if (handle == INVALID_HANDLE_VALUE) |
| return 0; |
| |
| if (!ReadFile( handle, &APMHeader, sizeof(APMFILEHEADER), &size, NULL ) || size != sizeof(APMFILEHEADER)) |
| { |
| CloseHandle( handle ); |
| return 0; |
| } |
| checksum = 0; |
| p = (WORD *) &APMHeader; |
| |
| for(i=0; i<10; i++) |
| checksum ^= *p++; |
| if (checksum != APMHeader.checksum) { |
| char msg[128]; |
| sprintf(msg, "Computed checksum %04x != stored checksum %04x\n", |
| checksum, APMHeader.checksum); |
| MessageBoxA(hMainWnd, msg, "Checksum failed", MB_OK); |
| CloseHandle( handle ); |
| return 0; |
| } |
| |
| if (!ReadFile( handle, &mfHeader, sizeof(METAHEADER), &size, NULL) || size != sizeof(METAHEADER)) |
| { |
| CloseHandle( handle ); |
| return 0; |
| } |
| |
| if (!(lpData = GlobalAlloc(GPTR, (mfHeader.mtSize * 2L)))) |
| { |
| CloseHandle( handle ); |
| return 0; |
| } |
| |
| SetFilePointer( handle, sizeof(APMFILEHEADER), NULL, FILE_BEGIN ); |
| if (!ReadFile(handle, lpData, mfHeader.mtSize * 2, &size, NULL ) || size != mfHeader.mtSize * 2) |
| { |
| GlobalFree(lpData); |
| CloseHandle( handle ); |
| return 0; |
| } |
| CloseHandle( handle ); |
| |
| if (!(hmf = SetMetaFileBitsEx(mfHeader.mtSize*2, lpData))) { |
| GlobalFree(lpData); |
| return 0; |
| } |
| |
| |
| width = APMHeader.bbox.Right - APMHeader.bbox.Left; |
| height = APMHeader.bbox.Bottom - APMHeader.bbox.Top; |
| |
| /* printf("Ok! width %d height %d inch %d\n", width, height, APMHeader.inch); */ |
| hdc = GetDC(hMainWnd); |
| width = width * GetDeviceCaps(hdc, LOGPIXELSX)/APMHeader.inch; |
| height = height * GetDeviceCaps(hdc,LOGPIXELSY)/APMHeader.inch; |
| ReleaseDC(hMainWnd, hdc); |
| |
| deltax = 0; |
| deltay = 0 ; |
| GlobalFree(lpData); |
| return hmf; |
| } |
| |
| static void DoOpenFile(LPCWSTR filename) |
| { |
| if (!filename) return; |
| |
| isAldus = FileIsPlaceable(filename); |
| if (isAldus) { |
| hmf = GetPlaceableMetaFile(filename); |
| } else { |
| RECT r; |
| isEnhanced = FileIsEnhanced(filename); |
| if (isEnhanced) |
| enhmf = GetEnhMetaFileW(filename); |
| else |
| hmf = GetMetaFileW(filename); |
| GetClientRect(hMainWnd, &r); |
| width = r.right - r.left; |
| height = r.bottom - r.top; |
| } |
| InvalidateRect( hMainWnd, NULL, TRUE ); |
| } |
| |
| static void UpdateWindowCaption(void) |
| { |
| WCHAR szCaption[MAX_PATH]; |
| WCHAR szView[MAX_PATH]; |
| static const WCHAR hyphenW[] = { ' ','-',' ',0 }; |
| |
| LoadStringW(hInst, IDS_DESCRIPTION, szView, sizeof(szView)/sizeof(WCHAR)); |
| |
| if (szFileTitle[0] != '\0') |
| { |
| lstrcpyW(szCaption, szFileTitle); |
| LoadStringW(hInst, IDS_DESCRIPTION, szView, sizeof(szView)/sizeof(WCHAR)); |
| lstrcatW(szCaption, hyphenW); |
| lstrcatW(szCaption, szView); |
| } |
| else |
| lstrcpyW(szCaption, szView); |
| |
| SetWindowTextW(hMainWnd, szCaption); |
| } |
| |
| static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam) |
| { |
| switch (uMessage) |
| { |
| case WM_PAINT: |
| { |
| PAINTSTRUCT ps; |
| BeginPaint(hwnd, &ps); |
| SetMapMode(ps.hdc, MM_ANISOTROPIC); |
| /* Set the window extent to a sane value in case the metafile doesn't */ |
| SetWindowExtEx(ps.hdc, width, height, NULL); |
| SetViewportExtEx(ps.hdc, width, height, NULL); |
| SetViewportOrgEx(ps.hdc, deltax, deltay, NULL); |
| if (isEnhanced && enhmf) |
| { |
| RECT r; |
| GetClientRect(hwnd, &r); |
| PlayEnhMetaFile(ps.hdc, enhmf, &r); |
| } |
| else if (hmf) |
| PlayMetaFile(ps.hdc, hmf); |
| EndPaint(hwnd, &ps); |
| } |
| break; |
| |
| case WM_COMMAND: /* message: command from application menu */ |
| switch (LOWORD(wparam)) |
| { |
| case IDM_OPEN: |
| { |
| WCHAR filename[MAX_PATH]; |
| if (FileOpen(hwnd, filename, sizeof(filename)/sizeof(WCHAR))) |
| { |
| szFileTitle[0] = 0; |
| GetFileTitleW(filename, szFileTitle, sizeof(szFileTitle)/sizeof(WCHAR)); |
| DoOpenFile(filename); |
| UpdateWindowCaption(); |
| } |
| } |
| break; |
| |
| case IDM_SET_EXT_TO_WIN: |
| { |
| RECT r; |
| GetClientRect(hwnd, &r); |
| width = r.right - r.left; |
| height = r.bottom - r.top; |
| deltax = deltay = 0; |
| InvalidateRect( hwnd, NULL, TRUE ); |
| } |
| break; |
| |
| |
| case IDM_LEFT: |
| deltax += 100; |
| InvalidateRect( hwnd, NULL, TRUE ); |
| break; |
| case IDM_RIGHT: |
| deltax -= 100; |
| InvalidateRect( hwnd, NULL, TRUE ); |
| break; |
| case IDM_UP: |
| deltay += 100; |
| InvalidateRect( hwnd, NULL, TRUE ); |
| break; |
| case IDM_DOWN: |
| deltay -= 100; |
| InvalidateRect( hwnd, NULL, TRUE ); |
| break; |
| |
| case IDM_EXIT: |
| DestroyWindow(hwnd); |
| break; |
| |
| default: |
| return DefWindowProcW(hwnd, uMessage, wparam, lparam); |
| } |
| break; |
| |
| case WM_DESTROY: /* message: window being destroyed */ |
| PostQuitMessage(0); |
| break; |
| |
| default: /* Passes it on if unprocessed */ |
| return DefWindowProcW(hwnd, uMessage, wparam, lparam); |
| } |
| return 0; |
| } |
| |
| static BOOL InitApplication(HINSTANCE hInstance) |
| { |
| WNDCLASSEXW wc; |
| |
| /* Load the application description strings */ |
| LoadStringW(hInstance, IDS_DESCRIPTION, szTitle, sizeof(szTitle)/sizeof(WCHAR)); |
| |
| /* Fill in window class structure with parameters that describe the |
| main window */ |
| |
| wc.cbSize = sizeof(WNDCLASSEXW); |
| wc.style = CS_HREDRAW | CS_VREDRAW; /* Class style(s) */ |
| wc.lpfnWndProc = WndProc; /* Window Procedure */ |
| wc.cbClsExtra = 0; /* No per-class extra data */ |
| wc.cbWndExtra = 0; /* No per-window extra data */ |
| wc.hInstance = hInstance; /* Owner of this class */ |
| wc.hIcon = NULL; |
| wc.hIconSm = NULL; |
| wc.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); |
| wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); /* Default color */ |
| wc.lpszMenuName = szAppName; /* Menu name from .rc */ |
| wc.lpszClassName = szAppName; /* Name to register as */ |
| |
| if (!RegisterClassExW(&wc)) return FALSE; |
| |
| /* Call module specific initialization functions here */ |
| |
| return TRUE; |
| } |
| |
| static BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) |
| { |
| /* Save the instance handle in a global variable for later use */ |
| hInst = hInstance; |
| |
| /* Create main window */ |
| hMainWnd = CreateWindowW(szAppName, /* See RegisterClass() call */ |
| szTitle, /* window title */ |
| WS_OVERLAPPEDWINDOW, /* Window style */ |
| CW_USEDEFAULT, 0, /* positioning */ |
| CW_USEDEFAULT, 0, /* size */ |
| NULL, /* Overlapped has no parent */ |
| NULL, /* Use the window class menu */ |
| hInstance, |
| NULL); |
| |
| if (!hMainWnd) |
| return FALSE; |
| |
| /* Call module specific instance initialization functions here */ |
| |
| /* show the window, and paint it for the first time */ |
| ShowWindow(hMainWnd, nCmdShow); |
| UpdateWindow(hMainWnd); |
| |
| return TRUE; |
| } |
| |
| static void HandleCommandLine(LPWSTR cmdline) |
| { |
| /* skip white space */ |
| while (*cmdline == ' ') cmdline++; |
| |
| if (*cmdline) |
| { |
| /* file name is passed on the command line */ |
| if (cmdline[0] == '"') |
| { |
| cmdline++; |
| cmdline[lstrlenW(cmdline) - 1] = 0; |
| } |
| szFileTitle[0] = 0; |
| GetFileTitleW(cmdline, szFileTitle, sizeof(szFileTitle)/sizeof(WCHAR)); |
| DoOpenFile(cmdline); |
| UpdateWindowCaption(); |
| } |
| } |
| |
| int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) |
| { |
| MSG msg; |
| |
| /* Other instances of app running? */ |
| if (!hPrevInstance) |
| { |
| /* stuff to be done once */ |
| if (!InitApplication(hInstance)) |
| { |
| return FALSE; /* exit */ |
| } |
| } |
| |
| /* stuff to be done every time */ |
| if (!InitInstance(hInstance, nCmdShow)) |
| { |
| return FALSE; |
| } |
| |
| HandleCommandLine(lpCmdLine); |
| |
| /* Main loop */ |
| /* Acquire and dispatch messages until a WM_QUIT message is received */ |
| while (GetMessageW(&msg, NULL, 0, 0)) |
| { |
| TranslateMessage(&msg); |
| DispatchMessageW(&msg); |
| } |
| |
| return msg.wParam; |
| } |