Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1821 lines
46 KiB

/*++
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 <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <shellapi.h>
#include <stdio.h>
#include <stdlib.h>
#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<argc; i++) {
if (argv[i][0] == L'-' || argv[i][0] == L'/') {
switch (towlower(argv[i][1])) {
case L'p':
if (towlower(argv[i][2]) == L't') {
hThread = PrintTiffFile( NULL, argv[i+1], argv[i+2] );
} else {
hThread = PrintTiffFile( NULL, argv[i+1], NULL );
}
if (hThread) {
WaitForSingleObject( hThread, INFINITE );
}
return 0;
default:
break;
}
} else {
//
// must be a file name for viewing
//
wcscpy( TiffFileName, argv[i] );
}
}
if ((!IsFaxViewerDefaultViewer()) && IsItOkToAskForDefault()) {
int Answer = DialogBox( hInstance, MAKEINTRESOURCE(IDD_VIEWER), NULL, AskViewerDlgProc );
if (Answer == IDOK) {
MakeFaxViewerDefaultViewer();
}
}
CxScreen = GetSystemMetrics( SM_CXSCREEN );
CyScreen = GetSystemMetrics( SM_CYSCREEN );
ScrollWidth = GetSystemMetrics( SM_CYVSCROLL );
ScrollHeight = GetSystemMetrics( SM_CYHSCROLL );
CurrPage = 1;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wc.lpszMenuName = MAKEINTRESOURCE( FAXVIEW );
wc.lpszClassName = L"FaxView";
if (!RegisterClass(&wc)) {
return FALSE;
}
lb.lbStyle = BS_SOLID;
lb.lbColor = RGB( 221,232,23 );
lb.lbHatch = 0;
wc.lpfnWndProc = (WNDPROC)ChildWndProc;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_CROSS);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"FaxViewChild";
if (!RegisterClass(&wc)) {
return FALSE;
}
hwndMain = CreateWindow(
L"FaxView", // window class name
L"FaxView", // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL // creation parameters
);
if (!hwndMain) {
return 0;
}
hMenu = GetMenu( hwndMain );
hMenuZoom = GetSubMenu( GetSubMenu( hMenu, 1 ), 3 );
Hourglass = LoadCursor( NULL, IDC_WAIT );
if (!Hourglass) {
DebugPrint(( L"LoadCursor() failed for IDC_WAIT, ec=%d", GetLastError() ));
}
//
// create the coolbar
//
hwndCoolbar = CreateWindowEx(
WS_EX_TOOLWINDOW,
REBARCLASSNAME,
NULL,
WS_VISIBLE |
WS_BORDER |
WS_CHILD |
WS_CLIPCHILDREN |
WS_CLIPSIBLINGS |
RBS_TOOLTIPS |
RBS_BANDBORDERS |
CCS_NODIVIDER |
CCS_NOPARENTALIGN,
0,
0,
200,
100,
hwndMain,
(HMENU) IDM_COOLBAR,
hInstance,
NULL
);
if (!hwndCoolbar) {
return 0;
}
//
// create and populate the toolbar
//
hwndToolbar = CreateWindowEx(
WS_EX_TOOLWINDOW,
TOOLBARCLASSNAME,
NULL,
WS_CHILD | TBSTYLE_FLAT | CCS_ADJUSTABLE | CCS_NODIVIDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NOPARENTALIGN,
0,
0,
0,
0,
hwndCoolbar,
(HMENU) IDM_TOOLBAR,
hInstance,
NULL
);
SendMessage( hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0 );
SendMessage( hwndToolbar, TB_SETMAXTEXTROWS, 2, 0 );
SendMessage( hwndToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(24,24) );
tbab.hInst = hInstance;
tbab.nID = IDB_OPEN_BIG;
SendMessage( hwndToolbar, TB_ADDBITMAP, 1, (LPARAM) &tbab );
tbab.nID = IDB_PRINT_BIG;
SendMessage( hwndToolbar, TB_ADDBITMAP, 1, (LPARAM) &tbab );
tbab.nID = IDB_ZOOM_BIG;
SendMessage( hwndToolbar, TB_ADDBITMAP, 1, (LPARAM) &tbab );
tbab.nID = IDB_HELP_BIG;
SendMessage( hwndToolbar, TB_ADDBITMAP, 1, (LPARAM) &tbab );
SendMessage( hwndToolbar, TB_ADDSTRING, 0, (LPARAM) L"Open\0Print\0Zoom\0Help\0\0" );
SendMessage( hwndToolbar, TB_ADDBUTTONS, sizeof(TbButton)/sizeof(TBBUTTON), (LPARAM)&TbButton );
SendMessage( hwndToolbar, TB_SETBUTTONWIDTH, 0, MAKELONG(50,200) );
ShowWindow( hwndToolbar, SW_SHOW );
//
// add the toolbar to the coolbar
//
lButtonSize = SendMessage( hwndToolbar, TB_GETBUTTONSIZE, 0, 0 );
ZeroMemory( &rbbi, sizeof(rbbi) );
rbbi.cbSize = sizeof(REBARBANDINFO);
rbbi.fMask = RBBIM_CHILD |
RBBIM_CHILDSIZE |
RBBIM_ID |
RBBIM_STYLE |
RBBIM_COLORS ;
rbbi.cxMinChild = LOWORD(lButtonSize);
rbbi.cyMinChild = HIWORD(lButtonSize);
rbbi.clrFore = GetSysColor(COLOR_BTNTEXT);
rbbi.clrBack = GetSysColor(COLOR_BTNFACE);
rbbi.fStyle = RBBS_CHILDEDGE | RBBS_FIXEDBMP;
rbbi.wID = IDM_TOOLBAR;
rbbi.hwndChild = hwndToolbar;
rbbi.lpText = NULL;
rbbi.hbmBack = NULL;
rbbi.iImage = 0;
SendMessage( hwndCoolbar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbbi );
SetBackground();
MoveCoolbar( TOP );
GetWindowRect( hwndCoolbar, &rc );
ToolbarHeight = rc.bottom - rc.top - 1;
hwndStatusbar = CreateStatusWindow(
WS_CHILD | WS_VISIBLE | WS_BORDER,
L"Fax Viewer",
hwndMain,
IDM_STATUSBAR
);
GetWindowRect( hwndStatusbar, &rect );
StatusbarHeight = rect.bottom - rect.top;
InitializeStatusBar( hwndMain );
if (TiffFileName[0]) {
PostMessage( hwndMain, WM_OPEN_FILE, 0, (LPARAM) TiffFileName );
}
GetClientRect( hwndMain, &rc );
hwndView = CreateWindow(
L"FaxViewChild", // window class name
NULL, // window caption
WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE, // window style
rc.left, // initial x position
rc.top + ToolbarHeight + SEPHEIGHT, // initial y position
rc.right - rc.left, // initial x size
rc.bottom - rc.top - ToolbarHeight - SEPHEIGHT - StatusbarHeight, // initial y size
hwndMain, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL // creation parameters
);
if (!hwndView) {
return 0;
}
hwndTooltip = CreateWindowEx(
WS_EX_TOOLWINDOW,
TOOLTIPS_CLASS,
NULL,
WS_CHILD,
0,
0,
0,
0,
hwndView,
(HMENU) IDM_TOOLTIP,
hInstance,
NULL
);
if (!hwndTooltip) {
return 0;
}
ShowWindow( hwndMain, SW_SHOWNORMAL );
ShowWindow( hwndView, SW_SHOWNORMAL );
UpdateWindow( hwndMain );
UpdateWindow( hwndView );
InvalidateRect( hwndView, NULL, TRUE );
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return 0;
}
BOOL
ReadTiffData(
HANDLE hTiff,
LPBYTE *TiffData,
DWORD Width,
LPDWORD TiffDataLinesAlloc,
DWORD PageNumber
)
{
DWORD Lines = 0;
TiffSeekToPage( hTiff, PageNumber, FILLORDER_LSB2MSB );
TiffUncompressMmrPage( hTiff, (LPDWORD) *TiffData, &Lines );
if (Lines > *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 );
}