目录

ImGui

创建窗口

1
2
3
//实例1
ImGui::Begin("Hello, world!");
ImGui::End();
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//实例2

static bool flag = true;
if(flag) 
{
    if(ImGui::Begin("Close Window", &flag)) 
    {
      //TODO
    }
    ImGui::End();
}
1
2
3
4
5
IMGUI_API bool Begin(
  const char* name, //相当于窗口的id
  bool* p_open = NULL, //窗口右上角的X
  ImGuiWindowFlags flags = 0	//样式
);

参数1:name,相当于窗口的id,是独一无二的 参数2:p_open,如果设置这个参数,窗口的右上角就会出现一个X按钮来执行关闭窗口的功能。这个参数和X按钮绑定,当X按钮被按下时,p_open被设为false 参数3:flags,这个参数的类型实际上是int,用来指示当前窗口的某个feature是否应该激活 flags是一个整数,表示你需要的样式的和,以下是所有的flag

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  ImGuiWindowFlags_None                   = 0,
    ImGuiWindowFlags_NoTitleBar             = 1 << 0,   // 禁用标题栏
    ImGuiWindowFlags_NoResize               = 1 << 1,   // 禁用右下角调整功能
    ImGuiWindowFlags_NoMove                 = 1 << 2,   // 禁止移动窗口
    ImGuiWindowFlags_NoScrollbar            = 1 << 3,   // Disable scrollbars (window can still scroll with mouse or programmatically)
    ImGuiWindowFlags_NoScrollWithMouse      = 1 << 4,   // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set.
    ImGuiWindowFlags_NoCollapse             = 1 << 5,   // 通过双击禁止用户折叠窗口
    ImGuiWindowFlags_AlwaysAutoResize       = 1 << 6,   // Resize every window to its content every frame
    ImGuiWindowFlags_NoBackground           = 1 << 7,   // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f).
    ImGuiWindowFlags_NoSavedSettings        = 1 << 8,   // Never load/save settings in .ini file
    ImGuiWindowFlags_NoMouseInputs          = 1 << 9,   // Disable catching mouse, hovering test with pass through.
    ImGuiWindowFlags_MenuBar                = 1 << 10,  // Has a menu-bar
    ImGuiWindowFlags_HorizontalScrollbar    = 1 << 11,  // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section.
    ImGuiWindowFlags_NoFocusOnAppearing     = 1 << 12,  // Disable taking focus when transitioning from hidden to visible state
    ImGuiWindowFlags_NoBringToFrontOnFocus  = 1 << 13,  // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus)
    ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14,  // Always show vertical scrollbar (even if ContentSize.y < Size.y)
    ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15,  // Always show horizontal scrollbar (even if ContentSize.x < Size.x)
    ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16,  // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient)
    ImGuiWindowFlags_NoNavInputs            = 1 << 18,  // No gamepad/keyboard navigation within the window
    ImGuiWindowFlags_NoNavFocus             = 1 << 19,  // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)
    ImGuiWindowFlags_UnsavedDocument        = 1 << 20,  // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker.
    ImGuiWindowFlags_NoNav                  = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
    ImGuiWindowFlags_NoDecoration           = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,
    ImGuiWindowFlags_NoInputs               = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,

    // [Internal]
    ImGuiWindowFlags_NavFlattened           = 1 << 23,  // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
    ImGuiWindowFlags_ChildWindow            = 1 << 24,  // Don't use! For internal use by BeginChild()
    ImGuiWindowFlags_Tooltip                = 1 << 25,  // Don't use! For internal use by BeginTooltip()
    ImGuiWindowFlags_Popup                  = 1 << 26,  // Don't use! For internal use by BeginPopup()
    ImGuiWindowFlags_Modal                  = 1 << 27,  // Don't use! For internal use by BeginPopupModal()
    ImGuiWindowFlags_ChildMenu              = 1 << 28   // Don't use! For internal use by BeginMenu()

