当前位置: 首页 > news >正文

实现第一个动态链接库 游戏插件 成功在主程序中运行 dll 中定义的类

devc++ 5.11编译环境

dll编译环境设置参考

Dev c++ C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客 

 插件 DLL代码和主程序代码如下

注意 dll 代码中的class 类名需要 和主程序 相同

其中使用了函数指针和强制类型转换

函数指针教程参考

以动态库链接库 .dll 探索结构体参数-CSDN博客

注意,退出游戏后需等30-50秒,让dll自行销毁,然后重开时才能正常运行。否则进入后不显示地图。

有dll时:

 

 无DLL插件读取到时,即dll不在同程序目录下

 

dll.h
#ifndef _DLL_H_
#define _DLL_H_
#include <iostream>
using namespace std;
// 游戏背景操作板,可以通过坐标直接改
class Bkmap
{public:Bkmap(int height,int wide){this->wide=wide;this->height=height;this->bkmap=new char*[this->height];for(int i=0; i<height; i++){this->bkmap[i]=new char[this->wide];for(int j=0; j<wide; j++){this->bkmap[i][j]='\0';}}}public:char** bkmap;int wide;int height;};// 玩家类,移动,攻击,地图修改
class Player
{public:Player(int x,int y,int limitx,int limity){this->playerx=x;this->playery=y;is_atk=0;is_buff=0;flag_x=0;flag_y=0;this->limitx=limitx;this->limity=limity;}~Player();public:char player='1';int playerx;int playery;int flag_x;int flag_y;int limitx;int limity;int is_atk;int is_buff;public:
};// 攻击类,这里直线攻击做测试
class Aking
{public:Aking(int height,int wide,int atk_time,int number){this->height=height;this->wide=wide;this->number=number;this->atk_time=atk_time;atk_count=0;}public:int height;																// 攻击范围长宽int wide;int number;																// 攻击序号,因为有多个攻击技能,所以编号,可以查找攻击int atk_time;															// 攻击时长int atk_count;															// 当前攻击持续时间public:// 攻击中void atking(Bkmap* bkmap,Player* player){if (atk_count != atk_time)										// 攻击{atk_count++;cout<<"DLL"<<atk_count<<endl; cout<<"DLL:playerx player y:"<<player->playerx<<","<<player->playery<<endl;cout<<"DLL: player is_atk:"<<player->is_atk<<endl;for(int j=0; j<10; j++){bkmap->bkmap[player->playery][player->playerx+1+j]='P';}}else{atk_count=0;player->is_atk=0; 												// 玩家状态复位}}
};static Aking* akv3=new Aking(20,50,20,3); 										// 静态类,在调用时,保存被调用的值,调用结束后数值不清空 extern "C"{void mainDll(Bkmap* bkmap,Player* player);
}#endif

插件 dll.cpp

/* Replace "dll.h" with the name of your header */
#include "dll.h"
#include <windows.h>void mainDll(Bkmap* bkmap,Player* player)
{
//	cout<<"DLL: atking class start"<<endl;akv3->atking(bkmap,player);
}

 

主程序,注意和dll放在同一个目录下

