我需要一些额外的步骤来注册对 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 在有或没有擦除背景的情况下被触发,但基本上我假设我可能需要调用一些东西来注册 BeginPaintEndPaint 之外的图形更改)。如果有人可以通过指出问题来提供帮助,或者如果您愿意并且有时间告诉我 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 消息处理程序中的整个客户区无效。如果要更改频率,只需 KillTimerSetTimer 使用新的间隔。您还可以将任意数据与窗口相关联。要获得强大且最小的实现,请查看win-win crate。

以上是关于我需要一些额外的步骤来注册对 DeviceContext 的更改吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 注册表单中添加额外的字段?

几分钟快速了解Eureka原理

django注册自定义发送激活邮件

您可能需要额外的加载器来处理这些加载器的结果

数据结构的扩张

如何影响目标的顺序,为 Makefile.am 添加额外的步骤等?