以上内容在imgui.h的枚举ImGuiWindowFlags_里也有。

Demo窗口

1
	ImGui::ShowDemoWindow();

主菜单栏

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//ImGui::BeginMainMenuBar();
//ImGui::EndMainMenuBar();

if (ImGui::BeginMainMenuBar())
{
    if (ImGui::BeginMenu("File"))
    {
        if (ImGui::MenuItem("Quit", "Alt+F4")) break;
        ImGui::EndMenu();
    }
    if (ImGui::BeginMenu("Edit"))
    {
        if( ImGui::MenuItem("TODO") ){
            //do something
        }
        ImGui::EndMenu();
    }
    ImGui::EndMainMenuBar();
}

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/gLsKwsB.png

菜单(横排)与菜单项(竖排)

1
2
3
4
5
	if (ImGui::BeginMenu("Test Menu"))//菜单(横排)
  {
    ImGui::Menultem("Test Menu Item", NULL, new bool(true));//菜单项(竖排)
		ImGui::EndMenu();
  }  

次菜单栏

1
2
	ImGui::BeginMenuBar();
	ImGui::EndMenuBar();

通过BeginMenuBar()和BeginMenu()来分别定制顶部菜单栏和对应的下拉菜单栏的内容; 注意任意的beginXXX都要对应一个endXXX

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/gLcyDJ1obw6B35A.png

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
static bool no_close = false;
bool p_open = true;

ImGuiWindowFlags JR_window_flags = 0;
JR_window flags = ImGuiWindowFlags MenuBar;
if (!ImGui::Begin ("HelloWindow", &p_open, JR_window_flags)) {
	ImGui::End();
	return 0;
}
if (ImGui::BeginMenuBar())
{
	if (ImGui::BeginMenu("Test Menu"))
  {
    ImGui::Menultem("Test Menu Item",. NULL, new bool(true));
		ImGui::EndMenu();
  }
	ImGui::EndMenuBar();
}
ImGui::End();

https://img-blog.csdnimg.cn/20200706142329810.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20xODcxODMwMDQ3MQ==,size_16,color_FFFFFF,t_70

Text及Text各种效果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
//Text 与 禁用的Text
ImGui::Text("Text");
ImGui::TextDisabled("Disabled text");

//格式字串
ImGui::Text("haha%d", 123);

//颜色
ImGui::TextColored(ImVec4(255, 0, 0, 255), "red");
ImGui::TextColored(ImVec4(0, 255, 0, 255), "blue");
ImGui::TextColored(ImVec4(0, 0, 255, 255), "green");
ImGui::TextColored(ImVec4(128, 128, 128, 255), "grey");

//项目文字(前面带点)
ImGui::BulletText("aaa");
ImGui::BulletText("bbb");
ImGui::BulletText("ccc");

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/image-20220218103308814.png

按钮及事件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
if(ImGui::Button("I am a Button")) {

    // 按钮事件
}
ImGui::SameLine();//不换行

//颜色
ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0.0f, 0.6f, 0.6f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0.0f, 0.7f, 0.7f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(0.0f, 0.8f, 0.8f));

ImGui::Button("Red");

ImGui::PopStyleColor(3);

//箭头按钮
ImGui::ArrowButton("##Left", ImGuiDir_Left);ImGui::SameLine();//不换行
ImGui::ArrowButton("##Right", ImGuiDir_Right);

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/OkTeoNI.png

单选框

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
//实例1

