WinAPI LoadImage к кнопке имеет границу, но LoadBitmap не имеет - PullRequest
0 голосов
/ 03 сентября 2018

Мое приложение - 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 и изображение не появляется. поэтому я не могу использовать LoadBitmap с Resources. почему-то Resources не идет с DLL данными в Game, и игра не находит ресурсы, поэтому не может найти изображение.

Итак, в качестве альтернативы я попытался использовать LoadImage() из файл диска . и так это сработало и на кнопке появилось изображение.

Когда я вставляю его в любое приложение , например, в блокнот, оно выглядит так:

(Это то, что я хочу, чтобы это было похоже)

enter image description here

Но когда я добавляю DLL в игру, кнопка появляется в border & 3D Effect :

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 .

К сожалению, я не смог сделать ничего из этого и понятия не имею, как это сделать, я ищу весь интернет, но ничего не нашел по этому поводу.

Как я могу этого достичь, какие-нибудь идеи?

1 Ответ

0 голосов
/ 04 сентября 2018

К сожалению, ваша погоня за LoadBitmap является охотой на снайперов. Визуальные стили - единственное, что вызывает различный внешний вид. Даже если вы получите код для использования ресурса, вы все равно будете иметь неправильный внешний вид, если не включите визуальные стили.

В MSDN есть ссылка, специально предназначенная для использования визуальных стилей в подключаемой библиотеке DLL, когда основное приложение не использует их:

Суть в том, что вам нужно использовать макрос ISOLATION_AWARE_ENABLED и манифестировать вашу DLL для визуальных стилей.

Вам также нужно будет позвонить InitCommonControlsEx. Это упомянуто в нескольких других разделах вышеупомянутого документа. Для плоских кнопок передайте флаг ICC_STANDARD_CLASSES (внутри структуры).


У вас есть пара ошибок в коде, и они могут помешать правильной активации визуальных стилей, даже когда вы выполняете манифестацию и изоляцию.

  1. Ваша DLL не должна иметь функцию WinMain. Пусть есть одна функция, выполняющая всю работу, которая вызывается как из WinMain, так и из потока DLL, вместо вызова потока из DLL WinMain. Само по себе это не так, просто плохой стиль, но это вызвало следующую ошибку, которая является более серьезной:

  2. Ваш параметр hInstance скрывает глобальную переменную hInstance, что приводит к неправильному значению wc.hInstance. Если WinMain и DllMain оба задают глобальную переменную, а затем весь остальной код использует глобальную, у вас не будет этой проблемы. Но для его исправления нужен код, работающий в EXE, а не DLL, что означает удаление вызова из потока DLL в WinMain.

...