当前位置: 首页 > news >正文

新闻类网站排版网站建设建网站需要什么

新闻类网站排版网站建设,建网站需要什么,企业营销型网站建设优惠,导航网站能个人备案视频参考:https://www.bilibili.com/video/BV1aDmqYnEnc/ BitBlt 是 Windows GDI#xff08;图形设备接口#xff09;中的一个函数#xff0c;用于在设备上下文#xff08;device context, DC#xff09;之间复制位图数据。BitBlt 的主要用途是将一个图像区域从一个地方复…视频参考:https://www.bilibili.com/video/BV1aDmqYnEnc/ BitBlt 是 Windows GDI图形设备接口中的一个函数用于在设备上下文device context, DC之间复制位图数据。BitBlt 的主要用途是将一个图像区域从一个地方复制到另一个地方常用于图像绘制、屏幕刷新、动画等。 BitBlt 函数的基本签名如下 BOOL BitBlt(HDC hdcDest, // 目标设备上下文句柄int nXDest, // 目标区域左上角的X坐标int nYDest, // 目标区域左上角的Y坐标int nWidth, // 复制区域的宽度int nHeight, // 复制区域的高度HDC hdcSrc, // 源设备上下文句柄int nXSrc, // 源区域左上角的X坐标int nYSrc, // 源区域左上角的Y坐标DWORD dwRop // 光栅操作代码 );按照下面修改对 DIBSection 的内存分配进行了优化通过直接使用 VirtualAlloc 和 VirtualFree 管理内存这种方法比之前使用 CreateDIBSection 更加灵活且具备一定的性能和内存管理优势。以下是两个版本的主要区别和优化原因: 直接控制内存分配和释放 后面的代码版本用 VirtualAlloc 和 VirtualFree 直接管理内存而不是依赖 CreateDIBSection 自动创建的位图内存。这种方式可以带来以下好处 更灵活的内存管理可以更精确地控制内存分配和释放的方式MEM_COMMIT 和 MEM_RELEASE避免了不必要的内存开销。 减少资源依赖省去了调用 DeleteObject 和 CreateDIBSection 的复杂性减少对 GDI图形设备接口的依赖简化代码逻辑。 避免频繁的设备上下文操作 在前一个版本中每次都需要检查和重新生成设备上下文BitmapDeviceContext。而后面版本取消了设备上下文的依赖通过 VirtualAlloc 直接分配内存从而避免了设备上下文的频繁操作这样可以减少系统开销并提高性能。 改善代码健壮性和性能 后面的代码版本简化了 DIBSection 的创建过程同时提高了代码的健壮性。例如 在释放内存前检查 BitmapMemory 是否为 NULL确保不会重复释放无效的内存地址。 设置了 BytesPerPixel 和 BitmapMemorySize 来准确计算内存大小避免了内存浪费。 增加跨平台适应性 虽然 CreateDIBSection 在 Windows 平台上性能优越但直接使用 VirtualAlloc 可以更轻松地适配其他平台的内存管理逻辑。因此改用 VirtualAlloc 更有利于将代码改进为跨平台兼容的代码。 精确管理内存的页属性 通过 VirtualAlloc 和 VirtualFree可以更好地设置页面属性例如 PAGE_READWRITE从而实现更细粒度的内存访问控制。在某些特殊场景下如多线程渲染或共享内存可以显著提高内存访问的效率和安全性。 删掉 global_variable HBITMAP BitmapHandle; global_variable HDC BitmapDeviceContext;删掉 // TODO: 释放之前的 DIBSection if (BitmapHandle) { // 如果位图句柄有效释放之前创建的 DIBSectionDeleteObject(BitmapHandle); // 删除现有的位图对象 }// 如果没有有效的设备上下文BitmapDeviceContext则创建一个 if (!BitmapDeviceContext) {// TODO: 在某些特殊情况下是否需要重新创建这些对象BitmapDeviceContext CreateCompatibleDC(0); // 创建一个与屏幕兼容的设备上下文 }删掉 BitmapHandle CreateDIBSection(BitmapDeviceContext, // 设备上下文NULL 表示不绑定设备BitmapInfo, // 位图信息包括位图的大小、颜色深度等DIB_RGB_COLORS, // 使用 RGB 颜色类型BitmapMemory, // 位图的内存指针返回图像数据的指针NULL, // 内存映射文件句柄NULL 表示不使用0); // 偏移量通常设置为 0// 释放设备上下文BitmapDeviceContext ReleaseDC(0, BitmapDeviceContext); // 释放设备上下文不再需要继续使用在创建 DIBSection设备独立位图时需要指定内存来存储位图的数据这个数据包括像素的 RGB 值可能还要考虑字节对齐和填充。为确保位图可以正确显示我们需要理解每行像素的对齐方式。 1. 位图内存计算方法 在位图中每行的宽度以字节为单位需要是 4 字节的倍数这是因为 Windows 位图格式要求每行都对齐到 4 字节。若行宽不足 4 字节系统会自动填充使得每行的内存占用达到 4 字节的倍数。这个填充过程称为“位图行填充”或“字节对齐”。 每行的实际字节数计算公式为 行字节数 ( ( 位图宽度 × 位深度 31 ) / 32 ) × 4 \text{行字节数} ((\text{位图宽度} \times \text{位深度} 31) / 32) \times 4 行字节数((位图宽度×位深度31)/32)×4 以 32 位位图为例 每像素 4 字节32 位 RGBA每通道 8 位。所以每行的字节数应该是 width * 4若不满 4 字节倍数则按上述公式补齐。 2. 分配内存大小 总的内存大小就是每行实际字节数乘以位图的高度 总内存大小 行字节数 × 位图高度 \text{总内存大小} \text{行字节数} \times \text{位图高度} 总内存大小行字节数×位图高度 示例代码 假设我们有一个 width 和 height 定义的 32 位位图。以下代码展示如何创建 DIBSection 并分配内存 int width 640; // 位图宽度 int height 480; // 位图高度BITMAPINFO BitmapInfo; ZeroMemory(BitmapInfo, sizeof(BitmapInfo));// 设置位图信息头 BitmapInfo.bmiHeader.biSize sizeof(BITMAPINFOHEADER); BitmapInfo.bmiHeader.biWidth width; BitmapInfo.bmiHeader.biHeight -height; // 负值表示自上而下的位图 BitmapInfo.bmiHeader.biPlanes 1; BitmapInfo.bmiHeader.biBitCount 32; // 32 位每像素 4 字节 BitmapInfo.bmiHeader.biCompression BI_RGB;// 计算每行所需字节数并分配内存 int rowBytes ((width * 32 31) / 32) * 4; // 计算每行对齐字节数 int totalBytes rowBytes * height; // 计算总内存大小void* BitmapMemory; HBITMAP hBitmap CreateDIBSection(hdc, BitmapInfo, DIB_RGB_COLORS, BitmapMemory, NULL, 0);if (hBitmap BitmapMemory) {// BitmapMemory 现在可以用于存储位图的像素数据memset(BitmapMemory, 0, totalBytes); // 初始化内存 } else {// 错误处理 }注意事项 内存对齐确保行对齐后再进行像素数据写入否则图像可能会出现错位。高度符号biHeight 为负时位图自上而下排列正值则自下而上排列。颜色格式32 位位图中每像素占 4 字节顺序为 BGRA。 VirtualAlloc 函数参数详解 参数 lpAddress指定内存块的起始地址。 通常设为 NULL由系统自动选择一个合适的地址。如果需要特定的地址例如共享内存可以指定一个具体地址但需要确保该地址未被占用。 dwSize要分配的内存大小单位是字节。 内存大小会自动按页面大小通常是 4KB向上取整系统为每一块分配的内存区域至少是一个页面。 flAllocationType内存分配类型可以是以下几种 MEM_RESERVE保留一块虚拟内存地址空间但不实际分配物理内存。这通常用于分配较大内存但暂不使用。MEM_COMMIT分配物理内存并映射到虚拟地址。已提交的内存可以被进程实际访问和操作。MEM_RESET将已提交的内存重置并告知系统当前内存内容可以丢弃。MEM_RELEASE释放已分配的内存需配合 VirtualFree 使用可以将之前保留的内存归还给系统。 flProtect内存保护属性用于指定分配内存的访问权限 PAGE_READONLY内存只读。PAGE_READWRITE内存可读写。PAGE_EXECUTE_READWRITE内存可执行、可读写。PAGE_NOACCESS内存不可访问用于调试或保护内存不被意外修改。 返回值 返回分配的内存起始地址LPVOID如果失败则返回 NULL。可以通过 GetLastError 获取失败的原因。 其他信息 内存对齐VirtualAlloc 返回的内存块通常是页面对齐的4KB 或 64KB 边界非常适合高效地管理大块数据。内存保护PAGE_READONLY、PAGE_READWRITE 等保护属性可以用来提高内存安全性限制不必要的读写和执行权限。性能影响VirtualAlloc 属于低级内存管理函数其效率较低频繁调用会影响程序性能通常用于分配较大内存。与 VirtualFree 配合使用用 VirtualAlloc 分配的内存必须使用 VirtualFree 来释放。 HeapAlloc 函数参数详解 HeapAlloc 是 Windows API 中用于动态分配内存的函数之一。它在堆中分配内存块适合需要分配小块内存的场景相比 VirtualAlloc 更灵活管理更细粒度。它可以与 HeapFree 配合使用来手动管理进程内存从而控制内存分配和释放的效率。 biHeight 的作用和含义 BITMAPINFO 结构中的 biHeight 字段用于指定位图的高度并且具有重要的方向性含义。它的取值直接影响图像在内存中的存储顺序和显示方向。 定义高度biHeight 表示位图的高度单位为像素。它指定了图像的行数。控制图像存储方向 如果 biHeight 是 正数则图像数据会自 底部向上 存储称为“自底向上位图”bottom-up bitmap。这种情况是 Windows 默认的存储方式。如果 biHeight 是 负数则图像数据会自 顶部向下 存储称为“自顶向下位图”top-down bitmap。这种模式可以让图像按从上至下的方式存储在内存中更符合大多数图像处理逻辑的顺序。 将 char *Row (char *)BitmapMemory 替换为 uint8 *Row (uint8 *)BitmapMemory 的好处在于更加清晰地表达了数据的含义和意图以及可能带来编译器优化和跨平台一致性方面的优势。以下是主要的好处 1. 更清晰的数据语义 uint8 表示一个无符号的 8 位整数即范围是 0 到 255。对于位图或图像处理通常每个像素通道例如 R、G、B、A 通道的值在 0 到 255 之间因此使用 uint8 更能表达数据是图像像素的含义。char 类型在 C 标准中是一个 8 位有符号或无符号类型取决于平台或编译器设置。这可能引发一些与负值相关的问题例如在处理像素数据时不希望看到负数值但 char 在一些平台上默认是有符号类型。 2. 避免符号位带来的错误或歧义 使用 uint8 明确指定为无符号类型可以避免因符号位导致的计算或比较错误。尤其在处理颜色、图像或二进制数据时符号位没有实际意义使用无符号类型可以避免误解。如果将 char 作为 8 位像素数据类型则在一些平台上 char 被解释为有符号类型这会导致数据值范围从 -128 到 127而不是图像通常期望的 0 到 255 的范围。使用 uint8 解决了此类平台差异。 3. 跨平台一致性和编译器优化 使用 uint8 明确指定类型大小确保无论在哪个平台上uint8 都是 8 位且无符号的。这在跨平台开发中非常有帮助避免了 char 可能是有符号或无符号的二义性问题。在一些编译器上uint8 可能更符合编译器的优化路径尤其是一些用于图像处理的 SIMD单指令多数据指令集通常对无符号数据类型优化更好。 4. 可读性提升 使用 uint8 明确表示每个像素通道为 8 位的无符号整数方便后续代码阅读和维护减少了潜在的类型转换和符号解释错误使代码逻辑更加清晰、易读。 总结 将 char *Row 替换为 uint8 *Row 提高了数据表达的精确性减少了符号位可能带来的歧义并增加了跨平台的一致性和代码的可读性尤其适用于图像处理、颜色计算等直接涉及 8 位数据的场景。 然而这个char 可能是16 位的 typedef uint8_t uint8; 和 typedef unsigned int uint8; 在本质上有很大的区别具体来说二者主要在类型大小、范围、平台依赖性等方面存在差异。下面是详细的分析 特性typedef uint8_t uint8;typedef unsigned int uint8;类型大小8 位固定4 字节通常依平台而异取值范围0 到 2550 到 4294967295通常平台一致性跨平台一致始终 8 位依平台可能不同可能是 32 位或 64 位标准化C99 标准定义C 标准中不对大小有明确规定使用场景字节数据如图像、网络协议、文件整数运算可能不适用于精确字节处理 uint8 *Row (uint8 *)BitmapMemory;1. 指针增量的大小不同 uint8 *Row (uint8 *)BitmapMemory; Row 是一个指向 uint8 类型的指针uint8 是一个 1 字节8 位的类型。因此指针加法时每次递增的地址值是 1 字节。也就是说 Row; // 增加 1 字节指向下一个 uint8uint16 *Row (uint16 *)BitmapMemory; Row 是一个指向 uint16 类型的指针uint16 是一个 2 字节16 位的类型。因此指针加法时每次递增的地址值是 2 字节。也就是说 Row; // 增加 2 字节指向下一个 uint16选择使用哪个类型的指针取决于数据的存储方式和你需要操作的数据类型大小。如果你正在处理图像数据并且每个像素是 8 位的如 RGBA 图像的单通道则使用 uint8 *Row 更合适。如果你的数据是 16 位或 2 字节宽的数据例如某些音频数据或高分辨率图像则使用 uint16 *Row 可以更高效地访问数据。 在图像处理和计算机图形学中pitch 和 stride 常被用来描述图像中行与行之间的字节偏移量但两者通常有细微的区别具体如下 1. Pitch 定义Pitch 通常是图像缓冲区中一行像素实际占用的字节数包括任何用于对齐的填充字节。用途通常用于计算在图像行之间的内存偏移量以确保图像在内存中按行存储时对齐。例如可能图像的实际宽度不满足某些内存对齐要求Pitch 就是调整后实际的每行字节数。示例如果一行像素需要 300 字节但出于对齐原因需要 320 字节则 Pitch 是 320 字节。 2. Stride 定义Stride 也指行与行之间的字节偏移量通常等于图像实际宽度以像素表示乘以每个像素的字节数。但在某些环境中Stride 也可能包括了对齐字节因此它与 Pitch 含义相同。用途Stride 是计算行的字节偏移量的关键参数尤其在不同图像处理库中Stride 和 Pitch 的使用取决于实现方式有时可互换。示例如果图像宽度是 100 像素每个像素 4 字节则 Stride 是 400 字节。如果此值包含对齐比如 512 字节则和 Pitch 相同。 主要区别 Pitch 更强调图像缓冲区的实际存储宽度含对齐字节数。Stride 在某些情况下只代表“图像宽度 * 每像素字节数”的值也可包含对齐字节。 在具体实现时许多库将 Pitch 和 Stride 视作同义但要注意文档细节因为它们的定义在不同上下文中会有所不同。 通过你的注释可以更清晰地理解 Pitch 和 Stride 的实际效果。以下是详细解释 内存布局说明 WIDTH -0 Width * BytesPerPixel BitmapMemory - 0 BB GG RR XX BB GG RR XX BB GG RR XX ... BitmapMemory Pitch 1 BB GG RR XX BB GG RR XX BB GG RR XX ...WIDTH表示图像的宽度以像素为单位。BytesPerPixel每个像素占用的字节数。此处假设每个像素 4 字节 (BB GG RR XX)。BitmapMemory指向图像在内存中的起始地址。Pitch代表从一行像素数据的开始位置到下一行数据开始位置之间的偏移字节数。 Pitch 和 Stride 区别 在上面布局的情况下Pitch 是一行在内存中所占的总字节数Stride 表示图像中一行实际像素宽度乘以每像素的字节数。它们的区别主要是 Pitch 通常大于或等于 Stride原因是可能包含额外的填充字节使得图像每行数据按特定对齐方式存储如 4 字节或 8 字节对齐。 Stride 是图像宽度 (Width) 和每像素字节数 (BytesPerPixel) 的乘积即 Width * BytesPerPixel。 例如如果图像宽度为 100 像素每像素 4 字节那么 Stride 100 * 4 400 字节。 解释示例中的 Pitch 如果 Pitch 和 Stride 相同说明没有额外的对齐填充字节。 但在某些情况下为了满足内存对齐要求 Pitch 可能比 Stride 大比如 Pitch 设置为 512 字节而实际一行只需要 400 字节Stride则每行多出 112 字节的填充数据用于保证内存对齐。 内存布局 在这种格式下每个像素占用 4 个字节通常按行存储。例如假设图像为 2x2 像素内存中的数据可能会如下所示 像素编号红色 ®绿色 (G)蓝色 (B)填充字节 (XX)Pixel 1255000Pixel 2025500Pixel 3002550Pixel 425525500 假设图像是 2x2 像素每个像素占 4 字节的内存空间 Pixel 1: [255, 0, 0, 0]Pixel 2: [0, 255, 0, 0]Pixel 3: [0, 0, 255, 0]Pixel 4: [255, 255, 0, 0] 内存布局按行存储 Row 1: [255, 0, 0, 0, 0, 255, 0, 0] // 第一行两个像素 Row 2: [0, 0, 255, 0, 255, 255, 0, 0] // 第二行两个像素小端模式Little Endian是指数据的低字节存在低地址处数据的高字节存在高地址处。在小端模式下如果我们将一个 4 字节的整数 0x000000FF 存储在内存中那么它会被存储为 内存地址: 0x00 0x01 0x02 0x03 存储数据: 0xFF 0x00 0x00 0x00如何避免阻塞主窗口 GetMessage 会导致调用它的线程进入阻塞状态等待消息队列中的新消息。因此在常见的 Windows GUI 应用程序中如果主窗口和消息循环都在主线程中运行那么 GetMessage 的阻塞确实会阻塞主窗口。换句话说在 GetMessage 等待消息时主线程会暂停执行其他操作直到收到新消息此时才会继续处理。 如果你希望在阻塞的情况下主窗口保持响应通常可以使用以下方法 多线程 将耗时的操作放到后台线程中运行这样主线程只处理消息循环而不会卡住 UI。比如使用 CreateThread 创建一个新线程或使用标准库中的多线程工具如 std::thread。 PeekMessage 使用 PeekMessage 而不是 GetMessage因为 PeekMessage 可以非阻塞地检查消息队列是否有消息允许主线程在没有新消息时继续处理其他事情。不过 PeekMessage 需要搭配一定的循环逻辑来避免占用过多的 CPU 资源。 消息钩子或定时器 通过 SetTimer 设置定时器来定期触发消息循环从而让主线程定期处理 UI 更新而不会因为 GetMessage 的阻塞而停顿。还可以用 SetWindowsHookEx 注册消息钩子以捕获和处理特定类型的消息。 使用这些方法可以让 GetMessage 等待消息的同时保持主窗口的响应性。 PeekMessageA 函数用于检查应用程序的消息队列中是否有特定消息并根据需要将该消息从队列中移除。与 GetMessage 不同PeekMessage 是非阻塞的——即便消息队列中没有符合条件的消息它也会立即返回。下面是该函数的详细参数说明 BOOL WINAPI PeekMessageA(_Out_ LPMSG lpMsg, // 指向接收消息结构的指针_In_opt_ HWND hWnd, // 指定要检查消息的窗口句柄可以为 NULL_In_ UINT wMsgFilterMin, // 要检查的消息类型的最小值_In_ UINT wMsgFilterMax, // 要检查的消息类型的最大值_In_ UINT wRemoveMsg // 指定是否从队列中移除消息 );参数解释 lpMsg 指向一个 MSG 结构的指针。PeekMessage 将在 lpMsg 中填入符合条件的消息内容。MSG 结构包括消息的类型、窗口句柄、消息时间、消息来源坐标等。 hWnd 指定要检查消息的窗口句柄。如果 hWnd 为 NULL则检查当前线程中所有窗口的消息如果设置为特定的窗口句柄则只检查该窗口的消息。 wMsgFilterMin 和 wMsgFilterMax 用于设定消息类型的范围。wMsgFilterMin 是要过滤的最小消息值而 wMsgFilterMax 是最大消息值。此范围可以用于指定只处理某类消息。例如设置 wMsgFilterMin 为 WM_KEYFIRSTwMsgFilterMax 为 WM_KEYLAST 可以过滤所有键盘消息。如果希望不过滤消息通常会将这两个值设置为 0 和 0。 wRemoveMsg 指定是否从消息队列中移除消息可以取以下值 PM_NOREMOVE不从队列中移除消息只查看消息内容。PM_REMOVE将消息从消息队列中移除类似于 GetMessage 的行为。PM_NOYIELD只对 16 位应用程序有效现代 32 位和 64 位应用程序中不会用到。 返回值 返回值为非零 表示消息队列中存在符合条件的消息。返回值为零 表示没有符合条件的消息。 使用场景 PeekMessageA 通常在需要频繁检查消息队列但不希望阻塞的场景下使用例如游戏主循环或其他实时更新的应用程序中搭配非阻塞逻辑可以实现更高的响应性 MSG msg; while (true) {if (PeekMessage(msg, NULL, 0, 0, PM_REMOVE)) {if (msg.message WM_QUIT) break;TranslateMessage(msg);DispatchMessage(msg);}// 其他循环逻辑例如渲染或更新 }在此代码中PeekMessage 检查并移除消息如果没有消息程序将继续执行其他操作不会像 GetMessage 那样因阻塞而停止。 // game.cpp : Defines the entry point for the application. //#include cstdint #include stdint.h #include windows.h #include winuser.h#define internal static // 用于定义内翻译单元内部函数 #define local_persist static // 局部静态变量 #define global_variable static // 全局变量typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; typedef uint64_t uint64;typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; typedef int64_t int64;// TODO: 全局变量 global_variable bool Running;global_variable BITMAPINFO BitmapInfo; global_variable void *BitmapMemory; // 后备缓冲区的宽度和高度 global_variable int BitmapWidth; global_variable int BitmapHeight; global_variable int BytesPerPixel 4;internal void RenderWeirdGradient(int xOffset, int yOffset) {int width BitmapWidth;int height BitmapHeight;int Pitch width * BytesPerPixel;uint8 *Row (uint8 *)BitmapMemory;for (int Y 0; Y BitmapHeight; Y) {uint32 *Pixel (uint32 *)Row;for (int X 0; X BitmapWidth; X) {uint8 Blue (X xOffset);uint8 Green (Y yOffset);*Pixel ((Green 8) | Blue);}Row Pitch;} }// 这个函数用于重新调整 DIB设备独立位图大小 internal void Win32ResizeDIBSection(int width, int height) {// device independent bitmap设备独立位图// TODO: 进一步优化代码的健壮性// 可能的改进先不释放先尝试其他方法再如果失败再释放。if (BitmapMemory) {VirtualFree(BitmapMemory, // 指定要释放的内存块起始地址0, // 要释放的大小字节对部分释放有效整体释放则设为 0MEM_RELEASE); // MEM_RELEASE释放整个内存块将内存和地址空间都归还给操作系统}// 赋值后备缓冲的宽度和高度BitmapWidth width;BitmapHeight height;// 设置位图信息头BITMAPINFOHEADERBitmapInfo.bmiHeader.biSize sizeof(BITMAPINFOHEADER); // 位图头大小BitmapInfo.bmiHeader.biWidth BitmapWidth; // 设置位图的宽度BitmapInfo.bmiHeader.biHeight -BitmapHeight; // 设置位图的高度BitmapInfo.bmiHeader.biPlanes 1; // 设置颜色平面数通常为 1BitmapInfo.bmiHeader.biBitCount 32; // 每像素的位数这里为 32 位即 RGBABitmapInfo.bmiHeader.biCompression BI_RGB; // 无压缩直接使用 RGB 颜色模式// 创建 DIBSection设备独立位图并返回句柄// TODO我们可以自己分配int BitmapMemorySize (BitmapWidth * BitmapHeight) * BytesPerPixel;BitmapMemory VirtualAlloc(0, // lpAddress指定内存块的起始地址。// 通常设为 NULL由系统自动选择一个合适的地址。BitmapMemorySize, // 要分配的内存大小单位是字节。MEM_COMMIT, // 分配物理内存并映射到虚拟地址。已提交的内存可以被进程实际访问和操作。PAGE_READWRITE // 内存可读写);// TODO:可能会把它清除成黑色 }// 这个函数用于将 DIBSection 绘制到窗口设备上下文 internal void Win32UpdateWindow(HDC DeviceContext, RECT *windowRect, int X,int Y, int Width, int Height) {int WindowWidth windowRect-right - windowRect-left;int WindowHeight windowRect-bottom - windowRect-top;// 使用 StretchDIBits 将 DIBSection 绘制到设备上下文中StretchDIBits(DeviceContext, // 目标设备上下文窗口或屏幕的设备上下文/*X, Y, Width, Height, // 目标区域的 x, y 坐标及宽高X, Y, Width, Height,*/0, 0, BitmapWidth, BitmapHeight, //0, 0, WindowWidth, WindowHeight,// 源区域的 x, y 坐标及宽高此处源区域与目标区域相同BitmapMemory, // 位图内存指针指向 DIBSection 数据BitmapInfo, // 位图信息包含位图的大小、颜色等信息DIB_RGB_COLORS, // 颜色类型使用 RGB 颜色SRCCOPY); // 使用 SRCCOPY 操作符进行拷贝即源图像直接拷贝到目标区域 }LRESULT CALLBACK Win32MainWindowCallback(HWND hwnd, // 窗口句柄表示消息来源的窗口UINT Message, // 消息标识符表示当前接收到的消息类型WPARAM wParam, // 与消息相关的附加信息取决于消息类型LPARAM LParam) { // 与消息相关的附加信息取决于消息类型LRESULT Result 0; // 定义一个变量来存储消息处理的结果switch (Message) { // 根据消息类型进行不同的处理case WM_CREATE: {OutputDebugStringA(WM_CREATE\n);};case WM_SIZE: { // 窗口大小发生变化时的消息RECT clientRect;GetClientRect(hwnd, clientRect);// 计算绘制区域的宽度和高度int Height clientRect.bottom - clientRect.top;int Width clientRect.right - clientRect.left;Win32ResizeDIBSection(Width, Height);OutputDebugStringA(WM_SIZE\n); // 输出调试信息表示窗口大小已改变} break;case WM_DESTROY: { // 窗口销毁时的消息// TODO: 处理错误用重建窗口Running false;} break;case WM_CLOSE: { // 窗口关闭时的消息// TODO: 像用户发送消息进行处理Running false;} break;case WM_ACTIVATEAPP: { // 应用程序激活或失去焦点时的消息OutputDebugStringA(WM_ACTIVATEAPP\n); // 输出调试信息表示应用程序激活或失去焦点} break;case WM_PAINT: { // 处理 WM_PAINT 消息通常在窗口需要重新绘制时触发PAINTSTRUCT Paint; // 定义一个 PAINTSTRUCT 结构体保存绘制的信息// 调用 BeginPaint 开始绘制并获取设备上下文 (HDC)同时填充 Paint 结构体HDC DeviceContext BeginPaint(hwnd, Paint);// 获取当前绘制区域的左上角坐标int X Paint.rcPaint.left;int Y Paint.rcPaint.top;// 计算绘制区域的宽度和高度int Height Paint.rcPaint.bottom - Paint.rcPaint.top;int Width Paint.rcPaint.right - Paint.rcPaint.left;RECT clientRect;GetClientRect(hwnd, clientRect);Win32UpdateWindow(DeviceContext, clientRect, X, Y, Width, Height);#if 0local_persist DWORD Operation WHITENESS;// 使用 WHITENESS 操作符填充矩形区域为白色PatBlt(DeviceContext, X, Y, Width, Height, Operation);// 设置窗体的颜色在刷新时白色和黑色之间来回变换if (Operation WHITENESS) {Operation BLACKNESS;} else {Operation WHITENESS;} #endif// 调用 EndPaint 结束绘制并释放设备上下文EndPaint(hwnd, Paint);} break;default: { // 对于不处理的消息调用默认的窗口过程Result DefWindowProc(hwnd, Message, wParam,LParam); // 调用默认窗口过程处理消息} break;}return Result; // 返回处理结果 }int CALLBACK WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, //PSTR cmdline, int cmdshow) {WNDCLASS WindowClass {};// 使用大括号初始化所有成员都被初始化为零0或 nullptr// WindowClass.style表示窗口类的样式。通常设置为一些 Windows// 窗口样式标志例如 CS_HREDRAW, CS_VREDRAW。WindowClass.style CS_OWNDC | CS_HREDRAW | CS_VREDRAW;// CS_HREDRAW 当窗口的宽度发生变化时窗口会被重绘。// CS_VREDRAW 当窗口的高度发生变化时窗口会被重绘// WindowClass.lpfnWndProc指向窗口过程函数的指针窗口过程用于处理与窗口相关的消息。WindowClass.lpfnWndProc Win32MainWindowCallback;// WindowClass.hInstance指定当前应用程序的实例句柄Windows// 应用程序必须有一个实例句柄。WindowClass.hInstance hInst;// WindowClass.lpszClassName指定窗口类的名称通常用于创建窗口时注册该类。WindowClass.lpszClassName gameWindowClass; // 类名if (RegisterClass(WindowClass)) { // 如果窗口类注册成功HWND Window CreateWindowEx(0, // 创建窗口使用扩展窗口风格WindowClass.lpszClassName, // 窗口类的名称指向已注册的窗口类game, // 窗口标题窗口的名称WS_OVERLAPPEDWINDOW |WS_VISIBLE, // 窗口样式重叠窗口带有菜单、边框等并且可见CW_USEDEFAULT, // 窗口的初始位置使用默认位置X坐标CW_USEDEFAULT, // 窗口的初始位置使用默认位置Y坐标CW_USEDEFAULT, // 窗口的初始宽度使用默认宽度CW_USEDEFAULT, // 窗口的初始高度使用默认高度0, // 父窗口句柄此处无父窗口传00, // 菜单句柄此处没有菜单传0hInst, // 当前应用程序的实例句柄0 // 额外的创建参数此处没有传递额外参数);// 如果窗口创建成功Window 将保存窗口的句柄if (Window) { // 检查窗口句柄是否有效若有效则进入消息循环int xOffset 0;int yOffset 0;Running true;while (Running) { // 启动一个无限循环等待和处理消息MSG Message; // 声明一个 MSG 结构体用于接收消息while (PeekMessage(Message,// 指向一个 MSG 结构的指针。PeekMessage// 将在 lpMsg 中填入符合条件的消息内容。0,// hWnd 为NULL则检查当前线程中所有窗口的消息// 如果设置为特定的窗口句柄则只检查该窗口的消息。0, //0, // 用于设定消息类型的范围PM_REMOVE // 将消息从消息队列中移除类似于 GetMessage 的行为。)) {if (Message.message WM_QUIT) {Running false;}TranslateMessage(Message); // 翻译消息如果是键盘消息需要翻译DispatchMessage(Message); // 分派消息调用窗口过程处理消息}RenderWeirdGradient(xOffset, yOffset);// 这个地方需要渲染一下不然是黑屏{HDC DeviceContext GetDC(Window);RECT WindowRect;GetClientRect(Window, WindowRect);int WindowWidth WindowRect.right - WindowRect.left;int WindowHeigh WindowRect.bottom - WindowRect.top;Win32UpdateWindow(DeviceContext, WindowRect, 0, 0, WindowWidth,WindowHeigh);ReleaseDC(Window, DeviceContext);}xOffset;}} else { // 如果窗口创建失败// 这里可以处理窗口创建失败的逻辑// 比如输出错误信息或退出程序等// TODO:}} else { // 如果窗口类注册失败// 这里可以处理注册失败的逻辑// 比如输出错误信息或退出程序等// TODO:}return 0; }
http://www.hkea.cn/news/14430518/

