查看“SimpleNotepad”的源代码
←
SimpleNotepad
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看和复制此页面的源代码。
<syntaxhighlight lang="c++"> #define _CRT_SECURE_NO_WARNINGS 1 #include <tchar.h> #include <windows.h> #include <commdlg.h> // 用于文件对话框 #include <stdio.h> #include <string.h> #include <shlobj.h> // 用于目录选择对话框 #include <wincrypt.h> // 用于Base64解码 #include <rpcdce.h> // 包含UUID相关函数声明 #include "Scintilla.h" // Scintilla头文件 #include "Lexilla.h" // Scintilla头文件 #pragma comment(lib, "shell32.lib") // 链接Shell32库 #pragma comment(lib, "crypt32.lib") // 链接加密库 #define SCI_SETLEXER 2001 #define SCLEX_CPP 1 // C/C++ 解析器 ID #define SCE_C_WORD 5 // C 语言关键字样式 ID // 释放内存的宏(避免重复代码) #define SAFE_FREE(ptr) if (ptr) { LocalFree(ptr); ptr = NULL; } // 在现有宏定义处添加SCI_PASTE消息定义(Scintilla粘贴命令) #define SCI_PASTE 2178 // 在现有宏定义后添加以下内容(自动换行相关) #define SCI_SETWRAPMODE 2268 // 设置自动换行模式的消息 #define SC_WRAP_NONE 0 // 不自动换行 #define SC_WRAP_WORD 1 // 按单词换行(推荐,保持单词完整性) #define SC_WRAP_CHAR 2 // 按字符换行 // 全局变量 HWND hScintilla; // Scintilla控件句柄 char g_szFileName[MAX_PATH] = ""; // 当前打开的文件名 // 函数声明 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void InitScintilla(HWND hWnd); // 初始化Scintilla控件 void DoFileOpen(HWND hWnd); // 打开文件 void DoFileSave(HWND hWnd); // 保存文件 void HandleConvertAction(HWND hWnd, HWND hScintilla); // 声明解码函数(需与之前的函数实现放在同一编译单元) //BYTE* Base64DecodeWide(WCHAR * base64Wide, DWORD * outSize); BOOL Base64DecodeWide(WCHAR * base64Wide, BYTE * *outBuffer, DWORD * outSize); BOOL WriteBytesToFile(const BYTE * bytes, DWORD byteCount, LPCWSTR filePath); char* GenerateUUID(); LPCWSTR ConcatToLPCWSTR(LPCWSTR wideStr, const char* ansiStr); char* ConcatAnsiStrings(int count, ...); /** * 将WCHAR*类型的Base64字符串解码为字节数组 * @param base64Wide 宽字符Base64字符串(WCHAR*) * @param outSize 输出:解码后的字节数组长度(成功时有效) * @return 成功返回解码后的字节数组(需用LocalFree释放),失败返回NULL */ //BYTE* Base64DecodeWide(WCHAR* base64Wide, DWORD* outSize) { // // 初始化输出长度为0 // *outSize = 0; // // // 步骤1:将宽字符串转换为UTF-8多字节字符串 // int utf8Length = WideCharToMultiByte( // CP_UTF8, 0, base64Wide, -1, NULL, 0, NULL, NULL // ); // if (utf8Length == 0) return NULL; // // char* base64Utf8 = (char*)LocalAlloc(LPTR, utf8Length * sizeof(char)); // if (!base64Utf8) return NULL; // // if (WideCharToMultiByte( // CP_UTF8, 0, base64Wide, -1, base64Utf8, utf8Length, NULL, NULL // ) == 0) { // SAFE_FREE(base64Utf8); // return NULL; // } // // // 步骤2:计算Base64解码所需的缓冲区大小 // DWORD decodedSize = 0; // if (!CryptStringToBinaryA( // base64Utf8, 0, CRYPT_STRING_BASE64, NULL, &decodedSize, NULL, NULL // )) { // SAFE_FREE(base64Utf8); // return NULL; // } // // // 步骤3:分配缓冲区并执行解码 // BYTE* decodedBytes = (BYTE*)LocalAlloc(LPTR, decodedSize); // if (!decodedBytes) { // SAFE_FREE(base64Utf8); // return NULL; // } // // if (!CryptStringToBinaryA( // base64Utf8, 0, CRYPT_STRING_BASE64, decodedBytes, &decodedSize, NULL, NULL // )) { // SAFE_FREE(decodedBytes); // SAFE_FREE(base64Utf8); // return NULL; // } // // // 输出结果并清理中间变量 // *outSize = decodedSize; // SAFE_FREE(base64Utf8); // return decodedBytes; // 返回解码后的字节数组 //} int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 加载Scintilla动态库并注册窗口类 HMODULE hSci = LoadLibrary(L"Scintilla.dll"); // 需确保该DLL在程序目录下 if (hSci == NULL) { MessageBox(NULL, L"无法加载Scintilla.dll", L"错误", MB_ICONERROR); return 0; } const char CLASS_NAME[] = "SimpleNotepadClass"; WNDCLASS wc = { 0 }; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.hCursor = LoadCursor(NULL, IDC_ARROW); RegisterClass(&wc); // 创建主窗口 HWND hWnd = CreateWindowEx( 0, CLASS_NAME, L"Base64Converter", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, // WS_CLIPCHILDREN避免子控件重绘问题 CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL ); if (hWnd == NULL) return 0; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // 消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } // 窗口消息处理 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: { // 创建菜单 HMENU hMenu = CreateMenu(); // 只添加一个菜单项(按钮),ID设为1,文本可自定义 AppendMenu(hMenu, MF_STRING, 1, L"转成文件导出到目录"); // 单个菜单项,&C表示Alt+C为快捷键 SetMenu(hWnd, hMenu); // 创建Scintilla编辑控件(添加WS_TABSTOP样式) hScintilla = CreateWindowEx( 0, L"Scintilla", L"", WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | WS_TABSTOP, // 增加WS_TABSTOP 0, 0, 0, 0, hWnd, (HMENU)100, ((LPCREATESTRUCT)lParam)->hInstance, NULL ); InitScintilla(hWnd); // 创建后主动设置焦点到Scintilla SetFocus(hScintilla); break; } case WM_SIZE: { // 窗口大小改变时,调整Scintilla控件大小 RECT rc; GetClientRect(hWnd, &rc); MoveWindow(hScintilla, 0, 0, rc.right, rc.bottom, TRUE); break; } case WM_COMMAND: { switch (LOWORD(wParam)) { case 1: // 这里的1对应上面定义的菜单项ID // 调用封装后的处理函数 HandleConvertAction(hWnd, hScintilla); break; case 4: DestroyWindow(hWnd); break; } break; } case WM_DESTROY: PostQuitMessage(0); break; // 处理粘贴消息 case WM_PASTE: // 将粘贴消息转发给Scintilla控件 SendMessage(hScintilla, SCI_PASTE, 0, 0); return 0; // 处理键盘快捷键(确保Ctrl+V能触发粘贴) case WM_KEYDOWN: // 检测Ctrl+V组合键 if (wParam == 'V' && (GetKeyState(VK_CONTROL) & 0x8000)) { SendMessage(hScintilla, SCI_PASTE, 0, 0); return 0; } break; case WM_SETFOCUS: // 当窗口获得焦点时,将焦点传递给Scintilla控件 SetFocus(hScintilla); return 0; default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0; } // 转换处理函数的实现 void HandleConvertAction(HWND hWnd, HWND hScintilla) { // 获取Scintilla中的文本长度 int textLength = SendMessage(hScintilla, SCI_GETLENGTH, 0, 0); if (textLength == 0) { // 文本为空时弹窗提示 MessageBox(hWnd, L"输入区域不能为空,请先输入内容!", L"提示", MB_ICONWARNING | MB_OK); return; } // 弹出目录选择对话框 TCHAR szDir[MAX_PATH] = { 0 }; // 存储选择的目录路径 BROWSEINFOW bi = { 0 }; bi.hwndOwner = hWnd; // 父窗口句柄 bi.pszDisplayName = szDir; // 接收选择的目录名称 bi.lpszTitle = L"请选择导出目录"; // 对话框标题 bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; // 只允许选择文件系统目录,使用新样式 // 显示目录选择对话框 LPITEMIDLIST pidl = SHBrowseForFolderW(&bi); if (pidl == NULL) { // 用户取消选择 MessageBox(hWnd, L"已取消导出", L"提示", MB_OK); return; } // 将选择的目录ID转换为实际路径 if (!SHGetPathFromIDListW(pidl, szDir)) { MessageBox(hWnd, L"获取目录路径失败", L"错误", MB_ICONERROR | MB_OK); CoTaskMemFree(pidl); // 释放内存 return; } // 释放资源 CoTaskMemFree(pidl); //输出方式仍需根据项目的字符集(ANSI / Unicode) 选择对应方法 //右键点击项目名称→“属性”→“配置属性”→“高级”→“高级属性”→“字符集” // 3. 显示选择的目录(此处可替换为实际导出逻辑) // 设置控制台为 UTF-8 编码(避免乱码) SetConsoleOutputCP(CP_UTF8); /* 调试输出(自动适配 Unicode/ANSI) OutputDebugString 是一个宏,会根据字符集自动映射到: Unicode 环境 → OutputDebugStringW(接收宽字符串 wchar_t*) ANSI 环境 → OutputDebugStringA(接收ANSI字符串 char*) _T("字符串")也会自动适配:Unicode 环境下为宽字符串(L"字符串"),ANSI 环境下为 ANSI字符串("字符串")。 */ // OutputDebugString(_T("当前目录:")); // 输出固定字符串 OutputDebugString(szDir); // 输出 TCHAR 数组 OutputDebugString(_T("\n")); // 输出换行 // 2. 获取Scintilla中的Base64字符串 // 分配缓冲区(+1用于存储终止符) //WCHAR* base64Str = (WCHAR*)LocalAlloc(LPTR, (textLength + 1) * sizeof(WCHAR)); /*if (!base64Str) { MessageBox(hWnd, L"内存分配失败", L"错误", MB_ICONERROR | MB_OK); return; }*/ // 先获取 ANSI/UTF-8 编码的文本(用 char* 接收) char* ansiStr = (char*)LocalAlloc(LPTR, (textLength + 1) * sizeof(char)); // +1 留空字符位置 SendMessage(hScintilla, SCI_GETTEXT, textLength + 1, (LPARAM)ansiStr); // 将 ANSI/UTF-8 转换为宽字符(WCHAR*) // ->计算转换所需的宽字符数 int wideCharCount = MultiByteToWideChar( CP_UTF8, // 假设 Scintilla 用 UTF-8 编码(若为 ANSI 则用 CP_ACP) 0, // 转换选项(0 为默认) ansiStr, // 源 ANSI/UTF-8 字符串 -1, // 自动计算源字符串长度(包含空字符) NULL, // 目标缓冲区(先传 NULL 计算长度) 0 // 目标缓冲区大小(0 表示仅计算长度) ); // ->分配宽字符缓冲区并转换 // WCHAR是宽字符串,每个字符占2个字节 WCHAR* wideStr = (WCHAR*)LocalAlloc(LPTR, wideCharCount * sizeof(WCHAR)); MultiByteToWideChar( CP_UTF8, // 同上,与源编码一致 0, ansiStr, -1, wideStr, // 目标宽字符缓冲区 wideCharCount // 缓冲区大小(用上面计算的结果) ); //OutputDebugStringW(L"获取到的Base64字符串:\n"); //OutputDebugStringW(wideStr); // 直接传 WCHAR*,无需转换 //OutputDebugStringW(L"\n"); BYTE* decodedBytes = NULL; DWORD decodedSize = 0; // 调用解码函数 if (Base64DecodeWide(wideStr, &decodedBytes, &decodedSize)) { // 解码成功:decodedBytes 是解码后的字节数组,decodedSize 是长度 OutputDebugStringW(L"解码成功!字节数:"); WCHAR sizeStr[32] = { 0 }; // 正确调用:添加缓冲区大小 _countof(sizeStr) _itow_s(decodedSize, sizeStr, _countof(sizeStr), 10); // 转换数字为宽字符串 OutputDebugStringW(sizeStr); OutputDebugStringW(L"\n"); // 初始化COM库(CoCreateGuid依赖COM) CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); char* uuid = GenerateUUID(); if (uuid) { OutputDebugStringW(L"生成的UUID: "); OutputDebugStringW(uuid); OutputDebugStringW(L"\n"); LocalFree(uuid); // 必须释放内存 } else { printf("UUID生成失败\n"); } // 释放COM库 CoUninitialize(); // 使用字节数组(例如写入文件、解析图片等) // ... // 4. 步骤2:调用字节数组写入文件函数(输出为PNG图片文件) //LPCWSTR outputPath = L"E:\\record\\2025\\09\\15\\test_output.png"; // 输出文件路径 //const char* tempStr = '\\' + uuid + '.png'; char str1[50] = "\\"; strcat(str1, uuid); strcat(str1, ".png"); LPCWSTR outputPath = ConcatToLPCWSTR(szDir, str1); //szDir BOOL writeOk = WriteBytesToFile(decodedBytes, decodedSize, outputPath); if (writeOk) { OutputDebugStringW(L"字节数组写入文件成功!"); } else { OutputDebugStringW(L"字节数组写入文件失败!"); } // 用完后释放内存 LocalFree(decodedBytes); // 必须释放内存 //free(combined); } else { OutputDebugStringW(L"解码失败!\n"); } LocalFree(wideStr); LocalFree(ansiStr); } // 初始化Scintilla控件(设置语法高亮、行号等) void InitScintilla(HWND hWnd) { // 必须先发送SCI_SETFONT以初始化字体 SendMessage(hScintilla, SCI_STYLESETFONT, 0, (LPARAM)"Consolas"); SendMessage(hScintilla, SCI_STYLESETSIZE, 10, 0); // 字体大小 // 显示行号 SendMessage(hScintilla, SCI_SETMARGINTYPEN, 0, SC_MARGIN_NUMBER); // 第0个边距用于行号 SendMessage(hScintilla, SCI_SETMARGINWIDTHN, 0, 50); // 行号边距宽度 // 设置语法高亮(以C语言为例) SendMessage(hScintilla, SCI_SETLEXER, SCLEX_CPP, 0); // 使用C++语法解析器 // 设置关键字颜色(示例:关键字为蓝色) SendMessage(hScintilla, SCI_STYLESETFORE, SCE_C_WORD, 0x0000FF); // 关键字颜色 SendMessage(hScintilla, SCI_SETKEYWORDS, 0, (LPARAM)"if else for while int char"); // 关键字列表 // 新增:启用自动换行(按单词换行) SendMessage(hScintilla, SCI_SETWRAPMODE, SC_WRAP_CHAR, 0); } // 打开文件并加载到Scintilla void DoFileOpen(HWND hWnd) { OPENFILENAME ofn = { 0 }; char szFile[MAX_PATH] = ""; ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hWnd; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = L"文本文件(*.txt)\0*.txt\0C文件(*.c)\0*.c\0所有文件(*.*)\0*.*\0"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; if (GetOpenFileName(&ofn)) { // 读取文件内容 FILE* f = fopen(szFile, "rb"); if (f) { fseek(f, 0, SEEK_END); int nSize = ftell(f); fseek(f, 0, SEEK_SET); char* pBuf = malloc(nSize + 1); fread(pBuf, 1, nSize, f); pBuf[nSize] = '\0'; fclose(f); // 将内容显示到Scintilla SendMessage(hScintilla, SCI_CLEARALL, 0, 0); SendMessage(hScintilla, SCI_SETTEXT, 0, (LPARAM)pBuf); free(pBuf); // 记录文件名 strcpy(g_szFileName, szFile); SetWindowText(hWnd, g_szFileName); // 更新窗口标题 } } } // 保存Scintilla内容到文件 void DoFileSave(HWND hWnd) { char szFile[MAX_PATH] = ""; if (g_szFileName[0] == '\0') { // 若未保存过,弹出另存为对话框 OPENFILENAME ofn = { 0 }; ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hWnd; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = L"文本文件(*.txt)\0*.txt\0C文件(*.c)\0*.c\0所有文件(*.*)\0*.*\0"; ofn.nFilterIndex = 1; ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT; if (!GetSaveFileName(&ofn)) return; strcpy(g_szFileName, szFile); } // 从Scintilla获取文本内容 int nLen = SendMessage(hScintilla, SCI_GETLENGTH, 0, 0) + 1; char* pBuf = malloc(nLen); SendMessage(hScintilla, SCI_GETTEXT, nLen, (LPARAM)pBuf); // 写入文件 FILE* f = fopen(g_szFileName, "wb"); if (f) { fwrite(pBuf, 1, nLen - 1, f); // 减去最后的'\0' fclose(f); SetWindowText(hWnd, g_szFileName); // 更新窗口标题 } free(pBuf); } /** * 将 WCHAR* 类型的 Base64 字符串解码为字节数组 * @param base64Wide 宽字符 Base64 字符串(WCHAR*) * @param outBuffer 输出:解码后的字节数组(需调用者释放) * @param outSize 输出:解码后的字节数组长度 * @return 成功返回 TRUE,失败返回 FALSE */ BOOL Base64DecodeWide(WCHAR* base64Wide, BYTE** outBuffer, DWORD* outSize) { // 步骤1:将 WCHAR*(宽字符)转换为 UTF-8 多字节字符串(char*) int utf8Length = WideCharToMultiByte( CP_UTF8, // 目标编码:UTF-8 0, // 转换选项(0 为默认) base64Wide, // 源宽字符串 -1, // 自动计算长度(包含终止符) NULL, // 目标缓冲区(先计算长度) 0, // 缓冲区大小(0 表示仅计算) NULL, NULL ); if (utf8Length == 0) return FALSE; // 分配 UTF-8 缓冲区并转换 char* base64Utf8 = (char*)LocalAlloc(LPTR, utf8Length * sizeof(char)); if (!base64Utf8) return FALSE; if (WideCharToMultiByte( CP_UTF8, 0, base64Wide, -1, base64Utf8, utf8Length, NULL, NULL ) == 0) { SAFE_FREE(base64Utf8); return FALSE; } // 步骤2:使用 Windows API 解码 Base64 字符串为字节数组 // 2.1 先获取解码所需的缓冲区大小 DWORD decodedSize = 0; if (!CryptStringToBinaryA( base64Utf8, // 源 Base64 字符串(UTF-8) 0, // 字符串长度(0 表示自动计算) CRYPT_STRING_BASE64, // 编码类型:Base64 NULL, // 目标缓冲区(先计算大小) &decodedSize, // 输出:所需缓冲区大小 NULL, NULL )) { SAFE_FREE(base64Utf8); return FALSE; } // 2.2 分配缓冲区并解码 *outBuffer = (BYTE*)LocalAlloc(LPTR, decodedSize); if (!*outBuffer) { SAFE_FREE(base64Utf8); return FALSE; } if (!CryptStringToBinaryA( base64Utf8, 0, CRYPT_STRING_BASE64, *outBuffer, &decodedSize, NULL, NULL )) { SAFE_FREE(*outBuffer); SAFE_FREE(base64Utf8); return FALSE; } // 输出结果 *outSize = decodedSize; SAFE_FREE(base64Utf8); // 释放中间缓冲区 return TRUE; } /** * 将字节数组写入指定文件 * @param bytes 要写入的字节数组 * @param byteCount 字节数组的长度 * @param filePath 目标文件路径(宽字符) * @return 成功返回TRUE,失败返回FALSE */ BOOL WriteBytesToFile(const BYTE* bytes, DWORD byteCount, LPCWSTR filePath) { // 参数合法性检查 if (!bytes || byteCount == 0 || !filePath) { return FALSE; } // 打开/创建文件(覆盖现有文件) HANDLE hFile = CreateFileW( filePath, // 文件路径 GENERIC_WRITE, // 写入权限 0, // 不共享 NULL, // 默认安全属性 CREATE_ALWAYS, // 存在则覆盖,不存在则创建 FILE_ATTRIBUTE_NORMAL, // 正常文件属性 NULL // 无模板 ); if (hFile == INVALID_HANDLE_VALUE) { return FALSE; // 文件打开失败 } // 写入字节数组 DWORD bytesWritten = 0; BOOL writeSuccess = WriteFile( hFile, // 文件句柄 bytes, // 要写入的数据 byteCount, // 数据长度 &bytesWritten, // 实际写入字节数 NULL // 无重叠操作 ); // 检查是否完全写入 BOOL success = writeSuccess && (bytesWritten == byteCount); // 关闭文件句柄(无论成功与否都要关闭) CloseHandle(hFile); return success; } // 生成UUID并返回字符串(格式:8-4-4-4-12,共36个字符) // 注意:调用后需用LocalFree释放返回的字符串,避免内存泄漏 char* GenerateUUID() { GUID guid; HRESULT result = CoCreateGuid(&guid); if (result != S_OK) { return NULL; // 生成失败返回NULL } // 转换GUID为宽字符串(格式带花括号,如 {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}) // 方法1:使用栈上的固定大小缓冲区(简单场景,无需手动释放) WCHAR wideUuid[40]; // 40足够容纳带花括号的UUID(38字符+终止符) if (StringFromGUID2(&guid, wideUuid, _countof(wideUuid)) == 0) { return NULL; // 转换失败 } //WCHAR* wideUuid; //if (StringFromGUID2(&guid, wideUuid, 40) == 0) { // 40足够容纳UUID字符串 // return NULL; //} // 转换宽字符串为ANSI字符串(去掉花括号) char* ansiUuid = (char*)LocalAlloc(LPTR, 37); // 36个字符 + 终止符 if (!ansiUuid) { LocalFree(wideUuid); return NULL; } // 提取中间36个字符(去掉首尾的花括号) WideCharToMultiByte(CP_ACP, 0, wideUuid + 1, 36, ansiUuid, 36, NULL, NULL); ansiUuid[36] = '\0'; // 手动添加终止符 // 释放宽字符串内存 //LocalFree(wideUuid); return ansiUuid; } // 拼接LPCWSTR(宽字符串)和char*(窄字符串),返回LPCWSTR(需用LocalFree释放) // 注意:返回的LPCWSTR本质是动态分配的WCHAR*,使用后必须释放 LPCWSTR ConcatToLPCWSTR(LPCWSTR wideStr, const char* ansiStr) { if (!wideStr || !ansiStr) { return NULL; // 输入参数无效 } // 步骤1:将char*(窄字符串)转换为宽字符串WCHAR* int ansiLen = strlen(ansiStr); // 计算转换后的宽字符串长度(不含终止符) int wideConvLen = MultiByteToWideChar( CP_ACP, // 源编码(ANSI,需与char*编码一致,UTF-8用CP_UTF8) 0, // 转换选项(0表示默认) ansiStr, // 源窄字符串 ansiLen, // 源长度(不含终止符) NULL, // 目标缓冲区(先计算长度) 0 // 目标缓冲区大小(0表示仅计算长度) ); if (wideConvLen == 0) { return NULL; // 转换失败 } // 分配转换后的宽字符串缓冲区(+1用于终止符) WCHAR* convertedWide = (WCHAR*)LocalAlloc(LPTR, (wideConvLen + 1) * sizeof(WCHAR)); if (!convertedWide) { return NULL; // 内存分配失败 } // 执行转换 if (MultiByteToWideChar( CP_ACP, 0, ansiStr, ansiLen, convertedWide, wideConvLen ) == 0) { LocalFree(convertedWide); // 转换失败,释放内存 return NULL; } convertedWide[wideConvLen] = L'\0'; // 手动添加宽字符串终止符 // 步骤2:拼接两个宽字符串(原LPCWSTR + 转换后的宽字符串) int originalWideLen = wcslen(wideStr); // 原宽字符串长度(不含终止符) int totalLen = originalWideLen + wideConvLen; // 总长度(不含终止符) // 分配拼接后的缓冲区(+1用于终止符) WCHAR* result = (WCHAR*)LocalAlloc(LPTR, (totalLen + 1) * sizeof(WCHAR)); if (!result) { LocalFree(convertedWide); // 内存分配失败,释放临时缓冲区 return NULL; } // 安全复制原宽字符串到结果缓冲区 wcscpy_s(result, totalLen + 1, wideStr); // 安全追加转换后的宽字符串 wcscat_s(result, totalLen + 1, convertedWide); // 释放临时转换的宽字符串 LocalFree(convertedWide); // WCHAR* 可隐式转换为 LPCWSTR(const WCHAR*) return result; } // 拼接多个const char*字符串,返回可作为const char*的结果(需用free释放) char* ConcatAnsiStrings(int count, ...) { if (count <= 0) return NULL; va_list args; va_start(args, count); // 步骤1:计算所有字符串的总长度(不含终止符) size_t totalLen = 0; for (int i = 0; i < count; i++) { const char* str = va_arg(args, const char*); if (!str) { // 忽略NULL,避免计算错误 continue; } totalLen += strlen(str); } va_end(args); // 重置参数列表 // 步骤2:分配内存(总长度 + 1个终止符) char* result = (char*)malloc(totalLen + 1); if (!result) return NULL; // 步骤3:拼接所有字符串 result[0] = '\0'; // 初始化空字符串 va_start(args, count); for (int i = 0; i < count; i++) { const char* str = va_arg(args, const char*); if (!str) { continue; } // 安全追加字符串(确保不溢出) if (strcat_s(result, totalLen + 1, str) != 0) { free(result); va_end(args); return NULL; } } va_end(args); return result; } </syntaxhighlight>
返回至
SimpleNotepad
。
导航菜单
个人工具
登录
名字空间
页面
讨论
变种
视图
阅读
查看源代码
查看历史
更多
搜索
导航
首页
Spring Boot 2 零基础入门
Spring Cloud
Spring Boot
设计模式之禅
VUE
Vuex
Maven
算法
技能树
Wireshark
IntelliJ IDEA
ElasticSearch
VirtualBox
软考
正则表达式
程序员精讲
软件设计师精讲
初级程序员 历年真题
C
SQL
Java
FFmpeg
Redis
Kafka
MySQL
Spring
Docker
JMeter
Apache
Linux
Windows
Git
ZooKeeper
设计模式
Python
MyBatis
软件
数学
PHP
IntelliJ IDEA
CS基础知识
网络
项目
未分类
MediaWiki
镜像
问题
健身
国债
英语
烹饪
常见术语
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息