static int a = 0;
ImGui::RadioButton("RadioButton0", &a, 0);
ImGui::RadioButton("RadioButton1", &a, 1);				ImGui::RadioButton("RadioButton2", &a, 2);
switch (a)
{
  case 0:
    printf("多选框0被选中");
    break;
  case 1:
    printf("多选框1被选中");
    break;
  case 2:
    printf("多选框2被选中");
    break;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//实例2

static int select = -1;
ImGui::RadioButton("Zero", &select, 0); ImGui::SameLine();
ImGui::RadioButton("One", &select, 1); ImGui::SameLine();
ImGui::RadioButton("Two", &select, 2);

if(select >= 0)
{
    ImGui::Text("You Select %d\n", select);
}

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/5WOuE62.png

复选框

1
2
3
4
5
6
//实例1

static bool b = false;
ImGui::Checkbox("CheckBoxB", &b);
static bool c = false;
ImGui::Checkbox("CheckBoxC", &c);
1
2
3
4
5
6
7
8
9
//实例2

static bool flag = false;
if(ImGui::Checkbox("FirstBox", &flag))
{
    // do something
}
if(flag)
    ImGui::Text("the box has been checked");

折叠框控件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
if (ImGui::CollapsingHeader(u8"文本框"))
{
  //Todo
}
if (ImGui::TreeNode(u8"滑块"))
{
  //Todo
  
  ImGui::TreePop();
}
//区别
//CollapsingHeader整个按钮可以点击
//TreeNode只有文字可以点击

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/image-20220218114529051.png

文本框

1
2
3
ImGui::Text("Text1");
ImGui::BulletText("Text2");//文本前有个圆圈
HelpMarker("This is a helpMaker");
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
static void HelpMarker(const char* desc)
{
	ImGui::TextDisabled("(?)");
	if (ImGui::IsItemHovered())
	{
		ImGui::BeginTooltip();
		ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
		ImGui::TextUnformatted(desc);
		ImGui::PopTextWrapPos();
		ImGui::EndTooltip();
	}
}

滑块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//实例1

float f = 0.f;
ImGui::SliderFloat("FloatSlider", &f, 0.f, 1.f);
static int e = 0;
ImGui::SliderInt("IntSlider", &e, 0, 100);

//非常简单的两个函数
const char* label, float* v, float v_min, float v_max
const char* label, int* v, int v_min, int v_max
1
2
3
4
5
6
7
8
//实例2

static float x = 0.f;
static float y = 0.f;        
static int radius = 0;      
ImGui::SliderFloat("x",&x,0.f,1080.f);
ImGui::SliderFloat("y",&y,0.f,720.f);
ImGui::SliderInt("Size",&radius,0,100);

https://cdn.jsdelivr.net/gh/xinqinew/pic@main/img/C2g4EiT.png

Tab菜单(横向子菜单)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
{
    if (ImGui::BeginTabItem("Avocado"))
    {
        ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
        ImGui::EndTabItem();
    }
    if (ImGui::BeginTabItem("Broccoli"))
    {
        ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
        ImGui::EndTabItem();
    }
    if (ImGui::BeginTabItem("Cucumber"))
    {
        ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
        ImGui::EndTabItem();
    }
    ImGui::EndTabBar();
}
ImGui::Separator();
ImGui::TreePop();

显示中文

1
2
3
4
5
6
ImFont* font = io.Fonts->AddFontFromFileTTF(
  "c:\\Windows\\Fonts\\msyh.ttc", //字体文件
  18.0f, //控制字体大小
  NULL, 
  io.Fonts->GetGlyphRangesChineseFull() //中文
);

内存加载字体

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include "baidu_font.hpp" 

	ImFontConfig f_cfg;
	f_cfg.FontDataOwnedByAtlas = false;
	ImFont* font = io.Fonts->AddFontFromMemoryTTF(
		(void*)baidu_font_data, //字体文件
		baidu_font_size,
		18.0f, //控制字体大小
		&f_cfg,
		io.Fonts->GetGlyphRangesChineseFull() //中文
	);

生成字体

1
2
#终端下运行
binary_to_compressed_c.exe -nocompress baidu.ttf baidu_font > baidu_font.hpp

设置不同控件的颜色

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

				ImGuiStyle* style = &ImGui::GetStyle();//先拿到样式指针
        
        //        ImColor();//参数123 对应RGB值 参数4对应透明度 0为完全透明 和窗口背景同一个颜色
        
        style->Colors[ImGuiCol_Button] = ImColor(84, 255, 159, 255);//按钮闲置状态下的颜色
        style->Colors[ImGuiCol_ButtonActive] = ImColor(255, 0, 0, 255);//按钮按下时候的颜色
        style->Colors[ImGuiCol_ButtonHovered] = ImColor(41, 40, 41, 255);//当鼠标放在按钮上的颜色
        
        //一些其他常用控件
        style->Colors[ImGuiCol_TitleBg] = ImColor(84 ,255 ,159,255);
        style->Colors[ImGuiCol_TitleBgActive] = ImColor(255, 0, 0, 255);
        style->Colors[ImGuiCol_TitleBgCollapsed] = ImColor(0, 0, 0, 130);

        style->Colors[ImGuiCol_Separator] = ImColor(70, 70, 70, 255);
        style->Colors[ImGuiCol_SeparatorActive] = ImColor(76, 76, 76, 255);
        style->Colors[ImGuiCol_SeparatorHovered] = ImColor(76, 76, 76, 255);

        style->Colors[ImGuiCol_FrameBg] = ImColor(37, 36, 37, 255);
        style->Colors[ImGuiCol_FrameBgActive] = ImColor(37, 36, 37, 255);
        style->Colors[ImGuiCol_FrameBgHovered] = ImColor(37, 36, 37, 255);

        style->Colors[ImGuiCol_Header] = ImColor(0, 0, 0, 0);
        style->Colors[ImGuiCol_HeaderActive] = ImColor(0, 0, 0, 0);
        style->Colors[ImGuiCol_HeaderHovered] = ImColor(46, 46, 46, 255);

        style->Colors[ImGuiCol_Tab] = ImColor(0, 0, 0, 0);
        style->Colors[ImGuiCol_TabActive] = ImColor(255, 0, 0, 255);
        style->Colors[ImGuiCol_TabHovered] = ImColor(255, 0, 0, 255);
        

设置不同控件的样式

1
2
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.0f);        
ImGui::PushStyleVar(ImGuiStyleVar_GrabRounding, 22.0f);
1
2
3
4
5
ImGuiStyle* style = &ImGui::GetStyle();//先拿到样式指针
style->FrameRounding = f;
style->FrameBorderSize = 12.0f;
style->GrabRounding = 12.0f;
style->WindowMinSize = ImVec2(100, 600);

