//
要把滚动功能做得尽善尽美真不是容易
// 一个完善的滚动功能,应该可以让用户用键盘和鼠标调整滚动条的位置
// 而且滑块的大小不应该是固定的
// 这需要调用SetScrollInfo和GetScrollInfo来处理
// WM_VSCROLL和WM_HSCROLL消息
// 同时还要处理WM_KEYDOWN消息和WM_MOUSEWHEEL消息
// 还要在WM_SIZE消息中更新滚动条的信息
// 总结:
// 1.在窗口大小改变时,即处理WM_SIZE消息时更新滚动条的信息以改变滚动条滑块的大小
// 而这会同时改变位置的范围.这须要调用SetScrollInfo
// 2.处理WM_VSCROLL和WM_HSCROLL,根据消息参数改变滚动条的位置
// 这其中要多次调用SetScrollInfo和GetScrollInfo
// 3.处理WM_KEYDOWN和WM_MOUSEWHEEL完善功能
// 以下的程序在窗口中显示了显示器的内容
// 由于窗口没有显示器大,所以需要滚动条
#define _WIN32_WINNT 0x0500 // 为了使用WM_MOUSEWHEEL
#include < windows.h >
// 过程函数的返回值都是LRESULT,类型都是CALLBACK
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpszCmdLine, int nCmdShow)
{
HWND hwnd; // 主窗口句柄,在CreateWindow中赋值
MSG msg; // 消息变量,在GetMessage中使用
WNDCLASS wndclass; // 窗口类
TCHAR * szAppName = TEXT( " CBViewer " ); // 类名和窗口名
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 窗口背景
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); // 鼠标
wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION); // 图标
wndclass.lpszClassName = szAppName; // 类名
wndclass.cbClsExtra = 0 ; // 类的额外参数
wndclass.cbWndExtra = 0 ; // 窗口的额外参数.用于基于同一窗口类的窗口各自区分.
// 在自定义对话框类时必须指定为DLGWINDOWEXTRA的大小
wndclass.lpszMenuName = NULL; // 菜单名.可以用作子窗口的id
wndclass.style = CS_HREDRAW | CS_VREDRAW; // 窗口风格
wndclass.lpfnWndProc = WndProc; // 窗口过程
wndclass.hInstance = hInstance; // 包含窗口过程的实例句柄
if ( ! RegisterClass( & wndclass) ) // 注册窗口类
return 0 ;
hwnd = CreateWindow( // 创建窗口
szAppName, // 窗口类名
szAppName, // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口风格
CW_USEDEFAULT, // 初始的x坐标
CW_USEDEFAULT, // 初始的y坐标
CW_USEDEFAULT, // 初始的宽度
CW_USEDEFAULT, // 初始的高度
NULL, // 父窗口
NULL, // 菜单
hInstance, // 和窗口相关的实例句柄
NULL // 额外参数
);
ShowWindow( hwnd,nCmdShow ); // 显示窗口
UpdateWindow( hwnd ); // 更新窗口
while ( GetMessage( & msg,NULL, 0 , 0 ) ) // 消息循环
{
TranslateMessage( & msg); // 将WM_XXXKEYXXX消息翻译为WM_CHAR消息
DispatchMessage( & msg); // 传递消息到窗口过程
}
return msg.wParam; // 返回
}
LRESULT WINAPI WndProc( HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam )
{
static int nDeltaPerLine, nAccumDelta ; // 在WM_MOUSEWHEEL中使用
static HDC hdcMem; // 用作BitBlt的源DC
static HBITMAP hbmp; // 桌面位图
static int cxScreen, cyScreen; // 屏幕大小
switch ( message )
{
case WM_CREATE:
{
HWND hwndDesktop = GetDesktopWindow(); // 桌面句柄
HDC hdcDesktop = GetWindowDC(hwndDesktop); // 桌面DC
cxScreen = GetSystemMetrics(SM_CXSCREEN); // 桌面大小
cyScreen = GetSystemMetrics(SM_CYSCREEN);
hbmp = CreateCompatibleBitmap( // 与桌面DC兼容的位图
hdcDesktop,
cxScreen,
cyScreen);
hdcMem = CreateCompatibleDC(hdcDesktop); // 与桌面DC兼容的内存DC
SelectObject(hdcMem, hbmp);
// 将桌面内容保存到内存位图中, 以在WM_PAINT中画到客户窗口
BitBlt(hdcMem, 0 , 0 , cxScreen, cyScreen, hdcDesktop, 0 , 0 , SRCCOPY);
ReleaseDC(hwndDesktop, hdcDesktop);
}
case WM_SETTINGCHANGE:
{
ULONG ulScrollLines ;
SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0 , & ulScrollLines, 0 ) ;
// ulScrollLines usually equals 3 or 0 (for no scrolling)
// WHEEL_DELTA equals 120, so nDeltaPerLine will be 40
if (ulScrollLines)
{
nDeltaPerLine = WHEEL_DELTA / ulScrollLines ;
}
else
{
nDeltaPerLine = 0 ;
}
return 0 ;
}
case WM_SIZE:
{
SCROLLINFO sif;
// 设置垂直滚动条的信息
sif.cbSize = sizeof (sif);
sif.fMask = SIF_RANGE | SIF_PAGE;
sif.nMax = GetSystemMetrics(SM_CYSCREEN);
sif.nMin = 0 ;
sif.nPage = HIWORD(lParam);
SetScrollInfo(hwnd, SB_VERT, & sif, TRUE);
// 设置水平滚动条的信息
sif.cbSize = sizeof (sif);
sif.fMask = SIF_RANGE | SIF_PAGE;
sif.nMax = GetSystemMetrics(SM_CXSCREEN);
sif.nMin = 0 ;
sif.nPage = LOWORD(lParam);
SetScrollInfo(hwnd, SB_HORZ, & sif, TRUE);
return 0 ;
}
case WM_VSCROLL:
{
int nVertPos;
SCROLLINFO sif;
sif.cbSize = sizeof (sif);
sif.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_VERT, & sif);
// 保存滚动条的当前位置.如果处理完消息后,滚动条的位置没变,我们就不用更新窗口了
nVertPos = sif.nPos;
switch ( LOWORD(wParam) )
{
case SB_LINEUP:
sif.nPos -= sif.nPage / 10 ;
break ;
case SB_LINEDOWN:
sif.nPos += sif.nPage / 10 ;
break ;
case SB_PAGEUP:
sif.nPos -= sif.nPage;
break ;
case SB_PAGEDOWN:
sif.nPos += sif.nPage;
break ;
case SB_THUMBTRACK:
sif.nPos = HIWORD(wParam);
break ;
}
sif.cbSize = sizeof (sif);
sif.fMask = SIF_POS;
// 设置滚动条的信息,然后再重新取得它的信息.因为windows会另外自动调整
// 滚动条的信息,而不是直接使用你设置的信息
// 例如对于sif.nMax,windows把它设置为sif.nMax = sif.nMax-sif.nPage+1
SetScrollInfo(hwnd, SB_VERT, & sif, TRUE);
GetScrollInfo(hwnd, SB_VERT, & sif);
if ( nVertPos != sif.nPos )
{
ScrollWindow(hwnd, 0 , nVertPos - sif.nPos, NULL, NULL);
UpdateWindow(hwnd);
}
return 0 ;
}
case WM_HSCROLL: // 水平滚动条几乎和垂直的一样处理,只是消息名称变了一点
{
int nHorzPos;
SCROLLINFO sif;
sif.cbSize = sizeof (sif);
sif.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_HORZ, & sif);
// 保存滚动条的当前位置.如果处理完消息后,滚动条的位置没变,我们就不用更新窗口了
nHorzPos = sif.nPos;
switch ( LOWORD(wParam) )
{
case SB_LINELEFT:
sif.nPos -= sif.nPage / 10 ;
break ;
case SB_LINERIGHT:
sif.nPos += sif.nPage / 10 ;
break ;
case SB_PAGELEFT:
sif.nPos -= sif.nPage;
break ;
case SB_PAGERIGHT:
sif.nPos += sif.nPage;
break ;
case SB_THUMBTRACK:
sif.nPos = HIWORD(wParam);
break ;
}
sif.cbSize = sizeof (sif);
// 设置滚动条的信息,然后再重新取得它的信息.因为windows会另外自动调整
// 滚动条的信息,而不是直接使用你设置的信息
// 例如对于sif.nMax,windows把它设置为sif.nMax = sif.nMax-sif.nPage+1
SetScrollInfo(hwnd, SB_HORZ, & sif, TRUE);
GetScrollInfo(hwnd, SB_HORZ, & sif);
if ( nHorzPos != sif.nPos )
{
ScrollWindow(hwnd, nHorzPos - sif.nPos, 0 , NULL, NULL);
UpdateWindow(hwnd);
}
return 0 ;
}
case WM_KEYDOWN:
{
switch (wParam)
{
// 模拟滚动信息.这样处理的话,当我们的程序逻辑改变的时候,只要修改一个地方的代码即可
case VK_LEFT:
SendMessage(hwnd, WM_HSCROLL, SB_LINELEFT, (LPARAM)NULL);
break ;
case VK_RIGHT:
SendMessage(hwnd, WM_HSCROLL, SB_LINERIGHT, (LPARAM)NULL);
break ;
case VK_UP:
SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)NULL);
break ;
case VK_DOWN:
SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)NULL);
break ;
case VK_PRIOR:
SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)NULL);
break ;
case VK_NEXT:
SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)NULL);
break ;
}
return 0 ;
}
case WM_MOUSEWHEEL: // 用鼠标滚轮也可以调整滚动条的位置
{
if (nDeltaPerLine == 0 )
{
break ;
}
nAccumDelta += ( short ) HIWORD (wParam) ; // 120 or -120
while (nAccumDelta >= nDeltaPerLine)
{
// 当滚动滑轮同时按下CTRL, 我们调整水平滚动条的位置
// 否则调整垂直滚动条的位置
// 在这里,和处理键盘消息一样,还是用模拟滚动消息的方法
SendMessage (hwnd,
LOWORD(wParam) & MK_CONTROL ? WM_HSCROLL : WM_VSCROLL,
LOWORD(wParam) & MK_CONTROL ? SB_LINELEFT : SB_LINEUP,
0 );
nAccumDelta -= nDeltaPerLine ;
}
while (nAccumDelta <= - nDeltaPerLine)
{
SendMessage (hwnd,
LOWORD(wParam) & MK_CONTROL ? WM_HSCROLL : WM_VSCROLL,
LOWORD(wParam) & MK_CONTROL ? SB_LINEDOWN : SB_LINEDOWN,
0 ) ;
nAccumDelta += nDeltaPerLine ;
}
return 0 ;
}
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
SCROLLINFO sif;
int nVertPos, nHorzPos;
// 取得滚动信息以决定我们的图画到哪到位置
sif.cbSize = sizeof (sif);
sif.fMask = SIF_POS;
GetScrollInfo(hwnd, SB_VERT, & sif);
nVertPos = sif.nPos;
// 取得滚动信息以决定我们的图画到哪到位置
sif.cbSize = sizeof (sif);
sif.fMask = SIF_POS;
GetScrollInfo(hwnd, SB_HORZ, & sif);
nHorzPos = sif.nPos;
// 画图
hdc = BeginPaint(hwnd, & ps);
BitBlt(hdc, - nHorzPos, - nVertPos, cxScreen, cyScreen, hdcMem, 0 , 0 , SRCCOPY);
EndPaint(hwnd, & ps);
return 0 ;
}
case WM_DESTROY:
DeleteDC(hdcMem); // 别忘了做清理工作!!!
DeleteObject(hbmp);
PostQuitMessage( 0 );
return 0 ;
}
return DefWindowProc( hwnd,message,wParam,lParam );
}
// 一个完善的滚动功能,应该可以让用户用键盘和鼠标调整滚动条的位置
// 而且滑块的大小不应该是固定的
// 这需要调用SetScrollInfo和GetScrollInfo来处理
// WM_VSCROLL和WM_HSCROLL消息
// 同时还要处理WM_KEYDOWN消息和WM_MOUSEWHEEL消息
// 还要在WM_SIZE消息中更新滚动条的信息
// 总结:
// 1.在窗口大小改变时,即处理WM_SIZE消息时更新滚动条的信息以改变滚动条滑块的大小
// 而这会同时改变位置的范围.这须要调用SetScrollInfo
// 2.处理WM_VSCROLL和WM_HSCROLL,根据消息参数改变滚动条的位置
// 这其中要多次调用SetScrollInfo和GetScrollInfo
// 3.处理WM_KEYDOWN和WM_MOUSEWHEEL完善功能
// 以下的程序在窗口中显示了显示器的内容
// 由于窗口没有显示器大,所以需要滚动条
#define _WIN32_WINNT 0x0500 // 为了使用WM_MOUSEWHEEL
#include < windows.h >
// 过程函数的返回值都是LRESULT,类型都是CALLBACK
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpszCmdLine, int nCmdShow)
{
HWND hwnd; // 主窗口句柄,在CreateWindow中赋值
MSG msg; // 消息变量,在GetMessage中使用
WNDCLASS wndclass; // 窗口类
TCHAR * szAppName = TEXT( " CBViewer " ); // 类名和窗口名
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 窗口背景
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); // 鼠标
wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION); // 图标
wndclass.lpszClassName = szAppName; // 类名
wndclass.cbClsExtra = 0 ; // 类的额外参数
wndclass.cbWndExtra = 0 ; // 窗口的额外参数.用于基于同一窗口类的窗口各自区分.
// 在自定义对话框类时必须指定为DLGWINDOWEXTRA的大小
wndclass.lpszMenuName = NULL; // 菜单名.可以用作子窗口的id
wndclass.style = CS_HREDRAW | CS_VREDRAW; // 窗口风格
wndclass.lpfnWndProc = WndProc; // 窗口过程
wndclass.hInstance = hInstance; // 包含窗口过程的实例句柄
if ( ! RegisterClass( & wndclass) ) // 注册窗口类
return 0 ;
hwnd = CreateWindow( // 创建窗口
szAppName, // 窗口类名
szAppName, // 窗口标题
WS_OVERLAPPEDWINDOW, // 窗口风格
CW_USEDEFAULT, // 初始的x坐标
CW_USEDEFAULT, // 初始的y坐标
CW_USEDEFAULT, // 初始的宽度
CW_USEDEFAULT, // 初始的高度
NULL, // 父窗口
NULL, // 菜单
hInstance, // 和窗口相关的实例句柄
NULL // 额外参数
);
ShowWindow( hwnd,nCmdShow ); // 显示窗口
UpdateWindow( hwnd ); // 更新窗口
while ( GetMessage( & msg,NULL, 0 , 0 ) ) // 消息循环
{
TranslateMessage( & msg); // 将WM_XXXKEYXXX消息翻译为WM_CHAR消息
DispatchMessage( & msg); // 传递消息到窗口过程
}
return msg.wParam; // 返回
}
LRESULT WINAPI WndProc( HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam )
{
static int nDeltaPerLine, nAccumDelta ; // 在WM_MOUSEWHEEL中使用
static HDC hdcMem; // 用作BitBlt的源DC
static HBITMAP hbmp; // 桌面位图
static int cxScreen, cyScreen; // 屏幕大小
switch ( message )
{
case WM_CREATE:
{
HWND hwndDesktop = GetDesktopWindow(); // 桌面句柄
HDC hdcDesktop = GetWindowDC(hwndDesktop); // 桌面DC
cxScreen = GetSystemMetrics(SM_CXSCREEN); // 桌面大小
cyScreen = GetSystemMetrics(SM_CYSCREEN);
hbmp = CreateCompatibleBitmap( // 与桌面DC兼容的位图
hdcDesktop,
cxScreen,
cyScreen);
hdcMem = CreateCompatibleDC(hdcDesktop); // 与桌面DC兼容的内存DC
SelectObject(hdcMem, hbmp);
// 将桌面内容保存到内存位图中, 以在WM_PAINT中画到客户窗口
BitBlt(hdcMem, 0 , 0 , cxScreen, cyScreen, hdcDesktop, 0 , 0 , SRCCOPY);
ReleaseDC(hwndDesktop, hdcDesktop);
}
case WM_SETTINGCHANGE:
{
ULONG ulScrollLines ;
SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0 , & ulScrollLines, 0 ) ;
// ulScrollLines usually equals 3 or 0 (for no scrolling)
// WHEEL_DELTA equals 120, so nDeltaPerLine will be 40
if (ulScrollLines)
{
nDeltaPerLine = WHEEL_DELTA / ulScrollLines ;
}
else
{
nDeltaPerLine = 0 ;
}
return 0 ;
}
case WM_SIZE:
{
SCROLLINFO sif;
// 设置垂直滚动条的信息
sif.cbSize = sizeof (sif);
sif.fMask = SIF_RANGE | SIF_PAGE;
sif.nMax = GetSystemMetrics(SM_CYSCREEN);
sif.nMin = 0 ;
sif.nPage = HIWORD(lParam);
SetScrollInfo(hwnd, SB_VERT, & sif, TRUE);
// 设置水平滚动条的信息
sif.cbSize = sizeof (sif);
sif.fMask = SIF_RANGE | SIF_PAGE;
sif.nMax = GetSystemMetrics(SM_CXSCREEN);
sif.nMin = 0 ;
sif.nPage = LOWORD(lParam);
SetScrollInfo(hwnd, SB_HORZ, & sif, TRUE);
return 0 ;
}
case WM_VSCROLL:
{
int nVertPos;
SCROLLINFO sif;
sif.cbSize = sizeof (sif);
sif.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_VERT, & sif);
// 保存滚动条的当前位置.如果处理完消息后,滚动条的位置没变,我们就不用更新窗口了
nVertPos = sif.nPos;
switch ( LOWORD(wParam) )
{
case SB_LINEUP:
sif.nPos -= sif.nPage / 10 ;
break ;
case SB_LINEDOWN:
sif.nPos += sif.nPage / 10 ;
break ;
case SB_PAGEUP:
sif.nPos -= sif.nPage;
break ;
case SB_PAGEDOWN:
sif.nPos += sif.nPage;
break ;
case SB_THUMBTRACK:
sif.nPos = HIWORD(wParam);
break ;
}
sif.cbSize = sizeof (sif);
sif.fMask = SIF_POS;
// 设置滚动条的信息,然后再重新取得它的信息.因为windows会另外自动调整
// 滚动条的信息,而不是直接使用你设置的信息
// 例如对于sif.nMax,windows把它设置为sif.nMax = sif.nMax-sif.nPage+1
SetScrollInfo(hwnd, SB_VERT, & sif, TRUE);
GetScrollInfo(hwnd, SB_VERT, & sif);
if ( nVertPos != sif.nPos )
{
ScrollWindow(hwnd, 0 , nVertPos - sif.nPos, NULL, NULL);
UpdateWindow(hwnd);
}
return 0 ;
}
case WM_HSCROLL: // 水平滚动条几乎和垂直的一样处理,只是消息名称变了一点
{
int nHorzPos;
SCROLLINFO sif;
sif.cbSize = sizeof (sif);
sif.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_HORZ, & sif);
// 保存滚动条的当前位置.如果处理完消息后,滚动条的位置没变,我们就不用更新窗口了
nHorzPos = sif.nPos;
switch ( LOWORD(wParam) )
{
case SB_LINELEFT:
sif.nPos -= sif.nPage / 10 ;
break ;
case SB_LINERIGHT:
sif.nPos += sif.nPage / 10 ;
break ;
case SB_PAGELEFT:
sif.nPos -= sif.nPage;
break ;
case SB_PAGERIGHT:
sif.nPos += sif.nPage;
break ;
case SB_THUMBTRACK:
sif.nPos = HIWORD(wParam);
break ;
}
sif.cbSize = sizeof (sif);
// 设置滚动条的信息,然后再重新取得它的信息.因为windows会另外自动调整
// 滚动条的信息,而不是直接使用你设置的信息
// 例如对于sif.nMax,windows把它设置为sif.nMax = sif.nMax-sif.nPage+1
SetScrollInfo(hwnd, SB_HORZ, & sif, TRUE);
GetScrollInfo(hwnd, SB_HORZ, & sif);
if ( nHorzPos != sif.nPos )
{
ScrollWindow(hwnd, nHorzPos - sif.nPos, 0 , NULL, NULL);
UpdateWindow(hwnd);
}
return 0 ;
}
case WM_KEYDOWN:
{
switch (wParam)
{
// 模拟滚动信息.这样处理的话,当我们的程序逻辑改变的时候,只要修改一个地方的代码即可
case VK_LEFT:
SendMessage(hwnd, WM_HSCROLL, SB_LINELEFT, (LPARAM)NULL);
break ;
case VK_RIGHT:
SendMessage(hwnd, WM_HSCROLL, SB_LINERIGHT, (LPARAM)NULL);
break ;
case VK_UP:
SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)NULL);
break ;
case VK_DOWN:
SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)NULL);
break ;
case VK_PRIOR:
SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)NULL);
break ;
case VK_NEXT:
SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)NULL);
break ;
}
return 0 ;
}
case WM_MOUSEWHEEL: // 用鼠标滚轮也可以调整滚动条的位置
{
if (nDeltaPerLine == 0 )
{
break ;
}
nAccumDelta += ( short ) HIWORD (wParam) ; // 120 or -120
while (nAccumDelta >= nDeltaPerLine)
{
// 当滚动滑轮同时按下CTRL, 我们调整水平滚动条的位置
// 否则调整垂直滚动条的位置
// 在这里,和处理键盘消息一样,还是用模拟滚动消息的方法
SendMessage (hwnd,
LOWORD(wParam) & MK_CONTROL ? WM_HSCROLL : WM_VSCROLL,
LOWORD(wParam) & MK_CONTROL ? SB_LINELEFT : SB_LINEUP,
0 );
nAccumDelta -= nDeltaPerLine ;
}
while (nAccumDelta <= - nDeltaPerLine)
{
SendMessage (hwnd,
LOWORD(wParam) & MK_CONTROL ? WM_HSCROLL : WM_VSCROLL,
LOWORD(wParam) & MK_CONTROL ? SB_LINEDOWN : SB_LINEDOWN,
0 ) ;
nAccumDelta += nDeltaPerLine ;
}
return 0 ;
}
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
SCROLLINFO sif;
int nVertPos, nHorzPos;
// 取得滚动信息以决定我们的图画到哪到位置
sif.cbSize = sizeof (sif);
sif.fMask = SIF_POS;
GetScrollInfo(hwnd, SB_VERT, & sif);
nVertPos = sif.nPos;
// 取得滚动信息以决定我们的图画到哪到位置
sif.cbSize = sizeof (sif);
sif.fMask = SIF_POS;
GetScrollInfo(hwnd, SB_HORZ, & sif);
nHorzPos = sif.nPos;
// 画图
hdc = BeginPaint(hwnd, & ps);
BitBlt(hdc, - nHorzPos, - nVertPos, cxScreen, cyScreen, hdcMem, 0 , 0 , SRCCOPY);
EndPaint(hwnd, & ps);
return 0 ;
}
case WM_DESTROY:
DeleteDC(hdcMem); // 别忘了做清理工作!!!
DeleteObject(hbmp);
PostQuitMessage( 0 );
return 0 ;
}
return DefWindowProc( hwnd,message,wParam,lParam );
}