【发布时间】:2019-02-08 17:38:07
【问题描述】:
我的应用是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);
DLL 注入任何应用程序但游戏时,LoadBitmap() 有效。
我想是因为当我将DLL 注入游戏时,它不会从Resources 加载并且图像不会出现。所以我无法使用来自Resources 的LoadBitmap。不知何故,Resources 不与DLL 数据一起去Game 并且游戏找不到资源所以它找不到图像。
另外,我尝试使用 磁盘文件 中的LoadImage()。这样它就起作用了,图像出现在按钮上。
当我将它注入到 任何应用程序(如记事本)中时,它会显示为:
(这就是我想要的样子)
但是当我将DLL 注入游戏时,按钮会出现在边框和3D 效果中:
经过大量搜索,我认为我正在注入的 游戏 不会将 视觉样式 应用于我的 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 找到我的图像,并使用Resources 中的LoadBitmap()。所以按钮不会有边框和3d效果。
2.继续使用磁盘文件中的LoadImage(),并尝试隐藏边框和3d 效果,例如为我的DLL GUI 启用视觉样式。
不幸的是,我无法做到这些,也不知道该怎么做,我正在搜索整个互联网,但没有找到任何相关信息。
我怎么能做到这一点,有什么想法吗?
【问题讨论】:
-
什么是
hInstance。哪个实例返回GetWindowLong(hwnd, GWL_HINSTANCE) -
hInstance是一个保存当前实例的全局变量,等于GetModuleHandle(0)。我猜GetWindowLong(hwnd, GWL_HINSTANCE)应该返回与hInstance相同的句柄 -
@CrisiFati 好的,我会发布代码。
-
所以您正在尝试从 exe 文件加载资源。使用您的 dll 实例作为
hInstance。即使是 exe 中的资源,也不要使用GetModuleHandle(0)。使用 Windows 传递给您的值。 https://blogs.msdn.microsoft.com/oldnewthing/20050418-59/?p=35873