view.c 11.4 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
  if (!(hmf = SetMetaFileBitsEx(mfHeader.mtSize*2, lpData))) {
    GlobalFree(lpData);
171
    return 0;
172
  }
173 174 175 176 177 178


  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);  */
179
  hdc = GetDC(hMainWnd);
180 181
  width = width * GetDeviceCaps(hdc, LOGPIXELSX)/APMHeader.inch;
  height = height * GetDeviceCaps(hdc,LOGPIXELSY)/APMHeader.inch;
182
  ReleaseDC(hMainWnd, hdc);
183 184 185

  deltax = 0;
  deltay = 0 ;
186
  GlobalFree(lpData);
187 188 189
  return hmf;
}

190
static void DoOpenFile(LPCWSTR filename)
191 192 193 194 195 196 197 198 199 200
{
  if (!filename) return;

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

211 212 213 214 215 216
static void UpdateWindowCaption(void)
{
  WCHAR szCaption[MAX_PATH];
  WCHAR szView[MAX_PATH];
  static const WCHAR hyphenW[] = { ' ','-',' ',0 };

217
  LoadStringW(hInst, IDS_DESCRIPTION, szView, ARRAY_SIZE(szView));
218 219 220 221

  if (szFileTitle[0] != '\0')
  {
    lstrcpyW(szCaption, szFileTitle);
222
    LoadStringW(hInst, IDS_DESCRIPTION, szView, ARRAY_SIZE(szView));
223 224 225 226 227 228 229 230 231
    lstrcatW(szCaption, hyphenW);
    lstrcatW(szCaption, szView);
  }
  else
    lstrcpyW(szCaption, szView);

  SetWindowTextW(hMainWnd, szCaption);
}

232
static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
Alexandre Julliard's avatar
Alexandre Julliard committed
233 234 235
{
  switch (uMessage)
    {
236
    case WM_PAINT:
Alexandre Julliard's avatar
Alexandre Julliard committed
237
      {
238
	PAINTSTRUCT ps;
Alexandre Julliard's avatar
Alexandre Julliard committed
239 240
	BeginPaint(hwnd, &ps);
	SetMapMode(ps.hdc, MM_ANISOTROPIC);
241 242
	/* 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
243
	SetViewportExtEx(ps.hdc, width, height, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
244
	SetViewportOrgEx(ps.hdc, deltax, deltay, NULL);
245 246 247 248 249 250 251 252
       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
253 254 255 256 257
	EndPaint(hwnd, &ps);
      }
      break;

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

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

284

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

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

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

static BOOL InitApplication(HINSTANCE hInstance)
{
323
  WNDCLASSEXW wc;
324 325

  /* Load the application description strings */
326
  LoadStringW(hInstance, IDS_DESCRIPTION, szTitle, ARRAY_SIZE(szTitle));
327 328 329 330

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

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

344
  if (!RegisterClassExW(&wc)) return FALSE;
345 346 347 348 349 350 351 352 353 354 355 356

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

    /* Call module specific instance initialization functions here */

    /* show the window, and paint it for the first time */
373 374
    ShowWindow(hMainWnd, nCmdShow);
    UpdateWindow(hMainWnd);
375 376 377 378

    return TRUE;
}

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

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

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

419
    HandleCommandLine(lpCmdLine);
420

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

    return msg.wParam;
}