view.c 11.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * 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
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 18
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
19
#include <windows.h>
20
#include <commdlg.h>
21
#include "resource.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
22

Alexandre Julliard's avatar
Alexandre Julliard committed
23
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
24

25
static HINSTANCE hInst;
26
static HWND hMainWnd;
27
static WCHAR szAppName[5] = {'V','i','e','w',0};
28 29
static WCHAR szTitle[MAX_PATH];
static WCHAR szFileTitle[MAX_PATH];
30 31

static HMETAFILE hmf;
32
static HENHMETAFILE enhmf;
33 34
static int deltax = 0, deltay = 0;
static int width = 0, height = 0;
35
static BOOL isAldus, isEnhanced;
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

#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

Alexandre Julliard's avatar
Alexandre Julliard committed
51

52
static BOOL FileOpen(HWND hWnd, WCHAR *fn, int fnsz)
Alexandre Julliard's avatar
Alexandre Julliard committed
53
{
54 55 56 57 58 59
  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;
Alexandre Julliard's avatar
Alexandre Julliard committed
60 61
  ofn.hwndOwner = hWnd;
  ofn.lpstrFile = fn;
62 63 64
  if( fnsz < 1 )
    return FALSE;
  *fn = 0;
65
  return GetOpenFileNameW(&ofn);
Alexandre Julliard's avatar
Alexandre Julliard committed
66 67
}

68
static BOOL FileIsEnhanced( LPCWSTR szFileName )
69 70
{
  ENHMETAHEADER enh;
71 72
  HANDLE handle;
  DWORD size;
73

74 75 76
  handle = CreateFileW( szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
  if (handle == INVALID_HANDLE_VALUE)
77 78
    return FALSE;

79 80 81
  if (!ReadFile( handle, &enh, sizeof(ENHMETAHEADER), &size, NULL ) || size != sizeof(ENHMETAHEADER) )
  {
      CloseHandle( handle );
82
      return FALSE;
83 84
  }
  CloseHandle( handle );
85 86 87 88 89

  /* Is it enhanced? */
  return (enh.dSignature == ENHMETA_SIGNATURE);
}

90
static BOOL FileIsPlaceable( LPCWSTR szFileName )
91 92
{
  APMFILEHEADER	apmh;
93 94
  HANDLE handle;
  DWORD size;
95

96 97 98
  handle = CreateFileW( szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
  if (handle == INVALID_HANDLE_VALUE)
99 100
    return FALSE;

101 102 103
  if (!ReadFile( handle, &apmh, sizeof(APMFILEHEADER), &size, NULL ) || size != sizeof(APMFILEHEADER))
  {
      CloseHandle( handle );
104
      return FALSE;
105 106
  }
  CloseHandle( handle );
107 108 109 110 111

  /* Is it placeable? */
  return (apmh.key == APMHEADER_KEY);
}

112
static HMETAFILE GetPlaceableMetaFile( LPCWSTR szFileName )
113 114 115 116
{
  LPBYTE lpData;
  METAHEADER mfHeader;
  APMFILEHEADER	APMHeader;
117 118
  HANDLE handle;
  DWORD size;
119 120 121 122 123
  HMETAFILE hmf;
  WORD checksum, *p;
  HDC hdc;
  int i;

124 125 126 127 128 129 130 131 132 133
  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;
  }
134 135 136 137 138 139 140 141 142
  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);
143 144
    MessageBoxA(hMainWnd, msg, "Checksum failed", MB_OK);
    CloseHandle( handle );
145 146 147
    return 0;
  }

148 149 150 151 152
  if (!ReadFile( handle, &mfHeader, sizeof(METAHEADER), &size, NULL) || size != sizeof(METAHEADER))
  {
      CloseHandle( handle );
      return 0;
  }
153

154 155 156 157 158
  if (!(lpData = GlobalAlloc(GPTR, (mfHeader.mtSize * 2L))))
  {
      CloseHandle( handle );
      return 0;
  }
159

160 161
  SetFilePointer( handle, sizeof(APMFILEHEADER), NULL, FILE_BEGIN );
  if (!ReadFile(handle, lpData, mfHeader.mtSize * 2, &size, NULL ) || size != mfHeader.mtSize * 2)
162
  {
163
    GlobalFree(lpData);
164
    CloseHandle( handle );
165 166
    return 0;
  }
167
  CloseHandle( handle );
168 169 170 171 172 173 174 175 176

  if (!(hmf = SetMetaFileBitsEx(mfHeader.mtSize*2, 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);  */
177
  hdc = GetDC(hMainWnd);
178 179
  width = width * GetDeviceCaps(hdc, LOGPIXELSX)/APMHeader.inch;
  height = height * GetDeviceCaps(hdc,LOGPIXELSY)/APMHeader.inch;
180
  ReleaseDC(hMainWnd, hdc);
181 182 183 184 185 186

  deltax = 0;
  deltay = 0 ;
  return hmf;
}

187
static void DoOpenFile(LPCWSTR filename)
188 189 190 191 192 193 194 195 196 197
{
  if (!filename) return;

  isAldus = FileIsPlaceable(filename);
  if (isAldus) {
    hmf = GetPlaceableMetaFile(filename);
  } else {
    RECT r;
    isEnhanced = FileIsEnhanced(filename);
    if (isEnhanced)
198
       enhmf = GetEnhMetaFileW(filename);
199
    else
200
       hmf = GetMetaFileW(filename);
201 202 203 204 205 206
    GetClientRect(hMainWnd, &r);
    width = r.right - r.left;
    height = r.bottom - r.top;
  }
  InvalidateRect( hMainWnd, NULL, TRUE );
}
Alexandre Julliard's avatar
Alexandre Julliard committed
207

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
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);
}