绘制线

1
2
3
4
5
6
7
8
9
ImGui::GetForegroundDrawList()->AddLine(
  ImVec2(800, 300), //参数1是 x1,y1,也可以写成{800,300} 就不需要这个 ImVec2这个 
  ImVec2(900, 300), //参数2是 x2,y2  
  ImColor(84, 255, 159, 255), //参数3是颜色 RGB值和透明度
  1.0f	//参数4是线条粗细 
); 
ImGui::GetForegroundDrawList()->AddLine({ 800,300 }, { 800,400 }, ImColor(84, 255, 159, 255), 1.0f);
ImGui::GetForegroundDrawList()->AddLine({ 900,300 }, { 900,400 }, ImColor(84, 255, 159, 255), 1.0f);
ImGui::GetForegroundDrawList()->AddLine({ 800,400 }, { 900,400 }, ImColor(84, 255, 159, 255), 1.0f);

绘制四边形

1
2
3
4
5
6
ImGui::GetForegroundDrawList()->AddRect(
  {650,300},	//左上角
  {750,400},	//右下角
  ImColor(84, 255, 159, 255),//颜色
  5.f	//圆角弧度
);

绘制文字

1
2
3
auto DrawList = ImGui::GetForegroundDrawList();
DrawList->AddText(font, font->FontSize, ImVec2(400, 400), ImColor(255, 255, 255, 255), u8"你好世界 hello world 123");
DrawList->AddText(font1, font1->FontSize, ImVec2(400, 450), ImColor(84, 255, 159, 255), u8"我真帅");
1
2
3
4
5
//参数1 是字体指针
//参数2 是字体大小
//参数3 是绘制字体的坐标
//参数4 是字体颜色
//参数5 是要绘制的文字 如果想要绘制中文 记得加上u8

