/*++ Copyright (c) 1996 Microsoft Corporation Module Name: faxview.c Abstract: This file implements a simple TIFF image viewer. Environment: WIN32 User Mode Author: Wesley Witt (wesw) 17-Feb-1996 --*/ #include #include #include #include #include #include #include "resource.h" #include "tifflib.h" #include "faxutil.h" #define WM_OPEN_FILE (WM_USER + 501) #define WM_VIEW_REFRESH (WM_USER + 503) #define WM_VIEW_CLOSE (WM_USER + 504) #define TOP 0 #define LEFT 1 #define BOTTOM 2 #define RIGHT 3 #define SEPHEIGHT 7 #define FILLORDER_LSB2MSB 2 typedef struct _TOOLBAR_STATE { ULONG Id; BOOL State; LPSTR Msg; } TOOLBAR_STATE, *PTOOLBAR_STATE; // // globals // LPBYTE bmiBuf[sizeof(BITMAPINFOHEADER)+(sizeof(RGBQUAD)*2)]; PBITMAPINFO bmi = (PBITMAPINFO) bmiBuf; TIFF_INFO TiffInfo; HWND hwndMain; HWND hwndView; HWND hwndEdit; HWND hwndCoolbar; HWND hwndTooltip; HMENU hMenu; HMENU hMenuZoom; HANDLE hTiff; LPBYTE TiffData; DWORD TiffDataSize; DWORD TiffDataLinesAlloc; DWORD CxScreen; DWORD CyScreen; DWORD CxClient; DWORD CyClient; DWORD ScrollWidth; DWORD ScrollHeight; DWORD VScrollMax; DWORD HScrollMax; DWORD VScrollPage; DWORD VScrollLine; DWORD HScrollLine; INT VscrollPos; INT HscrollPos; INT ScrollPosTrack = -1; DWORD Width; DWORD Height; DWORD OrigWidth; DWORD OrigHeight; WCHAR TiffFileName[MAX_PATH*2]; WCHAR PrinterName[MAX_PATH*2]; WCHAR LastDir[MAX_PATH*2]; DWORD CurrPage; HWND hwndToolbar; HWND hwndStatusbar; DWORD ToolbarHeight; DWORD StatusbarHeight; HMENU hmenuFrame; BOOL TiffFileOpened; DWORD CurrZoom; HCURSOR Hourglass; WNDPROC OrigEditProc; BOOL FileIsOpen; HIMAGELIST himlCoolbar; HBITMAP hBitmapBackground; HINSTANCE hInstance; TBBUTTON TbButton[] = { { -1, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 }, { 0, IDM_FILEOPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 0 }, { 1, IDM_PRINT, TBSTATE_INDETERMINATE, TBSTYLE_BUTTON, {0,0}, 0, 1 }, { 2, IDM_ZOOM, TBSTATE_INDETERMINATE, TBSTYLE_DROPDOWN, {0,0}, 0, 2 }, { -1, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 }, { -1, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, 0, -1 }, { 3, IDM_HELP, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 3 } }; TOOLBAR_STATE ToolbarState[] = { { IDM_FILEOPEN, TRUE, "" }, { IDM_PRINT, TRUE, "" }, { IDM_PAGE_UP, TRUE, "" }, { IDM_PAGE_DOWN, TRUE, "" } }; #define MAX_TOOLBAR_STATES (sizeof(ToolbarState)/sizeof(TOOLBAR_STATE)) double Zooms[] = { 1.00, .90, .80, .70, .60, .50, .40, .30, .20, .10 }; #define MAX_ZOOMS (sizeof(Zooms)/sizeof(double)) // // prototypes // VOID PopUpMsg( LPWSTR format, ... ); LRESULT WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); LRESULT ChildWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); BOOL ReadTiffData( HANDLE hTiff, LPBYTE *TiffData, DWORD Width, LPDWORD TiffDataLinesAlloc, DWORD PageNumber ); HDC GetPrinterDC( void ); BOOL TiffMailDefault( LPWSTR TiffFileName, LPWSTR ProfileName, LPWSTR Password, PULONG ResultCode ); VOID InitializeStatusBar( HWND hwnd ); BOOL BrowseForFileName( HWND hwnd, LPWSTR FileName, LPWSTR Extension, LPWSTR FileDesc, LPWSTR Dir ); BOOL PrintSetup( HWND hwnd ); HANDLE PrintTiffFile( HWND hwnd, LPWSTR FileName, LPWSTR PrinterName ); BOOL IsFaxViewerDefaultViewer( VOID ); BOOL MakeFaxViewerDefaultViewer( VOID ); BOOL IsItOkToAskForDefault( VOID ); BOOL SetAskForViewerValue( DWORD Ask ); BOOL SaveWindowPlacement( HWND hwnd ); BOOL QueryWindowPlacement( HWND hwnd ); BOOL OpenTiffFile( LPWSTR FileName, HWND hwnd ) { HANDLE _hTiff; TIFF_INFO _TiffInfo; LPBYTE _TiffData; DWORD _TiffDataSize; _hTiff = TiffOpen( FileName, &_TiffInfo, TRUE ); if (!_hTiff) { PopUpMsg( L"Could not open TIFF file [%s]", FileName ); return FALSE; } if ( (_TiffInfo.ImageWidth != 1728) || (_TiffInfo.CompressionType != 4 ) ) { PopUpMsg( L"Not valid MS TIFF file\n" ); TiffClose( _hTiff ); return FALSE; } _TiffDataSize = _TiffInfo.ImageHeight * (_TiffInfo.ImageWidth / 8); _TiffData = (LPBYTE) VirtualAlloc( NULL, _TiffDataSize, MEM_COMMIT, PAGE_READWRITE ); if (!_TiffData) { TiffClose( _hTiff ); PopUpMsg( L"could allocate memory for TIFF data\n" ); return FALSE; } hTiff = _hTiff; TiffInfo = _TiffInfo; TiffData = _TiffData; TiffDataSize = _TiffDataSize; TiffDataLinesAlloc = TiffInfo.ImageHeight; CurrPage = 1; ReadTiffData( hTiff, &TiffData, TiffInfo.ImageWidth, &TiffDataLinesAlloc, CurrPage ); bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi->bmiHeader.biWidth = TiffInfo.ImageWidth; bmi->bmiHeader.biHeight = - (INT) TiffInfo.ImageHeight; bmi->bmiHeader.biPlanes = 1; bmi->bmiHeader.biBitCount = 1; bmi->bmiHeader.biCompression = BI_RGB; bmi->bmiHeader.biSizeImage = 0; bmi->bmiHeader.biXPelsPerMeter = 7874; bmi->bmiHeader.biYPelsPerMeter = 7874; bmi->bmiHeader.biClrUsed = 0; bmi->bmiHeader.biClrImportant = 0; if (TiffInfo.PhotometricInterpretation) { bmi->bmiColors[0].rgbBlue = 0; bmi->bmiColors[0].rgbGreen = 0; bmi->bmiColors[0].rgbRed = 0; bmi->bmiColors[0].rgbReserved = 0; bmi->bmiColors[1].rgbBlue = 0xff; bmi->bmiColors[1].rgbGreen = 0xff; bmi->bmiColors[1].rgbRed = 0xff; bmi->bmiColors[1].rgbReserved = 0; } else { bmi->bmiColors[0].rgbBlue = 0xff; bmi->bmiColors[0].rgbGreen = 0xff; bmi->bmiColors[0].rgbRed = 0xff; bmi->bmiColors[0].rgbReserved = 0; bmi->bmiColors[1].rgbBlue = 0; bmi->bmiColors[1].rgbGreen = 0; bmi->bmiColors[1].rgbRed = 0; bmi->bmiColors[1].rgbReserved = 0; } OrigWidth = Width = TiffInfo.ImageWidth; OrigHeight = Height = TiffInfo.ImageHeight; TiffFileOpened = TRUE; return TRUE; } VOID FitRectToScreen( PRECT prc ) { INT cxScreen; INT cyScreen; INT delta; cxScreen = GetSystemMetrics(SM_CXSCREEN); cyScreen = GetSystemMetrics(SM_CYSCREEN); if (prc->right > cxScreen) { delta = prc->right - prc->left; prc->right = cxScreen; prc->left = prc->right - delta; } if (prc->left < 0) { delta = prc->right - prc->left; prc->left = 0; prc->right = prc->left + delta; } if (prc->bottom > cyScreen) { delta = prc->bottom - prc->top; prc->bottom = cyScreen; prc->top = prc->bottom - delta; } if (prc->top < 0) { delta = prc->bottom - prc->top; prc->top = 0; prc->bottom = prc->top + delta; } } VOID CenterWindow( HWND hwnd, HWND hwndToCenterOver ) { RECT rc; RECT rcOwner; RECT rcCenter; HWND hwndOwner; GetWindowRect( hwnd, &rc ); if (hwndToCenterOver) { hwndOwner = hwndToCenterOver; GetClientRect( hwndOwner, &rcOwner ); } else { hwndOwner = GetWindow( hwnd, GW_OWNER ); if (!hwndOwner) { hwndOwner = GetDesktopWindow(); } GetWindowRect( hwndOwner, &rcOwner ); } // // Calculate the starting x,y for the new // window so that it would be centered. // rcCenter.left = rcOwner.left + (((rcOwner.right - rcOwner.left) - (rc.right - rc.left)) / 2); rcCenter.top = rcOwner.top + (((rcOwner.bottom - rcOwner.top) - (rc.bottom - rc.top)) / 2); rcCenter.right = rcCenter.left + (rc.right - rc.left); rcCenter.bottom = rcCenter.top + (rc.bottom - rc.top); FitRectToScreen( &rcCenter ); SetWindowPos(hwnd, NULL, rcCenter.left, rcCenter.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); } LRESULT AskViewerDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_INITDIALOG: CenterWindow( hwnd, GetDesktopWindow() ); break; case WM_COMMAND: switch( wParam ) { case IDOK: SetAskForViewerValue( !IsDlgButtonChecked( hwnd, IDC_DEFAULT_VIEWER ) == BST_CHECKED ); EndDialog( hwnd, IDOK ); break; case IDCANCEL: SetAskForViewerValue( !IsDlgButtonChecked( hwnd, IDC_DEFAULT_VIEWER ) == BST_CHECKED ); EndDialog( hwnd, IDCANCEL ); break; } break; } return FALSE; } void MoveCoolbar( DWORD HowAlign ) { RECT rc; RECT rcCoolbar; int x; int y; int cx; int cy; GetClientRect( hwndMain, &rc ); GetWindowRect( hwndCoolbar, &rcCoolbar ); switch( HowAlign ) { default: case TOP: x = 0; y = 0; cx = rc.right - rc.left; cy = rc.bottom - rc.top; break; case LEFT: x = 0; y = 0; cx = rcCoolbar.right - rcCoolbar.left; cy = rc.bottom - rc.top; break; case BOTTOM: x = 0; y = rc.bottom - (rcCoolbar.bottom - rcCoolbar.top); cx = rc.right - rc.left; cy = rcCoolbar.bottom - rcCoolbar.top; break; case RIGHT: x = rc.right - (rcCoolbar.right - rcCoolbar.left); y = 0; cx = rcCoolbar.right - rcCoolbar.left; cy = rc.bottom - rc.top; break; } MoveWindow( hwndCoolbar, x, y, cx, cy, TRUE ); } VOID LoadBackgroundBitmap( VOID ) { COLORREF clrFace; HBITMAP hbmSave; UINT n; UINT i; RGBQUAD rgbTable[256]; RGBQUAD rgbFace; HDC hdc; if (hBitmapBackground) { DeleteObject( hBitmapBackground ); } hBitmapBackground = (HBITMAP) LoadImage( hInstance, MAKEINTRESOURCE(IDB_COOLBAR), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_CREATEDIBSECTION ); hdc = CreateCompatibleDC(NULL); clrFace = GetSysColor(COLOR_BTNFACE); if (clrFace != RGB(192,192,192)) { hbmSave = (HBITMAP) SelectObject( hdc, hBitmapBackground ); n = GetDIBColorTable(hdc, 0, 256, rgbTable); rgbFace.rgbRed = GetRValue(clrFace); rgbFace.rgbGreen = GetGValue(clrFace); rgbFace.rgbBlue = GetBValue(clrFace); for (i = 0; i < n; i++) { rgbTable[i].rgbRed = (rgbTable[i].rgbRed * rgbFace.rgbRed ) / 192; rgbTable[i].rgbGreen = (rgbTable[i].rgbGreen * rgbFace.rgbGreen) / 192; rgbTable[i].rgbBlue = (rgbTable[i].rgbBlue * rgbFace.rgbBlue ) / 192; } SetDIBColorTable(hdc, 0, n, rgbTable); SelectObject(hdc, hbmSave); } DeleteDC( hdc ); } VOID SetBackground( VOID ) { REBARBANDINFO rbbi; DWORD fMask; LoadBackgroundBitmap(); if (hBitmapBackground) { fMask = RBBIM_BACKGROUND; rbbi.hbmBack = hBitmapBackground; } else { fMask = RBBIM_BACKGROUND | RBBIM_COLORS; rbbi.hbmBack = NULL; rbbi.clrFore = GetSysColor(COLOR_BTNTEXT); rbbi.clrBack = GetSysColor(COLOR_BTNFACE); } rbbi.cbSize = sizeof(REBARBANDINFO); rbbi.fMask = RBBIM_ID | RBBIM_CHILD; if (SendMessage( hwndCoolbar, RB_GETBANDINFO, 0, (LPARAM) &rbbi )) { rbbi.fMask = fMask; SendMessage( hwndCoolbar, RB_SETBANDINFO, 0, (LPARAM) &rbbi ); InvalidateRect( rbbi.hwndChild, NULL, TRUE ); } } int WINAPI wWinMain( HINSTANCE hInst, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ) /*++ Routine Description: Main entry point for the TIFF image viewer. Arguments: hInstance - Instance handle hPrevInstance - Not used lpCmdLine - Command line arguments nShowCmd - How to show the window Return Value: Return code, zero for success. --*/ { LPWSTR *argv; DWORD argc; WNDCLASS wc; MSG msg; RECT rect; DWORD i; HANDLE hThread; LOGBRUSH lb; RECT rc; TBADDBITMAP tbab; INITCOMMONCONTROLSEX iccex; REBARBANDINFO rbbi; LRESULT lButtonSize; hInstance = hInst; // // general init code // HeapInitialize(NULL,NULL,NULL,0); iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); iccex.dwICC = ICC_COOL_CLASSES; InitCommonControlsEx( &iccex ); FaxTiffInitialize(); // // process the command line // argv = CommandLineToArgvW( GetCommandLine(), &argc ); for (i=1; i *TiffDataLinesAlloc) { *TiffDataLinesAlloc = Lines; VirtualFree( *TiffData, 0, MEM_RELEASE ); *TiffData = (LPBYTE) VirtualAlloc( NULL, Lines * (Width / 8), MEM_COMMIT, PAGE_READWRITE ); if (!*TiffData) { return FALSE; } } if (!TiffUncompressMmrPage( hTiff, (LPDWORD) *TiffData, &Lines )) { return FALSE; } EnableMenuItem( hMenu, IDM_PAGE_UP, PageNumber == 1 ? MF_GRAYED : MF_ENABLED ); return TRUE; } VOID PopUpMsg( LPWSTR format, ... ) /*++ Routine Description: Pops up a message box to indicate an error. Arguments: format - Format string ... - Other arguments Return Value: None. --*/ { WCHAR buf[1024]; va_list arg_ptr; va_start( arg_ptr, format ); _vsnwprintf( buf, sizeof(buf), format, arg_ptr ); va_end( arg_ptr ); MessageBox( NULL, buf, L"FaxView", MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION ); } VOID ChangeTitle( HWND hwnd, LPWSTR FileName ) /*++ Routine Description: Changes the title text of the window. Arguments: hwnd - Window handle Return Value: None. --*/ { LPWSTR p; WCHAR WindowTitle[128]; p = wcsrchr( FileName, L'\\' ); if (p) { FileName = p + 1; } if (TiffFileName[0]) { swprintf( WindowTitle, L"FaxView - %s Page %d of %d", FileName, CurrPage, TiffInfo.PageCount ); } else { swprintf( WindowTitle, L"FaxView" ); } SetWindowText( hwnd, WindowTitle ); } VOID UpdateStatusBar( LPWSTR lpszStatusString, WORD partNumber, WORD displayFlags ) { SendMessage( hwndStatusbar, SB_SETTEXT, partNumber | displayFlags, (LPARAM)lpszStatusString ); } VOID InitializeStatusBar( HWND hwnd ) { UpdateStatusBar( L"Fax Viewer", 0, 0 ); } LRESULT WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) /*++ Routine Description: Window procedure for the TIFF image viewer main window. Arguments: hwnd - Window handle message - message identifier wParam - Parameter lParam - Parameter Return Value: Return result, zero for success. --*/ { HDC hdc; RECT rc; HCURSOR OldCursor; BOOL ReOpen; PAINTSTRUCT ps; LPWSTR p; WCHAR FileName[MAX_PATH*2]; switch (message) { case WM_CREATE: hmenuFrame = GetMenu( hwnd ); QueryWindowPlacement( hwnd ); return 0; case WM_PAINT: GetClientRect( hwnd, &rc ); rc.top += ToolbarHeight; rc.bottom = rc.top + SEPHEIGHT; hdc = BeginPaint( hwnd, &ps ); DrawEdge( hdc, &rc, EDGE_RAISED, BF_TOP | BF_BOTTOM | BF_MIDDLE ); EndPaint( hwnd, &ps ); return 0; case WM_OPEN_FILE: ReOpen = FALSE; wcscpy( FileName, (LPWSTR) lParam ); goto open_file; return 0; case WM_NOTIFY: if (((LPNMHDR)lParam)->code == TBN_DROPDOWN) { SendMessage( hwndToolbar, TB_GETRECT, IDM_ZOOM, (LPARAM)&rc ); rc.top = rc.bottom; MapWindowPoints( hwndToolbar, HWND_DESKTOP, (POINT *)&rc, 2 ); TrackPopupMenu( hMenuZoom, TPM_LEFTALIGN | TPM_LEFTBUTTON, rc.left, rc.top, 0, hwnd, NULL ); } return 0; case WM_COMMAND: if (HIWORD(wParam) == 0) { switch( wParam ) { case IDM_FILEOPEN: ReOpen = TiffFileOpened; // // ask the user to choose a file name // if (!BrowseForFileName( hwnd, FileName, L"tif", L"Fax Image Files", LastDir )) { return 0; } open_file: if (!OpenTiffFile( FileName, hwnd )) { return 0; } // // update the last directory name // p = wcsrchr( FileName, L'\\' ); if (p) { wcscpy( LastDir, FileName ); p = wcsrchr( LastDir, L'\\' ); if (p) { *p = 0; } } wcscpy( TiffFileName, FileName ); OldCursor = SetCursor( Hourglass ); if (ReOpen) { TiffFileOpened = FALSE; TiffClose( hTiff ); VirtualFree( TiffData, 0, MEM_RELEASE ); TiffData = NULL; hTiff = NULL; Width = 0; Height = 0; OrigWidth = 0; OrigHeight = 0; TiffDataSize = 0; SendMessage( hwndView, WM_VIEW_CLOSE, 0, 0 ); } ChangeTitle( hwnd, TiffFileName ); SendMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); SetCursor( OldCursor ); EnableMenuItem( hMenu, IDM_CLOSE, MF_ENABLED ); EnableMenuItem( hMenu, IDM_PRINT, MF_ENABLED ); EnableMenuItem( hMenu, IDM_PRINT_SETUP, MF_ENABLED ); EnableMenuItem( hMenu, IDM_ZOOM, MF_ENABLED ); EnableMenuItem( hMenu, IDM_PAGE_UP, MF_GRAYED ); if (TiffInfo.PageCount > 1) { EnableMenuItem( hMenu, IDM_PAGE_DOWN, MF_ENABLED ); } SendMessage( hwndToolbar, TB_SETSTATE, IDM_PRINT, (LPARAM) MAKELONG(TBSTATE_ENABLED, 0) ); SendMessage( hwndToolbar, TB_SETSTATE, IDM_ZOOM, (LPARAM) MAKELONG(TBSTATE_ENABLED, 0) ); return 0; case IDM_ZOOM_100: case IDM_ZOOM_90: case IDM_ZOOM_80: case IDM_ZOOM_70: case IDM_ZOOM_60: case IDM_ZOOM_50: case IDM_ZOOM_40: case IDM_ZOOM_30: case IDM_ZOOM_20: case IDM_ZOOM_10: CheckMenuItem( hMenuZoom, CurrZoom+IDM_ZOOM_100, MF_UNCHECKED ); CheckMenuItem( hMenuZoom, wParam, MF_CHECKED ); CurrZoom = wParam - IDM_ZOOM_100; SendMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); return 0; case IDM_PAGE_UP: if (CurrPage == 1) { MessageBeep( MB_ICONEXCLAMATION ); return 0; } ReadTiffData( hTiff, &TiffData, TiffInfo.ImageWidth, &TiffDataLinesAlloc, --CurrPage ); ChangeTitle( hwnd, TiffFileName ); SendMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); return 0; case IDM_PAGE_DOWN: if (CurrPage == TiffInfo.PageCount) { MessageBeep( MB_ICONEXCLAMATION ); return 0; } ReadTiffData( hTiff, &TiffData, TiffInfo.ImageWidth, &TiffDataLinesAlloc, ++CurrPage ); ChangeTitle( hwnd, TiffFileName ); SendMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); return 0; case IDM_PRINT_SETUP: PrintSetup( hwnd ); return 0; case IDM_PRINT: PrintTiffFile( hwnd, TiffFileName, NULL ); return 0; case IDM_CLOSE: TiffFileOpened = FALSE; TiffClose( hTiff ); VirtualFree( TiffData, 0, MEM_RELEASE ); TiffData = NULL; hTiff = NULL; Width = 0; Height = 0; OrigWidth = 0; OrigHeight = 0; TiffDataSize = 0; TiffFileName[0] = 0; ChangeTitle( hwnd, TiffFileName ); SendMessage( hwndView, WM_VIEW_CLOSE, 0, 0 ); EnableMenuItem( hMenu, IDM_CLOSE, MF_GRAYED ); EnableMenuItem( hMenu, IDM_PRINT, MF_GRAYED ); EnableMenuItem( hMenu, IDM_PRINT_SETUP, MF_GRAYED ); EnableMenuItem( hMenu, IDM_PAGE_UP, MF_GRAYED ); EnableMenuItem( hMenu, IDM_PAGE_DOWN, MF_GRAYED ); EnableMenuItem( hMenu, IDM_ZOOM, MF_GRAYED ); SendMessage( hwndToolbar, TB_SETSTATE, IDM_PRINT, (LPARAM) MAKELONG(TBSTATE_INDETERMINATE, 0) ); SendMessage( hwndToolbar, TB_SETSTATE, IDM_ZOOM, (LPARAM) MAKELONG(TBSTATE_INDETERMINATE, 0) ); return 0; case IDM_EXIT: PostQuitMessage( 0 ); return 0; case IDM_HELP: WinHelp(hwnd, TEXT( "faxview.HLP" ), HELP_FINDER, 0L); return 0; case IDM_ABOUT: ShellAbout( hwnd, L"Fax Viewer", NULL, NULL ); break; } } return 0; case WM_SIZE: MoveCoolbar( TOP ); SendMessage( hwndToolbar, message, wParam, lParam ); SendMessage( hwndStatusbar, message, wParam, lParam ); InitializeStatusBar( hwnd ); CyClient = HIWORD(lParam) - ToolbarHeight - SEPHEIGHT - StatusbarHeight; CxClient = LOWORD(lParam); // // resize the view window // GetClientRect( hwnd, &rc ); MoveWindow( hwndView, rc.left, rc.top+ToolbarHeight+SEPHEIGHT, CxClient, CyClient, TRUE ); return 0; case WM_KEYDOWN: switch( wParam ) { case VK_NEXT: if (GetKeyState( VK_CONTROL ) & 0x8000) { SendMessage( hwnd, WM_COMMAND, IDM_PAGE_DOWN, 0 ); } else { SendMessage( hwndView, WM_VSCROLL, MAKELONG(SB_PAGEDOWN,0), 0 ); } break; case VK_PRIOR: if (GetKeyState( VK_CONTROL ) & 0x8000) { SendMessage( hwnd, WM_COMMAND, IDM_PAGE_UP, 0 ); } else { SendMessage( hwndView, WM_VSCROLL, MAKELONG(SB_PAGEUP,0), 0 ); } break; case VK_END: SendMessage( hwndView, WM_VSCROLL, MAKELONG(SB_BOTTOM,0), 0 ); break; case VK_HOME: SendMessage( hwndView, WM_VSCROLL, MAKELONG(SB_TOP,0), 0 ); break; case VK_LEFT: SendMessage( hwndView, WM_HSCROLL, MAKELONG(SB_LINELEFT,0), 0 ); break; case VK_RIGHT: SendMessage( hwndView, WM_HSCROLL, MAKELONG(SB_LINERIGHT,0), 0 ); break; case VK_UP: SendMessage( hwndView, WM_VSCROLL, MAKELONG(SB_LINEUP,0), 0 ); break; case VK_DOWN: SendMessage( hwndView, WM_VSCROLL, MAKELONG(SB_LINEDOWN,0), 0 ); break; case VK_F4: SendMessage( hwnd, WM_COMMAND, IDM_FILEOPEN, 0 ); break; case VK_F1: SendMessage( hwnd, WM_COMMAND, IDM_HELP, 0 ); break; } return 0; case WM_SYSCOLORCHANGE: SendMessage( hwndCoolbar, message, wParam, lParam ); SetBackground(); return 0; case WM_DESTROY: SaveWindowPlacement( hwnd ); PostQuitMessage( 0 ); return 0; } return DefWindowProc( hwnd, message, wParam, lParam ); } VOID UpdateScrollInfo( HWND hwnd ) { SCROLLINFO si; // // set the vertical scroll amounts for pages & lines // if (TiffInfo.PageCount) { VScrollMax = TiffInfo.PageCount * Height; VScrollPage = Height; VScrollLine = VScrollPage / 10; HScrollLine = TiffInfo.ImageWidth / 10; } else { VScrollMax = 0; VScrollPage = 0; VScrollLine = 0; } si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE; GetScrollInfo( hwnd, SB_VERT, &si ); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE; si.nMin = 0; si.nMax = VScrollMax; si.nPage = CyClient; SetScrollInfo( hwnd, SB_VERT, &si, TRUE ); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE; GetScrollInfo( hwnd, SB_HORZ, &si ); HScrollMax = Width - CxClient; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_RANGE; si.nMin = 0; si.nMax = HScrollMax; si.nPage = CxClient; SetScrollInfo( hwnd, SB_HORZ, &si, TRUE ); } DWORD ScrollPosToPage( DWORD ScrollPos ) { DWORD Page = 0; Page = ScrollPos / VScrollPage; Page = Page + (((ScrollPos % VScrollPage) > 0) ? 1 : 0); return Page == 0 ? 1 : Page; } VOID ScrollViewVertically( HWND hwnd, INT ScrollCode, INT Position ) { INT OldScrollPos; RECT rcClip; INT Delta; SCROLLINFO si; DWORD NewPage; DWORD Remaining; OldScrollPos = VscrollPos; if (ScrollCode == SB_LINEUP || ScrollCode == SB_LINEDOWN) { if (ScrollCode == SB_LINEUP) { VscrollPos -= VScrollLine; } else { VscrollPos += VScrollLine; } line_scroll: VscrollPos = max( 0, min( VscrollPos, (int) VScrollMax ) ); SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); Delta = VscrollPos - OldScrollPos; if (Delta == 0) { MessageBeep( MB_ICONASTERISK ); return; } else if (Delta > 0) { if (VscrollPos < (INT)VScrollPage) { Remaining = VScrollPage - VscrollPos; } else if (VscrollPos % VScrollPage == 0) { Remaining = 0; } else { Remaining = TiffInfo.ImageHeight - (VscrollPos % VScrollPage); } if (Remaining < CyClient) { VscrollPos -= (CyClient - Remaining); Delta -= (CyClient - Remaining); if (Delta == 0) { // // advance to the next page // if (CurrPage == TiffInfo.PageCount) { MessageBeep( MB_ICONASTERISK ); VscrollPos = OldScrollPos; return; } ReadTiffData( hTiff, &TiffData, TiffInfo.ImageWidth, &TiffDataLinesAlloc, ++CurrPage ); ChangeTitle( hwndMain, TiffFileName ); VscrollPos = VScrollPage*(CurrPage-1); SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); PostMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); return; } SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); } GetClientRect( hwnd, &rcClip ); ScrollWindow( hwnd, 0, -Delta, NULL, &rcClip ); } else { if (OldScrollPos % VScrollPage == 0) { // // advance to the previous page // if (CurrPage == 1) { MessageBeep( MB_ICONASTERISK ); return; } ReadTiffData( hTiff, &TiffData, TiffInfo.ImageWidth, &TiffDataLinesAlloc, --CurrPage ); ChangeTitle( hwndMain, TiffFileName ); VscrollPos = VScrollPage * (CurrPage - 1) + TiffInfo.ImageHeight - CyClient; SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); PostMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); return; } if (ScrollPosToPage( VscrollPos ) != CurrPage) { // // the file was positioned just below the top // of the previous page, so lets align to the beginning // of the current page // Remaining = -((INT)OldScrollPos - ((INT)CurrPage - 1) * (INT)TiffInfo.ImageHeight); VscrollPos -= Delta - Remaining; Delta = Remaining; } GetClientRect( hwnd, &rcClip ); ScrollWindow( hwnd, 0, -Delta, NULL, &rcClip ); } return; } if (ScrollCode == SB_THUMBTRACK) { if (ScrollPosTrack == -1) { ScrollPosTrack = VscrollPos; } VscrollPos = max( 0, min( Position, (int) VScrollMax ) ); SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); return; } if (ScrollCode == SB_ENDSCROLL && ScrollPosTrack != -1) { si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS; GetScrollInfo( hwnd, SB_VERT, &si ); VscrollPos = si.nPos; Delta = VscrollPos - ScrollPosTrack; ScrollPosTrack = -1; NewPage = ScrollPosToPage( VscrollPos ); if (NewPage != CurrPage) { // // the user changed pages // CurrPage = NewPage; ReadTiffData( hTiff, &TiffData, TiffInfo.ImageWidth, &TiffDataLinesAlloc, CurrPage ); ChangeTitle( hwndMain, TiffFileName ); VscrollPos = VScrollPage*(CurrPage-1); SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); PostMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); return; } else { SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); if (Delta != 0) { GetClientRect( hwnd, &rcClip ); ScrollWindow( hwnd, 0, -Delta, NULL, &rcClip ); } return; } return; } if (ScrollCode == SB_PAGEDOWN) { VscrollPos += CyClient; goto line_scroll; return; } if (ScrollCode == SB_PAGEUP) { VscrollPos -= CyClient; goto line_scroll; return; } if (ScrollCode == SB_TOP) { CurrPage = 1; ReadTiffData( hTiff, &TiffData, TiffInfo.ImageWidth, &TiffDataLinesAlloc, CurrPage ); ChangeTitle( hwndMain, TiffFileName ); VscrollPos = 0; SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); PostMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); return; } if (ScrollCode == SB_BOTTOM) { CurrPage = TiffInfo.PageCount; ReadTiffData( hTiff, &TiffData, TiffInfo.ImageWidth, &TiffDataLinesAlloc, CurrPage ); ChangeTitle( hwndMain, TiffFileName ); VscrollPos = 0; SetScrollPos( hwnd, SB_VERT, VscrollPos, TRUE ); PostMessage( hwndView, WM_VIEW_REFRESH, 0, 0 ); return; } } LRESULT ChildWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { static double ZoomPct = 1.00; static HDC hdcMem = NULL; RECT rc; PAINTSTRUCT ps; HDC hdc; HCURSOR OldCursor; int OldScrollPos; int Delta; HBITMAP hBmp; switch (message) { case WM_CREATE: ZoomPct = Zooms[CurrZoom]; return 0; case WM_VSCROLL: ScrollViewVertically( hwnd, LOWORD(wParam), HIWORD(wParam) ); UpdateScrollInfo( hwnd ); return 0; case WM_HSCROLL: OldScrollPos = HscrollPos; GetClientRect( hwnd, &rc ); switch (LOWORD (wParam)) { case SB_LINEUP: HscrollPos -= HScrollLine; break; case SB_LINEDOWN: HscrollPos += HScrollLine; break; case SB_PAGEUP: HscrollPos -= CxClient; break; case SB_PAGEDOWN: HscrollPos += CxClient; break; case SB_THUMBPOSITION: HscrollPos = HIWORD(wParam); break; case SB_THUMBTRACK: HscrollPos = HIWORD(wParam); break; } HscrollPos = max( 0, min( HscrollPos, (int) HScrollMax ) ); SetScrollPos( hwnd, SB_HORZ, HscrollPos, TRUE ); Delta = HscrollPos - OldScrollPos; if (Delta != 0) { ScrollWindow( hwnd, -Delta, 0, &rc, &rc ); } return 0; case WM_PAINT: hdc = BeginPaint( hwnd, &ps ); if (TiffFileOpened) { GetClientRect( hwnd, &rc ); BitBlt( hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hdcMem, HscrollPos + ((int)ps.rcPaint.left - (int)rc.left), (VscrollPos%VScrollPage) + ((int)ps.rcPaint.top - (int)rc.top), SRCCOPY ); } EndPaint( hwnd, &ps ); return 0; case WM_VIEW_CLOSE: DeleteDC( hdcMem ); hdcMem = NULL; VscrollPos = 0; HscrollPos = 0; UpdateScrollInfo( hwnd ); return 0; case WM_VIEW_REFRESH: ZoomPct = Zooms[CurrZoom]; HscrollPos = 0; Width = (DWORD)(OrigWidth * ZoomPct); Height = (DWORD)(OrigHeight * ZoomPct); SetScrollPos( hwnd, SB_HORZ, HscrollPos, TRUE ); OldCursor = SetCursor( Hourglass ); DeleteDC( hdcMem ); hdc = GetDC( hwnd ); hBmp = CreateCompatibleBitmap( hdc, Width, Height ); hdcMem = CreateCompatibleDC( hdc ); SelectObject( hdcMem, hBmp ); StretchDIBits( hdcMem, 0, 0, Width, Height, 0, 0, TiffInfo.ImageWidth, TiffInfo.ImageHeight, TiffData, bmi, DIB_RGB_COLORS, SRCCOPY ); ReleaseDC( hwnd, hdc ); DeleteObject( hBmp ); UpdateScrollInfo( hwnd ); InvalidateRect( hwnd, NULL, TRUE ); SetCursor( OldCursor ); return 0; case WM_SIZE: UpdateScrollInfo( hwnd ); GetClientRect( hwnd, &rc ); CyClient = rc.bottom - rc.top; CxClient = rc.right - rc.left; return 0; } return DefWindowProc( hwnd, message, wParam, lParam ); }