229
static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
Alexandre Julliard's avatar
Alexandre Julliard committed
230 231 232
{
  switch (uMessage)
    {
233
    case WM_PAINT:
Alexandre Julliard's avatar
Alexandre Julliard committed
234
      {
235
	PAINTSTRUCT ps;
Alexandre Julliard's avatar
Alexandre Julliard committed
236 237
	BeginPaint(hwnd, &ps);
	SetMapMode(ps.hdc, MM_ANISOTROPIC);
238 239
	/* Set the window extent to a sane value in case the metafile doesn't */
	SetWindowExtEx(ps.hdc, width, height, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
240
	SetViewportExtEx(ps.hdc, width, height, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
241
	SetViewportOrgEx(ps.hdc, deltax, deltay, NULL);
242 243 244 245 246 247 248 249
       if (isEnhanced && enhmf)
       {
           RECT r;
           GetClientRect(hwnd, &r);
           PlayEnhMetaFile(ps.hdc, enhmf, &r);
       }
       else if (hmf)
           PlayMetaFile(ps.hdc, hmf);
Alexandre Julliard's avatar
Alexandre Julliard committed
250 251 252 253 254
	EndPaint(hwnd, &ps);
      }
      break;

    case WM_COMMAND: /* message: command from application menu */
255
        switch (LOWORD(wparam))
Alexandre Julliard's avatar
Alexandre Julliard committed
256 257 258
	{
	case IDM_OPEN:
	  {
259 260
              WCHAR filename[MAX_PATH];
              if (FileOpen(hwnd, filename, sizeof(filename)/sizeof(WCHAR)))
261 262 263
              {
                  szFileTitle[0] = 0;
                  GetFileTitleW(filename, szFileTitle, sizeof(szFileTitle));
264
                  DoOpenFile(filename);
265 266
                  UpdateWindowCaption();
              }
Alexandre Julliard's avatar
Alexandre Julliard committed
267 268
	  }
	  break;
269

Alexandre Julliard's avatar
Alexandre Julliard committed
270 271 272 273 274 275
	case IDM_SET_EXT_TO_WIN:
	  {
	    RECT r;
	    GetClientRect(hwnd, &r);
	    width = r.right - r.left;
	    height = r.bottom - r.top;
276
	    deltax = deltay = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
277 278 279 280
	    InvalidateRect( hwnd, NULL, TRUE );
	  }
	  break;

281

Alexandre Julliard's avatar
Alexandre Julliard committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	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:
304
	  return DefWindowProcW(hwnd, uMessage, wparam, lparam);
Alexandre Julliard's avatar
Alexandre Julliard committed
305 306 307 308 309 310 311
	}
      break;

    case WM_DESTROY:  /* message: window being destroyed */
      PostQuitMessage(0);
      break;

Francois Gouget's avatar
Francois Gouget committed
312
    default:          /* Passes it on if unprocessed */
313
      return DefWindowProcW(hwnd, uMessage, wparam, lparam);
Alexandre Julliard's avatar
Alexandre Julliard committed
314 315 316
    }
    return 0;
}
317 318 319

static BOOL InitApplication(HINSTANCE hInstance)
{
320
  WNDCLASSEXW wc;
321 322

  /* Load the application description strings */
323
  LoadStringW(hInstance, IDS_DESCRIPTION, szTitle, sizeof(szTitle)/sizeof(WCHAR));
324 325 326 327

  /* Fill in window class structure with parameters that describe the
     main window */

328
  wc.cbSize        = sizeof(WNDCLASSEXW);
329 330 331 332 333
  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 */
334 335
  wc.hIcon         = NULL;
  wc.hIconSm       = NULL;
336
  wc.hCursor       = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
337 338 339 340
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);           /* Default color */
  wc.lpszMenuName  = szAppName;                       /* Menu name from .rc */
  wc.lpszClassName = szAppName;                      /* Name to register as */

341
  if (!RegisterClassExW(&wc)) return FALSE;
342 343 344 345 346 347 348 349 350 351 352 353

  /* 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 */
354
    hMainWnd = CreateWindowW(szAppName,          /* See RegisterClass() call */
355 356 357 358 359 360 361 362 363 364
                            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)
365 366 367 368 369
        return FALSE;

    /* Call module specific instance initialization functions here */

    /* show the window, and paint it for the first time */
370 371
    ShowWindow(hMainWnd, nCmdShow);
    UpdateWindow(hMainWnd);
372 373 374 375

    return TRUE;
}

376
static void HandleCommandLine(LPWSTR cmdline)
377 378 379 380 381 382 383 384 385 386
{
    /* skip white space */
    while (*cmdline == ' ') cmdline++;

    if (*cmdline)
    {
        /* file name is passed on the command line */
        if (cmdline[0] == '"')
        {
            cmdline++;
387
            cmdline[lstrlenW(cmdline) - 1] = 0;
388
        }
389 390
        szFileTitle[0] = 0;
        GetFileTitleW(cmdline, szFileTitle, sizeof(szFileTitle));
391
        DoOpenFile(cmdline);
392
        UpdateWindowCaption();
393 394 395
    }
}

396
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
{
    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;
    }

416
    HandleCommandLine(lpCmdLine);
417

418 419
    /* Main loop */
    /* Acquire and dispatch messages until a WM_QUIT message is received */
420
    while (GetMessageW(&msg, NULL, 0, 0))
421
    {
422 423
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
424 425 426 427
    }

    return msg.wParam;
}