绘制图片

1
2
3
4
5
6
7
8
DrawList->AddImage(
  m_srv,	//ImTextureTD 图像纹理
  {200,200},	//矩形的左上角
  {300,300},	//矩形的右下角
  {0,0},			//剪切 0-1的小数,表示要渲染的图片在材质的位置
  {1,1},			//剪切 0-1的小数,表示要渲染的图片在材质的位置
  ImColor(255, 255, 255, 255)	//颜色及透明度
);
  1. 首先必须导入stb_image.h

    1
    2
    3
    
    //在文件头部包含以下内容
    #define STB_IMAGE_IMPLEMENTATION
    #include "stb_image.h"
    
  2. 在适当的位置添加函数LoadTextureFromFile

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    
    bool LoadTextureFromFile(const char* filename, ID3D11ShaderResourceView** out_srv, int* out_width, int* out_height)
    {
        // Load from disk into a raw RGBA buffer
        int image_width = 0;
        int image_height = 0;
        unsigned char* image_data = stbi_load(filename, &image_width, &image_height, NULL, 4);
        if (image_data == NULL)
            return false;
    
        // Create texture
        D3D11_TEXTURE2D_DESC desc;
        ZeroMemory(&desc, sizeof(desc));
        desc.Width = image_width;
        desc.Height = image_height;
        desc.MipLevels = 1;
        desc.ArraySize = 1;
        desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        desc.SampleDesc.Count = 1;
        desc.Usage = D3D11_USAGE_DEFAULT;
        desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
        desc.CPUAccessFlags = 0;
    
        ID3D11Texture2D *pTexture = NULL;
        D3D11_SUBRESOURCE_DATA subResource;
        subResource.pSysMem = image_data;
        subResource.SysMemPitch = desc.Width * 4;
        subResource.SysMemSlicePitch = 0;
        g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
    
        // Create texture view
        D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
        ZeroMemory(&srvDesc, sizeof(srvDesc));
        srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
        srvDesc.Texture2D.MipLevels = desc.MipLevels;
        srvDesc.Texture2D.MostDetailedMip = 0;
        g_pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, out_srv);
        pTexture->Release();
    
        *out_width = image_width;
        *out_height = image_height;
        stbi_image_free(image_data);
    
        return true;
    }
    
  3. 在需要绘制图片的地方引用以下代码

    1
    2
    3
    4
    5
    6
    7
    
    int my_image_width = 0;
    int my_image_height = 0;
    ID3D11ShaderResourceView* my_texture = NULL;
    bool ret = LoadTextureFromFile("d:/ccz.jpg", &my_texture, &my_image_width, &my_image_height);
    //bool ret = LoadTextureFromFile("./sources/MyImage01.jpg", &my_texture, &my_image_width, &my_image_height);
    IM_ASSERT(ret);
    ImGui::Image((void*)my_texture, ImVec2(my_image_width, my_image_height));
    