相关文章:

  • 文章网站后台浙江+外贸网站建设
  • 女人脱内衣裤给男人做网站营业推广的目标通常是
  • 响应式网站和营销型网站node做网站优势
  • 企业营销型网站案例鞍山建一个网站大概要多少钱
  • 电商网站建设哪好多用户电商平台
  • 公众号搭建第三方平台2014中文网站seo排名名单
  • 现在市面网站做推广好网站制作视频教程
  • 勒流有做网站的吗网站每月流量
  • 用模板做的网站多少钱WordPress制作404页面
  • 社交网站第一步怎么做百度竞价推广技巧
  • 南城网站建设公司案例深圳品牌网站推广公司
  • 如何把自己的网站推广国内网站主机
  • 网站建站设计电子商务静态网页模板
  • 有关做服装的网站吗购物网站哪个东西便宜质量好
  • 绿色为主色的网站wordpress 双会员系统
  • 素材网站免费短视频wordpress调用最新评论
  • 郴州住房和城乡建设部网站网站备案号收回
  • 卫生局网站建设实施方案长沙网站建设公司哪家专业
  • 电器企业网站建设方案书google搜索优化方法
  • 网站开发及建设wordpress视频防盗链
  • 资兴市建设局网站南京多样化的网站建设定制公司
  • 建设vip视频解析网站违法吗网页打不开怎么解决手机
  • 新纪实网站建设百度云网站建设教程视频
  • 吉林网站网站建设湖南正规关键词优化首选
  • 重庆网站seo教程app交互设计
  • 沈阳网站优化推广方案网站建设小程序开发报价
  • 开发大型网站的最主流语言上海网站建设领导品牌
  • 北京网站建设模板免费搭建网站教程
  • 唐山住房和城乡建设网站东鹏拼奖网站怎么做
  • 住房和城乡建设部网站监理合同外网网站建设