#include <iostream>
#include <string.h>
#include <windows.h>#define KEY_DOWN(vKey) ((GetAsyncKeyState(vKey) & 0x8000) ? 1:0)							// 判断是否按下按键,按下之后,最高位变成 1,所以需要位运算去除其他位,只检测最高位
#define KEY_DOWN_FOREGROUND(hWnd, vk) (KEY_DOWN(vk) && GetForegroundWindow() == hWnd) 		// 前景窗口判断
#pragma warning(disable : 4996)
using namespace std;// 加入的游戏背景数据,通常不修改,放到 Bkmap 进行修改
class Gamemap
{public:Gamemap(int height,int wide){this->wide=wide;this->height=height;this->gamemap=new int*[this->height];for(int i=0; i<height; i++){this->gamemap[i]=new int[this->wide];for(int j=0; j<this->wide; j++){this->gamemap[i][j]=0;}}}~Gamemap();public:int** gamemap;int wide;int height;
};
// 游戏背景操作板,可以通过坐标直接改
class Bkmap
{public:Bkmap(int height,int wide){this->wide=wide;this->height=height;this->bkmap=new char*[this->height];for(int i=0; i<height; i++){this->bkmap[i]=new char[this->wide];for(int j=0; j<wide; j++){this->bkmap[i][j]='\0';}}}public:char** bkmap;int wide;int height;public:void adddata(){for(int i=0; i<this->height; i++)								// 地图数据写入{for(int j=0; j<this->wide-1; j++){this->bkmap[i][j]='*';}this->bkmap[i][this->wide-1]='\0';cout<<this->bkmap[i]<<"ok"<<endl;}}void fresh(Gamemap* gamemap){for(int i=0; i<gamemap->height; i++)							// 地图复印到选区{for(int j=0; j<gamemap->wide; j++){if(gamemap->gamemap[i][j]==0)this->bkmap[i][j]=' ';					// 这里决定地图打印在屏幕的样子}}}};
// 字符串缓冲类
class Showmap
{public:Showmap(int height,int wide){this->showmap=new char[wide*height+1000];strcpy(showmap,"");
//			showmap={};												// 不能这样写,否则报错,指针重新变空}public:char* showmap;public:void adddata(Bkmap* bkmap){cout<<"test"<<endl;if(showmap==NULL){cout<<"NULL";cout<<"函数因空指针结束"<<endl;return;}strcpy(showmap,"");for(int i=0; i<bkmap->height; i++)								// 选区加入到打印缓冲区{strcat(showmap,bkmap->bkmap[i]);strcat(this->showmap,"\n");}}void show(){cout<<this->showmap;}
};// 玩家类,移动,攻击,地图修改
class Player
{public:Player(int x,int y,int limitx,int limity){this->playerx=x;this->playery=y;is_atk=0;is_buff=0;flag_x=0;flag_y=0;this->limitx=limitx;this->limity=limity;}~Player();public:char player='1';int playerx;int playery;int flag_x;int flag_y;int limitx;int limity;int is_atk;int is_buff;public://玩家移动检测void checkmove(HWND hwnd){flag_x=0;flag_y=0;if (KEY_DOWN_FOREGROUND(hwnd, 0x41))			// A{flag_x -= 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x57))			// W{flag_y -= 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x44))			// D{flag_x += 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x53))			// S{flag_y += 1;}}// 打包速度检测void checkspeed(){if (flag_x > 1)														// 速度限制flag_x = 1;else if (flag_x < -1)flag_x = -1;if (flag_y > 1)flag_y = 1;else if (flag_y < -1)flag_y = -1;}// 改变玩家位置void move(){if (flag_x)															// 位移改变playerx += flag_x;if (flag_y)playery += flag_y;}
//		边界检测void checkboundary(){if (playerx >= limitx)												// 角色位置限制playerx = limitx - 1;else if (playerx < 0)playerx = 0;if (playery >= limity)playery = limity - 1;else if (playery < 0)playery = 0;}void putinmap(Bkmap* bkmap){bkmap->bkmap[playery][playerx]=player;}
//		检测攻击void checkatk(HWND hwnd){if (is_atk == 0 && KEY_DOWN_FOREGROUND(hwnd, 0x4A))			// j 键攻击{is_atk = 1;}}
//		检测buffvoid checkbuff(HWND hwnd){if (is_buff == 0 && KEY_DOWN_FOREGROUND(hwnd, 0x4B))		// k 键增加范围 buff{is_buff = 1;}}// 绘制地图void drawmap(HWND hwnd,Gamemap* gamemap){if (KEY_DOWN_FOREGROUND(hwnd, 0x30))								// 0 键绘制地图gamemap->gamemap[playery][playerx] = 0;if (KEY_DOWN_FOREGROUND(hwnd, 0x36))								// 6 键绘制地图gamemap->gamemap[playery][playerx] = 6;if (KEY_DOWN_FOREGROUND(hwnd, 0x37))								// 7 键绘制地图gamemap->gamemap[playery][playerx] = 7;if (KEY_DOWN_FOREGROUND(hwnd, 0x38))								// 8 键绘制地图gamemap->gamemap[playery][playerx] = 8;if (KEY_DOWN_FOREGROUND(hwnd, 0x39))								// 9 键绘制地图gamemap->gamemap[playery][playerx] = 9;}
};class Dlling
{typedef void(*Menu)(Bkmap* bkmap,Player* player);										// 定义函数指针,函数返回值是 void, 指针类型名是 Menu, 参数是Bkmap*public:Dlling(char* name,int number){mainDll="mainDll";HINSTANCE hDLL = LoadLibrary(name);													// 加载dll库if(hDLL==NULL){cout<<"没有在本目录里找到 dllv3.dll"<<endl;atk=NULL;Sleep(300);}else{void(*atkv2)(Bkmap* bkmap,Player*)= (void (*)(Bkmap*,Player*))GetProcAddress(hDLL,mainDll);		// 加载dll 的入口主函数 强制类型转换后,加载的dll主函数成为atkv2的替身if(atkv2==NULL){cout<<"dllv3 插件没有读取"<<endl;atk=NULL;Sleep(300);}else{cout<<"dllv3 读取成功"<<endl;Sleep(300);atk = atkv2;}}count=0;}public:char* mainDll;Menu atk;int count;													// 成员是一个指针,目前没有函数替身,所以没有编译报错public:void aking(Bkmap* bkmap,Player* player){cout<<"class_atkv3"<<endl;if(player->is_atk&&atk!=NULL){cout<<"class_atkv3 is going"<<endl;atk(bkmap,player);										// 函数指针在初始化过程在有了替身函数,所以可以加入变量}else if(player->is_atk&&atk==NULL){cout<<"dll是空的,跳过执行函数"<<endl;count++;if(count>10){player->is_atk=0;count=0;}}}
};int main()
{Gamemap* gamemap = new Gamemap(20,50);Bkmap* bkmap=new Bkmap(20,50);Showmap* showmap= new Showmap(20,80);Dlling* dll = new Dlling("dllv3.dll",3);bkmap->fresh(gamemap);
//	bkmap->adddata();showmap->adddata(bkmap);showmap->show();HWND hwnd = GetForegroundWindow();									// 获取前端窗口句柄,由于程序刚运行时是在前端,所以这就是本程序的窗口句柄Player* player = new Player(0,0,50,20);while(1){if (KEY_DOWN_FOREGROUND(hwnd, VK_ESCAPE)){printf("游戏退出\n");break;}if(KEY_DOWN_FOREGROUND(hwnd,0x31)){player->is_atk=1;}player->checkmove(hwnd);player->checkspeed();player->move();player->checkboundary();bkmap->fresh(gamemap);dll->aking(bkmap,player);player->putinmap(bkmap);showmap->adddata(bkmap);cout<<"玩家位置:"<<player->playerx<<","<<player->playery<<endl;showmap->show();Sleep(100);system("cls");}return 0;}

相关文章:

实现第一个动态链接库 游戏插件 成功在主程序中运行 dll 中定义的类

devc 5.11编译环境 dll编译环境设置参考 Dev c C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客 插件 DLL代码和主程序代码如下 注意 dll 代码中的class 类名需要 和主程序 相同 其中使用了函数指针和强制类型转换 函数指针教程参考 以动态库链接库 .dll 探索结构体…...

算法第三十九天-验证二叉树的前序序列化

验证二叉树的前序序列化 题目要求 解题思路 方法一&#xff1a;栈 栈的思路是「自底向上」的想法。下面要结合本题是「前序遍历」这个重要特点。 我们知道「前序遍历」是按照「根节点-左子树-右子树」的顺序遍历的&#xff0c;只有当根节点的所有左子树遍历完成之后&#xf…...

Rust---复合数据类型之字符串与切片(2)

目录 字符串操作删除 (Delete)连接 (Concatenate)字符串转义前情回顾: Rust—复合数据类型之字符串(1) 字符串操作 删除 (Delete) 删除方法仅适用于 String 类型,分别是: pop(),remove(),truncate(),clear(),此外还有drain() 方法。 pop 方法:pop() 方法返回一个 O…...

iOS 应用内网络请求设置代理

主要通过URLSessionConfiguration 的connectionProxyDictionary 属性 为了方便其他同学使用&#xff0c;我们可以通过界面来进行设定&#xff08;是否开启代理、服务端、端口&#xff09;&#xff0c;从而达到类似系统上的设定 具体链接参考&#xff1a;为 iOS 网络请求设置代理…...

什么是MariaDB

2024年4月6日&#xff0c;周六晚上 今晚在Debian12上安装mysql时&#xff0c;运行后却发现是MariaDB MariaDB是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是MySQL的一个分支和替代品。MariaDB由MySQL的原始开发者之一Michael "Monty&qu…...

【面试八股总结】传输控制协议TCP(三)

参考资料 &#xff1a;小林Coding、阿秀、代码随想录 一、TCP拥塞控制⭐ 1. 慢启动 – Slow Start 慢启动是指TCP连接刚建立&#xff0c;一点一点地提速&#xff0c;试探一下网络的承受能力&#xff0c;以免直接扰乱了网络通道的秩序。 慢启动算法&#xff1a; 初始拥塞窗口…...

今年过去了多少天?(switch)

//今年已经过去了几天&#xff1f; #include <stdio.h> int monthday(int year,int month){switch(month){case 1:return 31;case 2:if ((year % 4 0 && year % 100 ! 0)||year % 400 0){return 29;}else{return 28;}break;case 3:return 31;case 4:return 30;…...

提升团队工程交付能力,从“看见”工程活动和研发模式开始

作者&#xff1a;张裕、雅纯 理想中的研发团队应当具有以下特征&#xff1a; 总是工作在最高优先级的事项上 理想的研发团队能够识别并始终集中精力在当前最紧迫和最有价值的任务上。这需要团队具备出色的项目管理能力和决策能力&#xff0c;以便能够正确评估优先级&#xff0…...

前端学习之DOM编程案例:全选反选案例

代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>全选反选</title> </head> <body><input type"checkbox" id"all">全选<ul><li><…...

golang map

1.底层实现 2.如何解决hash冲突 3.扩容机制 4.无序 5.非线程安全 6.不可寻址 runtime/map.go 1.底层实现 底层基于hash表实现&#xff0c;实现有2个结构体hmap&#xff0c;bmap&#xff0c;map由若干个桶存储&#xff0c;每个桶存8个元素&#xff0c;使用链地址解决hash冲突 …...

设计模式:享元模式案例

让我们以游戏开发中的棋类游戏&#xff08;例如国际象棋&#xff09;为例来展示享元模式的代码实现。在这个例子中&#xff0c;棋子的类型是内部状态&#xff0c;而棋子的位置是外部状态。 Java 代码示例 import java.util.HashMap; import java.util.Map;// 享元接口 interf…...

pandas(day5)

一. 检测重复值 1.1 检测 data pd.read_csv("./teacher/订单数据.csv")检测行与行之前是否有重复值 data.drop_duplicates()检测 列是否有重复值出现&#xff0c; keep first 从前往后判定 &#xff0c; last是从后往前判定data.drop_duplicates(subset["产…...

如何注册midjourney账号

注册Midjourney账号比较简单&#xff0c;准备好上网工具&#xff0c;进入官网 Midjourney访问地址&#xff1a; https://www.midjourney.com/ 目前没有免费使用额度了&#xff0c;会员最低 10 美元/月&#xff0c;一般建议使用30美元/月的订阅方案。了解如何订阅可以查看订阅…...

探索数据结构:特殊的双向队列

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;数据结构与算法 贝蒂的主页&#xff1a;Betty’s blog 1. 双向队列的定义 **双向队列(double‑ended queue)**是一种特殊的队列…...

16_I2C库函数

I2C库函数 1.void I2C_DeInit(I2C_TypeDef* I2Cx);2.void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);3.void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);4.void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);5.void I2C_DMACmd(I2C_Type…...

十八、Rust gRPC 多 proto 演示

十八、Rust gRPC 多 proto 演示 网上及各官方资料&#xff0c;基本是一个 proto 文件&#xff0c;而实际项目&#xff0c;大多是有层级结构的多 proto 文件形式&#xff0c;本篇文章 基于此诉求&#xff0c;构建一个使用多 proto 文件的 rust grpc 使用示例。 关于 grpc 的实现…...

【Linux】Linux64位环境下编译32位报错skipping incompatible的解决办法

本文首发于 ❄️慕雪的寒舍 问题 如题&#xff0c;当我尝试在wsl2的ubuntu中使用-m32选项编译32位程序的时候&#xff0c;出现了下面的两种报错 ❯ g -m32 test.cpp -o test1 && ./test1 In file included from test.cpp:1: /usr/include/stdio.h:27:10: fatal error…...

vue指令v-model

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>vue指令v-model</title> </head>…...

CentOS安装MySQL数据库

一、更新yum源 #下载对应repo文件 wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo #清除缓存 yum clean all #生成新缓存 yum makecache #更新 yum update -y 二、安装MySQL #获取源 wget http://repo.mysql.com/mysql80-community-release-el7-3.…...

从B2B转向B2B2C模式:工业品牌史丹利百得的转型历程

图片来源&#xff1a;Twitter 在当今数据驱动的营销环境中&#xff0c;企业努力更好了解客户&#xff0c;并在整个客户旅程中提供个性化体验。史丹利百得&#xff08;Stanley Black & Decker&#xff09;是一家领先的工具和工业设备供应商&#xff0c;近年来开始重大转型。…...

APK安装器完整指南:在Windows上轻松安装安卓应用的终极方案

APK安装器完整指南&#xff1a;在Windows上轻松安装安卓应用的终极方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否想在Windows电脑上直接运行手机应用&…...

如何用JPlag守护代码原创性:5分钟快速上手指南

如何用JPlag守护代码原创性&#xff1a;5分钟快速上手指南 【免费下载链接】JPlag State-of-the-Art Source Code Plagiarism & Collusion Detection. Check for plagiarism in a set of programs. 项目地址: https://gitcode.com/gh_mirrors/jp/JPlag 你是否曾担心…...

3分钟掌握SRWE:打破屏幕分辨率限制的终极窗口编辑神器

3分钟掌握SRWE&#xff1a;打破屏幕分辨率限制的终极窗口编辑神器 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE SRWE&#xff08;Simple Runtime Window Editor&#xff09;是一款革命性的实时窗口编辑器&…...

如何彻底解决Minecraft离线启动限制:PrismLauncher-Cracked完全指南

如何彻底解决Minecraft离线启动限制&#xff1a;PrismLauncher-Cracked完全指南 【免费下载链接】PrismLauncher-Cracked This project is a Fork of Prism Launcher, which aims to unblock the use of Offline Accounts, disabling the restriction of having a functional O…...

Gmail只读命令行工具gcli:云端自动化邮件查询与SSH隧道授权方案

1. 项目概述&#xff1a;一个专为自动化场景设计的Gmail只读命令行工具 如果你和我一样&#xff0c;经常需要在没有图形界面的云服务器上处理邮件查询任务&#xff0c;那你一定对Gmail API的授权流程深恶痛绝。传统的OAuth流程要求你在浏览器里点来点去&#xff0c;但服务器上哪…...

智能网联汽车窄路车流预测与协同通行【附仿真】

✨ 长期致力于智能网联汽车、窄路段、短时车流量预测、协同通行研究工作&#xff0c;擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;点击《获取方式》 &#xff08;1&#xff09;窄路车流时空异质图特征构建&#xff…...

演讲口才课到底有没有用?上完三个月后的真实反馈

三个月前&#xff0c;林薇坐在会议室的角落里&#xff0c;手里攥着一份精心准备的方案&#xff0c;却迟迟没有开口。那一刻&#xff0c;她看着同事们侃侃而谈&#xff0c;心里反复问自己&#xff1a;为什么明明有想法&#xff0c;却说不出来&#xff1f;就是那个瞬间&#xff0…...

基于AI与胎心监护信号预测胎儿生物年龄:技术实现与临床价值

1. 项目概述&#xff1a;从胎心监护到胎儿“数字时钟” 在产科临床和围产期医学领域&#xff0c;评估胎儿宫内健康状况&#xff0c;尤其是其发育成熟度&#xff0c;一直是一项核心且充满挑战的任务。传统的评估方法&#xff0c;如通过超声测量胎儿双顶径、股骨长等生物参数来估…...

CV顶会周度精选:7篇驱动工业落地的视觉模型新范式

1. 这不是论文速读清单&#xff0c;而是一份“视觉模型进化切片报告” 你点开这篇标题&#xff0c;大概率是想快速抓住过去七天里计算机视觉领域真正值得花时间的几篇新工作——不是刷榜论文&#xff0c;不是工程缝合怪&#xff0c;而是那种读完会让人下意识摸键盘、想立刻跑个…...

gqty:零配置强类型GraphQL客户端,颠覆传统开发体验

1. 项目概述&#xff1a;一个颠覆性的GraphQL客户端方案如果你在过去几年里深度参与过前端开发&#xff0c;尤其是与GraphQL API打交道&#xff0c;那么你一定体会过那种“甜蜜的负担”。GraphQL带来的数据查询自由度和类型安全让人着迷&#xff0c;但随之而来的客户端状态管理…...