first commit

This commit is contained in:
taynpg 2024-03-08 11:35:52 +08:00
commit 4e0430cda2
11 changed files with 458 additions and 0 deletions

17
.clang-format Normal file
View File

@ -0,0 +1,17 @@
# .clang-format
# 风格格式化
BasedOnStyle: Google
# 4 空格缩进
IndentWidth: 4
# 连续对齐变量的声明
AlignConsecutiveDeclarations: true
# 指针左侧对齐
PointerAlignment: Left
# 访问说明符(public、private等)的偏移
AccessModifierOffset: -4
# 大括号
BreakBeforeBraces: Custom
BraceWrapping:
# 函数定义后面大括号在新行
AfterFunction: true

12
.clangd Normal file
View File

@ -0,0 +1,12 @@
Hover:
ShowAKA: Yes
Diagnostics:
UnusedIncludes: None # 禁用未使用头文件提示
Suppress: [
anon_type_definition, # 禁用匿名的typedef提示
unused-variable, # 禁用未使用变量提示
unused-function, # 禁用未使用函数提示
unused-includes
]
ClangTidy:
Remove: misc-unused-alias-decls

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
bui*
.vs

34
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,34 @@
{
"files.autoSave": "onFocusChange",
"editor.fontSize": 14,
"editor.fontFamily": "'FiraCode Nerd Font Mono', 'FiraCode Nerd Font Mono', 'FiraCode Nerd Font Mono'",
"cmake.configureOnOpen": true,
"cmake.debugConfig": {
"console": "externalTerminal",
"args": [
"G:\\ARTM\\bin\\x64\\Debug\\CaptureExe.exe"
]
},
"cmake.options.statusBarVisibility": "visible",
"cmake.generator": "Ninja",
"C_Cpp.intelliSenseEngine": "disabled",
"clangd.arguments": [
"--header-insertion=never",
"--all-scopes-completion",
"--completion-style=detailed",
"--clang-tidy",
"-j=4",
"--pch-storage=memory",
"--compile-commands-dir=build",
"--background-index",
"--ranking-model=heuristics",
"--function-arg-placeholders=false",
"--query-driver=/usr/bin/clang++"
],
"editor.inlayHints.enabled": "off",
"editor.unicodeHighlight.allowedLocales": {
"ja": true,
"zh-hant": true,
"zh-hans": true
}
}

21
CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
cmake_minimum_required (VERSION 3.8)
project (dll-dependent)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_PREFIX_PATH "C:/Bin/Boost")
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
if (MSVC)
add_compile_options(/source-charset:utf-8)
add_compile_options(/EHsc)
add_compile_options(-D_CRT_SECURE_NO_WARNINGS)
endif()
set(Boost_USE_STATIC_LIBS OFF)
find_package(Boost REQUIRED filesystem)
include_directories(${Boost_INCLUDES})
add_executable(dll-dependent main.cpp dll_handle.cpp cmd_opr.cpp)
target_link_libraries(dll-dependent PRIVATE ${Boost_LIBRARIES})

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# 简介
一个自动导入依赖dll库的工具。

50
cmd_opr.cpp Normal file
View File

@ -0,0 +1,50 @@
#include "cmd_opr.h"
#include <windows.h>
#include <stdio.h>
#include <iostream>
std::string CmdOpr::exec_cmd(const std::string& cmd)
{
std::string result{};
FILE* pipe = _popen(cmd.c_str(), "r");
if (!pipe) {
return result;
}
char buffer[128]{};
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != nullptr) {
result += buffer;
}
}
_pclose(pipe);
return result;
}
bool add_environment_path(const std::string& path)
{
// 获取当前的 PATH 变量需要动态调整缓冲区大小
DWORD bufferSize = GetEnvironmentVariable("PATH", nullptr, 0);
if (bufferSize == 0) {
std::cerr << "Failed to get PATH variable size!" << std::endl;
return false;
}
char* currentPath = new char[bufferSize];
GetEnvironmentVariable("PATH", currentPath, bufferSize);
// 构造新的 PATH 变量值(在原有路径后面添加新路径)
std::string newPath = std::string(currentPath) + ";" + path;
// 设置修改后的 PATH 变量到环境变量中
if (!SetEnvironmentVariable("PATH", newPath.c_str())) {
std::cerr << "Failed to set PATH variable!" << std::endl;
}
delete[] currentPath;
return true;
}