初始化交换链

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
void InitSwapChain()
{
        AllocConsole();
        freopen("CON", "w", stdout);
        SetConsoleTitle((LPCWSTR)"Hello World");


        //交接链
        DXGI_SWAP_CHAIN_DESC scd;
        ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
        scd.BufferCount = 1;//设置后缓冲
        scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;//设置颜色格式为RGBA
        scd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;//缩放比
        scd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;//扫描线
        scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;//渲染目标输出
        scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;//允许模式切换
        scd.OutputWindow = g_GamehWnd;//在目标窗口内部绘制另外一个窗口
        scd.SampleDesc.Count = 1;//1重采样
        scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;//常用参数
        scd.Windowed = ((GetWindowLongPtr(g_GamehWnd, GWL_STYLE) & WS_POPUP) != 0) ? FALSE : TRUE; //是否全屏,随目标窗口变化而定
        scd.BufferDesc.Width = 1920;
        scd.BufferDesc.Height = 1080;
        scd.BufferDesc.RefreshRate.Numerator = 144; //刷新率
        scd.BufferDesc.RefreshRate.Denominator = 1; //分母
        scd.SampleDesc.Quality = 0;   //采样等级                                                                                                                        

        D3D_FEATURE_LEVEL featrueLevel = D3D_FEATURE_LEVEL_11_0;
        D3D11CreateDeviceAndSwapChain(
                NULL,
                D3D_DRIVER_TYPE_HARDWARE,
                NULL,
                NULL,
                &featrueLevel,
                1,
                D3D11_SDK_VERSION,
                &scd,
                &pSwapChain,
                &pDevice,
                NULL,
                &pContext);

        printf("hWnd=%X\n", g_GamehWnd);
        printf("pSwapChain=%X\n", pSwapChain);
        printf("pDevice=%X\n", pDevice);
        printf("pContext=%X\n", pContext);

}

BOOL APIENTRY DllMain(HMODULE hModule,
        DWORD  ul_reason_for_call,
        LPVOID lpReserved
)
{
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
                ::CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)InitSwapChain, NULL, NULL, NULL);
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
                break;
        }
        return TRUE;
}

利用Detours库挂钩MessageBoxA

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
        DetourTransactionBegin();//开始HOOK
        DetourUpdateThread(GetCurrentThread());//刷新当前线程
        DetourAttach((PVOID*) &pPointer, pDetour);//要HOOK的函数的函数的地址,以及你自定义的函数的函数地址.
        DetourTransactionCommit();//提交HOOK 到此为止 HOOK完成
        
        
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourDetach((PVOID*) &pPointer, pDetour);
        DetourTransactionCommit();
        
        int (WINAPI* Real_MessageBoxA)(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType) = MessageBoxA;

        int WINAPI My_MessageBoxA(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType)
        {
                //return 之前 我们就可以做一些 想要做的事情
                lpText = "Hello World";
                lpCaption = "111111";

                return Real_MessageBoxA(hWnd, lpText, lpCaption, uType);
        }

利用Detours库挂钩游戏Present函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

        LONG_PTR* pSwapChainVT = (LONG_PTR*)(pSwapChain);//拿到虚表指针
        pSwapChainVT = (LONG_PTR*) (pSwapChainVT[0]);
        phookD3D11Present = (tD3D11Present)(pSwapChainVT[8]);
        
        typedef HRESULT(__stdcall* tD3D11Present) (IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags);
        static tD3D11Present phookD3D11Present = NULL;
        
        HRESULT __stdcall My_D3D11Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)
        {
        //做一些自己想要做的事情
        //比如一些绘制操作
        //比如一些画ui的操作

        printf("123123");
        return phookD3D11Present(pSwapChain, SyncInterval, Flags);
        }

ImGui的初始化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  void InitImGui()
{
        ImGui::CreateContext();
        ImGuiIO& io = ImGui::GetIO();
        ImFont* font = io.Fonts->AddFontFromMemoryTTF((void*)alifont_data, alifont_size, 17.0f, NULL, io.Fonts->GetGlyphRangesChineseFull());
        ImGuiStyle* style = &ImGui::GetStyle();
}

HRESULT __stdcall My_D3D11Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)
{
        //做一些自己想要做的事情
        //比如一些绘制操作
        //比如一些画ui的操作
        static bool bOnce = false;
        if (!bOnce)
        {
                bOnce = true;
                //在这个里面 做一些初始化的操作 
                InitImGui();//初始化IMGUI 
                //这个开关里面 只做 只执行一次的操作
                printf("bOnce\n");
        }

        // 我们可以做一些 需要一直重复的操作
        // 比如 我们绘制外挂页面
        // 这里到时候就写 绘制外挂页面的代码
        printf("121123\n");
        return phookD3D11Present(pSwapChain, SyncInterval, Flags);
}

