-1

My App is a DLL and i'm injecting it into a (Game) process .

When i use LoadBitmap() and use MAKEINTRESOURCE(IMAGE_RESOURCE_NAME)

Like this :

MyImage = LoadBitmap(hInstance, MAKEINTRESOURCE(IMAGE_RESOURCE_NAME))

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

The Create Button code :

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() works when i Inject the DLL into any application but the game. i think because when i inject the DLL to the game, it won't load from Resources and the image doesn't appear. so i'm not able to use LoadBitmap from Resources. somehow the Resources dosen't go with the DLL data to the Game and the game doesn't find the resources so it can't find the Image.

So alternatively i tried to use LoadImage() from disk file. and that way it worked and the Image appears on the button.

When i Inject it to any application like notepad it appears like this :

(That's what i want it to be like)

enter image description here

But when i inject the DLL to the game, the button appears in a border & 3D Effect :

enter image description here

With a lot of searching i assumed that The Game i'm injecting to doesn't apply Visual Styles to my DLL GUI Window and the Buttons appear in the Classy look, Border & 3D Effect. even BS_FLAT doesn't apply to the button.

Here's the full code I'm using :

#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;
}

I think i have two options.

1. try to make the game find my Images from Resources and use LoadBitmap() from Resources. so the button won't be with border & 3d effect.

2. continue using LoadImage() from disk file, and try to hide the border & 3d Effect, e.g Enable Visual Styles for my DLL GUI.

Unfortunately i couldn't do any of those and have no idea how to do that, i'm searching the whole internet but didn't find anything about that.

How could i achieve that, any ideas?