12
cmd_opr.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <string>
class CmdOpr
{
public:
CmdOpr() = default;
~CmdOpr() = default;
public:
static std::string exec_cmd(const std::string& cmd);
static bool add_environment_path(const std::string& path);
};

206
dll_handle.cpp Normal file
View File

@ -0,0 +1,206 @@
#include "dll_handle.h"
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/dll.hpp>
#include <boost/filesystem.hpp>
#include <chrono>
#include <fstream>
#include <iostream>
namespace fs = boost::filesystem;
bool DllHandle::read_ini(const std::string& purpose_dir)
{
no_dlls_.clear();
exe_dlls_.clear();
fs::path cur_exe = boost::dll::program_location();
fs::path config_path = cur_exe.parent_path().append("config.txt");
if (!fs::exists(config_path)) {
std::cout << "配置文件不存在,不进行设置。" << std::endl;
return false;
}
std::ifstream in(config_path.string(), std::ios::in);
if (!in.is_open()) {
std::cout << "打开配置文件失败:" << cur_exe.string()
<< ", 不进行设置。\n";
return false;
}
std::list<std::string> dirs{};
// dirs.push_back(purpose_dir);
std::string tmp{};
int add_status = 0;
while (std::getline(in, tmp)) {
dirs.push_back(tmp);
}
in.close();
for (const auto& data : dirs) {
if (!fs::exists(data) || !fs::is_directory(data)) {
continue;
}
for (auto const& entry : fs::recursive_directory_iterator(data)) {
if (!entry.is_regular_file() ||
entry.path().extension().string() != ".dll") {
continue;
}
DllInfo info;
info.name = entry.path().filename().string();
info.full_path = entry.path().string();
no_dlls_.push_back(info);
}
}
handle_multi_dll();
for (auto const& entry : fs::recursive_directory_iterator(purpose_dir)) {
if (!entry.is_regular_file() ||
entry.path().extension().string() != ".dll") {
continue;
}
DllInfo info;
info.name = entry.path().filename().string();
info.full_path = entry.path().string();
exe_dlls_.push_back(info);
}
return true;
}
std::list<std::string> DllHandle::get_dependents(const std::string& binary)
{
std::string cmd = "dumpbin /DEPENDENTS " + binary;
std::string result = CmdOpr::exec_cmd(cmd);
std::list<std::string> dlls{};
std::list<std::string> tmp{};
boost::split(tmp, result, boost::is_any_of("\n"));
for (const auto& data : tmp) {
if (!boost::contains(data, ".dll") || boost::contains(data, "Dump")) {
continue;
}
std::string dllname(data);
boost::trim(dllname);
dlls.push_back(dllname);
}
return dlls;
}
// 将字符串转换为小写形式
std::string toLower(const std::string& str)
{
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
return result;
}
bool DllHandle::find_dll(const std::string& name, DllInfo& info)
{
bool find = false;
// 先在 exe 所在的目录找。
for (const auto& data : exe_dlls_) {
if (toLower(name) != toLower(data.name)) {
continue;
}
info.name = name;
info.full_path = data.full_path;
find = true;
break;
}
// 如果找到了就不往下找了
if (find) {
return true;
}
for (const auto& data : no_dlls_) {
if (toLower(name) != toLower(data.name)) {
continue;
}
info.name = name;
info.full_path = data.full_path;
find = true;
break;
}
return find;
}
// 手动筛选多个dll的情况
void DllHandle::handle_multi_dll()
{
simple_dlls.clear();
for (const auto& data : no_dlls_) {
simple_dlls[toLower(data.name)].push_back(data);
}
for (auto& data : simple_dlls) {
if (data.second.size() > 1) {
std::cout << "========================\n";
std::cout << "多个重名的dll,选择哪一个?\n";
int index = 0;
for (auto& dll : data.second) {
dll.index = ++index;
std::cout << dll.index << ":" << dll.full_path << ".\n";
}
std::string input{};
std::cin >> input;
int select = std::stoi(input);
data.second.remove_if(
[&](const DllInfo& info) { return info.index != select; });
}
}
no_dlls_.clear();
for (const auto& data : simple_dlls) {
no_dlls_.push_back(data.second.front());
}
}
bool DllHandle::is_have(const std::list<DllInfo>& vec, const std::string& name)
{
bool find = false;
for (const auto& data : vec) {
if (toLower(data.name) != toLower(name)) {
continue;
}
find = true;
break;
}
return find;
}
void DllHandle::copy_dll(const std::string& purpose_dir,
const std::list<DllInfo>& tasks)
{
fs::path report_dir = fs::path(purpose_dir).parent_path();
auto now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::tm timeInfo;
localtime_s(&timeInfo, &currentTime);
char buffer[256]{};
std::strftime(buffer, sizeof(buffer), "report_%Y%m%d%H%M%S.txt", &timeInfo);
std::string report_name = report_dir.append(buffer).string();
std::ofstream out(report_name, std::ios::out);
if (!out.is_open()) {
std::cout << "打开报告文件:" << report_name << "失败,结束执行。\n";
return;
}
for (const auto& data : tasks) {
fs::path des = fs::path(purpose_dir).append(data.name);
if (fs::exists(des)) {
std::string s = "跳过已存在的文件:" + des.string();
out << s << "\n";
std::cout << s << "\n";
} else {
fs::copy(data.full_path, des);
std::string s = "复制文件:" + data.full_path;
out << s << "\n";
std::cout << s << "\n";
}
}
out.close();
}