在游戏内部绘制外挂页面

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
ID3D11Device* pDevice = NULL;//设备指针
ID3D11DeviceContext* pContext = NULL;//交换链条
IDXGISwapChain* pSwapChain = NULL; //交换链
ID3D11RenderTargetView* g_pRenderTargetView = NULL;

HRESULT __stdcall My_D3D11Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)
{
        //做一些自己想要做的事情
        //比如一些绘制操作
        //比如一些画ui的操作
        static bool bOnce = false;
        if (!bOnce)
        {
                bOnce = true;
                //在这个里面 做一些初始化的操作 
                InitImGui();//初始化IMGUI 
                //这个开关里面 只做 只执行一次的操作
                printf("bOnce\n");


                if (SUCCEEDED(pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)(&pDevice))))
                {
                        pDevice->GetImmediateContext(&pContext);
                }ID3D11Texture2D* renderTargetTexture = nullptr;
                //获取了缓冲区的地址
                if (SUCCEEDED(pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (PVOID*)(&renderTargetTexture))))
                {
                        //创建目标视图
                        pDevice->CreateRenderTargetView(renderTargetTexture, NULL, &g_pRenderTargetView);
                        //释放后缓冲
                        renderTargetTexture->Release();
                }
                //初始化DX11
                ImGui_ImplWin32_Init(g_GamehWnd);
                ImGui_ImplDX11_Init(pDevice, pContext);
                ImGui_ImplDX11_CreateDeviceObjects();
        }
        //绑定到渲染管线
        pContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);
        ImGui_ImplDX11_NewFrame();
        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();


        {
                //在这里写上我们需要的窗口代码
                ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_FirstUseEver);
                ImGui::SetNextWindowSize(ImVec2(100, 200));

                ImGui::Begin("Menu");
                ImGui::End();

        }




        ImGui::EndFrame();
        ImGui::Render();
        ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
        // 我们可以做一些 需要一直重复的操作
        // 比如 我们绘制外挂页面
        // 这里到时候就写 绘制外挂页面的代码
        printf("121123\n");
        return phookD3D11Present(pSwapChain, SyncInterval, Flags);
}
HRESULT __stdcall My_D3D11Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)
{
        //做一些自己想要做的事情
        //比如一些绘制操作
        //比如一些画ui的操作
        static bool bOnce = false;
        if (!bOnce)
        {
                bOnce = true;
                //在这个里面 做一些初始化的操作 
                InitImGui();//初始化IMGUI 
                //这个开关里面 只做 只执行一次的操作
                printf("bOnce\n");


                if (SUCCEEDED(pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)(&pDevice))))
                {
                        pDevice->GetImmediateContext(&pContext);
                }ID3D11Texture2D* renderTargetTexture = nullptr;
                //获取了缓冲区的地址
                if (SUCCEEDED(pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (PVOID*)(&renderTargetTexture))))
                {
                        //创建目标视图
                        pDevice->CreateRenderTargetView(renderTargetTexture, NULL, &g_pRenderTargetView);
                        //释放后缓冲
                        renderTargetTexture->Release();
                }
                //初始化DX11
                ImGui_ImplWin32_Init(g_GamehWnd);
                ImGui_ImplDX11_Init(pDevice, pContext);
                ImGui_ImplDX11_CreateDeviceObjects();
        }
        //绑定到渲染管线
        pContext->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);
        ImGui_ImplDX11_NewFrame();
        ImGui_ImplWin32_NewFrame();
        ImGui::NewFrame();


        {
                //在这里写上我们需要的窗口代码
                ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_FirstUseEver);
                ImGui::SetNextWindowSize(ImVec2(100, 200));

                ImGui::Begin("Menu");
                ImGui::End();

        }




        ImGui::EndFrame();
        ImGui::Render();
        ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
        // 我们可以做一些 需要一直重复的操作
        // 比如 我们绘制外挂页面
        // 这里到时候就写 绘制外挂页面的代码
        printf("121123\n");
        return phookD3D11Present(pSwapChain, SyncInterval, Flags);
}