Amr SubZero
  • 1,196
  • 5
  • 19
  • 30
  • Please post the code as instructed in [\[SO\]: How to create a Minimal, Complete, and Verifiable example (mcve)](https://stackoverflow.com/help/mcve). an example working with resources: https://stackoverflow.com/questions/39748850/how-can-i-embed-an-exe-file-inside-a-vc-exe-program/39753407#39753407. – CristiFati Sep 03 '18 at 18:25
  • What is `hInstance`. Which instance returns `GetWindowLong(hwnd, GWL_HINSTANCE)` – Daniel Sęk Sep 03 '18 at 18:37
  • ```hInstance``` is a global variable holding the current instance which equals to ```GetModuleHandle(0)```. and ```GetWindowLong(hwnd, GWL_HINSTANCE)``` should return the same handle of the ```hInstance``` i guess – Amr SubZero Sep 03 '18 at 18:42
  • @CrisiFati okay, i will post the code. – Amr SubZero Sep 03 '18 at 18:48
  • So you are trying to load resource from exe file. Use your dll instance as `hInstance`. Don't use `GetModuleHandle(0)` even for resources in exe. Use values passed to you by Windows. [https://blogs.msdn.microsoft.com/oldnewthing/20050418-59/?p=35873](https://blogs.msdn.microsoft.com/oldnewthing/20050418-59/?p=35873) – Daniel Sęk Sep 03 '18 at 18:49
  • I don't use ```GetModuleHandle(0)``` i'm setting the ```hInstance``` to the current instance handle in the ```dllMain()``` function. i understand you clearly i cant load resources from the wrong instance, but why it loads resources from any other apps like notepad, teamviewer, etc.. and not loading resources only in the game i'm injecting to! if the instance is wrong, it shouldn't load on any exe app. i will post the code to make things clear. – Amr SubZero Sep 03 '18 at 18:56
  • The `hInstance` passed into `DllMain` and the value returned from `GetModuleHandle(0)` will not ever be the same. You seem to insist both that they were, and weren't the same. Showing some code would certainly help clear up any confusion. – IInspectable Sep 03 '18 at 20:00
  • i have posted the full code i'm using. – Amr SubZero Sep 03 '18 at 20:37

1 Answers1

1

Unfortunately, your pursuit of LoadBitmap is a snipe hunt. Visual Styles are the only thing causing the different appearance. Even if you get the code for using a resource working, you'll still have the wrong appearance unless you enable visual styles.

MSDN has a reference specifically for using Visual Styles in a plugin DLL, when the main application doesn't use them:

The gist is that you need to use the ISOLATION_AWARE_ENABLED macro and manifest your DLL for visual styles.

You will also need to call InitCommonControlsEx. That's mentioned in several other sections of the above document. For flat buttons, pass the ICC_STANDARD_CLASSES flag (inside the structure).


You do have a couple mistakes in your code, and these might prevent visual styles from properly activating even when you do the manifesting and isolation.

  1. Your DLL should not have a WinMain function. Let there be one function doing all the work that gets called from both WinMain and the DLL thread, instead of having the DLL thread call WinMain. This isn't wrong by itself, just bad style, but it caused the next error which is a bigger problem:

  2. Your hInstance parameter hides the global hInstance variable, resulting in the wrong value for wc.hInstance. If WinMain and DllMain both set the global variable, and then all the rest of the code used the global, you wouldn't be having this problem. But fixing it needs code running in the EXE and not the DLL, which means removing the call from the DLL thread to WinMain.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • it's correct, the visual styles causes this issue. I've tried to enable visual styles to my DLL following the link you provided, but no luck at all. faced alot of problems with manifest (how to add it to the dll) in a right way. but i couldn't do that even after 3 hours of tries and searching. if i understood the two mistakes you mentioned. my code should be like that : https://pastebin.com/phNufk11 if you could help, please give me some code examples, thanks! – Amr SubZero Sep 04 '18 at 13:21
  • 1
    @AmrSubZero: Renaming the main function to `DllMain` is also a bad idea, since (1) now you are ignoring the `reason_for_call` parameter and (2) now you're doing all that work inside the loader lock. – Ben Voigt Sep 04 '18 at 13:24
  • I couldn't understand ```Your DLL should not have a WinMain function. Let there be one function that gets called from WinMain``` how can i call that ```Function``` from ```WinMain``` when i should not have a ```WinMain``` function? i can't undersand the couple mistakes. the second mistake i tried to make a global ```static HINSTANCE mainInstance``` setting it to ```hModule``` in the ```dllMain(HINSTANCE hModule, ...)``` and then use the ```mainInstance``` on the rest of my code. is that correct? can you please provide me a code example, if that possible? – Amr SubZero Sep 04 '18 at 13:34
  • 1
    @AmrSubZero: The change you made with `mainInstance` is fine. For the first change, you just needed to rename `WinMain` to a non-magic function name, like `void DoAllTheThings(void)`. And call it from your thread procedure where you were calling `WinMain()`. Then for your EXE, you'll have a new `WinMain` that does `mainInstance = hInstance;` and then calls `DoAllTheThings()`. EXE path: `WinMain()` -> `DoAllTheThings()`. DLL path: `DllMain()` -> `CreateThread()` -> `Win_Thread` -> `DoAllTheThings()`. The part that sets `mainInstance` needs to be different in EXE and DLL. – Ben Voigt Sep 04 '18 at 13:40
  • Sir, you didn't understand me clearly, i have no control on the ```EXE``` it's a game i only create a ```DLL``` with a ```WinAPI GUI``` and inject it into the game ```(EXE)``` then the ```DLL GUI``` appears after injection. i have no control on the exe/game. the problem happens because the game doesn't apply ```visual styles``` to my ```DLL GUI``` somehow. so i need to Enable Visual Styles to my **DLL GUI**. i couldn't do that! it's a way too difficult to understand how to add the ```Manifest``` file into my project etc. – Amr SubZero Sep 04 '18 at 13:46
  • @AmrSubZero: I'm talking about an EXE version for testing. That is why you wrote that code in `WinMain()` in the first place, right? You can also just have `DllMain()` -> `CreateThread()` -> `Win_Thread` -> `DoAllTheThings()` and not have any function named `WinMain()`. What you can't do is: (1) run your main code inside `DllMain()` while the loader lock is held, or (2) use the `WinMain()` parameter `hInstance` when started as a DLL (since you were passing `NULL` from `Win_Thread`). – Ben Voigt Sep 04 '18 at 13:54
  • For the manifest part, you can see this document which was linked from the first page I gave you: https://msdn.microsoft.com/library/ms649781(v=VS.85).aspx#extensions – Ben Voigt Sep 04 '18 at 13:56