Win32将图片资源编译进程序,设置窗体程序背景图片的方法

⌚Time: 2023-01-18 21:52:43

👨‍💻Author: Jack Ge

如何将图片等资源编译进程序,而不是在程序运行时以文件形式载入。

在win32编程中,为方便项目中的资源统一管理,提供了一个格式统一的资源文件.rc,对各种资源进行管理

在vc++中,会使用rc.exe对.rc文件进行编译,生成.res的汇编文件,使用cl.exe编译c/c++文件,生成.obj的汇编文件,由link.exe链接这些文件和user32.lib生成.exe

在mingw编译器中,使用windres.exe对.rc文件进行编译,使用g++/gcc对源文件进行编译再进行链接

使用windres.exe编译rc文件的方法

创建一个res文件夹,包含ico图标和bmp图片资源

res文件夹下创建一个Resource.h,定义资源ID,包括两个图标ID和一个图片ID


#define IDI_ICON_0 1000 

#define IDI_ICON_1 1001

#define IDB_BITMAP_0 1010 

res文件夹下创建一个rc文件Resource.rc,编辑内容


//包含头文件

#include <windows.h>

#include "Resource.h"

//包含图片资源的格式,资源id 资源类型 路径

IDI_ICON_0 ICON "appIcon.ico"

IDI_ICON_1 ICON "windowIcon.ico"

IDB_BITMAP_0 BITMAP "bg.bmp"

res文件夹的内容,包含2个ico图标,1个bmp图片,一个Resource.h和Resource.rc

使用windres编译它们


windres -i Resource.rc -o Resource.o

会多了一个Resource.o文件,这就是编译完成的目标文件,其中包含了图标和图片资源

建立一个测试文件

a0118.cpp


#include <windows.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);



int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)

{

    // Register the window class.

    const char CLASS_NAME[]  = "test Class";



    WNDCLASSA wc = { };



    wc.lpfnWndProc   = WindowProc;

    wc.hInstance     = hInstance;

    wc.lpszClassName = CLASS_NAME;



    RegisterClassA(&wc);



    // Create the window.



    HWND hwnd = CreateWindowExA(

        0,                              // Optional window styles.

        CLASS_NAME,                     // Window class

        "Window",    // Window text

        WS_OVERLAPPEDWINDOW,            // Window style



        // Size and position

        CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,



        NULL,       // Parent window    

        NULL,       // Menu

        hInstance,  // Instance handle

        NULL        // Additional application data

        );



    if (hwnd == NULL)

    {

        return 0;

    }



    ShowWindow(hwnd, nCmdShow);



    // Run the message loop.



    MSG msg = { };

    while (GetMessage(&msg, NULL, 0, 0) > 0)

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }



    return 0;

}



LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    switch (uMsg)

    {

    case WM_DESTROY:

        PostQuitMessage(0);

        return 0;



    case WM_PAINT:

        { 

            PAINTSTRUCT ps;

            HDC dc = BeginPaint(hwnd, &ps);



            EndPaint(hwnd, &ps);

        }

        return 0;



    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);

}


使用命令对其与资源文件编译,进行链接


windres res/Resource.rc -o res/Resource.o

g++ -c a0118.cpp

g++ a0118.o res/Resource.o -o a.exe -lgdi32

结果产生的exe文件图标变成了appIcon.ico这个图标文件,因为会选中资源ID最小的图标作为程序图标

但窗体图标并没有改变

包含Resource.h,通过向窗体发送消息WM_SETICON,设置图标ID


#include "res/Resource.h"

...

//设置窗体图标 IDI_ICON_1

HICON hIcon = LoadIcon((HINSTANCE)GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON_1));

SendMessage(hwnd,WM_SETICON, ICON_BIG, (LPARAM)hIcon);

SendMessage(hwnd,WM_SETICON, ICON_SMALL, (LPARAM)hIcon);

之后再进行编译链接就可以设置窗体图标了

背景的绘制

窗体的WM_PAINT事件处理中绘制窗体背景IDB_BITMAP_0


    case WM_PAINT://背景图片绘制

        {

            HBITMAP hBitmap;

            BITMAP  bitmap;

            hBitmap = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_0));

            GetObject(hBitmap, sizeof(bitmap), &bitmap);

 

            PAINTSTRUCT ps;

            HDC dc = BeginPaint(hwnd, &ps);

 

            HDC memdc = CreateCompatibleDC(dc);

            SelectObject(memdc, hBitmap);

            RECT rc;

            GetClientRect(hwnd,&rc);

            SetStretchBltMode(dc,COLORONCOLOR);

            int showWidth = rc.right-rc.left;

            int showHeight = rc.bottom-rc.top;

            StretchBlt(dc,rc.left,rc.top,showWidth,showHeight,memdc,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);

            DeleteDC(memdc);

            EndPaint(hwnd, &ps);

        }

程序代码


#include <windows.h>

#include "res/Resource.h"

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);



int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)

{

    // Register the window class.

    const char CLASS_NAME[]  = "test Class";



    WNDCLASSA wc = { };



    wc.lpfnWndProc   = WindowProc;

    wc.hInstance     = hInstance;

    wc.lpszClassName = CLASS_NAME;



    RegisterClassA(&wc);



    // Create the window.



    HWND hwnd = CreateWindowExA(

        0,                              // Optional window styles.

        CLASS_NAME,                     // Window class

        "Window",    // Window text

        WS_OVERLAPPEDWINDOW,            // Window style



        // Size and position

        CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,



        NULL,       // Parent window    

        NULL,       // Menu

        hInstance,  // Instance handle

        NULL        // Additional application data

        );



    if (hwnd == NULL)

    {

        return 0;

    }



    ShowWindow(hwnd, nCmdShow);



    //设置图标

        HICON hIcon = LoadIcon((HINSTANCE)GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON_1));

    SendMessage(hwnd,WM_SETICON, ICON_BIG, (LPARAM)hIcon);

        SendMessage(hwnd,WM_SETICON, ICON_SMALL, (LPARAM)hIcon);

    // Run the message loop.



    MSG msg = { };

    while (GetMessage(&msg, NULL, 0, 0) > 0)

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }



    return 0;

}



LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    switch (uMsg)

    {

    case WM_DESTROY:

        PostQuitMessage(0);

        return 0;



    case WM_PAINT://背景图片绘制

        {

            HBITMAP hBitmap;

            BITMAP  bitmap;

            hBitmap = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BITMAP_0));

            GetObject(hBitmap, sizeof(bitmap), &bitmap);

 

            PAINTSTRUCT ps;

            HDC dc = BeginPaint(hwnd, &ps);

 

            HDC memdc = CreateCompatibleDC(dc);

            SelectObject(memdc, hBitmap);

            //BitBlt(dc,0,0,bitmap.bmWidth,bitmap.bmHeight,memdc,0,0,SRCCOPY);

            RECT rc;

            GetClientRect(hwnd,&rc);

            SetStretchBltMode(dc,COLORONCOLOR);

            

            int showWidth = rc.right-rc.left;

            int showHeight = rc.bottom-rc.top;

            StretchBlt(dc,rc.left,rc.top,showWidth,showHeight,memdc,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);

            DeleteDC(memdc);

            DeleteObject(hBitmap);

            EndPaint(hwnd, &ps);

        }

        return 0;



    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);

}