38
dll_handle.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include <list>
#include <string>
#include <map>
#include "cmd_opr.h"
struct DllInfo {
int index{};
std::string name{};
std::string full_path{};
};
class DllHandle {
public:
DllHandle() = default;
~DllHandle() = default;
public:
// 读取配置文件
bool read_ini(const std::string& purpose_dir);
// 获取一个二进制文件的依赖(参数为全路径)
std::list<std::string> get_dependents(const std::string& binary);
// 查找配置文件中配置的目录中指定名称的dll的信息
bool find_dll(const std::string& name, DllInfo& info);
// 是否在容器中
static bool is_have(const std::list<DllInfo>& vec, const std::string& name);
// 处理dll复制
static void copy_dll(const std::string& purpose_dir,
const std::list<DllInfo>& tasks);
// 手动筛选多个dll的情况
void handle_multi_dll();
private:
std::list<DllInfo> no_dlls_{};
std::list<DllInfo> exe_dlls_{};
std::map<std::string, std::list<DllInfo>> simple_dlls{};
};

63
main.cpp Normal file
View File

@ -0,0 +1,63 @@
#include <boost/filesystem.hpp>
#include <iostream>
#include "dll_handle.h"
namespace fs = boost::filesystem;
/*
*
1.GBK编码
2.dll
3. config.txt
*/
int main(int argc, char** argv)
{
if (argc < 2) {
std::string info("参数不够,第二个参数传入要处理的二进制文件路径(注意需要全路径)\n"
"配置文件名为 config.txt,与当前程序同目录,内容格式为:\n"
"每一行一个文件夹。");
std::cout << info << std::endl;
return 0;
}
fs::path exe_path(argv[1]);
if (!fs::exists(exe_path)) {
std::cout << "传入的路径不存在,请检查。" << std::endl;
return 0;
}
fs::path exe_dir = exe_path.parent_path();
DllHandle handle{};
handle.read_ini(exe_dir.string());
// handle.get_dependents()
// // Get All Dlls Dependents
std::list<std::string> tmp_list{};
std::list<DllInfo> task{};
tmp_list = handle.get_dependents(argv[1]);
DllInfo tmp_info{};
while (!tmp_list.empty()) {
std::string& name = tmp_list.front();
if (DllHandle::is_have(task, name) ||
!handle.find_dll(name, tmp_info)) {
tmp_list.pop_front();
continue;
}
// std::cout << tmp_info.name << "\n";
auto dep = handle.get_dependents(tmp_info.full_path);
for (const auto& data : dep) {
tmp_list.push_back(data);
}
task.push_back(tmp_info);
tmp_list.pop_front();
}
handle.copy_dll(exe_dir.string(), task);
return 0;
}