我需要一些额外的步骤来注册对 DeviceContext 的更改吗?
Posted
技术标签:
【中文标题】我需要一些额外的步骤来注册对 DeviceContext 的更改吗?【英文标题】:Do I need some extra steps to register the changes to the DeviceContext? 【发布时间】:2021-08-25 21:22:32 【问题描述】:所以我试图用 rust 制作一个 win32 覆盖,但过了一段时间我意识到由于我组织代码的方式不佳,有些东西太难添加 - 我正在尝试以更合适的方式重写它方式。然而,我的特殊问题是现在处于重写状态(现在使用 mem dc 进行双缓冲),我无法让我的位图出现在屏幕上。
由于 GetLastError 返回 0,我似乎无法确定问题所在。
我当前的窗口脚本如下:
use crate::static_helpers::win32_string;
use winapi::um::winuser::WM_PAINT, WM_TIMER, WNDCLASSW, DefWindowProcW, ShowWindow, SW_NORMAL, WS_POPUP, WS_EX_TRANSPARENT, WS_EX_LAYERED, WS_EX_TOPMOST, WS_EX_TOOLWINDOW, WS_VISIBLE, CreateWindowExW, RegisterClassW, CS_HREDRAW, CS_OWNDC, CS_VREDRAW, SetLayeredWindowAttributes, SW_SHOWMAXIMIZED, LWA_COLORKEY, ReleaseDC, InvalidateRect, EndPaint, PAINTSTRUCT, BeginPaint, GetClientRect, MSG, GetMessageW, SetTimer, USER_TIMER_MINIMUM, TIMERPROC, GetDC, UpdateWindow;
use winapi::shared::windef::HWND__, HDC__, HWND, RECT, HDC, HBITMAP, HGDIOBJ;
use std::time::SystemTime;
use winapi::shared::minwindef::UINT, WPARAM, LPARAM, LRESULT, HINSTANCE;
use std::ptr::null_mut;
use winapi::um::wingdi::CreateSolidBrush, RGB, DeleteDC, SelectObject, BitBlt, GetStockObject, DC_PEN, SRCCOPY, CreateCompatibleDC, BITMAP, CreateBitmap, CreateCompatibleBitmap, ExtFloodFill;
use winapi::um::libloaderapi::GetModuleHandleW;
use winapi::um::errhandlingapi::GetLastError;
pub struct Overlay
window_class: WNDCLASSW,
// window class stored
window_handle: *mut HWND__,
// window handle stored
mem_dc: Option<*mut HDC__>,
// buffer dc
screen_dc: Option<*mut HDC__>,
// screen dc
bitmap_bg: HBITMAP,
impl Overlay
// redirects event handling to default handler
pub unsafe extern "system" fn proc_msg(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> LRESULT
match msg
_ => return DefWindowProcW(hwnd, msg, wparam, lparam);
// creates new instance
pub unsafe fn new(class_name: String, window_name: String) -> Self
// gets module instance handle to register stuff
let hinstance = GetModuleHandleW(null_mut());
// makes window class
let wnd_class = WNDCLASSW
style: CS_HREDRAW | CS_OWNDC | CS_VREDRAW,
lpfnWndProc: Some(Self::proc_msg),
hInstance: hinstance as HINSTANCE,
lpszClassName: win32_string(&class_name).as_ptr(),
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: CreateSolidBrush(RGB(0, 0, 0)), // brush so repaint works
lpszMenuName: null_mut(),
;
// registers class (returns atom but i don`t need it so far)
RegisterClassW(&wnd_class);
/*
creating window
transparent style for event pipethrough, toolwindow style hides from alt+tab and task mgr
popup and visible are to keep it fullscreen with no title bar
*/
let handle: *mut HWND__ = CreateWindowExW(WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
win32_string(&class_name).as_ptr(),
win32_string(&window_name).as_ptr(),
WS_POPUP | WS_VISIBLE,
0,
0,
1919,
1079,
null_mut(),
null_mut(),
hinstance,
null_mut(),
) as *mut HWND__;
// getting window dc
let window_dc = GetDC(handle);
//make a buffer dc
let mem_dc = CreateCompatibleDC(window_dc);
//make bg bitmap and fill it to change size of dc
let bmp = CreateCompatibleBitmap(mem_dc, 1920, 1080);
SelectObject(mem_dc, bmp as HGDIOBJ);
ShowWindow(handle, SW_NORMAL);
return Self
window_class: wnd_class,
window_handle: handle,
mem_dc: Some(mem_dc),
screen_dc: Some(window_dc),
bitmap_bg: bmp,
;
pub unsafe fn make_transparent(&mut self)
ShowWindow(self.window_handle, SW_SHOWMAXIMIZED); // maximize
SetLayeredWindowAttributes(self.window_handle, RGB(0, 0, 0), 0, LWA_COLORKEY); // set transparent
pub fn die(&mut self)
unsafe
match self.mem_dc
Some(mut hDC) =>
DeleteDC(hDC);
_ =>
match self.screen_dc
Some(mut hDC) =>
ReleaseDC(self.window_handle, hDC);
_ =>
// takes anything which takes mutable dc, and handle - and returns bool
pub unsafe fn do_loop<T1: FnMut(*mut HWND, *mut HDC__) -> bool>(&mut self, mut cb: T1)
let mut rc: RECT = RECT::default();
loop
let mut msg: MSG = std::mem::uninitialized(); // later switch to zeroed
if GetMessageW(&mut msg as *mut MSG, self.window_handle, 0, 0).is_positive()
//prep dc canvas
ExtFloodFill(self.mem_dc.unwrap(), 1920, 1080, RGB(0, 0, 0), FLOODFILLBORDER);
// passing window handle and buffer dc
if cb(&mut self.window_handle, self.mem_dc.unwrap())
// if returned true - change current screen to buffer dc
BitBlt(self.screen_dc.unwrap(), 0, 0, 1920, 1080, self.mem_dc.unwrap(), 0, 0, SRCCOPY);
;
else
break;
我尝试在我的main.rs
中调用它,如下所示:
mod overlay;
mod static_helpers;
mod event_poller;
use static_helpers::TestCat;
use overlay::Overlay;
use winapi::um::libloaderapi::GetModuleHandleW;
use std::ptr::null_mut;
use winapi::shared::windef::HDC;
use winapi::um::wingdi::BitBlt, SRCCOPY;
fn main()
let REDRAW: String = String::from("REDRAW");
unsafe
let mut ticker = event_poller::EventPoller::new();
ticker.add_event((40, "REDRAW".to_owned()));
let cat = TestCat::new("C:\\Users\\grass\\Desktop\\codes\\Rust\\catso_v2\\src\\cat2.bmp");
let mut win: Overlay = Overlay::new("hewwo".to_owned(), "UwU".to_owned());
win.make_transparent();
win.do_loop(|handle, hdc| -> bool
match (&mut ticker).ask()
None =>
Some(events) =>
if events.contains(&REDRAW)
BitBlt(hdc, 0, 0, 100, 100, cat.src, 0, 0, SRCCOPY);
return true;
;
false
);
win.die();
计时器结构(存储在ticker
变量中)正常工作,但为了完整起见,这里是:
use std::time::SystemTime;
pub struct EventPoller
events: Vec::<(u128, SystemTime, String)>,
impl EventPoller
pub fn new() -> Self
Self
events: Vec::new(),
pub fn add_event(&mut self, event: (u128, String))
&self.events.push((event.0, SystemTime::now(), event.1));
pub fn ask(&mut self) -> Option<Vec<String>>
let now = SystemTime::now();
let mut time_passed: u128;
let mut ret: Vec<String> = Vec::new();
for i in 0..(&self.events).len() as usize
time_passed = now.duration_since((&self.events[i]).1).unwrap().as_millis();
if time_passed > (&self.events[i]).0
ret.push((&mut self.events[i]).2.clone());
(&mut self.events[i]).1 = now.clone();
if ret.len() > 0
Some(ret)
else
None
同样适用于一个简单的 TestCat
结构,它仅用于测试目的(见下文):
pub struct TestCat
pub src: *mut HDC__
impl TestCat
pub unsafe fn new(fname: &str) -> Self
let im_handle = LoadImageW(null_mut(),
win32_string(fname).as_ptr(),
IMAGE_BITMAP,
LR_DEFAULTSIZE as i32,
LR_DEFAULTSIZE as i32,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
let hdc: HDC = CreateCompatibleDC(null_mut());
SelectObject(hdc,im_handle);
Self src: hdc
到目前为止,我尝试做的几件事是:
在开始时将位图添加到mem_dc
,以确保它不包含 1x1 单色的。
事先调用InvalidateRect
,带或不带擦除参数。
捕获 WM_DRAW 消息并预先检查可用更新,然后在其中调用相同的 BitBlt
。
以下是我的旧代码 - 到目前为止有效,并且是造成混乱的根源,因为我真的不明白关键区别是什么:
transparent_window.rs
:
#![windows_subsystem = "windows"]
use std::alloc::alloc, Layout;
use std::collections::HashMap;
use std::ffi::c_void, OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::ptr::null, null_mut;
use std::ptr;
use std::time::SystemTime;
use winapi::shared::minwindef::HINSTANCE, LPARAM, LRESULT, UINT, WPARAM;
use winapi::shared::windef::HDC, HDC__, HGDIOBJ, HWND, HWND__, POINT, RECT, SIZE;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::libloaderapi::GetModuleHandleW;
use winapi::um::wingdi::AC_SRC_ALPHA, AC_SRC_OVER, BitBlt, BLENDFUNCTION, CreateCompatibleDC, CreatePen, CreateSolidBrush, DC_PEN, DeleteDC, DeleteObject, DEVMODEW, GetClipBox, GetStockObject, PS_SOLID, Rectangle, RGB, SelectObject, SRCCOPY;
use winapi::um::winuser::BeginPaint, CDS_FULLSCREEN, ChangeDisplaySettingsW, CreateWindowExW, CS_HREDRAW, CS_OWNDC, CS_VREDRAW, CW_USEDEFAULT, DefWindowProcW, DispatchMessageW, EndPaint, GetClientRect, GetDC, GetMessageW, GetParent, GetWindow, GetWindowLongW, GetWindowRect, GW_HWNDNEXT, GWL_EXSTYLE, IMAGE_BITMAP, InvalidateRect, LoadImageW, LR_LOADFROMFILE, LWA_COLORKEY, MSG, PAINTSTRUCT, RDW_ERASE, RDW_INVALIDATE, RDW_UPDATENOW, RedrawWindow, RegisterClassW, ReleaseDC, ScreenToClient, SetLayeredWindowAttributes, SetWindowLongW, ShowWindow, SW_NORMAL, SW_SHOWMAXIMIZED, TranslateMessage, ULW_COLORKEY, UpdateLayeredWindow, WM_ERASEBKGND, WM_PAINT, WM_TIMER, WNDCLASSW, WS_EX_APPWINDOW, WS_EX_CLIENTEDGE, WS_EX_DLGMODALFRAME, WS_EX_LAYERED, WS_EX_STATICEDGE, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_POPUPWINDOW, WS_SYSMENU, WS_THICKFRAME, WS_VISIBLE;
use winapi::um::winuser::WM_KEYDOWN, WM_KEYUP;
fn win32_string(value: &str) -> Vec<u16>
OsStr::new(value).encode_wide().chain(once(0)).collect()
pub struct BasicWindow
window_class: WNDCLASSW,
window_handle: *mut HWND__,
mem_DC: Option<*mut HDC__>,
screen_DC: Option<*mut HDC__>,
UpdateClock: SystemTime,
update_frequency: u128,
impl BasicWindow
pub unsafe extern "system" fn proc_msg(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> LRESULT
match msg
_ => return DefWindowProcW(hwnd, msg, wparam, lparam);
pub fn new(class_name: String, window_name: String) -> Self
unsafe
let hinstance = GetModuleHandleW(null_mut());
let wnd_class = WNDCLASSW
style: CS_HREDRAW | CS_OWNDC | CS_VREDRAW,
lpfnWndProc: Some(Self::proc_msg),
hInstance: hinstance as HINSTANCE,
lpszClassName: win32_string(&class_name).as_ptr(),
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: CreateSolidBrush(RGB(0, 0, 0)),
lpszMenuName: null_mut(),
;
let atom = RegisterClassW(&wnd_class);
let handle: *mut HWND__ = CreateWindowExW(WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
win32_string(&class_name).as_ptr(),
win32_string(&window_name).as_ptr(),
WS_POPUP | WS_VISIBLE,
0,
0,
1919,
1079,
null_mut(),
null_mut(),
hinstance,
null_mut(),
) as *mut HWND__;
ShowWindow(handle, SW_NORMAL);
return Self
window_class: wnd_class,
window_handle: handle,
mem_DC: None,
screen_DC: None,
UpdateClock: SystemTime::now(),
update_frequency: 40,
;
pub unsafe fn make_transparent(&mut self)
let show_outcome = ShowWindow(self.window_handle, SW_SHOWMAXIMIZED);
let outcome = SetLayeredWindowAttributes(self.window_handle, RGB(0, 0, 0), 0, LWA_COLORKEY);
println!("Error: :?\nSetLayeredWindowAttributes outcome: :?\nShowWindow outcome: :?",
GetLastError(),
outcome,
show_outcome);
pub fn die(&mut self)
unsafe
match self.mem_DC
Some(mut hDC) =>
DeleteDC(hDC);
_ =>
match self.screen_DC
Some(mut hDC) =>
ReleaseDC(self.window_handle, hDC);
_ =>
pub unsafe fn do_loop<T1: FnMut() -> Option<(HDC, u32, u32, u32, u32, u32, u32)>>(&mut self,
mut tile_giver: T1)
loop
let mut msg: MSG = std::mem::uninitialized();
if GetMessageW(&mut msg as *mut MSG, self.window_handle, 0, 0).is_positive()
match msg.message
WM_PAINT =>
println!("WM_PAINT!!");
let mut ps = PAINTSTRUCT::default();
let dc = BeginPaint(self.window_handle, &mut ps);
let mut rc = RECT::default();
GetClientRect(self.window_handle, &mut rc);
let hdi_obj_original = SelectObject(ps.hdc, GetStockObject(DC_PEN as i32));
match (tile_giver())
(Some((hdc, x, y, w, h, x_pos, y_pos))) =>
println!("blt returned: :?", BitBlt(dc, x_pos as i32, y_pos as i32, w as i32, h as i32, hdc, x as i32, y as i32, SRCCOPY));
_ =>
SelectObject(ps.hdc, hdi_obj_original);
EndPaint(self.window_handle, &ps);
InvalidateRect(self.window_handle,
&mut rc,
1);
_ =>
else
break;
我传递给它的 do_loop
方法的闭包:
|| -> Option<(HDC, u32, u32, u32, u32, u32, u32)>
let x = sprite.give_tile();
sprite.skip();
x
其中通过的dc获取方式如下:
let im_handle = LoadImageW(null_mut(),
win32_string(fname).as_ptr(),
IMAGE_BITMAP,
LR_DEFAULTSIZE as i32,
LR_DEFAULTSIZE as i32,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
let hdc: HDC = CreateCompatibleDC(null_mut());
SelectObject(hdc,im_handle);
为了提供可重现的示例 - 这是我的 cargo.toml
文件:
[dependencies]
winapi = "0.3.9"
[features]
default=["winapi/winuser","winapi/minwindef","winapi/windef",
"winapi/wingdi","winapi/libloaderapi","winapi/errhandlingapi","winapi/impl-default"]
我怀疑有一些函数可以在执行位 blit 后触发实际的视觉更新,比如 invalidate rect(我知道InvalidateRect
只会导致 WM_PAINT 在有或没有擦除背景的情况下被触发,但基本上我假设我可能需要调用一些东西来注册 BeginPaint
和 EndPaint
之外的图形更改)。如果有人可以通过指出问题来提供帮助,或者如果您愿意并且有时间告诉我 WM_PAINT WindowProc 匹配臂之外的最小绘图过程应该是什么样子。
更新: 作为对反馈的回应,我从代码中剔除了不必要的内容,剩下的内容如下:
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::ptr::null_mut;
use std::time::SystemTime;
use winapi::shared::minwindef::HINSTANCE;
use winapi::shared::windef::HDC__, HWND__;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::libloaderapi::GetModuleHandleW;
use winapi::um::wingdi::BitBlt, CreateCompatibleDC, CreateSolidBrush, ExtFloodFill, FLOODFILLBORDER, RGB, SelectObject, SRCCOPY;
use winapi::um::winuser::CreateWindowExW, CS_HREDRAW, CS_OWNDC, CS_VREDRAW, DefWindowProcW, GetDC, GetMessageW, IMAGE_BITMAP, LoadImageW, LR_CREATEDIBSECTION, LR_DEFAULTSIZE, LR_LOADFROMFILE, LWA_COLORKEY, MSG, RegisterClassW, SetLayeredWindowAttributes, ShowWindow, SW_SHOWMAXIMIZED, WNDCLASSW, WS_EX_LAYERED, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_POPUP, WS_VISIBLE;
pub fn win32_string(value: &str) -> Vec<u16>
OsStr::new(value).encode_wide().chain(once(0)).collect()
unsafe fn make_win() -> (*mut HWND__, *mut HDC__, *mut HDC__)
let hinstance = GetModuleHandleW(null_mut());
let wndclass = WNDCLASSW
style: CS_HREDRAW | CS_OWNDC | CS_VREDRAW,
lpfnWndProc: Some(DefWindowProcW),
hInstance: hinstance as HINSTANCE,
lpszClassName: win32_string("uwu").as_ptr(),
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: CreateSolidBrush(RGB(0, 0, 0)),
lpszMenuName: null_mut(),
;
RegisterClassW(&wndclass);
let handle: *mut HWND__ = CreateWindowExW(WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
win32_string("uwu").as_ptr(),
win32_string("owo").as_ptr(),
WS_POPUP | WS_VISIBLE,
0,
0,
1919,
1079,
null_mut(),
null_mut(),
hinstance,
null_mut(),
) as *mut HWND__;
let mut dc = GetDC(handle);
let mut c_mem_dc = CreateCompatibleDC(dc);
return (handle, dc, c_mem_dc);
pub unsafe fn make_trasnparent(handle: *mut HWND__)
ShowWindow(handle, SW_SHOWMAXIMIZED);
SetLayeredWindowAttributes(handle, RGB(0, 0, 0),
0, LWA_COLORKEY);
fn main()
unsafe
let (handle, dc, c_mem_dc) = make_win();
make_trasnparent(handle);
let mut image = CreateCompatibleDC(null_mut());
SelectObject(image, LoadImageW(null_mut(),
win32_string("C:\\Users\\grass\\Desktop\\codes\\Rust\\catso_v2\\src\\cat2.bmp").as_ptr(),
IMAGE_BITMAP,
LR_DEFAULTSIZE as i32,
LR_DEFAULTSIZE as i32,
LR_LOADFROMFILE | LR_CREATEDIBSECTION));
let mut msg: MSG = std::mem::uninitialized();
let mut back_then = SystemTime::now();
loop
if GetMessageW(&mut msg as *mut MSG, handle, 0, 0).is_positive()
let now = SystemTime::now();
if now.duration_since(back_then)
.unwrap()
.as_millis() > 40
ExtFloodFill(c_mem_dc, 1920, 1080, RGB(0, 0, 0), FLOODFILLBORDER);
BitBlt(c_mem_dc, 0, 0, 100, 100, image, 0, 0, SRCCOPY);
BitBlt(dc, 0, 0, 1920, 1080, c_mem_dc, 0, 0, SRCCOPY);
back_then = now;
;
else
break;
问题依旧,同样使用cargo.toml
。
更新:
我已经打印了几次迭代的所有返回值。到目前为止,我加载的图像返回了一个有效的句柄,CreateCompatibleDC
也是如此。 BitBlt
都返回 1,因此它们成功了。 GetLastError
总是返回零。
我尝试做的另一件事是创建一个兼容的位图并将其选择到 c_mem_dc
以确保它具有适当的位图大小,如下所述:another SO question 但是这没有帮助。
【问题讨论】:
复杂的代码无法帮助我们重现问题,您能否在没有私人信息的情况下显示a minimal, reproducible sample? @SongZhu 我希望更新问题中的压缩版本更好。我不确定我理解你所说的私人信息是什么意思?图像的路径是关注的主题? - 我应该提供图片吗? 【参考方案1】:很抱歉我对rust了解不多,所以我通过C++尝试了代码,确实可以重现问题。我认为你的绘图有问题。
我修改为如下代码,大家可以参考修改为rust代码:
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HBITMAP bitmap;
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR szCmdLine, _In_ int iCmdShow)
static TCHAR szAppName[] = TEXT("hello windows");
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_OWNDC | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
HWND hwnd = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW,
szAppName,
TEXT("the hello program"),
WS_POPUP | WS_VISIBLE,
0,
0,
800,
600,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0),
0, LWA_COLORKEY);
bitmap = (HBITMAP)LoadImage(NULL, L"shaokao.bmp", IMAGE_BITMAP, LR_DEFAULTSIZE,
LR_DEFAULTSIZE, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
return msg.wParam;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
PAINTSTRUCT ps;
HDC hdc;
switch (message)
case WM_PAINT:
BITMAP bm;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, bitmap);
GetObject(bitmap, sizeof(bm), &bm);
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
return DefWindowProc(hwnd, message, wParam, lParam);
它对我有用。
【讨论】:
是的,我有一些类似的东西也适用于我 - 我的问题是我想避免在 WindowProc 中绘图。因为我想介绍一些可通过自引用访问的变量并控制绘图频率。 你得到了所有这些,并且仍然在WM_PAINT
处理程序中进行所有渲染。为此,请使用计时器 (SetTimer
) 并使 WM_TIMER
消息处理程序中的整个客户区无效。如果要更改频率,只需 KillTimer
和 SetTimer
使用新的间隔。您还可以将任意数据与窗口相关联。要获得强大且最小的实现,请查看win-win crate。以上是关于我需要一些额外的步骤来注册对 DeviceContext 的更改吗?的主要内容,如果未能解决你的问题,请参考以下文章