7 Commits
11 changed files with 651 additions and 176 deletions
+7
View File
@@ -4,4 +4,11 @@
// 主窗体标题
#define MAIN_FRAME_TITTLE L"DLT Splitter —— Dev by : LuChiChick"
// 主窗体最小面积
#define MAIN_FRAME_SIZE_WIDTH_MIN 400
#define MAIN_FRAME_SIZE_HEIGHT_MIN 400 * 1.5
// 单次允许选择的最大文件数量
#define MAX_SINGLE_SELECT_FILE_COUNT 512
#endif
+17 -21
View File
@@ -101,46 +101,42 @@ namespace DLT_Type
} DLT_Msg_Node;
}
// DLT 文件
class DLT_File
// DLT 日志
class DLT_Log
{
private:
FILE *p_file; // 文件指针
size_t msg_count; // 消息条目计数
size_t payload_max_len; // 最长载荷长度
size_t loaded_msg_count; // 消息条目计数
size_t max_payload_len; // 最长载荷长度
size_t mem_use; // 存储占用
DLT_Type::DLT_Msg_Node *Msg_List_Head; // 消息列表
DLT_Type::DLT_Msg_Node *Msg_List_Head; // 消息列表
DLT_Type::DLT_Msg_Node *Msg_List_End; // 消息列表尾
/**
* @brief 读取dlt文件
* @brief 从文件中读取dlt头
* @param p_file 要读取的文件
* @param Msg 读取后存储的目标结构体
* @return DLT_Type::DLT_Err 错误类型枚举
*/
DLT_Type::DLT_Err dlt_file_read_header(DLT_Type::DLT_Msg *Msg);
DLT_Type::DLT_Err dlt_file_read_header(FILE *p_file, DLT_Type::DLT_Msg *Msg);
/**
* @brief 读取dlt文件载荷
* @brief 从文件中读取dlt载荷
* @param p_file 要读取的文件
* @param Msg 读取后存储的目标结构体
* @return DLT_Type::DLT_Err 错误类型枚举
*/
DLT_Type::DLT_Err dlt_file_read_payload(DLT_Type::DLT_Msg *Msg);
/**
* @brief 解析dlt文件
* @param null
* @return DLT_Type::DLT_Err 错误类型枚举
*/
DLT_Type::DLT_Err dlt_file_parse(void);
DLT_Type::DLT_Err dlt_file_read_payload(FILE *p_file, DLT_Type::DLT_Msg *Msg);
public:
DLT_File(); // 构造函数
~DLT_File(); // 析构函数
DLT_Log(); // 构造函数
~DLT_Log(); // 析构函数
/**
* @brief 打开DLT文件
* @brief 从文件加载DLT消息,多个文件会顺序加入
* @param file_name_str 目标文件名
* @return DLT_Type::DLT_Err 错误类型枚举
*/
DLT_Type::DLT_Err open(const char *file_name_str);
DLT_Type::DLT_Err load_from_file(const char *file_name_str);
/**
* @brief 获取解析完成的消息列表
+9
View File
@@ -11,6 +11,11 @@ extern "C"
#include "d3d11.h"
}
#include "Type_Descriptions.hpp"
// 主窗体句柄
extern HWND Main_Window_hWnd;
// D3D11 相关
extern ID3D11Device *g_pd3dDevice; // D3D11 设备句柄
extern ID3D11DeviceContext *g_pd3dDeviceContext; // D3D11 设备上下文句柄
@@ -20,4 +25,8 @@ extern bool g_SwapChainOccluded; // 交换链是否阻塞
extern ID3D11RenderTargetView *g_mainRenderTargetView; // D3D11 渲染目标
// 文件输入相关
extern Input_File_Node *input_dlt_file_list_head;
extern size_t input_dlt_file_count;
#endif
+11
View File
@@ -0,0 +1,11 @@
#ifndef __TYPE_DESCRIPTIONS_HPP__
#define __TYPE_DESCRIPTIONS_HPP__
// 文件节点
typedef struct Input_File_Node
{
char *file_name_str;
Input_File_Node *p_next;
} Input_File_Node;
#endif
+15
View File
@@ -6,5 +6,20 @@
// UI布局
void UI_Layout();
// 组件
namespace Widgets
{
// 拖拽输入区域
void Drag_Input_Area(const ImVec2 &size = ImVec2(0, 0));
// 文件列表区域
void File_List_Area(const ImVec2 &size = ImVec2(0, 0));
// 工作流区域
void Workflow_Area(const ImVec2 &size = ImVec2(0, 0));
// 控制面板区域
void Control_Panel(const ImVec2 &size = ImVec2(0, 0));
}
#endif
+1 -1
View File
@@ -486,7 +486,7 @@ CSV_Type::CSV_Err CSV_Table::export_to_file(const char *file_name_str)
size_t count = 0;
for (decltype(this->Column_List_Head) p_target_column = this->Column_List_Head; p_target_column != nullptr; p_target_column = p_target_column->p_next_column)
{
if (fprintf(p_file, "%s,", p_target_column->column_title_str) < 0)
if (fprintf(p_file, strstr(p_target_column->column_title_str, ",") ? "\"%s\"," : "%s,", p_target_column->column_title_str) < 0)
goto file_write_error;
p_parallel_cell_list[count] = p_target_column->Cell_List_Head;
count++;
+2 -23
View File
@@ -7,32 +7,11 @@ extern "C"
#include "CSV_Utilities.hpp"
}
DLT_File File;
DLT_Log File;
// 命令行处理
void Pre_Command_Solve(void)
{
CSV_Table CSV;
CSV.insert_column_before((unsigned)0, "First insert");
CSV.append_column("Test column");
CSV.append_column("Test column 2");
CSV.append_column("Test column 3");
CSV.insert_column_after("Test column 2", "Test insert column");
CSV.insert_column_after("Test column 3", "Test insert column after End");
CSV.insert_column_before("Test column", "Test insert column before Head");
CSV.insert_column_before("Test column", "Test insert column before Origin");
CSV.insert_cell_before("Test column 2", 0, "0");
CSV.append_cell("Test column 2", "1");
CSV.insert_cell_before("Test column 2", 0, "Insert");
CSV.insert_cell_after("Test column 3", (unsigned)0, "Insert Cell");
CSV.append_cell("Test column 3", "1");
CSV.append_cell("Test column 3", "MyWawwww,dwadawdawd");
CSV.append_cell("Test column 3", "3");
CSV.export_to_file("new.csv");
// 获取命令行
int argc;
LPWSTR *argv;
@@ -47,7 +26,7 @@ void Pre_Command_Solve(void)
char *strTo = (char *)malloc(size_needed);
WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, &strTo[0], size_needed, NULL, NULL);
err = File.open(strTo);
err = File.load_from_file(strTo);
DLT_Type::DLT_Msg_Node *p_list;
File.get_msg_list(p_list);
+74 -72
View File
@@ -8,29 +8,24 @@ extern "C"
}
// 构造函数
DLT_File::DLT_File()
DLT_Log::DLT_Log()
{
// 初始化内容
this->p_file = nullptr;
this->msg_count = 0;
this->payload_max_len = 0;
this->loaded_msg_count = 0;
this->max_payload_len = 0;
this->Msg_List_Head = nullptr;
this->Msg_List_End = nullptr;
}
// 析构函数
DLT_File::~DLT_File()
DLT_Log::~DLT_Log()
{
clear();
}
// 清理请求的存储并恢复初始状态
void DLT_File::clear(void)
void DLT_Log::clear(void)
{
if (this->p_file != nullptr)
{
fclose(this->p_file);
this->p_file = nullptr;
}
if (this->Msg_List_Head == nullptr)
return;
@@ -45,13 +40,14 @@ void DLT_File::clear(void)
}
// 初始化内容
this->p_file = nullptr;
this->msg_count = 0;
this->payload_max_len = 0;
this->loaded_msg_count = 0;
this->max_payload_len = 0;
this->mem_use = 0;
this->Msg_List_Head = nullptr;
this->Msg_List_End = nullptr;
}
DLT_Type::DLT_Err DLT_File::dlt_file_read_header(DLT_Type::DLT_Msg *Msg)
DLT_Type::DLT_Err DLT_Log::dlt_file_read_header(FILE *p_file, DLT_Type::DLT_Msg *Msg)
{
if (Msg == nullptr)
return DLT_Type::DLT_ERROR_NULL_POINTER;
@@ -60,9 +56,9 @@ DLT_Type::DLT_Err DLT_File::dlt_file_read_header(DLT_Type::DLT_Msg *Msg)
{
// 读取存储头
if (fread(&(Msg->storage_header), sizeof(Msg->storage_header), 1, this->p_file) != 1)
if (fread(&(Msg->storage_header), sizeof(Msg->storage_header), 1, p_file) != 1)
{
if (feof(this->p_file))
if (feof(p_file))
return DLT_Type::DLT_ERROR_END_OF_FILE;
else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
@@ -76,9 +72,9 @@ DLT_Type::DLT_Err DLT_File::dlt_file_read_header(DLT_Type::DLT_Msg *Msg)
// 标准头
{
// 读取标准头
if (fread(&(Msg->standard_header), sizeof(Msg->standard_header), 1, this->p_file) != 1)
if (fread(&(Msg->standard_header), sizeof(Msg->standard_header), 1, p_file) != 1)
{
if (feof(this->p_file))
if (feof(p_file))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
@@ -105,9 +101,9 @@ DLT_Type::DLT_Err DLT_File::dlt_file_read_header(DLT_Type::DLT_Msg *Msg)
{
msg_header_len += sizeof(Msg->standard_header_extra.ecu);
if (fread(&(Msg->standard_header_extra.ecu), sizeof(Msg->standard_header_extra.ecu), 1, this->p_file) != 1)
if (fread(&(Msg->standard_header_extra.ecu), sizeof(Msg->standard_header_extra.ecu), 1, p_file) != 1)
{
if (feof(this->p_file))
if (feof(p_file))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
@@ -119,9 +115,9 @@ DLT_Type::DLT_Err DLT_File::dlt_file_read_header(DLT_Type::DLT_Msg *Msg)
{
msg_header_len += sizeof(Msg->standard_header_extra.seid);
if (fread(&(Msg->standard_header_extra.seid), sizeof(Msg->standard_header_extra.seid), 1, this->p_file) != 1)
if (fread(&(Msg->standard_header_extra.seid), sizeof(Msg->standard_header_extra.seid), 1, p_file) != 1)
{
if (feof(this->p_file))
if (feof(p_file))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
@@ -146,9 +142,9 @@ DLT_Type::DLT_Err DLT_File::dlt_file_read_header(DLT_Type::DLT_Msg *Msg)
{
msg_header_len += sizeof(Msg->standard_header_extra.tmsp);
if (fread(&(Msg->standard_header_extra.tmsp), sizeof(Msg->standard_header_extra.tmsp), 1, this->p_file) != 1)
if (fread(&(Msg->standard_header_extra.tmsp), sizeof(Msg->standard_header_extra.tmsp), 1, p_file) != 1)
{
if (feof(this->p_file))
if (feof(p_file))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
@@ -175,9 +171,9 @@ DLT_Type::DLT_Err DLT_File::dlt_file_read_header(DLT_Type::DLT_Msg *Msg)
msg_header_len += sizeof(Msg->extendedheader);
// 读取标扩展头
if (fread(&(Msg->extendedheader), sizeof(Msg->extendedheader), 1, this->p_file) != 1)
if (fread(&(Msg->extendedheader), sizeof(Msg->extendedheader), 1, p_file) != 1)
{
if (feof(this->p_file))
if (feof(p_file))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
@@ -187,29 +183,28 @@ DLT_Type::DLT_Err DLT_File::dlt_file_read_header(DLT_Type::DLT_Msg *Msg)
// 计算Payload长度
Msg->payload_length = Msg->standard_header.len - msg_header_len;
// 统计最长长度
if (Msg->payload_length > this->payload_max_len)
this->payload_max_len = Msg->payload_length;
return DLT_Type::DLT_ERROR_NONE;
}
DLT_Type::DLT_Err DLT_File::dlt_file_read_payload(DLT_Type::DLT_Msg *Msg)
DLT_Type::DLT_Err DLT_Log::dlt_file_read_payload(FILE *p_file, DLT_Type::DLT_Msg *Msg)
{
if (Msg == nullptr)
return DLT_Type::DLT_ERROR_NULL_POINTER;
// 读取Payload
Msg->payload_buffer = (uint8_t *)malloc(Msg->payload_length);
this->mem_use += Msg->payload_length;
if (Msg->payload_buffer == nullptr)
return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;
if (fread(Msg->payload_buffer, Msg->payload_length, 1, this->p_file) != 1)
if (fread(Msg->payload_buffer, Msg->payload_length, 1, p_file) != 1)
{
free(Msg->payload_buffer);
this->mem_use -= Msg->payload_length;
Msg->payload_buffer = nullptr;
if (feof(this->p_file))
if (feof(p_file))
return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
else
return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
@@ -218,76 +213,79 @@ DLT_Type::DLT_Err DLT_File::dlt_file_read_payload(DLT_Type::DLT_Msg *Msg)
return ::DLT_Type::DLT_ERROR_NONE;
}
DLT_Type::DLT_Err DLT_File::dlt_file_parse(void)
DLT_Type::DLT_Err DLT_Log::load_from_file(const char *file_name_str)
{
DLT_Type::DLT_Msg_Node *p_list_end = nullptr;
// 打开文件
FILE *p_file = fopen(file_name_str, "rb");
if (p_file == nullptr)
return DLT_Type::DLT_ERROR_FILE_OPEN_FAILED;
// 解析消息内容
{
DLT_Type::DLT_Err err = DLT_Type::DLT_ERROR_NONE;
while (1)
{
DLT_Type::DLT_Msg Msg;
err = dlt_file_read_header(&Msg);
err = dlt_file_read_header(p_file, &Msg);
if (err != DLT_Type::DLT_ERROR_NONE)
{
if (err == DLT_Type::DLT_ERROR_END_OF_FILE)
break;
fclose(p_file);
return err;
}
err = dlt_file_read_payload(&Msg);
err = dlt_file_read_payload(p_file, &Msg);
if (err != DLT_Type::DLT_ERROR_NONE)
{
fclose(p_file);
return err;
}
DLT_Type::DLT_Msg_Node *p_target_msg = (DLT_Type::DLT_Msg_Node *)malloc(sizeof(DLT_Type::DLT_Msg_Node));
this->mem_use += sizeof(DLT_Type::DLT_Msg_Node);
if (p_target_msg == nullptr)
{
this->mem_use -= sizeof(DLT_Type::DLT_Msg_Node);
fclose(p_file);
return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;
}
p_target_msg->p_next = nullptr;
p_target_msg->Msg = Msg;
if (this->Msg_List_Head == nullptr)
{
this->Msg_List_Head = (DLT_Type::DLT_Msg_Node *)malloc(sizeof(DLT_Type::DLT_Msg_Node));
if (this->Msg_List_Head == nullptr)
return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;
this->Msg_List_Head->p_next = nullptr;
this->Msg_List_Head->Msg = Msg;
p_list_end = Msg_List_Head;
this->Msg_List_Head = this->Msg_List_End = p_target_msg;
}
else
{
DLT_Type::DLT_Msg_Node *p_target = (DLT_Type::DLT_Msg_Node *)malloc(sizeof(DLT_Type::DLT_Msg_Node));
if (p_target == nullptr)
return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;
p_target->p_next = nullptr;
p_target->Msg = Msg;
p_list_end->p_next = p_target;
p_list_end = p_target;
this->Msg_List_End->p_next = p_target_msg;
this->Msg_List_End = p_target_msg;
}
this->msg_count++;
// 统计最长长度
if (Msg.payload_length > this->max_payload_len)
this->max_payload_len = Msg.payload_length;
this->loaded_msg_count++;
}
}
fclose(p_file);
return DLT_Type::DLT_ERROR_NONE;
}
DLT_Type::DLT_Err DLT_File::open(const char *file_name_str)
size_t DLT_Log::get_msg_list(DLT_Type::DLT_Msg_Node *(&p_msg_list))
{
// 打开文件
this->p_file = fopen(file_name_str, "rb");
if (this->p_file == nullptr)
return DLT_Type::DLT_ERROR_FILE_OPEN_FAILED;
// 求解文件
return dlt_file_parse();
}
size_t DLT_File::get_msg_list(DLT_Type::DLT_Msg_Node *(&p_msg_list))
{
if (this->msg_count != 0)
if (this->loaded_msg_count != 0)
p_msg_list = this->Msg_List_Head;
else
p_msg_list = nullptr;
return this->msg_count;
return this->loaded_msg_count;
}
DLT_Type::DLT_Err DLT_File::export_to_csv(const char *file_name_str)
DLT_Type::DLT_Err DLT_Log::export_to_csv(const char *file_name_str)
{
FILE *p_file = fopen(file_name_str, "wb");
if (p_file == nullptr)
@@ -297,7 +295,7 @@ DLT_Type::DLT_Err DLT_File::export_to_csv(const char *file_name_str)
{
fprintf(p_file, "Index,Date&Time(Local),Timestamp,Count,ECU ID,Application ID,Context ID ,Session ID,Type,Sub Type,Mode,#Args,Payload,");
for (size_t count = 0; count < this->payload_max_len; count++)
for (size_t count = 0; count < this->max_payload_len; count++)
fprintf(p_file, "B%d,", count);
fseek(p_file, -1, SEEK_CUR);
fprintf(p_file, "\r\n");
@@ -305,7 +303,7 @@ DLT_Type::DLT_Err DLT_File::export_to_csv(const char *file_name_str)
// 遍历每行数据
DLT_Type::DLT_Msg_Node *p_msg = this->Msg_List_Head;
for (size_t line_count = 0; line_count < this->msg_count; line_count++)
for (size_t line_count = 0; line_count < this->loaded_msg_count; line_count++)
{
// 输出索引号
@@ -386,10 +384,12 @@ DLT_Type::DLT_Err DLT_File::export_to_csv(const char *file_name_str)
fprintf(p_file, "%s,", Type_str[p_msg->Msg.extendedheader.msin.MSTP]);
fprintf(p_file, "%s,", SubType_Str[p_msg->Msg.extendedheader.msin.MSTP][(p_msg->Msg.extendedheader.msin.MTIN - 1) % 0xF]);
// Mode ** #Args
// Mode && #Args
fprintf(p_file, "%s,", p_msg->Msg.extendedheader.msin.VERB ? "verbose" : "non-verbose");
fprintf(p_file, "%d,", p_msg->Msg.extendedheader.noar);
}
else
fprintf(p_file, "N/A,N/A,N/A,N/A,");
}
// Payload概览行
@@ -405,5 +405,7 @@ DLT_Type::DLT_Err DLT_File::export_to_csv(const char *file_name_str)
p_msg = p_msg->p_next;
}
fclose(p_file);
return DLT_Type::DLT_ERROR_NONE;
}
+7
View File
@@ -1,5 +1,8 @@
#include "Global_Variables.hpp"
// 主窗体句柄
HWND Main_Window_hWnd = nullptr;
// D3D11 相关
ID3D11Device *g_pd3dDevice = nullptr; // D3D11 设备句柄
ID3D11DeviceContext *g_pd3dDeviceContext = nullptr; // D3D11 设备上下文句柄
@@ -8,3 +11,7 @@ IDXGISwapChain *g_pSwapChain = nullptr; // DXGI 交换链句柄
bool g_SwapChainOccluded = false; // 交换链是否阻塞
ID3D11RenderTargetView *g_mainRenderTargetView = nullptr; // D3D11 渲染目标
// 文件输入相关
Input_File_Node *input_dlt_file_list_head;
size_t input_dlt_file_count;
+96 -11
View File
@@ -12,6 +12,7 @@ extern "C"
#include "d3d11.h"
#include "tchar.h"
#include "wchar.h"
#include "locale.h"
}
// 自定义头文件
@@ -35,6 +36,9 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg
// 入口主函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// 设置本地化以支持特殊字符
setlocale(LC_ALL, ".UTF-8");
// 命令行前置处理
Pre_Command_Solve();
@@ -61,20 +65,20 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
RegisterClassExW(&wc);
// 创建窗体
HWND hwnd = CreateWindowW(wc.lpszClassName, // 创建的窗体类名
Main_Window_hWnd = CreateWindowW(wc.lpszClassName, // 创建的窗体类名
MAIN_FRAME_TITTLE, // 窗体标题
WS_OVERLAPPEDWINDOW, // 窗体风格为标准可重叠的顶层窗口
100, // 起始坐标x
100, // 起始坐标y
(int)(1280 * main_scale), // 窗体长
(int)(720 * main_scale), // 窗体宽
(GetSystemMetrics(SM_CXSCREEN) - (MAIN_FRAME_SIZE_WIDTH_MIN * main_scale)) / 2, // 起始坐标x,设置为屏幕正中
(GetSystemMetrics(SM_CYSCREEN) - (MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale)) / 2, // 起始坐标y,设置为屏幕正中
(int)(MAIN_FRAME_SIZE_WIDTH_MIN * main_scale), // 窗体长
(int)(MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale), // 窗体宽
nullptr, // 父窗体句柄
nullptr, // 菜单句柄
wc.hInstance, // 创建实例句柄
nullptr); // 额外的事件参数指针
// 在窗体内创建 Direct 3D 设备
if (!CreateDeviceD3D(hwnd))
if (!CreateDeviceD3D(Main_Window_hWnd))
{
// 未创建完成时清理 Direct 3D 设备并清理窗体注册类
CleanupDeviceD3D();
@@ -84,9 +88,12 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
return -1;
}
// 启用文件拖拽输入
DragAcceptFiles(Main_Window_hWnd, TRUE);
// 显示窗体并强制更新一次窗体
ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);
ShowWindow(Main_Window_hWnd, SW_SHOWDEFAULT);
UpdateWindow(Main_Window_hWnd);
// 检查版本
IMGUI_CHECKVERSION();
@@ -130,7 +137,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
}
// 初始化渲染器后端(Renderer backends)
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplWin32_Init(Main_Window_hWnd);
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
// 字体配置相关
@@ -161,7 +168,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
{
// 非阻塞式获取所有窗体消息,Pick消息后从消息队列删除,并转译和派发消息
MSG msg;
while (PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))
while (PeekMessageW(&msg, nullptr, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg); // 转译
DispatchMessageW(&msg); // 派发
@@ -233,7 +240,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
ImNodes::DestroyContext(); // 销毁 ImNodes 上下文
CleanupDeviceD3D(); // 清理 Direct 3D 设备
DestroyWindow(hwnd); // 销毁窗体
DestroyWindow(Main_Window_hWnd); // 销毁窗体
UnregisterClassW(wc.lpszClassName, wc.hInstance); // 取消窗体注册类
return 0;
@@ -333,6 +340,84 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
// 筛查并处理余下的消息事件
switch (msg)
{
case WM_DROPFILES: // 文件拖拽事件
{
HDROP hDrop = (HDROP)wParam; // 拖拽数据句柄
// 获取拖拽的文件总数
UINT fileCount = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
// 非法输入检测
bool with_illegal_input = false;
bool with_duplicated_input = false;
// 添加到文件列表
for (UINT count = 0; count < fileCount; count++)
{
wchar_t filePath[MAX_PATH] = {L'\0'};
DragQueryFileW(
hDrop, // 拖拽句柄
count, // 文件索引(0 表示第一个文件)
filePath, // 存储路径的缓冲区
MAX_PATH // 缓冲区大小
);
char file_path_multi_byte[MAX_PATH] = {'\0'};
int size_needed = WideCharToMultiByte(CP_UTF8, 0, filePath, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, filePath, -1, file_path_multi_byte, size_needed, NULL, NULL);
// 重复文件剔除
bool duplicated = false;
for (Input_File_Node *p_file_node = input_dlt_file_list_head; p_file_node != nullptr; p_file_node = p_file_node->p_next)
if (!strcmp(p_file_node->file_name_str, file_path_multi_byte))
{
duplicated = true;
with_duplicated_input = true;
break;
}
if (duplicated)
continue;
// 文件类型后缀过滤
const char *p_extension_name = file_path_multi_byte + (strlen(file_path_multi_byte) - 4);
if (p_extension_name[0] != '.' || toupper(p_extension_name[1]) != 'D' || toupper(p_extension_name[2]) != 'L' || toupper(p_extension_name[3]) != 'T')
{
with_illegal_input = true;
continue;
}
// 开辟新文件节点
Input_File_Node *p_new_file_node = (Input_File_Node *)malloc(sizeof(Input_File_Node));
p_new_file_node->file_name_str = (char *)malloc(strlen(file_path_multi_byte) + 1);
memset(p_new_file_node->file_name_str, '\0', strlen(file_path_multi_byte) + 1);
memcpy(p_new_file_node->file_name_str, file_path_multi_byte, strlen(file_path_multi_byte) + 1);
p_new_file_node->p_next = nullptr;
// 插入文件列表
if (input_dlt_file_list_head == nullptr)
input_dlt_file_list_head = p_new_file_node;
else
{
Input_File_Node *p_target_node = input_dlt_file_list_head;
for (size_t count = 1; count < input_dlt_file_count; count++)
p_target_node = p_target_node->p_next;
p_target_node->p_next = p_new_file_node;
}
input_dlt_file_count++;
}
// 释放拖拽资源(必须调用,否则内存泄漏)
DragFinish(hDrop);
if (with_duplicated_input)
MessageBoxW(hWnd, L"存在重复输入", L"", MB_OK | MB_ICONWARNING);
if (with_illegal_input)
MessageBoxW(hWnd, L"存在非法输入,仅支持 .dlt 文件", L"", MB_OK | MB_ICONWARNING);
return 0;
}
case WM_SIZE: // 窗体大小变事件
if (wParam != SIZE_MINIMIZED) // 窗体未处于最小化时进行重绘
{
+367 -3
View File
@@ -1,4 +1,16 @@
#include "UI_Layout.hpp"
#include "imgui_impl_win32.h"
#include "Global_Variables.hpp"
#include "Config.hpp"
#include "DLT_Utilities.hpp"
extern "C"
{
#include "windows.h"
#include "stdio.h"
}
#include "thread"
// UI布局
void UI_Layout()
@@ -24,10 +36,221 @@ void UI_Layout()
// 设置窗体相关属性,不允许停靠
window_flags |= ImGuiWindowFlags_NoDocking;
ImGui::Begin("Main Panel", NULL, window_flags); // 创建Label
ImGui::Begin("Main Panel", NULL, window_flags); // 创建主面板
ImGui::PopStyleVar(2); // 退出绘制风格栈中的设置项
{
const ImGuiStyle &style = ImGui::GetStyle();
float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(MonitorFromPoint(POINT{0, 0}, MONITOR_DEFAULTTOPRIMARY));
// 拖拽输入区域
Widgets::Drag_Input_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().x / 2 > MAIN_FRAME_SIZE_WIDTH_MIN / 2 ? MAIN_FRAME_SIZE_WIDTH_MIN / 2 : ImGui::GetContentRegionAvail().x / 2));
// 文件列表组件
Widgets::File_List_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - (ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale + style.ItemSpacing.y)));
// 导出文件
Widgets::Control_Panel(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale));
}
ImGui::End();
// ImGui::ShowDemoWindow(nullptr);
}
void Widgets::Drag_Input_Area(const ImVec2 &size)
{
ImGui::BeginChild("Drag_Drop_Area", size);
{
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f); // 绘制风格栈压入窗口圆角为0
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
// 显示一个按钮,作为拖拽源
static bool pressed_hover = false;
if (ImGui::Button(pressed_hover ? u8"松开左键以添加" : u8"单击选择文件或拖拽文件到此处", ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y)))
{
OPENFILENAMEW ofn; // common dialog box structure
wchar_t szFile[MAX_PATH * MAX_SINGLE_SELECT_FILE_COUNT] = {L'\0'}; // buffer for file name
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn); // 结构体大小
ofn.hwndOwner = Main_Window_hWnd; // 对话框唤起窗体
ofn.lpstrFile = szFile; // 输出缓冲区
ofn.nMaxFile = sizeof(szFile); // 缓冲区大小
ofn.lpstrFilter = L"(.dlt)\0*.dlt\0"; // 文件格式筛选器
ofn.nFilterIndex = 1; // 默认选择的筛选器
// 文件路径必须存在 | 文件本身必须存在 | 允许多文件选择 | 使用资源管理器
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
// Display the Open dialog box.
// 处理文件输入
if (GetOpenFileNameW(&ofn))
{
// 重复输入检测
bool with_duplicated_input = false;
wchar_t *p_first_str = ofn.lpstrFile;
// 单文件
if ((p_first_str[wcslen(p_first_str)] == L'\0') && (p_first_str[wcslen(p_first_str) + 1] == L'\0'))
{
char file_path_multi_byte[MAX_PATH] = {'\0'};
int size_needed = WideCharToMultiByte(CP_UTF8, 0, p_first_str, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, p_first_str, -1, file_path_multi_byte, size_needed, NULL, NULL);
for (Input_File_Node *p_file_node = input_dlt_file_list_head; p_file_node != nullptr; p_file_node = p_file_node->p_next)
if (!strcmp(p_file_node->file_name_str, file_path_multi_byte))
{
with_duplicated_input = true;
break;
}
if (with_duplicated_input)
{
MessageBoxW(Main_Window_hWnd, L"存在重复输入", L"", MB_OK | MB_ICONWARNING);
}
else
{
// 开辟新文件节点
Input_File_Node *p_new_file_node = (Input_File_Node *)malloc(sizeof(Input_File_Node));
p_new_file_node->file_name_str = (char *)malloc(strlen(file_path_multi_byte) + 1);
memset(p_new_file_node->file_name_str, '\0', strlen(file_path_multi_byte) + 1);
memcpy(p_new_file_node->file_name_str, file_path_multi_byte, strlen(file_path_multi_byte) + 1);
p_new_file_node->p_next = nullptr;
// 插入文件列表
if (input_dlt_file_list_head == nullptr)
input_dlt_file_list_head = p_new_file_node;
else
{
Input_File_Node *p_target_node = input_dlt_file_list_head;
for (size_t count = 1; count < input_dlt_file_count; count++)
p_target_node = p_target_node->p_next;
p_target_node->p_next = p_new_file_node;
}
input_dlt_file_count++;
}
}
else
{
// 多文件输入时
char public_path_multi_byte[MAX_PATH] = {'\0'};
int size_needed = WideCharToMultiByte(CP_UTF8, 0, p_first_str, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, p_first_str, -1, public_path_multi_byte, size_needed, NULL, NULL);
for (wchar_t *p_file_name_str = ofn.lpstrFile + wcslen(ofn.lpstrFile) + 1; *p_file_name_str != L'\0'; p_file_name_str += (wcslen(p_file_name_str) + 1))
{
char file_name_multi_byte[MAX_PATH] = {'\0'};
char file_path_multi_byte[MAX_PATH] = {'\0'};
int size_needed = WideCharToMultiByte(CP_UTF8, 0, p_file_name_str, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, p_file_name_str, -1, file_name_multi_byte, size_needed, NULL, NULL);
// 拼接完整路径
sprintf(file_path_multi_byte, "%s\\%s", public_path_multi_byte, file_name_multi_byte);
for (Input_File_Node *p_file_node = input_dlt_file_list_head; p_file_node != nullptr; p_file_node = p_file_node->p_next)
if (!strcmp(p_file_node->file_name_str, file_path_multi_byte))
{
with_duplicated_input = true;
break;
}
if (with_duplicated_input)
continue;
// 开辟新文件节点
Input_File_Node *p_new_file_node = (Input_File_Node *)malloc(sizeof(Input_File_Node));
p_new_file_node->file_name_str = (char *)malloc(strlen(file_path_multi_byte) + 1);
memset(p_new_file_node->file_name_str, '\0', strlen(file_path_multi_byte) + 1);
memcpy(p_new_file_node->file_name_str, file_path_multi_byte, strlen(file_path_multi_byte) + 1);
p_new_file_node->p_next = nullptr;
// 插入文件列表
if (input_dlt_file_list_head == nullptr)
input_dlt_file_list_head = p_new_file_node;
else
{
Input_File_Node *p_target_node = input_dlt_file_list_head;
for (size_t count = 1; count < input_dlt_file_count; count++)
p_target_node = p_target_node->p_next;
p_target_node->p_next = p_new_file_node;
}
input_dlt_file_count++;
}
if (with_duplicated_input)
{
MessageBoxW(Main_Window_hWnd, L"存在重复输入", L"", MB_OK);
}
}
}
}
// 仅在外部拖拽入内时触发,内部拖拽不触发
pressed_hover = (ImGui::IsItemHovered() && (GetAsyncKeyState(VK_LBUTTON) < 0) && (!ImGui::IsMouseDown(ImGuiMouseButton_Left)));
ImGui::PopStyleVar(2);
}
ImGui::EndChild();
}
void Widgets::File_List_Area(const ImVec2 &size)
{
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::BeginChild("File_List_Area_Wrapper", size, ImGuiChildFlags_Border);
ImGui::PopStyleVar();
{
int element_id = 0;
Input_File_Node *p_file_node_pre = nullptr;
Input_File_Node *p_file_node = input_dlt_file_list_head;
for (size_t count = 0; count < input_dlt_file_count; count++)
{
ImGui::PushID(element_id++);
// 点击了删除
if (ImGui::Button("X"))
{
if (p_file_node == input_dlt_file_list_head)
{
free(input_dlt_file_list_head->file_name_str);
input_dlt_file_list_head = input_dlt_file_list_head->p_next;
free(p_file_node);
p_file_node = input_dlt_file_list_head;
}
else
{
p_file_node_pre->p_next = p_file_node->p_next;
free(p_file_node->file_name_str);
free(p_file_node);
}
input_dlt_file_count--;
count--;
ImGui::PopID();
continue;
}
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::InputText("##Text_Show", p_file_node->file_name_str, strlen(p_file_node->file_name_str) + 1, ImGuiInputTextFlags_ElideLeft | ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoUndoRedo);
ImGui::PopID();
p_file_node = p_file_node->p_next;
if (count == 0)
p_file_node_pre = input_dlt_file_list_head;
else
p_file_node_pre = p_file_node_pre->p_next;
}
}
ImGui::EndChild();
}
void Widgets::Workflow_Area(const ImVec2 &size)
{
ImNodes::BeginNodeEditor();
{
@@ -49,7 +272,148 @@ void UI_Layout()
}
ImNodes::EndNodeEditor();
}
ImGui::End();
ImGui::ShowDemoWindow(nullptr);
void Widgets::Control_Panel(const ImVec2 &size)
{
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::BeginChild("Control_Panel", size, ImGuiChildFlags_Border);
ImGui::PopStyleVar(2);
{
static bool export_confirmed = false;
static bool export_task_created = false;
static char export_file_path_str[MAX_PATH] = {'\0'};
if (!export_confirmed)
{
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f);
if (ImGui::Button(u8"导出", ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y)))
{
if (input_dlt_file_list_head == nullptr)
MessageBoxW(Main_Window_hWnd, L"需要至少输入一个文件", L"", MB_OK | MB_ICONERROR);
else
{
OPENFILENAMEW ofn; // common dialog box structure
static wchar_t szFile[MAX_PATH] = {L'\0'}; // buffer for file name
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn); // 结构体大小
ofn.hwndOwner = Main_Window_hWnd; // 对话框唤起窗体
ofn.lpstrFile = szFile; // 输出缓冲区
ofn.nMaxFile = sizeof(szFile); // 缓冲区大小
ofn.lpstrFilter = L"(.csv)\0*.csv\0"; // 文件格式筛选器
ofn.nFilterIndex = 1; // 默认选择的筛选器
// 文件路径必须存在 | 文件本身必须存在 | 使用资源管理器
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;
if (GetSaveFileNameW(&ofn))
{
// 提取文件路径
memset(export_file_path_str, '\0', sizeof(export_file_path_str));
int size_needed = WideCharToMultiByte(CP_UTF8, 0, szFile, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, szFile, -1, export_file_path_str, size_needed, NULL, NULL);
wchar_t File_Name[MAX_PATH] = {L'\0'};
wchar_t *p_str_end = szFile + wcslen(szFile);
// 处理后缀
char *p_extension_name = export_file_path_str + (strlen(export_file_path_str) - 4);
if (p_extension_name[0] != '.' || toupper(p_extension_name[1]) != 'C' || toupper(p_extension_name[2]) != 'S' || toupper(p_extension_name[3]) != 'V')
{
p_extension_name += 4;
p_extension_name[0] = '.';
p_extension_name[1] = 'c';
p_extension_name[2] = 's';
p_extension_name[3] = 'v';
p_str_end[0] = L'.';
p_str_end[1] = L'c';
p_str_end[2] = L's';
p_str_end[3] = L'v';
}
while (p_str_end != szFile && *(p_str_end - 1) != L'\\')
p_str_end--;
size_t len = wcslen(p_str_end);
for (size_t count = 0; count < len; count++, p_str_end++)
File_Name[count] = *p_str_end;
memcpy(szFile, File_Name, sizeof(File_Name));
// 判定是否覆盖文件
FILE *p_file = fopen(export_file_path_str, "rb");
if (p_file != nullptr)
{
fclose(p_file);
if (MessageBoxW(Main_Window_hWnd, L"文件已存在,是否覆盖?", L"", MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES)
export_confirmed = true;
}
else
export_confirmed = true;
}
}
}
ImGui::PopStyleVar();
}
else
{
// 创建导出任务
if (!export_task_created)
{
export_task_created = true;
// 执行导出任务的线程
std::thread export_thread(
[&]()
{
DLT_Log Log;
Input_File_Node *p_file_list = input_dlt_file_list_head;
DLT_Type::DLT_Err err;
while (p_file_list != nullptr)
{
err = Log.load_from_file(p_file_list->file_name_str);
if (err != DLT_Type::DLT_ERROR_NONE)
break;
p_file_list = p_file_list->p_next;
}
if (err != DLT_Type::DLT_ERROR_NONE)
{
switch (err)
{
case DLT_Type::DLT_ERROR_FILE_OPEN_FAILED: // 文件打开失败
MessageBoxW(Main_Window_hWnd, L"文件打开失败,检查路径是否存在特殊字符", L"", MB_OK | MB_ICONERROR);
break;
default:
MessageBoxW(Main_Window_hWnd, L"文件加载失败", L"", MB_OK | MB_ICONERROR);
}
}
else
{
err = Log.export_to_csv(export_file_path_str);
if (err == DLT_Type::DLT_ERROR_NONE)
MessageBoxW(Main_Window_hWnd, L"导出完成", L"", MB_OK);
else
MessageBoxW(Main_Window_hWnd, L"导出失败,检查文件占用", L"", MB_OK | MB_ICONERROR);
}
export_confirmed = false;
export_task_created = false;
});
// 分离线程
export_thread.detach();
}
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.5f);
ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y), u8"正在导出...");
ImGui::PopStyleVar();
}
}
ImGui::EndChild();
}