WinAPI LoadImage到按钮有边框但LoadBitmap没有

问题描述 投票:-1回答:1

我的应用程序是DLL,我将其注入(游戏)过程。

当我使用LoadBitmap()并使用MAKEINTRESOURCE(IMAGE_RESOURCE_NAME)

像这样 :

MyImage = LoadBitmap(hInstance, MAKEINTRESOURCE(IMAGE_RESOURCE_NAME))

SendMessage(MyButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)MyImage);

创建按钮代码:

MyButton = CreateWindow("BUTTON", "My Button", WS_VISIBLE | WS_CHILD | BS_BITMAP | BS_FLAT, 17, 18, 110, 30, hwnd, (HMENU)ButtonId, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);

当我将LoadBitmap()注入任何应用程序而不是游戏时,DLL工作。我想因为当我向游戏注入DLL时,它不会从Resources加载并且图像不会出现。所以我无法使用LoadBitmapResources。不知怎的,Resources没有使用DLL数据到Game并且游戏没有找到资源所以它找不到图像。

所以我也尝试从磁盘文件中使用LoadImage()。它的工作方式和图像出现在按钮上。

当我将它注入任何像记事本这样的应用程序时,它看起来像这样:

(这就是我希望它的样子)

enter image description here

但是当我向游戏注入DLL时,按钮出现在边框和3D效果中:

enter image description here

通过大量的搜索,我认为我注入的游戏不会将视觉样式应用于我的DLL GUI Window,并且按钮出现在Classy外观,边框和3D效果。甚至BS_FLAT也不适用于按钮。

这是我正在使用的完整代码:

#include "stdafx.h"
#include "Process.h"
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <tchar.h>
#include "resource.h"

HINSTANCE hInstance;

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

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc = { 0 };

    HWND MainHwnd;

    MSG Msg;

    wc.cbSize = sizeof(wc);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;

    wc.hbrBackground = (HBRUSH)(CreateSolidBrush(RGB(30, 30, 30)));
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;

    wc.lpszMenuName = NULL;
    wc.lpszClassName = "My Application";

    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    wc.hCursor = LoadCursor(NULL, IDC_ARROW);


    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, std::to_string(GetLastError()).c_str(), "RegisterClassEx!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    MainHwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        "Application",
        "My Application",
        WS_SYSMENU | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX,
        CW_USEDEFAULT, CW_USEDEFAULT, 400, 280,
        NULL, NULL, hInstance, NULL);

    if (MainHwnd == NULL)
    {
        MessageBox(NULL, std::to_string(GetLastError()).c_str(), "CreateWindow!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(MainHwnd, nCmdShow);
    UpdateWindow(MainHwnd);

    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;

}

int MyButtonId = 1000;

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE: {

        HWND MyButton;
        HBITMAP MyImage;

        MyButton = CreateWindow("BUTTON", "A Button Text", WS_VISIBLE | WS_CHILD | BS_BITMAP | BS_FLAT, 17, 18, 110, 30, hwnd, (HMENU)MyButtonId, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);

        ///////// --->

        // Here I'm using one of these :

        // Using LoadImage()
        MyImage = (HBITMAP)LoadImage(hInstance, "UI\\myimage.bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_LOADFROMFILE);

        // Using LoadBitmap() | My_Bitmap is an image resource name
        MyImage = LoadBitmap(hInstance, MAKEINTRESOURCE(My_Bitmap));

        ///////// <---

        SendMessage(MyButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)MyImage);

        break;
    }

    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

unsigned long __stdcall Win_Thread(LPVOID Param)
{
    WinMain(NULL, NULL, NULL, 1);
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        // Set hInstance to hModule
        hInstance = hModule;

        CreateThread(0, 0, LPTHREAD_START_ROUTINE(Win_Thread), hModule, 0, 0);
    }
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

我想我有两个选择。

1.尝试让游戏从Resources找到我的图像并使用来自LoadBitmap()Resources。所以按钮不会有边框和3D效果。

2.继续使用磁盘文件中的LoadImage(),并尝试隐藏边框和3d效果,例如为我的DLL GUI启用视觉样式。

不幸的是我不能做任何这些,也不知道该怎么做,我正在搜索整个互联网,但没有找到任何关于那个。

我怎么能实现这一点,任何想法?

c++ winapi win32gui
1个回答
1
投票

不幸的是,你对LoadBitmap的追求是一次狙击。视觉样式是导致不同外观的唯一因素。即使您获得使用资源的代码,除非启用视觉样式,否则您仍会出现错误的外观。

MSDN有一个专门用于在插件DLL中使用Visual Styles的参考,当主应用程序不使用它们时:

要点是你需要使用ISOLATION_AWARE_ENABLED宏并显示你的DLL用于视觉样式。

你还需要打电话给InitCommonControlsEx。在上述文件的其他几个部分中提到了这一点。对于平面按钮,传递ICC_STANDARD_CLASSES标志(在结构内)。


您的代码中确实存在一些错误,即使您执行清单和隔离,这些错误也可能会阻止视觉样式正确激活。

  1. 你的DLL不应该有WinMain函数。让一个函数完成从WinMain和DLL线程调用的所有工作,而不是让DLL线程调用WinMain。这本身并没有错,只是糟糕的风格,但它导致了下一个错误,这是一个更大的问题:
  2. 你的hInstance参数隐藏了全局hInstance变量,导致wc.hInstance的值不正确。如果WinMainDllMain都设置了全局变量,然后所有其余的代码都使用了全局变量,那么你就不会遇到这个问题。但修复它需要在EXE而不是DLL中运行代码,这意味着从DLL线程中删除调用到WinMain
© www.soinside.com 2019 - 2024. All rights reserved.