添加ImGui窗口消息响应

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

UINT_PTR oldWndProc = 0;

LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
        extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
        ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam);

        return CallWindowProc((WNDPROC)oldWndProc, hWnd, msg, wParam, lParam);
}

oldWndProc = SetWindowLongPtrA(g_GamehWnd, GWLP_WNDPROC, (LONG)WndProc);

TabBar控件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(200, 400));

if (ImGui::Begin("Menu"))
{
        Menu:oadTab();
        ImGui::End();
}
                
                
void Menu:oadTab()
{

        if (ImGui::BeginTabBar("TabBar"));
        {

                if (ImGui::BeginTabItem(u8"使用说明"))
                {
                        ImGui::Text(u8"我是一个文本框");
                        ImGui::EndTabItem();
                }

                if (ImGui::BeginTabItem(u8"功能设置"))
                {
                        if (ImGui::CollapsingHeader(u8"人物透视"))
                        {
                                static bool b = true;
                                ImGui::Checkbox(u8"显示骨骼", &b);
                                static bool c = true;
                                ImGui::Checkbox(u8"显示方框", &c);

                                static bool d = true;
                                ImGui::Checkbox(u8"显示血量", &d);
                                static bool e = true;
                                ImGui::Checkbox(u8"显示护甲", &e);
                        }
                        if (ImGui::CollapsingHeader(u8"物品透视"))
                        {
                                static int a = 0;
                                ImGui::RadioButton(u8"透视金堆", &a, 0); ImGui::SameLine();
                                ImGui::RadioButton(u8"透视盒子", &a, 111);
                        }
                        ImGui::EndTabItem();
                }




                ImGui::EndTabBar();
        }

远线程注入

  1. 使用进程PID打开进程,获得句柄
  2. 使用进程句柄申请内存空间
  3. 把dll路径写入内存
  4. 创建远程线程,调用LoadLibrary
  5. 释放收尾工作或者卸载dll
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
bool RemoteThreadInject(DWORD dwPid)
{
        //1.使用PID打开进程获取权限
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, dwPid);
        printf("hProcess=%d",hProcess);
        //2.申请内存,写入DLL路径
        int nLen = sizeof(WCHAR) * (wcslen(L"D:\\DetoursDemo.dll") + 1);
        LPVOID pBuf = VirtualAllocEx(hProcess, NULL, nLen, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
        if (!pBuf)
        {
                printf("申请内存失败!\n");
                return false;
        }
        else
        {
                printf("申请内存成功!  \n");
        }
        //3.写入内存
        SIZE_T dwWrite = 0;
        if (!WriteProcessMemory(hProcess, pBuf, "D:\\DetoursDemo.dll", nLen, &dwWrite))
        {
                printf("写入内存失败!\n");
                return false;
        }else
        {
                printf("写入内存成功!  \n");
        }
        //4.创建远程线程,让对方调用LoadLibrary
        HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, NULL,
                (LPTHREAD_START_ROUTINE)LoadLibraryA, pBuf, 0, 0);
        //5.等待线程结束返回,释放资源
        WaitForSingleObject(hRemoteThread, -1);
        CloseHandle(hRemoteThread);
        VirtualFreeEx(hProcess, pBuf, 0, MEM_FREE);
        return true;
}

int main()
{
        HWND Gameh = FindWindowA("Direct3DWindowClass", "EmptyProject11");
        DWORD pid = 0;
        if (Gameh != 0)
        {
                GetWindowThreadProcessId(Gameh,&pid);
                printf("Gameh=%d pid=%d\n", Gameh, pid);
                if (pid != 0)
                {
                        RemoteThreadInject(pid);
                }

        }
        getchar();
}

最好是 既然学了ImGui 最好用ImGui来写一个启动程序 ImGui 肯定是要比我们课堂上演示的黑框框要高大上很多