1 /* 2 * PROJECT: ReactOS Picture and Fax Viewer 3 * FILE: dll/win32/shimgvw/shimgvw.c 4 * PURPOSE: shimgvw.dll 5 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org) 6 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 7 */ 8 9 #define WIN32_NO_STATUS 10 #define _INC_WINDOWS 11 #define COM_NO_WINDOWS_H 12 13 #include <stdarg.h> 14 15 #include <windef.h> 16 #include <winbase.h> 17 #include <winnls.h> 18 #include <winreg.h> 19 #include <wingdi.h> 20 #include <windowsx.h> 21 #include <objbase.h> 22 #include <commctrl.h> 23 #include <commdlg.h> 24 #include <gdiplus.h> 25 #include <tchar.h> 26 #include <strsafe.h> 27 #include <shlwapi.h> 28 29 #define NDEBUG 30 #include <debug.h> 31 32 #include "shimgvw.h" 33 34 35 HINSTANCE hInstance; 36 SHIMGVW_SETTINGS shiSettings; 37 SHIMGVW_FILENODE *currentFile; 38 GpImage *image; 39 WNDPROC PrevProc = NULL; 40 41 HWND hDispWnd, hToolBar; 42 43 /* zooming */ 44 #define MIN_ZOOM 10 45 #define MAX_ZOOM 1600 46 UINT ZoomPercents = 100; 47 static const UINT ZoomSteps[] = 48 { 49 10, 25, 50, 100, 200, 400, 800, 1600 50 }; 51 52 static void ZoomInOrOut(BOOL bZoomIn) 53 { 54 INT i; 55 56 if (bZoomIn) /* zoom in */ 57 { 58 /* find next step */ 59 for (i = 0; i < ARRAYSIZE(ZoomSteps); ++i) 60 { 61 if (ZoomPercents < ZoomSteps[i]) 62 break; 63 } 64 if (i == ARRAYSIZE(ZoomSteps)) 65 ZoomPercents = MAX_ZOOM; 66 else 67 ZoomPercents = ZoomSteps[i]; 68 69 /* update tool bar buttons */ 70 SendMessage(hToolBar, TB_ENABLEBUTTON, IDC_ZOOMM, TRUE); 71 if (ZoomPercents >= MAX_ZOOM) 72 SendMessage(hToolBar, TB_ENABLEBUTTON, IDC_ZOOMP, FALSE); 73 else 74 SendMessage(hToolBar, TB_ENABLEBUTTON, IDC_ZOOMP, TRUE); 75 } 76 else /* zoom out */ 77 { 78 /* find previous step */ 79 for (i = ARRAYSIZE(ZoomSteps); i > 0; ) 80 { 81 --i; 82 if (ZoomSteps[i] < ZoomPercents) 83 break; 84 } 85 if (i < 0) 86 ZoomPercents = MIN_ZOOM; 87 else 88 ZoomPercents = ZoomSteps[i]; 89 90 /* update tool bar buttons */ 91 SendMessage(hToolBar, TB_ENABLEBUTTON, IDC_ZOOMP, TRUE); 92 if (ZoomPercents <= MIN_ZOOM) 93 SendMessage(hToolBar, TB_ENABLEBUTTON, IDC_ZOOMM, FALSE); 94 else 95 SendMessage(hToolBar, TB_ENABLEBUTTON, IDC_ZOOMM, TRUE); 96 } 97 98 /* redraw */ 99 InvalidateRect(hDispWnd, NULL, TRUE); 100 } 101 102 static void ResetZoom(void) 103 { 104 RECT Rect; 105 UINT ImageWidth, ImageHeight; 106 107 /* get disp window size and image size */ 108 GetClientRect(hDispWnd, &Rect); 109 GdipGetImageWidth(image, &ImageWidth); 110 GdipGetImageHeight(image, &ImageHeight); 111 112 /* compare two aspect rates. same as 113 (ImageHeight / ImageWidth < Rect.bottom / Rect.right) in real */ 114 if (ImageHeight * Rect.right < Rect.bottom * ImageWidth) 115 { 116 if (Rect.right < ImageWidth) 117 { 118 /* it's large, shrink it */ 119 ZoomPercents = (Rect.right * 100) / ImageWidth; 120 } 121 else 122 { 123 /* it's small. show as original size */ 124 ZoomPercents = 100; 125 } 126 } 127 else 128 { 129 if (Rect.bottom < ImageHeight) 130 { 131 /* it's large, shrink it */ 132 ZoomPercents = (Rect.bottom * 100) / ImageHeight; 133 } 134 else 135 { 136 /* it's small. show as original size */ 137 ZoomPercents = 100; 138 } 139 } 140 } 141 142 /* ToolBar Buttons */ 143 static const TBBUTTON Buttons [] = 144 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */ 145 {TBICON_PREV, IDC_PREV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, 146 {TBICON_NEXT, IDC_NEXT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, 147 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0}, 148 {TBICON_ZOOMP, IDC_ZOOMP, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, 149 {TBICON_ZOOMM, IDC_ZOOMM, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, 150 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0}, 151 {TBICON_ROT1, IDC_ROT1, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, 152 {TBICON_ROT2, IDC_ROT2, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, 153 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0}, 154 {TBICON_SAVE, IDC_SAVE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, 155 {TBICON_PRINT, IDC_PRINT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, 156 }; 157 158 static void pLoadImage(LPWSTR szOpenFileName) 159 { 160 /* check file presence */ 161 if (GetFileAttributesW(szOpenFileName) == 0xFFFFFFFF) 162 { 163 DPRINT1("File %s not found!\n", szOpenFileName); 164 return; 165 } 166 167 /* load now */ 168 GdipLoadImageFromFile(szOpenFileName, &image); 169 if (!image) 170 { 171 DPRINT1("GdipLoadImageFromFile() failed\n"); 172 return; 173 } 174 175 /* reset zoom */ 176 ResetZoom(); 177 178 /* redraw */ 179 InvalidateRect(hDispWnd, NULL, TRUE); 180 } 181 182 static void pSaveImageAs(HWND hwnd) 183 { 184 OPENFILENAMEW sfn; 185 ImageCodecInfo *codecInfo; 186 WCHAR szSaveFileName[MAX_PATH]; 187 WCHAR *szFilterMask; 188 GUID rawFormat; 189 UINT num; 190 UINT size; 191 UINT sizeRemain; 192 UINT j; 193 WCHAR *c; 194 195 GdipGetImageEncodersSize(&num, &size); 196 codecInfo = malloc(size); 197 if (!codecInfo) 198 { 199 DPRINT1("malloc() failed in pSaveImageAs()\n"); 200 return; 201 } 202 203 GdipGetImageEncoders(num, size, codecInfo); 204 GdipGetImageRawFormat(image, &rawFormat); 205 206 sizeRemain = 0; 207 208 for (j = 0; j < num; ++j) 209 { 210 // Every pair needs space for the Description, twice the Extensions, 1 char for the space, 2 for the braces and 2 for the NULL terminators. 211 sizeRemain = sizeRemain + (((wcslen(codecInfo[j].FormatDescription) + (wcslen(codecInfo[j].FilenameExtension) * 2) + 5) * sizeof(WCHAR))); 212 } 213 214 /* Add two more chars for the last terminator */ 215 sizeRemain = sizeRemain + (sizeof(WCHAR) * 2); 216 217 szFilterMask = malloc(sizeRemain); 218 if (!szFilterMask) 219 { 220 DPRINT1("cannot allocate memory for filter mask in pSaveImageAs()"); 221 free(codecInfo); 222 return; 223 } 224 225 ZeroMemory(szSaveFileName, sizeof(szSaveFileName)); 226 ZeroMemory(szFilterMask, sizeRemain); 227 ZeroMemory(&sfn, sizeof(sfn)); 228 sfn.lStructSize = sizeof(sfn); 229 sfn.hwndOwner = hwnd; 230 sfn.hInstance = hInstance; 231 sfn.lpstrFile = szSaveFileName; 232 sfn.lpstrFilter = szFilterMask; 233 sfn.nMaxFile = MAX_PATH; 234 sfn.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; 235 236 c = szFilterMask; 237 238 for (j = 0; j < num; ++j) 239 { 240 StringCbPrintfExW(c, sizeRemain, &c, &sizeRemain, 0, L"%ls (%ls)", codecInfo[j].FormatDescription, codecInfo[j].FilenameExtension); 241 242 /* Skip the NULL character */ 243 c++; 244 sizeRemain -= sizeof(*c); 245 246 StringCbPrintfExW(c, sizeRemain, &c, &sizeRemain, 0, L"%ls", codecInfo[j].FilenameExtension); 247 248 /* Skip the NULL character */ 249 c++; 250 sizeRemain -= sizeof(*c); 251 252 if (IsEqualGUID(&rawFormat, &codecInfo[j].FormatID) != FALSE) 253 { 254 sfn.nFilterIndex = j + 1; 255 } 256 } 257 258 if (GetSaveFileNameW(&sfn)) 259 { 260 if (GdipSaveImageToFile(image, szSaveFileName, &codecInfo[sfn.nFilterIndex - 1].Clsid, NULL) != Ok) 261 { 262 DPRINT1("GdipSaveImageToFile() failed\n"); 263 } 264 } 265 266 free(szFilterMask); 267 free(codecInfo); 268 } 269 270 static VOID 271 pLoadImageFromNode(SHIMGVW_FILENODE *node, HWND hwnd) 272 { 273 WCHAR szTitleBuf[800]; 274 WCHAR szResStr[512]; 275 WCHAR *c; 276 277 if (node) 278 { 279 c = wcsrchr(node->FileName, '\\'); 280 if (c) 281 { 282 c++; 283 } 284 285 LoadStringW(hInstance, IDS_APPTITLE, szResStr, ARRAYSIZE(szResStr)); 286 StringCbPrintfW(szTitleBuf, sizeof(szTitleBuf), L"%ls%ls%ls", szResStr, L" - ", c); 287 SetWindowTextW(hwnd, szTitleBuf); 288 289 if (image) 290 { 291 GdipDisposeImage(image); 292 } 293 294 pLoadImage(node->FileName); 295 } 296 } 297 298 static SHIMGVW_FILENODE* 299 pBuildFileList(LPWSTR szFirstFile) 300 { 301 HANDLE hFindHandle; 302 WCHAR *extension; 303 WCHAR szSearchPath[MAX_PATH]; 304 WCHAR szSearchMask[MAX_PATH]; 305 WCHAR szFileTypes[MAX_PATH]; 306 WIN32_FIND_DATAW findData; 307 SHIMGVW_FILENODE *currentNode = NULL; 308 SHIMGVW_FILENODE *root = NULL; 309 SHIMGVW_FILENODE *conductor = NULL; 310 ImageCodecInfo *codecInfo; 311 UINT num; 312 UINT size; 313 UINT j; 314 315 StringCbCopyW(szSearchPath, sizeof(szSearchPath), szFirstFile); 316 PathRemoveFileSpecW(szSearchPath); 317 318 GdipGetImageDecodersSize(&num, &size); 319 codecInfo = malloc(size); 320 if (!codecInfo) 321 { 322 DPRINT1("malloc() failed in pLoadFileList()\n"); 323 return NULL; 324 } 325 326 GdipGetImageDecoders(num, size, codecInfo); 327 328 root = malloc(sizeof(SHIMGVW_FILENODE)); 329 if (!root) 330 { 331 DPRINT1("malloc() failed in pLoadFileList()\n"); 332 free(codecInfo); 333 return NULL; 334 } 335 336 conductor = root; 337 338 for (j = 0; j < num; ++j) 339 { 340 StringCbCopyW(szFileTypes, sizeof(szFileTypes), codecInfo[j].FilenameExtension); 341 342 extension = wcstok(szFileTypes, L";"); 343 while (extension != NULL) 344 { 345 PathCombineW(szSearchMask, szSearchPath, extension); 346 347 hFindHandle = FindFirstFileW(szSearchMask, &findData); 348 if (hFindHandle != INVALID_HANDLE_VALUE) 349 { 350 do 351 { 352 PathCombineW(conductor->FileName, szSearchPath, findData.cFileName); 353 354 // compare the name of the requested file with the one currently found. 355 // if the name matches, the current node is returned by the function. 356 if (wcscmp(szFirstFile, conductor->FileName) == 0) 357 { 358 currentNode = conductor; 359 } 360 361 conductor->Next = malloc(sizeof(SHIMGVW_FILENODE)); 362 363 // if malloc fails, make circular what we have and return it 364 if (!conductor->Next) 365 { 366 DPRINT1("malloc() failed in pLoadFileList()\n"); 367 368 conductor->Next = root; 369 root->Prev = conductor; 370 371 FindClose(hFindHandle); 372 free(codecInfo); 373 return conductor; 374 } 375 376 conductor->Next->Prev = conductor; 377 conductor = conductor->Next; 378 } 379 while (FindNextFileW(hFindHandle, &findData) != 0); 380 381 FindClose(hFindHandle); 382 } 383 384 extension = wcstok(NULL, L";"); 385 } 386 } 387 388 // we now have a node too much in the list. In case the requested file was not found, 389 // we use this node to store the name of it, otherwise we free it. 390 if (currentNode == NULL) 391 { 392 StringCchCopyW(conductor->FileName, MAX_PATH, szFirstFile); 393 currentNode = conductor; 394 } 395 else 396 { 397 conductor = conductor->Prev; 398 free(conductor->Next); 399 } 400 401 // link the last node with the first one to make the list circular 402 conductor->Next = root; 403 root->Prev = conductor; 404 conductor = currentNode; 405 406 free(codecInfo); 407 408 return conductor; 409 } 410 411 static VOID 412 pFreeFileList(SHIMGVW_FILENODE *root) 413 { 414 SHIMGVW_FILENODE *conductor; 415 416 root->Prev->Next = NULL; 417 root->Prev = NULL; 418 419 while (root) 420 { 421 conductor = root; 422 root = conductor->Next; 423 free(conductor); 424 } 425 } 426 427 static VOID 428 ImageView_UpdateWindow(HWND hwnd) 429 { 430 InvalidateRect(hwnd, NULL, FALSE); 431 UpdateWindow(hwnd); 432 } 433 434 static VOID 435 ImageView_DrawImage(HWND hwnd) 436 { 437 GpGraphics *graphics; 438 UINT ImageWidth, ImageHeight; 439 INT ZoomedWidth, ZoomedHeight, x, y; 440 PAINTSTRUCT ps; 441 RECT rect; 442 HDC hdc; 443 444 hdc = BeginPaint(hwnd, &ps); 445 if (!hdc) 446 { 447 DPRINT1("BeginPaint() failed\n"); 448 return; 449 } 450 451 GdipCreateFromHDC(hdc, &graphics); 452 if (!graphics) 453 { 454 DPRINT1("GdipCreateFromHDC() failed\n"); 455 return; 456 } 457 458 GdipGetImageWidth(image, &ImageWidth); 459 GdipGetImageHeight(image, &ImageHeight); 460 461 if (GetClientRect(hwnd, &rect)) 462 { 463 FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); 464 465 ZoomedWidth = (ImageWidth * ZoomPercents) / 100; 466 ZoomedHeight = (ImageHeight * ZoomPercents) / 100; 467 468 x = (rect.right - ZoomedWidth) / 2; 469 y = (rect.bottom - ZoomedHeight) / 2; 470 471 DPRINT("x = %d, y = %d, ImageWidth = %u, ImageHeight = %u\n"); 472 DPRINT("rect.right = %ld, rect.bottom = %ld\n", rect.right, rect.bottom); 473 DPRINT("ZoomPercents = %d, ZoomedWidth = %d, ZoomedHeight = %d\n", 474 ZoomPercents, ZoomedWidth, ZoomedWidth); 475 476 if (ZoomPercents % 100 == 0) 477 { 478 GdipSetInterpolationMode(graphics, InterpolationModeNearestNeighbor); 479 GdipSetSmoothingMode(graphics, SmoothingModeNone); 480 } 481 else 482 { 483 GdipSetInterpolationMode(graphics, InterpolationModeHighQualityBilinear); 484 GdipSetSmoothingMode(graphics, SmoothingModeHighQuality); 485 } 486 487 Rectangle(hdc, x - 1, y - 1, x + ZoomedWidth + 1, y + ZoomedHeight + 1); 488 GdipDrawImageRectI(graphics, image, x, y, ZoomedWidth, ZoomedHeight); 489 } 490 GdipDeleteGraphics(graphics); 491 EndPaint(hwnd, &ps); 492 } 493 494 static BOOL 495 ImageView_LoadSettings() 496 { 497 HKEY hKey; 498 DWORD dwSize; 499 500 if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\shimgvw"), 0, KEY_READ, &hKey) == ERROR_SUCCESS) 501 { 502 dwSize = sizeof(SHIMGVW_SETTINGS); 503 if (RegQueryValueEx(hKey, _T("Settings"), NULL, NULL, (LPBYTE)&shiSettings, &dwSize) == ERROR_SUCCESS) 504 { 505 RegCloseKey(hKey); 506 return TRUE; 507 } 508 509 RegCloseKey(hKey); 510 } 511 512 return FALSE; 513 } 514 515 static VOID 516 ImageView_SaveSettings(HWND hwnd) 517 { 518 WINDOWPLACEMENT wp; 519 HKEY hKey; 520 521 ShowWindow(hwnd, SW_HIDE); 522 wp.length = sizeof(WINDOWPLACEMENT); 523 GetWindowPlacement(hwnd, &wp); 524 525 shiSettings.Left = wp.rcNormalPosition.left; 526 shiSettings.Top = wp.rcNormalPosition.top; 527 shiSettings.Right = wp.rcNormalPosition.right; 528 shiSettings.Bottom = wp.rcNormalPosition.bottom; 529 shiSettings.Maximized = (IsZoomed(hwnd) || (wp.flags & WPF_RESTORETOMAXIMIZED)); 530 531 if (RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\shimgvw"), 0, NULL, 532 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) 533 { 534 RegSetValueEx(hKey, _T("Settings"), 0, REG_BINARY, (LPBYTE)&shiSettings, sizeof(SHIMGVW_SETTINGS)); 535 RegCloseKey(hKey); 536 } 537 } 538 539 static BOOL 540 ImageView_CreateToolBar(HWND hwnd) 541 { 542 INT numButtons = sizeof(Buttons) / sizeof(Buttons[0]); 543 544 hToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, 545 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_BOTTOM | TBSTYLE_TOOLTIPS, 546 0, 0, 0, 0, hwnd, 547 0, hInstance, NULL); 548 if(hToolBar != NULL) 549 { 550 HIMAGELIST hImageList; 551 552 SendMessage(hToolBar, TB_SETEXTENDEDSTYLE, 553 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS); 554 555 SendMessage(hToolBar, TB_BUTTONSTRUCTSIZE, 556 sizeof(Buttons[0]), 0); 557 558 hImageList = ImageList_Create(TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, ILC_MASK | ILC_COLOR24, 1, 1); 559 560 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PREVICON), IMAGE_BITMAP, 561 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255)); 562 563 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_NEXTICON), IMAGE_BITMAP, 564 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255)); 565 566 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ZOOMPICON), IMAGE_BITMAP, 567 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255)); 568 569 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ZOOMMICON), IMAGE_BITMAP, 570 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255)); 571 572 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_SAVEICON), IMAGE_BITMAP, 573 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255)); 574 575 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PRINTICON), IMAGE_BITMAP, 576 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255)); 577 578 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ROT1ICON), IMAGE_BITMAP, 579 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255)); 580 581 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ROT2ICON), IMAGE_BITMAP, 582 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255)); 583 584 if (hImageList == NULL) return FALSE; 585 586 ImageList_Destroy((HIMAGELIST)SendMessage(hToolBar, TB_SETIMAGELIST, 587 0, (LPARAM)hImageList)); 588 589 SendMessage(hToolBar, TB_ADDBUTTONS, 590 numButtons, (LPARAM)Buttons); 591 592 return TRUE; 593 } 594 595 return FALSE; 596 } 597 598 LRESULT CALLBACK 599 ImageView_DispWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) 600 { 601 switch (Message) 602 { 603 case WM_PAINT: 604 { 605 ImageView_DrawImage(hwnd); 606 return 0L; 607 } 608 } 609 return CallWindowProc(PrevProc, hwnd, Message, wParam, lParam); 610 } 611 612 static VOID 613 ImageView_InitControls(HWND hwnd) 614 { 615 MoveWindow(hwnd, shiSettings.Left, shiSettings.Top, 616 shiSettings.Right - shiSettings.Left, 617 shiSettings.Bottom - shiSettings.Top, TRUE); 618 619 if (shiSettings.Maximized) ShowWindow(hwnd, SW_MAXIMIZE); 620 621 hDispWnd = CreateWindowEx(0, WC_STATIC, _T(""), 622 WS_CHILD | WS_VISIBLE, 623 0, 0, 0, 0, hwnd, NULL, hInstance, NULL); 624 625 SetClassLongPtr(hDispWnd, GCL_STYLE, CS_HREDRAW | CS_VREDRAW); 626 PrevProc = (WNDPROC) SetWindowLongPtr(hDispWnd, GWLP_WNDPROC, (LPARAM) ImageView_DispWndProc); 627 628 ImageView_CreateToolBar(hwnd); 629 } 630 631 static VOID 632 ImageView_OnMouseWheel(HWND hwnd, INT x, INT y, INT zDelta, UINT fwKeys) 633 { 634 if (zDelta != 0) 635 { 636 ZoomInOrOut(zDelta > 0); 637 } 638 } 639 640 LRESULT CALLBACK 641 ImageView_WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) 642 { 643 switch (Message) 644 { 645 case WM_CREATE: 646 { 647 ImageView_InitControls(hwnd); 648 return 0L; 649 } 650 651 case WM_KEYDOWN: 652 switch (LOWORD(wParam)) 653 { 654 case VK_LEFT: 655 PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_PREV, BN_CLICKED), (LPARAM)NULL); 656 break; 657 658 case VK_RIGHT: 659 PostMessage(hwnd, WM_COMMAND, MAKEWPARAM(IDC_NEXT, BN_CLICKED), (LPARAM)NULL); 660 break; 661 } 662 break; 663 664 case WM_COMMAND: 665 { 666 switch (wParam) 667 { 668 case IDC_PREV: 669 { 670 currentFile = currentFile->Prev; 671 pLoadImageFromNode(currentFile, hwnd); 672 } 673 674 break; 675 case IDC_NEXT: 676 { 677 currentFile = currentFile->Next; 678 pLoadImageFromNode(currentFile, hwnd); 679 } 680 681 break; 682 case IDC_ZOOMP: 683 { 684 ZoomInOrOut(TRUE); 685 } 686 break; 687 case IDC_ZOOMM: 688 { 689 ZoomInOrOut(FALSE); 690 } 691 break; 692 case IDC_SAVE: 693 pSaveImageAs(hwnd); 694 695 break; 696 case IDC_PRINT: 697 698 break; 699 case IDC_ROT1: 700 { 701 GdipImageRotateFlip(image, Rotate270FlipNone); 702 ImageView_UpdateWindow(hwnd); 703 } 704 705 break; 706 case IDC_ROT2: 707 { 708 GdipImageRotateFlip(image, Rotate90FlipNone); 709 ImageView_UpdateWindow(hwnd); 710 } 711 712 break; 713 } 714 } 715 break; 716 717 case WM_MOUSEWHEEL: 718 ImageView_OnMouseWheel(hwnd, 719 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 720 (SHORT)HIWORD(wParam), (UINT)LOWORD(wParam)); 721 break; 722 723 case WM_NOTIFY: 724 { 725 LPNMHDR pnmhdr = (LPNMHDR)lParam; 726 727 switch (pnmhdr->code) 728 { 729 case TTN_GETDISPINFO: 730 { 731 LPTOOLTIPTEXT lpttt; 732 UINT idButton; 733 734 lpttt = (LPTOOLTIPTEXT)lParam; 735 idButton = (UINT)lpttt->hdr.idFrom; 736 lpttt->hinst = hInstance; 737 738 switch (idButton) 739 { 740 case IDC_PREV: 741 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PREV_PIC); 742 break; 743 case IDC_NEXT: 744 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_NEXT_PIC); 745 break; 746 case IDC_ZOOMP: 747 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_IN); 748 break; 749 case IDC_ZOOMM: 750 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_OUT); 751 break; 752 case IDC_SAVE: 753 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SAVEAS); 754 break; 755 case IDC_PRINT: 756 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PRINT); 757 break; 758 case IDC_ROT1: 759 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ROT_COUNCW); 760 break; 761 case IDC_ROT2: 762 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ROT_CLOCKW); 763 break; 764 } 765 return TRUE; 766 } 767 } 768 break; 769 } 770 case WM_SIZING: 771 { 772 LPRECT pRect = (LPRECT)lParam; 773 if (pRect->right-pRect->left < 350) 774 pRect->right = pRect->left + 350; 775 776 if (pRect->bottom-pRect->top < 290) 777 pRect->bottom = pRect->top + 290; 778 return TRUE; 779 } 780 case WM_SIZE: 781 { 782 RECT rc; 783 SendMessage(hToolBar, TB_AUTOSIZE, 0, 0); 784 GetWindowRect(hToolBar, &rc); 785 MoveWindow(hDispWnd, 1, 1, LOWORD(lParam) - 1, HIWORD(lParam) - (rc.bottom - rc.top) - 1, TRUE); 786 /* is it maximized or restored? */ 787 if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED) 788 { 789 /* reset zoom */ 790 ResetZoom(); 791 } 792 return 0L; 793 } 794 case WM_DESTROY: 795 { 796 ImageView_SaveSettings(hwnd); 797 SetWindowLongPtr(hDispWnd, GWLP_WNDPROC, (LPARAM) PrevProc); 798 PostQuitMessage(0); 799 break; 800 } 801 } 802 803 return DefWindowProc(hwnd, Message, wParam, lParam); 804 } 805 806 LONG WINAPI 807 ImageView_CreateWindow(HWND hwnd, LPWSTR szFileName) 808 { 809 struct GdiplusStartupInput gdiplusStartupInput; 810 ULONG_PTR gdiplusToken; 811 WNDCLASS WndClass = {0}; 812 TCHAR szBuf[512]; 813 WCHAR szInitialFile[MAX_PATH]; 814 HWND hMainWnd; 815 MSG msg; 816 817 if (!ImageView_LoadSettings()) 818 { 819 shiSettings.Maximized = FALSE; 820 shiSettings.Left = 0; 821 shiSettings.Top = 0; 822 shiSettings.Right = 520; 823 shiSettings.Bottom = 400; 824 } 825 826 // Initialize GDI+ 827 gdiplusStartupInput.GdiplusVersion = 1; 828 gdiplusStartupInput.DebugEventCallback = NULL; 829 gdiplusStartupInput.SuppressBackgroundThread = FALSE; 830 gdiplusStartupInput.SuppressExternalCodecs = FALSE; 831 832 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 833 pLoadImage(szFileName); 834 835 // Create the window 836 WndClass.lpszClassName = _T("shimgvw_window"); 837 WndClass.lpfnWndProc = ImageView_WndProc; 838 WndClass.hInstance = hInstance; 839 WndClass.style = CS_HREDRAW | CS_VREDRAW; 840 WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON)); 841 WndClass.hCursor = LoadCursor(hInstance, IDC_ARROW); 842 WndClass.hbrBackground = NULL; /* less flicker */ 843 844 if (!RegisterClass(&WndClass)) return -1; 845 846 LoadString(hInstance, IDS_APPTITLE, szBuf, sizeof(szBuf) / sizeof(TCHAR)); 847 hMainWnd = CreateWindow(_T("shimgvw_window"), szBuf, 848 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CAPTION, 849 CW_USEDEFAULT, CW_USEDEFAULT, 850 0, 0, NULL, NULL, hInstance, NULL); 851 852 // make sure the path has no quotes on it 853 wcscpy(szInitialFile, szFileName); 854 PathUnquoteSpacesW(szInitialFile); 855 856 currentFile = pBuildFileList(szInitialFile); 857 if (currentFile) 858 { 859 pLoadImageFromNode(currentFile, hMainWnd); 860 } 861 862 // Show it 863 ShowWindow(hMainWnd, SW_SHOW); 864 UpdateWindow(hMainWnd); 865 866 // Message Loop 867 while(GetMessage(&msg,NULL,0,0)) 868 { 869 TranslateMessage(&msg); 870 DispatchMessageW(&msg); 871 } 872 873 pFreeFileList(currentFile); 874 875 if (image) 876 GdipDisposeImage(image); 877 GdiplusShutdown(gdiplusToken); 878 return -1; 879 } 880 881 VOID WINAPI 882 ImageView_FullscreenW(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow) 883 { 884 ImageView_CreateWindow(hwnd, (LPWSTR)path); 885 } 886 887 VOID WINAPI 888 ImageView_Fullscreen(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow) 889 { 890 ImageView_CreateWindow(hwnd, (LPWSTR)path); 891 } 892 893 VOID WINAPI 894 ImageView_FullscreenA(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow) 895 { 896 WCHAR szFile[MAX_PATH]; 897 898 if (MultiByteToWideChar(CP_ACP, 0, (char*)path, strlen((char*)path)+1, szFile, MAX_PATH)) 899 { 900 ImageView_CreateWindow(hwnd, (LPWSTR)szFile); 901 } 902 } 903 904 VOID WINAPI 905 ImageView_PrintTo(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow) 906 { 907 DPRINT("ImageView_PrintTo() not implemented\n"); 908 } 909 910 VOID WINAPI 911 ImageView_PrintToA(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow) 912 { 913 DPRINT("ImageView_PrintToA() not implemented\n"); 914 } 915 916 VOID WINAPI 917 ImageView_PrintToW(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow) 918 { 919 DPRINT("ImageView_PrintToW() not implemented\n"); 920 } 921 922 BOOL WINAPI 923 DllMain(IN HINSTANCE hinstDLL, 924 IN DWORD dwReason, 925 IN LPVOID lpvReserved) 926 { 927 switch (dwReason) 928 { 929 case DLL_PROCESS_ATTACH: 930 case DLL_THREAD_ATTACH: 931 hInstance = hinstDLL; 932 break; 933 } 934 935 return TRUE; 936 } 937